模型

在本教程中,我们介绍 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 官方文档

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

  • __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='2025-09-20 01:31:30.380_320018', created_at='2025-09-20 01:31:30.380', 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='2025-09-20 01:31:31.870_2d014e', created_at='2025-09-20 01:31:31.870', type='chat', usage=ChatUsage(input_tokens=10, output_tokens=7, time=1.489284, type='chat'), metadata=None)
作为 Msg 的响应: Msg(id='Zj2Q86hcx2bc58cPFQb7Zi', name='Friday', content=[{'type': 'text', 'text': '你好!有什么可以帮助你的吗?'}], role='assistant', metadata=None, timestamp='2025-09-20 01:31:31.870', 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='2025-09-20 01:31:32.977_813c95', created_at='2025-09-20 01:31:32.977', type='chat', usage=ChatUsage(input_tokens=26, output_tokens=1, time=1.105463, type='chat'), metadata=None)

块 1
        类型: <class 'list'>
        ChatResponse(content=[{'type': 'text', 'text': '1\n'}], id='2025-09-20 01:31:33.095_cadfe8', created_at='2025-09-20 01:31:33.095', type='chat', usage=ChatUsage(input_tokens=26, output_tokens=2, time=1.223066, type='chat'), metadata=None)

块 2
        类型: <class 'list'>
        ChatResponse(content=[{'type': 'text', 'text': '1\n2'}], id='2025-09-20 01:31:33.110_2589a8', created_at='2025-09-20 01:31:33.110', type='chat', usage=ChatUsage(input_tokens=26, output_tokens=3, time=1.237804, type='chat'), metadata=None)

块 3
        类型: <class 'list'>
        ChatResponse(content=[{'type': 'text', 'text': '1\n2\n'}], id='2025-09-20 01:31:33.167_fd92ab', created_at='2025-09-20 01:31:33.167', type='chat', usage=ChatUsage(input_tokens=26, output_tokens=4, time=1.295022, type='chat'), metadata=None)

块 4
        类型: <class 'list'>
        ChatResponse(content=[{'type': 'text', 'text': '1\n2\n3\n4\n'}], id='2025-09-20 01:31:33.413_70127e', created_at='2025-09-20 01:31:33.413', type='chat', usage=ChatUsage(input_tokens=26, output_tokens=8, time=1.541148, type='chat'), metadata=None)

块 5
        类型: <class 'list'>
        ChatResponse(content=[{'type': 'text', 'text': '1\n2\n3\n4\n5\n6\n'}], id='2025-09-20 01:31:33.694_5d3beb', created_at='2025-09-20 01:31:33.694', type='chat', usage=ChatUsage(input_tokens=26, output_tokens=12, time=1.82262, type='chat'), metadata=None)

块 6
        类型: <class 'list'>
        ChatResponse(content=[{'type': 'text', 'text': '1\n2\n3\n4\n5\n6\n7\n8\n'}], id='2025-09-20 01:31:34.664_3fccf7', created_at='2025-09-20 01:31:34.664', type='chat', usage=ChatUsage(input_tokens=26, output_tokens=16, time=2.791982, type='chat'), metadata=None)

块 7
        类型: <class 'list'>
        ChatResponse(content=[{'type': 'text', 'text': '1\n2\n3\n4\n5\n6\n7\n8\n9\n10'}], id='2025-09-20 01:31:34.903_4a9398', created_at='2025-09-20 01:31:34.903', type='chat', usage=ChatUsage(input_tokens=26, output_tokens=20, time=3.031548, type='chat'), metadata=None)

块 8
        类型: <class 'list'>
        ChatResponse(content=[{'type': 'text', 'text': '1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n11\n'}], id='2025-09-20 01:31:35.170_e49356', created_at='2025-09-20 01:31:35.170', type='chat', usage=ChatUsage(input_tokens=26, output_tokens=24, time=3.297699, type='chat'), metadata=None)

块 9
        类型: <class 'list'>
        ChatResponse(content=[{'type': 'text', 'text': '1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n11\n12\n1'}], id='2025-09-20 01:31:35.421_db0427', created_at='2025-09-20 01:31:35.421', type='chat', usage=ChatUsage(input_tokens=26, output_tokens=28, time=3.549505, type='chat'), metadata=None)

块 10
        类型: <class 'list'>
        ChatResponse(content=[{'type': 'text', 'text': '1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n11\n12\n13\n14'}], id='2025-09-20 01:31:35.673_ea4021', created_at='2025-09-20 01:31:35.673', type='chat', usage=ChatUsage(input_tokens=26, output_tokens=32, time=3.800738, type='chat'), metadata=None)

块 11
        类型: <class 'list'>
        ChatResponse(content=[{'type': 'text', 'text': '1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n11\n12\n13\n14\n15\n'}], id='2025-09-20 01:31:35.935_ab9310', created_at='2025-09-20 01:31:35.935', type='chat', usage=ChatUsage(input_tokens=26, output_tokens=36, time=4.063609, type='chat'), metadata=None)

