模型

在本教程中,我们介绍 AgentScope 中集成的模型 API、如何使用它们,以及如何集成新的模型 API。 AgentScope 目前支持的模型 API 和模型提供商包括:

API

兼容

流式

工具

视觉

推理

OpenAI

OpenAIChatModel

vLLM, DeepSeek

DashScope

DashScopeChatModel

Anthropic

AnthropicChatModel

Gemini

GeminiChatModel

Ollama

OllamaChatModel

备注

当使用 vLLM 时,需要在部署时为不同模型配置相应的工具调用参数,例如 --enable-auto-tool-choice--tool-call-parser 等参数。更多详情请参考 vLLM 官方文档

备注

兼容 OpenAI API 的模型(例如 vLLM 部署的模型),推荐使用 OpenAIChatModel,并通过 client_kwargs={"base_url": "http://your-api-endpoint"} 参数指定 API 端点。例如:

OpenAIChatModel(client_kwargs={"base_url": "http://localhost:8000/v1"})

备注

模型的行为参数(如温度、最大长度等)可以通过 generate_kwargs 参数在构造函数中提前设定。例如:

OpenAIChatModel(generate_kwargs={"temperature": 0.3, "max_tokens": 1000})

为了提供统一的模型接口,上述所有类均被统一为:

  • __call__ 函数的前三个参数是 messagestoolstool_choice,分别是输入消息,工具函数的 JSON schema,以及工具选择的模式。

  • 非流式返回时,返回类型是 ChatResponse 实例;流式返回时,返回的是 ChatResponse 的异步生成器。

备注

不同的模型 API 在输入消息格式上有所不同,AgentScope 通过 formatter 模块处理消息的转换,请参考 format

ChatResponse 包含大模型生成的推理/文本/工具使用内容、身份、创建时间和使用信息。

import asyncio
import json
import os

from agentscope.message import TextBlock, ToolUseBlock, ThinkingBlock, Msg
from agentscope.model import ChatResponse, DashScopeChatModel

response = ChatResponse(
    content=[
        ThinkingBlock(
            type="thinking",
            thinking="我应该在 Google 上搜索 AgentScope。",
        ),
        TextBlock(type="text", text="我将在 Google 上搜索 AgentScope。"),
        ToolUseBlock(
            type="tool_use",
            id="642n298gjna",
            name="google_search",
            input={"query": "AgentScope"},
        ),
    ],
)

print(response)
ChatResponse(content=[{'type': 'thinking', 'thinking': '我应该在 Google 上搜索 AgentScope。'}, {'type': 'text', 'text': '我将在 Google 上搜索 AgentScope。'}, {'type': 'tool_use', 'id': '642n298gjna', 'name': 'google_search', 'input': {'query': 'AgentScope'}}], id='2026-03-12 03:29:19.081_201680', created_at='2026-03-12 03:29:19.081', type='chat', usage=None, metadata=None)

DashScopeChatModel 为例,调用和返回结果如下:

async def example_model_call() -> None:
    """使用 DashScopeChatModel 的示例。"""
    model = DashScopeChatModel(
        model_name="qwen-max",
        api_key=os.environ["DASHSCOPE_API_KEY"],
        stream=False,
    )

    res = await model(
        messages=[
            {"role": "user", "content": "你好!"},
        ],
    )

    # 您可以直接使用响应内容创建 ``Msg`` 对象
    msg_res = Msg("Friday", res.content, "assistant")

    print("LLM 返回结果:", res)
    print("作为 Msg 的响应:", msg_res)


asyncio.run(example_model_call())
LLM 返回结果: ChatResponse(content=[{'type': 'text', 'text': '你好!有什么我可以帮助你的吗?'}], id='2026-03-12 03:29:20.550_74f84f', created_at='2026-03-12 03:29:20.551', type='chat', usage=ChatUsage(input_tokens=10, output_tokens=8, time=1.468278, type='chat', metadata=GenerationUsage(input_tokens=10, output_tokens=8)), metadata=None)
作为 Msg 的响应: Msg(id='PgaCKxKjBUvzgufWCixitg', name='Friday', content=[{'type': 'text', 'text': '你好!有什么我可以帮助你的吗?'}], role='assistant', metadata={}, timestamp='2026-03-12 03:29:20.551', invocation_id='None')

流式返回

要启用流式返回,请在模型的构造函数中将 stream 参数设置为 True。 流式返回中,__call__ 方法将返回一个 异步生成器,该生成器迭代返回 ChatResponse 实例。

