模型

在本教程中,我们介绍 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-02-15 03:07:03.982_1e9208', created_at='2026-02-15 03:07:03.982', 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-02-15 03:07:05.504_46d88c', created_at='2026-02-15 03:07:05.505', type='chat', usage=ChatUsage(input_tokens=10, output_tokens=8, time=1.521319, type='chat', metadata=GenerationUsage(input_tokens=10, output_tokens=8)), metadata=None)
作为 Msg 的响应: Msg(id='C4rLTyhmDd4EWTyJ5jc3tD', name='Friday', content=[{'type': 'text', 'text': '你好!有什么我可以帮助你的吗?'}], role='assistant', metadata={}, timestamp='2026-02-15 03:07:05.505', 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-02-15 03:07:06.754_b8f512', created_at='2026-02-15 03:07:06.754', type='chat', usage=ChatUsage(input_tokens=26, output_tokens=1, time=1.247558, type='chat', metadata=GenerationUsage(input_tokens=26, output_tokens=1)), metadata=None)

块 1
        类型: <class 'list'>
        ChatResponse(content=[{'type': 'text', 'text': '1\n'}], id='2026-02-15 03:07:06.818_e578b1', created_at='2026-02-15 03:07:06.818', type='chat', usage=ChatUsage(input_tokens=26, output_tokens=2, time=1.311745, type='chat', metadata=GenerationUsage(input_tokens=26, output_tokens=2)), metadata=None)

块 2
        类型: <class 'list'>
        ChatResponse(content=[{'type': 'text', 'text': '1\n2\n3'}], id='2026-02-15 03:07:06.882_3866c2', created_at='2026-02-15 03:07:06.882', type='chat', usage=ChatUsage(input_tokens=26, output_tokens=5, time=1.375557, type='chat', metadata=GenerationUsage(input_tokens=26, output_tokens=5)), metadata=None)

块 3
        类型: <class 'list'>
        ChatResponse(content=[{'type': 'text', 'text': '1\n2\n3\n4\n'}], id='2026-02-15 03:07:07.050_84eba9', created_at='2026-02-15 03:07:07.050', type='chat', usage=ChatUsage(input_tokens=26, output_tokens=8, time=1.543541, type='chat', metadata=GenerationUsage(input_tokens=26, output_tokens=8)), metadata=None)

块 4
        类型: <class 'list'>
        ChatResponse(content=[{'type': 'text', 'text': '1\n2\n3\n4\n5\n6\n7\n'}], id='2026-02-15 03:07:07.181_6d1df9', created_at='2026-02-15 03:07:07.181', type='chat', usage=ChatUsage(input_tokens=26, output_tokens=14, time=1.674468, type='chat', metadata=GenerationUsage(input_tokens=26, output_tokens=14)), metadata=None)

块 5
        类型: <class 'list'>
        ChatResponse(content=[{'type': 'text', 'text': '1\n2\n3\n4\n5\n6\n7\n8\n9\n10'}], id='2026-02-15 03:07:07.332_1280c3', created_at='2026-02-15 03:07:07.333', type='chat', usage=ChatUsage(input_tokens=26, output_tokens=20, time=1.826345, type='chat', metadata=GenerationUsage(input_tokens=26, output_tokens=20)), metadata=None)

块 6
        类型: <class 'list'>
        ChatResponse(content=[{'type': 'text', 'text': '1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n11\n12'}], id='2026-02-15 03:07:07.542_0a5be4', created_at='2026-02-15 03:07:07.542', type='chat', usage=ChatUsage(input_tokens=26, output_tokens=26, time=2.035612, type='chat', metadata=GenerationUsage(input_tokens=26, output_tokens=26)), metadata=None)

块 7
        类型: <class 'list'>
        ChatResponse(content=[{'type': 'text', 'text': '1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n11\n12\n13\n14'}], id='2026-02-15 03:07:07.797_2cf473', created_at='2026-02-15 03:07:07.797', type='chat', usage=ChatUsage(input_tokens=26, output_tokens=32, time=2.290942, type='chat', metadata=GenerationUsage(input_tokens=26, output_tokens=32)), metadata=None)

块 8
        类型: <class 'list'>
        ChatResponse(content=[{'type': 'text', 'text': '1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n11\n12\n13\n14\n15\n16'}], id='2026-02-15 03:07:07.941_2653f6', created_at='2026-02-15 03:07:07.941', type='chat', usage=ChatUsage(input_tokens=26, output_tokens=38, time=2.434726, type='chat', metadata=GenerationUsage(input_tokens=26, output_tokens=38)), metadata=None)

块 9
        类型: <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='2026-02-15 03:07:08.054_41d9d2', created_at='2026-02-15 03:07:08.054', type='chat', usage=ChatUsage(input_tokens=26, output_tokens=44, time=2.548043, type='chat', metadata=GenerationUsage(input_tokens=26, output_tokens=44)), metadata=None)

