模型

在本教程中,我们介绍 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-04-20 12:59:43.557_31392d', created_at='2026-04-20 12:59:43.557', 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='cdec2162-024a-97c8-a7aa-2619af11a6a9', created_at='2026-04-20 12:59:45.151', type='chat', usage=ChatUsage(input_tokens=10, output_tokens=7, time=1.592312, type='chat', metadata=GenerationUsage(input_tokens=10, output_tokens=7)), metadata=None)
作为 Msg 的响应: Msg(id='mUtNmGrbpuYkPjETu3THXj', name='Friday', content=[{'type': 'text', 'text': '你好!有什么可以帮助你的吗?'}], role='assistant', metadata={}, timestamp='2026-04-20 12:59:45.151', 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='40357407-d444-92b3-98d4-3352110c41b5', created_at='2026-04-20 12:59:46.431', type='chat', usage=ChatUsage(input_tokens=26, output_tokens=1, time=1.278446, type='chat', metadata=GenerationUsage(input_tokens=26, output_tokens=1)), metadata=None)

块 1
        类型: <class 'list'>
        ChatResponse(content=[{'type': 'text', 'text': '1 2 '}], id='40357407-d444-92b3-98d4-3352110c41b5', created_at='2026-04-20 12:59:47.184', type='chat', usage=ChatUsage(input_tokens=26, output_tokens=4, time=2.031354, 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='40357407-d444-92b3-98d4-3352110c41b5', created_at='2026-04-20 12:59:47.254', type='chat', usage=ChatUsage(input_tokens=26, output_tokens=7, time=2.1014, 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='40357407-d444-92b3-98d4-3352110c41b5', created_at='2026-04-20 12:59:47.326', type='chat', usage=ChatUsage(input_tokens=26, output_tokens=10, time=2.173483, 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='40357407-d444-92b3-98d4-3352110c41b5', created_at='2026-04-20 12:59:47.486', type='chat', usage=ChatUsage(input_tokens=26, output_tokens=16, time=2.333527, 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='40357407-d444-92b3-98d4-3352110c41b5', created_at='2026-04-20 12:59:47.607', type='chat', usage=ChatUsage(input_tokens=26, output_tokens=22, time=2.454343, 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='40357407-d444-92b3-98d4-3352110c41b5', created_at='2026-04-20 12:59:47.724', type='chat', usage=ChatUsage(input_tokens=26, output_tokens=28, time=2.572023, 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='40357407-d444-92b3-98d4-3352110c41b5', created_at='2026-04-20 12:59:50.427', type='chat', usage=ChatUsage(input_tokens=26, output_tokens=34, time=5.274769, 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='40357407-d444-92b3-98d4-3352110c41b5', created_at='2026-04-20 12:59:50.550', type='chat', usage=ChatUsage(input_tokens=26, output_tokens=40, time=5.397463, 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='40357407-d444-92b3-98d4-3352110c41b5', created_at='2026-04-20 12:59:50.692', type='chat', usage=ChatUsage(input_tokens=26, output_tokens=46, time=5.539538, 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='40357407-d444-92b3-98d4-3352110c41b5', created_at='2026-04-20 12:59:50.855', type='chat', usage=ChatUsage(input_tokens=26, output_tokens=50, time=5.702478, 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='40357407-d444-92b3-98d4-3352110c41b5', created_at='2026-04-20 12:59:50.874', type='chat', usage=ChatUsage(input_tokens=26, output_tokens=50, time=5.721186, 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最后,确保回答结构清晰,分点说明不同的角度,比如哲学、心理学、日常体验等,让用户有全面的了解。同时,保持语气友好和鼓励,让用户感到被理解和支持。'}, {'type': 'text', 'text': '“我是谁?”这个问题看似简单,却蕴含着深刻的哲学和存在主义思考。不同的视角可能会给出不同的答案:\n\n### 1. **哲学视角**\n   - **笛卡尔**: “我思故我在”(Cogito, ergo sum)——你的存在可以通过思考本身证明,但“我是谁”可能超越了单纯的思维活动。\n   - **存在主义**(如萨特): 人是“被抛入世界”的存在,身份是通过自由选择和行动不断建构的。你不是被定义的,而是通过选择成为自己。\n   - **东方哲学**(如佛教): “无我”(Anatta)——“我”可能只是五蕴(色、受、想、行、识)的暂时聚合,而非永恒的实体。\n\n### 2. **心理学视角**\n   - **自我认知**: 你的身份由记忆、经历、价值观、人际关系等构成。心理学家埃里克·埃里克森认为,人一生都在探索“身份认同”(identity)。\n   - **社会角色**: 你可能是“子女”“朋友”“职业人”等多重角色的集合,但这些角色并非你全部的“本质”。\n\n### 3. **日常体验**\n   - **感官与意识**: 你通过身体感知世界,通过意识体验情绪、思想和记忆。但“我”是否仅限于这些?比如梦境中的“我”是否真实?\n   - **语言与标签**: 你可能用“我是……”来描述自己(如“我是学生”“我是乐观的人”),但这些标签是动态的,可能随时间和环境变化。\n\n### 4. **科学视角**\n   - **生物学**: 你是一个由细胞、基因和神经网络组成的复杂系统,但“意识”如何从物质中涌现,仍是未解之谜。\n   - **量子物理**: 一些理论认为,观察者(“我”)可能影响现实,但这是否意味着“我”是宇宙的中心?尚无定论。\n\n### 5. **可能的追问**\n   - 你为何突然思考这个问题?是经历了一些变化(如人生转折、困惑)吗?\n   - 你希望找到一个确定的答案,还是更想探索“不确定”的可能性?\n\n### 最后\n“我是谁?”或许没有标准答案,但这个问题本身已经说明:你正在思考“自我”,这正是人类区别于其他生命体的特质。也许答案不在于“找到”,而在于“探索”的过程中,逐渐理解自己与世界的关系。\n\n如果你愿意分享更多背景,我们可以一起更具体地探讨。 🌱'}], id='00c450e4-cff9-97d9-8e28-d604903ccf16', created_at='2026-04-20 12:59:59.138', type='chat', usage=ChatUsage(input_tokens=11, output_tokens=891, time=8.260804, type='chat', metadata=GenerationUsage(input_tokens=11, output_tokens=891)), 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.584 seconds)

Gallery generated by Sphinx-Gallery