备注

AgentScope 中的流式返回结果为 累加式,这意味着每个 chunk 中的内容包含所有之前的内容加上新生成的内容。

async def example_streaming() -> None:
    """使用流式模型的示例。"""
    model = DashScopeChatModel(
        model_name="qwen-max",
        api_key=os.environ["DASHSCOPE_API_KEY"],
        stream=True,
    )

    generator = await model(
        messages=[
            {
                "role": "user",
                "content": "从 1 数到 20,只报告数字,不要任何其他信息。",
            },
        ],
    )
    print("响应的类型:", type(generator))

    i = 0
    async for chunk in generator:
        print(f"块 {i}")
        print(f"\t类型: {type(chunk.content)}")
        print(f"\t{chunk}\n")
        i += 1


asyncio.run(example_streaming())
响应的类型: <class 'async_generator'>
块 0
        类型: <class 'list'>
        ChatResponse(content=[{'type': 'text', 'text': '1'}], id='2026-03-12 03:29:21.616_4d8e84', created_at='2026-03-12 03:29:21.616', type='chat', usage=ChatUsage(input_tokens=26, output_tokens=1, time=1.063673, type='chat', metadata=GenerationUsage(input_tokens=26, output_tokens=1)), metadata=None)

块 1
        类型: <class 'list'>
        ChatResponse(content=[{'type': 'text', 'text': '1 2 '}], id='2026-03-12 03:29:21.755_148a5b', created_at='2026-03-12 03:29:21.755', type='chat', usage=ChatUsage(input_tokens=26, output_tokens=4, time=1.202535, type='chat', metadata=GenerationUsage(input_tokens=26, output_tokens=4)), metadata=None)

块 2
        类型: <class 'list'>
        ChatResponse(content=[{'type': 'text', 'text': '1 2 3 4'}], id='2026-03-12 03:29:21.820_0a4d09', created_at='2026-03-12 03:29:21.820', type='chat', usage=ChatUsage(input_tokens=26, output_tokens=7, time=1.267814, type='chat', metadata=GenerationUsage(input_tokens=26, output_tokens=7)), metadata=None)

块 3
        类型: <class 'list'>
        ChatResponse(content=[{'type': 'text', 'text': '1 2 3 4 5 '}], id='2026-03-12 03:29:21.886_2cb0db', created_at='2026-03-12 03:29:21.886', type='chat', usage=ChatUsage(input_tokens=26, output_tokens=10, time=1.333787, type='chat', metadata=GenerationUsage(input_tokens=26, output_tokens=10)), metadata=None)

块 4
        类型: <class 'list'>
        ChatResponse(content=[{'type': 'text', 'text': '1 2 3 4 5 6 7 8 '}], id='2026-03-12 03:29:22.897_83915c', created_at='2026-03-12 03:29:22.897', type='chat', usage=ChatUsage(input_tokens=26, output_tokens=16, time=2.344334, type='chat', metadata=GenerationUsage(input_tokens=26, output_tokens=16)), metadata=None)

块 5
        类型: <class 'list'>
        ChatResponse(content=[{'type': 'text', 'text': '1 2 3 4 5 6 7 8 9 10 1'}], id='2026-03-12 03:29:23.013_8efbdb', created_at='2026-03-12 03:29:23.013', type='chat', usage=ChatUsage(input_tokens=26, output_tokens=22, time=2.460341, type='chat', metadata=GenerationUsage(input_tokens=26, output_tokens=22)), metadata=None)

块 6
        类型: <class 'list'>
        ChatResponse(content=[{'type': 'text', 'text': '1 2 3 4 5 6 7 8 9 10 11 12 1'}], id='2026-03-12 03:29:23.154_7fb739', created_at='2026-03-12 03:29:23.154', type='chat', usage=ChatUsage(input_tokens=26, output_tokens=28, time=2.601353, type='chat', metadata=GenerationUsage(input_tokens=26, output_tokens=28)), metadata=None)

块 7
        类型: <class 'list'>
        ChatResponse(content=[{'type': 'text', 'text': '1 2 3 4 5 6 7 8 9 10 11 12 13 14 1'}], id='2026-03-12 03:29:23.314_55389b', created_at='2026-03-12 03:29:23.314', type='chat', usage=ChatUsage(input_tokens=26, output_tokens=34, time=2.761621, type='chat', metadata=GenerationUsage(input_tokens=26, output_tokens=34)), metadata=None)

