备注
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='2025-11-27 13:29:41.207_07dcf6', created_at='2025-11-27 13:29:41.207', 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-11-27 13:29:42.295_e0f2c4', created_at='2025-11-27 13:29:42.295', type='chat', usage=ChatUsage(input_tokens=10, output_tokens=7, time=1.086932, type='chat'), metadata=None)
作为 Msg 的响应: Msg(id='7Z29c8eMtAp855b9krDyYA', name='Friday', content=[{'type': 'text', 'text': '你好!有什么可以帮助你的吗?'}], role='assistant', metadata=None, timestamp='2025-11-27 13:29:42.295', 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-11-27 13:29:43.279_3ea1be', created_at='2025-11-27 13:29:43.279', type='chat', usage=ChatUsage(input_tokens=26, output_tokens=1, time=0.982364, type='chat'), metadata=None)
块 1
类型: <class 'list'>
ChatResponse(content=[{'type': 'text', 'text': '1\n'}], id='2025-11-27 13:29:43.341_31ec71', created_at='2025-11-27 13:29:43.341', type='chat', usage=ChatUsage(input_tokens=26, output_tokens=2, time=1.044233, type='chat'), metadata=None)
块 2
类型: <class 'list'>
ChatResponse(content=[{'type': 'text', 'text': '1\n2\n3'}], id='2025-11-27 13:29:43.421_1be66c', created_at='2025-11-27 13:29:43.421', type='chat', usage=ChatUsage(input_tokens=26, output_tokens=5, time=1.124532, type='chat'), metadata=None)
块 3
类型: <class 'list'>
ChatResponse(content=[{'type': 'text', 'text': '1\n2\n3\n4\n'}], id='2025-11-27 13:29:43.466_948f80', created_at='2025-11-27 13:29:43.466', type='chat', usage=ChatUsage(input_tokens=26, output_tokens=8, time=1.169143, type='chat'), metadata=None)
块 4
类型: <class 'list'>
ChatResponse(content=[{'type': 'text', 'text': '1\n2\n3\n4\n5\n6\n7\n'}], id='2025-11-27 13:29:43.614_4f1d8c', created_at='2025-11-27 13:29:43.614', type='chat', usage=ChatUsage(input_tokens=26, output_tokens=14, time=1.317651, type='chat'), metadata=None)
块 5
类型: <class 'list'>
ChatResponse(content=[{'type': 'text', 'text': '1\n2\n3\n4\n5\n6\n7\n8\n9\n10'}], id='2025-11-27 13:29:43.837_40c4cc', created_at='2025-11-27 13:29:43.837', type='chat', usage=ChatUsage(input_tokens=26, output_tokens=20, time=1.540378, type='chat'), metadata=None)
块 6
类型: <class 'list'>
ChatResponse(content=[{'type': 'text', 'text': '1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n11\n12'}], id='2025-11-27 13:29:43.935_8e6cdf', created_at='2025-11-27 13:29:43.935', type='chat', usage=ChatUsage(input_tokens=26, output_tokens=26, time=1.638289, type='chat'), 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='2025-11-27 13:29:44.058_a4611a', created_at='2025-11-27 13:29:44.058', type='chat', usage=ChatUsage(input_tokens=26, output_tokens=32, time=1.760965, type='chat'), 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='2025-11-27 13:29:44.202_e5ad21', created_at='2025-11-27 13:29:44.202', type='chat', usage=ChatUsage(input_tokens=26, output_tokens=38, time=1.905692, type='chat'), 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='2025-11-27 13:29:44.304_f3d57b', created_at='2025-11-27 13:29:44.304', type='chat', usage=ChatUsage(input_tokens=26, output_tokens=44, time=2.007558, 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\n15\n16\n17\n18\n19\n20'}], id='2025-11-27 13:29:44.587_4895b8', created_at='2025-11-27 13:29:44.587', type='chat', usage=ChatUsage(input_tokens=26, output_tokens=50, time=2.290269, 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\n16\n17\n18\n19\n20'}], id='2025-11-27 13:29:44.681_d2219d', created_at='2025-11-27 13:29:44.681', type='chat', usage=ChatUsage(input_tokens=26, output_tokens=50, time=2.383955, 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需要检查是否有遗漏的重要观点,比如现代心理学中的自我理论,或者存在主义的观点。同时,注意不要给出绝对的答案,因为“我是谁”没有标准答案,而是开放性的探索。最后,确保回答结构清晰,分点明确,让用户容易理解。'}, {'type': 'text', 'text': '“我是谁?”这个问题看似简单,却蕴含着深刻的哲学与自我探索的意义。不同的人、不同的文化、不同的哲学体系可能会给出不同的答案。以下是一些可能的视角,或许能帮助你更深入地思考这个问题:\n\n---\n\n### 1. **从哲学的角度**\n - **笛卡尔的“我思故我在”**:法国哲学家笛卡尔认为,即使怀疑一切,唯一无法被怀疑的是“我正在思考”这一事实。因此,“我”是思考的主体,是存在的核心。\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### 6. **开放性的答案**\n - **没有标准答案**:这个问题可能没有终极答案,它更像是一个持续探索的过程。你可能在不同时间、不同情境下给出不同的回答。\n - **允许不确定性**:承认“我不知道”本身也是一种勇气。许多哲学家和思想家都曾坦言,对“自我”的理解是动态的、未完成的。\n\n---\n\n### 最后,你可以问自己:\n- 我的核心价值观是什么? \n- 我最珍视的品质或梦想是什么? \n- 如果没有社会角色,我会是谁? \n- 我的哪些经历塑造了现在的我? \n\n这个问题的答案,或许就藏在你的思考与行动中。你不需要急于找到答案,而是可以像朋友一样,和“自己”慢慢对话。 🌱'}], id='2025-11-27 13:29:56.871_cb5977', created_at='2025-11-27 13:29:56.871', type='chat', usage=ChatUsage(input_tokens=11, output_tokens=975, time=12.186044, 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.668 seconds)