块 10
        类型: <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='2026-02-15 03:07:08.392_fb91bd', created_at='2026-02-15 03:07:08.392', type='chat', usage=ChatUsage(input_tokens=26, output_tokens=50, time=2.885933, type='chat', metadata=GenerationUsage(input_tokens=26, output_tokens=50)), 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\n16\n17\n18\n19\n20'}], id='2026-02-15 03:07:08.476_7f3676', created_at='2026-02-15 03:07:08.476', type='chat', usage=ChatUsage(input_tokens=26, output_tokens=50, time=2.969519, 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'}, {'type': 'text', 'text': '“我是谁?”是一个深刻而复杂的问题,不同的人、不同的文化、哲学体系和科学领域可能会给出不同的答案。以下是一些可能的视角,或许能帮助你更深入地思考这个问题:\n\n---\n\n### **1. 哲学视角**\n- **笛卡尔的“我思故我在”**:哲学家笛卡尔认为,“我思”是唯一不可怀疑的事实,因此“我”是思考的主体。你的存在可以通过思考本身证明。\n- **佛教的“无我”**:佛教认为“自我”是五蕴(色、受、想、行、识)的暂时聚合,没有永恒不变的“我”。你所感知的“我”可能只是因缘和合的产物。\n- **存在主义**:萨特等哲学家认为,“人是自由的”,“我”是通过选择和行动不断定义的。你的身份不是固定的,而是由你如何生活决定的。\n\n---\n\n### **2. 心理学视角**\n- **自我认知**:心理学认为“我”是由记忆、经验、性格、价值观、社会角色等构成的。你可能通过“我是谁”来探索自己的性格、目标或情感。\n- **身份认同**:心理学家埃里克森提出,人一生中会经历“身份与角色混淆”的阶段,通过探索和选择,逐渐形成稳定的自我认同。\n- **意识与潜意识**:弗洛伊德认为,自我(ego)是意识的主宰,而潜意识中隐藏着未被察觉的欲望和冲突。\n\n---\n\n### **3. 科学视角**\n- **生物学**:从基因和进化角度看,“我”是DNA编码的产物,是亿万年演化的结果。你的身体、大脑和行为都受到生物学规律的支配。\n- **神经科学**:大脑的神经元活动构成了“自我”的体验。科学家试图通过脑成像技术理解意识的起源,但“自我”仍是一个未解之谜。\n- **量子物理**:某些理论(如“观察者效应”)暗示,意识可能与宇宙的运行方式有关,但这一领域仍充满争议。\n\n---\n\n### **4. 个人视角**\n- **你可能是一个**:\n  - **名字、身份、职业、家庭角色**(例如:我是父母的孩子,是某个公司的员工)。\n  - **思想、情感、记忆的集合**(例如:我的想法、情绪、经历塑造了现在的我)。\n  - **未完成的潜力**(例如:我正在学习、成长、探索未来的可能性)。\n- **你可能感到困惑**:  \n  如果你此刻问“我是谁”,或许是因为你正在经历身份的转变、迷茫,或对某种角色(如学生、职场人、父母)感到不适应。这种困惑本身也是“自我探索”的一部分。\n\n---\n\n### **5. 简单的思考练习**\n你可以尝试回答这些问题,或许能更接近答案:\n- 我最珍视的价值观是什么?\n- 我的哪些特质是独一无二的?\n- 如果没有社会标签(如“学生”“程序员”),我还能如何定义自己?\n- 我的梦想和恐惧中,藏着什么样的“我”?\n\n---\n\n### **6. 一个可能的答案**\n“你是你此刻的体验,是过去经历的总和,也是未来可能性的起点。你既是独立的个体,也是与世界相互作用的一部分。你的‘身份’可能没有固定答案,但正是这种探索本身,让你成为独特的‘你’。”\n\n---\n\n如果你愿意分享更多背景(比如你为什么问这个问题),我可以提供更具体的思考方向。'}], id='2026-02-15 03:07:24.372_14d03d', created_at='2026-02-15 03:07:24.372', type='chat', usage=ChatUsage(input_tokens=11, output_tokens=1087, time=15.891855, type='chat', metadata=GenerationUsage(input_tokens=11, output_tokens=1087)), 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 20.396 seconds)

Gallery generated by Sphinx-Gallery