块 12
        类型: <class 'list'>
        ChatResponse(content=[{'type': 'text', 'text': '1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n11\n12\n13\n14\n15\n16\n1'}], id='2025-09-20 01:31:36.159_8e246f', created_at='2025-09-20 01:31:36.159', type='chat', usage=ChatUsage(input_tokens=26, output_tokens=40, time=4.287597, type='chat'), metadata=None)

块 13
        类型: <class 'list'>
        ChatResponse(content=[{'type': 'text', 'text': '1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n11\n12\n13\n14\n15\n16\n17\n18'}], id='2025-09-20 01:31:36.464_163c2c', created_at='2025-09-20 01:31:36.464', type='chat', usage=ChatUsage(input_tokens=26, output_tokens=44, time=4.592653, type='chat'), metadata=None)

块 14
        类型: <class 'list'>
        ChatResponse(content=[{'type': 'text', 'text': '1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n11\n12\n13\n14\n15\n16\n17\n18\n19\n'}], id='2025-09-20 01:31:36.721_241573', created_at='2025-09-20 01:31:36.721', type='chat', usage=ChatUsage(input_tokens=26, output_tokens=48, time=4.84891, type='chat'), metadata=None)

块 15
        类型: <class 'list'>
        ChatResponse(content=[{'type': 'text', 'text': '1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n11\n12\n13\n14\n15\n16\n17\n18\n19\n20'}], id='2025-09-20 01:31:36.901_fe4825', created_at='2025-09-20 01:31:36.901', type='chat', usage=ChatUsage(input_tokens=26, output_tokens=50, time=5.029228, type='chat'), metadata=None)

块 16
        类型: <class 'list'>
        ChatResponse(content=[{'type': 'text', 'text': '1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n11\n12\n13\n14\n15\n16\n17\n18\n19\n20'}], id='2025-09-20 01:31:36.922_3e0e32', created_at='2025-09-20 01:31:36.922', type='chat', usage=ChatUsage(input_tokens=26, output_tokens=50, time=5.049813, type='chat'), 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最后,确保语言亲切,避免学术化,让用户感到被理解和支持。可能需要提醒用户,自我认知是一个持续的过程,鼓励他们继续探索。'}, {'type': 'text', 'text': '“我是谁?”这个问题看似简单,却蕴含着深刻的哲学与自我探索的意义。不同的人、不同的阶段可能会有不同的答案。以下是一些可能的思考方向,或许能帮助你更接近自己的答案:\n\n---\n\n### 1. **从存在主义的角度**  \n   - **“我思故我在”**(笛卡尔):你的思考、感受、选择本身,就是你存在的证明。你是一个能反思、能提问的主体。  \n   - **“我是自由的”**(萨特):你并非被定义的“谁”,而是通过每一次选择、行动和决定,不断塑造自己的身份。  \n\n---\n\n### 2. **从心理学的角度**  \n   - **自我认知**:你可能是“过去经历的总和”——你的性格、习惯、价值观,都源于成长环境、教育、人际关系等。  \n   - **动态的自我**:你不是一成不变的“谁”,而是一个不断变化的个体。今天的你可能与昨天的你不同,未来的你也可能超越现在的自己。  \n\n---\n\n### 3. **从灵性或哲学的角度**  \n   - **“我是谁”是修行的起点**:许多灵性传统(如佛教、印度教)认为,真正的“我”并非肉体或名字,而是超越表象的本体。  \n   - **“我是光”**(基督教)或“我是道”(道教):某些信仰体系将“我”视为宇宙或真理的一部分,超越个体的局限。  \n\n---\n\n### 4. **从日常生活的角度**  \n   - **身份标签**:你可能是某个职业、家庭角色(如父母、子女)、兴趣爱好的集合。  \n   - **更深层的自我**:也许你更在意的是“我想要什么”“我为什么活着”“我如何与世界连接”。  \n\n---\n\n### 5. **如果这是你此刻的困惑**  \n   - **允许自己不确定**:很多人一生都在追问“我是谁”,这本身是成长的一部分。  \n   - **通过行动探索**:尝试新事物、与他人交流、记录内心感受,可能会逐渐发现更清晰的答案。  \n   - **接纳“未完成”的自己**:你不需要立刻找到全部答案,生命的复杂性正是它的魅力所在。  \n\n---\n\n### 最后,或许可以这样想:  \n**“我是谁”不是一个需要被解答的谜题,而是一段持续的旅程。**  \n每一次提问,都是你与自己对话的开始。你不需要急于找到终点,只需带着好奇和勇气,继续前行。  \n\n如果你愿意分享更多背景,我也可以尝试更具体地帮你分析~ 🌱'}], id='2025-09-20 01:31:46.001_3ba4a9', created_at='2025-09-20 01:31:46.001', type='chat', usage=ChatUsage(input_tokens=11, output_tokens=805, time=9.074034, type='chat'), 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 15.627 seconds)

Gallery generated by Sphinx-Gallery