块 8
        类型: <class 'list'>
        ChatResponse(content=[{'type': 'text', 'text': '1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 1'}], id='2026-03-12 03:29:23.561_79b384', created_at='2026-03-12 03:29:23.561', type='chat', usage=ChatUsage(input_tokens=26, output_tokens=40, time=3.008955, type='chat', metadata=GenerationUsage(input_tokens=26, output_tokens=40)), metadata=None)

块 9
        类型: <class 'list'>
        ChatResponse(content=[{'type': 'text', 'text': '1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 1'}], id='2026-03-12 03:29:23.573_b79afd', created_at='2026-03-12 03:29:23.573', type='chat', usage=ChatUsage(input_tokens=26, output_tokens=46, time=3.020578, type='chat', metadata=GenerationUsage(input_tokens=26, output_tokens=46)), metadata=None)

块 10
        类型: <class 'list'>
        ChatResponse(content=[{'type': 'text', 'text': '1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20'}], id='2026-03-12 03:29:23.731_5cbebd', created_at='2026-03-12 03:29:23.731', type='chat', usage=ChatUsage(input_tokens=26, output_tokens=50, time=3.178521, type='chat', metadata=GenerationUsage(input_tokens=26, output_tokens=50)), metadata=None)

块 11
        类型: <class 'list'>
        ChatResponse(content=[{'type': 'text', 'text': '1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20'}], id='2026-03-12 03:29:23.755_0f1025', created_at='2026-03-12 03:29:23.755', type='chat', usage=ChatUsage(input_tokens=26, output_tokens=50, time=3.202843, type='chat', metadata=GenerationUsage(input_tokens=26, output_tokens=50)), metadata=None)

推理模型

AgentScope 通过提供 ThinkingBlock 来支持推理模型。

async def example_reasoning() -> None:
    """使用推理模型的示例。"""
    model = DashScopeChatModel(
        model_name="qwen-turbo",
        api_key=os.environ["DASHSCOPE_API_KEY"],
        enable_thinking=True,
    )

    res = await model(
        messages=[
            {"role": "user", "content": "我是谁?"},
        ],
    )

    last_chunk = None
    async for chunk in res:
        last_chunk = chunk
    print("最终响应:")
    print(last_chunk)


