备注
Go to the end to download the full example code.
模型¶
在本教程中,我们介绍 AgentScope 中集成的模型 API、如何使用它们,以及如何集成新的模型 API。 AgentScope 目前支持的模型 API 和模型提供商包括:
API |
类 |
兼容 |
流式 |
工具 |
视觉 |
推理 |
|---|---|---|---|---|---|---|
OpenAI |
|
vLLM, DeepSeek |
✅ |
✅ |
✅ |
✅ |
DashScope |
|
✅ |
✅ |
✅ |
✅ |
|
Anthropic |
|
✅ |
✅ |
✅ |
✅ |
|
Gemini |
|
✅ |
✅ |
✅ |
✅ |
|
Ollama |
|
✅ |
✅ |
✅ |
✅ |
备注
当使用 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__函数的前三个参数是messages,tools和tool_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-05-14 09:37:12.426_133cfa', created_at='2026-05-14 09:37:12.426', 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='95401223-5bc6-972f-a0ea-7d2d0954ee49', created_at='2026-05-14 09:37:14.521', type='chat', usage=ChatUsage(input_tokens=10, output_tokens=7, time=2.094283, type='chat', metadata=GenerationUsage(input_tokens=10, output_tokens=7)), metadata=None)
作为 Msg 的响应: Msg(id='TEpWVPrMKKZ75PpaPTbW5V', name='Friday', content=[{'type': 'text', 'text': '你好!有什么可以帮助你的吗?'}], role='assistant', metadata={}, timestamp='2026-05-14 09:37:14.522', 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='663d7ef9-8c42-9712-a5d2-b965a3de800d', created_at='2026-05-14 09:37:15.558', type='chat', usage=ChatUsage(input_tokens=26, output_tokens=1, time=1.034918, type='chat', metadata=GenerationUsage(input_tokens=26, output_tokens=1)), metadata=None)
块 1
类型: <class 'list'>
ChatResponse(content=[{'type': 'text', 'text': '1\n'}], id='663d7ef9-8c42-9712-a5d2-b965a3de800d', created_at='2026-05-14 09:37:15.624', type='chat', usage=ChatUsage(input_tokens=26, output_tokens=2, time=1.101386, type='chat', metadata=GenerationUsage(input_tokens=26, output_tokens=2)), metadata=None)
块 2
类型: <class 'list'>
ChatResponse(content=[{'type': 'text', 'text': '1\n2\n3'}], id='663d7ef9-8c42-9712-a5d2-b965a3de800d', created_at='2026-05-14 09:37:15.691', type='chat', usage=ChatUsage(input_tokens=26, output_tokens=5, time=1.168485, 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='663d7ef9-8c42-9712-a5d2-b965a3de800d', created_at='2026-05-14 09:37:15.875', type='chat', usage=ChatUsage(input_tokens=26, output_tokens=8, time=1.351653, 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='663d7ef9-8c42-9712-a5d2-b965a3de800d', created_at='2026-05-14 09:37:16.013', type='chat', usage=ChatUsage(input_tokens=26, output_tokens=14, time=1.489776, 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='663d7ef9-8c42-9712-a5d2-b965a3de800d', created_at='2026-05-14 09:37:16.174', type='chat', usage=ChatUsage(input_tokens=26, output_tokens=20, time=1.650919, 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='663d7ef9-8c42-9712-a5d2-b965a3de800d', created_at='2026-05-14 09:37:16.432', type='chat', usage=ChatUsage(input_tokens=26, output_tokens=26, time=1.908942, 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='663d7ef9-8c42-9712-a5d2-b965a3de800d', created_at='2026-05-14 09:37:16.564', type='chat', usage=ChatUsage(input_tokens=26, output_tokens=32, time=2.040989, 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='663d7ef9-8c42-9712-a5d2-b965a3de800d', created_at='2026-05-14 09:37:16.912', type='chat', usage=ChatUsage(input_tokens=26, output_tokens=38, time=2.388899, 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='663d7ef9-8c42-9712-a5d2-b965a3de800d', created_at='2026-05-14 09:37:17.023', type='chat', usage=ChatUsage(input_tokens=26, output_tokens=44, time=2.500204, 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='663d7ef9-8c42-9712-a5d2-b965a3de800d', created_at='2026-05-14 09:37:17.160', type='chat', usage=ChatUsage(input_tokens=26, output_tokens=50, time=2.636831, 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='663d7ef9-8c42-9712-a5d2-b965a3de800d', created_at='2026-05-14 09:37:17.251', type='chat', usage=ChatUsage(input_tokens=26, output_tokens=50, time=2.727925, 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\n最后,确保回答既全面又不冗长,避免使用过于学术化的语言,保持自然和易懂。同时,鼓励用户进一步思考,而不是给出一个确定的答案,因为“我是谁”这个问题没有唯一的答案,每个人都有自己的理解和答案。'}, {'type': 'text', 'text': '“我是谁?”是一个跨越哲学、心理学、宗教和科学的深刻问题,答案因人而异,也可能随着时间和经历不断变化。以下是一些可能的视角,或许能帮助你探索这个命题:\n\n---\n\n### **1. 哲学视角:**\n- **笛卡尔的“我思故我在”** \n 法国哲学家笛卡尔认为,**“我思”是存在的唯一确定证据**。即使怀疑一切,思考本身证明了“我”的存在。 \n > *“我思故我在”(Cogito, ergo sum)* \n 这种观点强调**思维**作为自我存在的核心。\n\n- **佛教的“无我”** \n 佛教认为,“我”是五蕴(色、受、想、行、识)暂时聚合的幻象,**没有永恒不变的“自我”**。 \n > *“诸法无我”* \n 这种视角挑战了对“我”的执着,倡导通过觉察破除对自我的执念。\n\n- **存在主义的追问** \n 萨特认为,**“人是自由的”**,但这种自由也带来责任。你通过选择和行动定义自己,而非预设的本质。 \n > *“存在先于本质”* \n 你可能是“尚未完成的创造”。\n\n---\n\n### **2. 心理学视角:**\n- **自我认同(Self-Identity)** \n 心理学家埃里克森提出,**自我认同是人一生的课题**。它由你的经历、价值观、目标和与他人的关系共同塑造。 \n > *“我是谁?”* 可能是通过不断尝试、失败和反思逐渐清晰的。\n\n- **人格理论** \n 例如,**弗洛伊德的“本我、自我、超我”** 或 **荣格的“个体化”**,都试图解释“我”如何在潜意识、社会规范和内在理想中形成。\n\n- **神经科学** \n 大脑的神经网络和意识活动是“我”产生的基础,但**意识的起源仍是未解之谜**。你可能只是大脑中无数神经元的“叙事者”。\n\n---\n\n### **3. 宗教/灵性视角:**\n- **基督教** \n 《圣经》中,上帝创造人时赋予其“灵”,**“我”是上帝形象的体现**,但需通过信仰与救赎找到意义。\n\n- **道家思想** \n 老子提出“**我无我**”,强调放下对“小我”的执着,与“道”合一,回归自然本真。\n\n- **现代灵性** \n 一些灵性实践(如冥想、内观)主张**“我”是观察者**,超越身体和思维,体验更广阔的意识。\n\n---\n\n### **4. 简单直接的回答:**\n如果你希望一个更贴近生活的答案: \n> **“你是你此刻的体验”** \n- 你是一个独特的生命体,拥有独特的记忆、情感、思想和潜能。 \n- 你可能通过职业、爱好、人际关系、价值观等定义自己,但这些都只是“我”的一部分。 \n- **“我是谁?”** 可能是一个持续探索的过程,而非终点。\n\n---\n\n### **5. 你可以尝试的思考方式:**\n- **写下你的关键词**:比如“我热爱……”“我害怕……”“我梦想……”。 \n- **问自己**:如果失去所有外在标签(身份、职业、财富),我依然是谁? \n- **观察你的思维**:当你说“我是……”时,这些想法是真实的吗?还是被社会或他人塑造的?\n\n---\n\n最终,“我是谁?”没有标准答案,但这个问题本身可能就是你探索生命意义的起点。或许答案会随着你的人生旅程不断演变。 🌱 \n如果你愿意分享更多背景,我可以尝试更具体地回应。'}], id='c1d7fab8-ef58-93df-a385-e4912e55b62c', created_at='2026-05-14 09:37:32.666', type='chat', usage=ChatUsage(input_tokens=11, output_tokens=1234, time=15.410164, type='chat', metadata=GenerationUsage(input_tokens=11, output_tokens=1234)), 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.243 seconds)