asyncio.run(example_reasoning())
最终响应:
ChatResponse(content=[{'type': 'thinking', 'thinking': '好的,用户问“我是谁?”。这个问题看起来简单,但其实挺深奥的。首先,我需要考虑用户为什么会问这个问题。可能是在思考自我身份,或者有心理上的困惑,比如自我认同的问题。也有可能是在进行哲学思考,或者只是随便问问。\n\n接下来,我得分析用户可能的背景。如果用户是年轻人,可能是在探索自我,或者面临人生转折点。如果是成年人,可能是在经历某种危机或反思。也有可能用户是在测试我的反应,或者想看看我如何处理这类抽象问题。\n\n然后,我需要确定用户的需求。他们可能想要一个哲学性的回答,或者实际的建议。也有可能他们希望得到情感支持,或者只是想表达自己的困惑。这时候,我需要平衡不同可能性,提供既有深度又实用的回答。\n\n还要考虑文化差异。不同文化对“自我”的理解不同,比如东方哲学可能更强调集体,而西方可能更注重个人。但用户用中文提问,可能更倾向于东方视角,但也不能一概而论。\n\n另外,用户可能没有明确表达更深层的问题,比如对人生意义的迷茫,或者对自我价值的怀疑。这时候,我需要引导他们更具体地描述问题,或者提供一些思考方向。\n\n还要注意避免过于抽象的回答,让用户感到困惑。同时,要确保回答有帮助,而不是泛泛而谈。可能需要结合心理学、哲学或宗教的观点,但保持中立和客观。\n\n最后,检查是否有潜在的紧急情况,比如用户可能有自残或自杀的倾向,这时候需要提供适当的支持资源。但根据当前问题,可能还不至于,不过还是要注意语气,保持关怀和支持。\n'}, {'type': 'text', 'text': '“我是谁?”是一个跨越哲学、心理学、宗教和科学的深刻问题,不同领域和文化对此有不同的解读。以下是一些可能的视角,或许能帮助你思考这个问题:\n\n---\n\n### 1. **哲学视角**\n   - **存在主义**:萨特认为“存在先于本质”,人没有预设的本质,而是通过选择和行动定义自己。你通过每一次决定、每一次经历,不断“成为”自己。\n   - **东方哲学**:佛教认为“我”是五蕴(色、受、想、行、识)的暂时组合,本质上是空性;道家则强调“无我”与自然的融合。\n   - **怀疑论**:笛卡尔说“我思故我在”,但“我”是否只是思维的产物?还是更深层的存在?\n\n---\n\n### 2. **心理学视角**\n   - **自我认同**:心理学家埃里克森提出,人的发展需要通过“同一性探索”确定身份(如职业、价值观、人际关系)。你可能在寻找“我是谁”的答案,是成长的一部分。\n   - **潜意识**:弗洛伊德认为“我”由本我(本能)、自我(现实)和超我(道德)构成,而荣格则提到“个体化”过程——整合内在的阴影与光明面。\n   - **社会角色**:你可能通过家庭、职业、兴趣等标签定义自己,但这些是否真正代表“你”?\n\n---\n\n### 3. **科学视角**\n   - **生物学**:从基因到大脑神经网络,你的身体和思维是数亿年进化的结果。但“我”是否只是大脑的产物?还是某种更复杂的意识现象?\n   - **量子物理**:一些理论认为,观察者与被观察者不可分割,或许“我”是宇宙自我认知的方式。\n\n---\n\n### 4. **宗教与灵性**\n   - **基督教**:认为“我”是上帝创造的个体,灵魂与神的关系是核心。\n   - **印度教**:强调“梵我合一”——个体的“我”(Atman)与宇宙的“梵”(Brahman)本质相同。\n   - **神秘主义**:许多灵性传统认为,真正的“我”超越肉身和思维,是永恒的觉知或爱。\n\n---\n\n### 5. **日常生活的答案**\n   - **暂时性的定义**:你可以通过“我是谁?”来探索自己的特质。例如:\n     - **性格**:我是乐观/内向/好奇的?\n     - **能力**:我是擅长沟通/解决问题/创造的?\n     - **价值观**:我重视自由/责任/同理心?\n   - **关系中的角色**:我是家人、朋友、同事中的谁?这些角色如何塑造你?\n\n---\n\n### 6. **可能的困惑与挑战**\n   - **身份的流动性**:人会随着经历变化,比如从学生变为父母,身份可能不断重构。\n   - **社会的期待**:外界对“我”的定义(如职业、成就)可能与内在真实冲突。\n   - **孤独感**:当“我是谁”变得模糊时,可能感到迷失,但这也是自我探索的契机。\n\n---\n\n### 7. **你可以尝试的问题**\n   - 如果没有“社会身份”(如职业、家庭角色),我会是什么?\n   - 我最真实的感受是什么?(比如:愤怒、悲伤、喜悦、平静)\n   - 如果没有人定义我,我如何定义自己?\n   - 我的哪些特质是“天生的”,哪些是后天塑造的?\n\n---\n\n### 最终答案:**“你是正在探索‘我是谁’的你。”**\n这个问题没有标准答案,但它可能引导你更深入地理解自己。或许答案不在远方,而在你此刻的思考与感受中。如果你愿意,可以分享更多背景,我会尽力陪你一起探索。 🌱'}], id='2026-03-12 03:29:38.457_da0bcf', created_at='2026-03-12 03:29:38.457', type='chat', usage=ChatUsage(input_tokens=11, output_tokens=1173, time=14.697718, type='chat', metadata=GenerationUsage(input_tokens=11, output_tokens=1173)), metadata=None)

工具 API

不同的模型提供商在工具 API 方面有所不同,例如工具 JSON schema、工具调用/响应格式。 为了提供统一的接口,AgentScope 通过以下方式解决了这个问题:

  • 提供了统一的工具调用结构 block ToolUseBlock 和工具响应结构 ToolResultBlock

  • 在模型类的 __call__ 方法中提供统一的工具接口 tools,接受工具 JSON schema 列表,如下所示:

json_schemas = [
    {
        "type": "function",
        "function": {
            "name": "google_search",
            "description": "在 Google 上搜索查询。",
            "parameters": {
                "type": "object",
                "properties": {
                    "query": {
                        "type": "string",
                        "description": "搜索查询。",
                    },
                },
                "required": ["query"],
            },
        },
    },
]

进一步阅读

Total running time of the script: (0 minutes 19.381 seconds)

Gallery generated by Sphinx-Gallery