为什么需要 AgentScope?
Agent 框架如雨后春笋。LangChain 凭借先发优势占据了大量心智,AutoGPT 引爆了自主 Agent 的想象力,CrewAI 让多 Agent 协作变得简单……但当你真正要把 Agent 应用落地到生产环境时,问题来了:
- LangChain 的抽象层级太多,调试起来像在剥洋葱,而且和具体 LLM 的绑定太紧
- AutoGPT 很酷,但"完全自主"在生产环境约等于"不可控"
- CrewAI 的工作流编排很香,但遇到需要深度定制的场景就显得力不从心
- 几乎所有框架都在用僵化的 Prompt 工程来约束模型行为,而不是释放模型的推理潜能
它想解决的核心问题是:
- 模型能力快速迭代,框架如何跟上? —— 通过模块解耦和标准协议(A2A、MCP),让框架不被特定模型绑架
- 长对话场景下上下文爆炸怎么办? —— 工作记忆 + 长期记忆双轨制,配合智能压缩
- 复杂任务如何拆解执行? —— 内置 PlanNotebook 任务规划系统
- 如何让多个 Agent 协作? —— MsgHub 消息中心 + A2A 跨框架通信
- 怎么知道 Agent 到底行不行? —— 完整的评估框架 + 强化学习微调支持
说白了,AS 的野心是做 Agent 领域的 Spring Boot——开箱即用,但又足够灵活,能应对各种复杂场景。
接下来,我们深入代码,看看它是怎么做到的。
目录
- 整体架构速览
- Agent 核心:ReActAgent 的推理-行动循环
- A2A:Agent 间通信协议
- Memory:工作记忆与长期记忆双轨制
- Plan:任务规划系统
- Formatter:消息格式化层
- MCP:Model Context Protocol 集成
- Embedding:多模态向量化
- Evaluate:基准测试框架
- Model:LLM 适配层
整体架构速览
AgentScope 的核心设计理念是模块解耦、异步优先。整个框架以 ReActAgent 为核心,围绕其构建了完整的工具调用、记忆管理、任务规划、多 Agent 协作等能力。
flowchart TB
subgraph Core["🧠 AgentScope 核心"]
direction TB
Model["Model<br/>(LLM)"]
Formatter["Formatter<br/>(API适配)"]
Memory["Memory<br/>(工作/长期)"]
Toolkit["Toolkit<br/>(Tools+MCP+Skills)"]
Model & Formatter & Memory & Toolkit --> Agent
Agent["ReActAgent<br/>(推理-行动循环)"]
end
subgraph Extensions["🔌 扩展能力"]
Plan["Plan<br/>(任务规划)"]
RAG["RAG<br/>(知识检索)"]
A2A["A2A<br/>(Agent通信)"]
end
Agent --> Plan
Agent --> RAG
Agent --> A2A
关键设计特点:
- 全异步架构:所有核心方法都是
async,支持高并发场景 - 消息统一抽象:
Msg类支持多模态内容块(文本、图片、音频、视频、工具调用) - Hook 机制:支持类级别和实例级别的钩子,在 reply/observe/print 前后注入自定义逻辑
- 状态管理:通过
StateModule基类提供统一的状态序列化/反序列化能力
Agent 核心:ReActAgent 的推理-行动循环
ReActAgent 是 AgentScope 的核心实现,采用经典的 ReAct (Reasoning + Acting) 模式。
为什么选择 ReAct 模式?
在 Agent 架构设计上,业界有几种主流思路:
| 模式 | 代表框架 | 核心思想 | 适用场景 |
|---|---|---|---|
| Chain/Graph | LangChain, LangGraph | 预定义执行流程,节点间传递状态 | 流程固定、可预测的任务 |
| Plan-and-Execute | AutoGPT | 先规划完整计划,再逐步执行 | 目标明确、步骤可预判的任务 |
| ReAct | AgentScope, OpenAI Swarm | 推理-行动交替,边做边想 | 动态环境、需要实时调整的任务 |
| Crew/Role | CrewAI | 多角色分工协作 | 需要专业化分工的复杂任务 |
AgentScope 选择 ReAct 作为核心,但通过 PlanNotebook 模块补充了计划能力——这是一个务实的选择:
- ReAct 更贴近人类解决问题的方式:遇到问题 → 思考 → 尝试 → 观察结果 → 调整策略,循环往复
- 对模型能力的依赖更合理:不需要模型一次性规划出完美方案(这对当前的 LLM 来说很难),而是允许它在执行过程中不断调整
- 更好的容错性:单步失败可以在下一轮推理中修正,而不是整个计划报废
与 LangChain 的关键差异:
LangChain 的 Agent 核心是 AgentExecutor,它本质上也是 ReAct 循环,但:
- LangChain 的抽象层级更多(Chain → Agent → Tool → Memory),调试时经常迷失在层层回调中
- AgentScope 更扁平,
ReActAgent.reply()就是完整的推理-行动循环,一目了然
与 AutoGPT 的关键差异:
AutoGPT 的"完全自主"意味着人类几乎无法介入。AgentScope 的设计哲学是人机协作——支持实时打断、动态调整计划、Hook 注入等机制,让人类在需要时能随时接管。
核心流程
async def reply(self, msg, structured_model=None) -> Msg:
# 1. 循环前准备
await self.memory.add(msg) # 记录输入
await self._retrieve_from_long_term_memory(msg) # 长期记忆检索
await self._retrieve_from_knowledge(msg) # RAG 知识库检索
# 2. 推理-行动循环
for _ in range(self.max_iters):
await self._compress_memory_if_needed() # 内存压缩检查
msg_reasoning = await self._reasoning() # 推理
# 行动(支持并行/串行工具调用)
futures = [self._acting(tool_call) for tool_call in tool_calls]
if self.parallel_tool_calls:
await asyncio.gather(*futures)
else:
[await f for f in futures]
# 退出条件检查
if 满足结构化输出要求 or 无工具调用:
break
# 3. 循环后处理
if reply_msg is None:
reply_msg = await self._summarizing() # 达到最大迭代时生成摘要
# 记录到长期记忆
if self._static_control:
await self.long_term_memory.record([...])
return reply_msg
推理阶段 _reasoning()
推理阶段的核心职责是调用 LLM 生成下一步行动:
async def _reasoning(self, tool_choice=None) -> Msg:
# 1. 插入计划提示(如果启用了 PlanNotebook)
if self.plan_notebook:
hint_msg = await self.plan_notebook.get_current_hint()
await self.memory.add(hint_msg, marks=_MemoryMark.HINT)
# 2. 格式化消息并调用 LLM
prompt = await self.formatter.format([
Msg("system", self.sys_prompt, "system"),
*await self.memory.get_memory(),
])
await self.memory.delete_by_mark(mark=_MemoryMark.HINT) # 使用后清除提示
res = await self.model(prompt, tools=self.toolkit.get_json_schemas())
# 3. 处理输出(支持流式、TTS)
msg = Msg(name=self.name, content=[], role="assistant")
if self.model.stream:
async for chunk in res:
msg.content = chunk.content
await self.print(msg, False)
# ...
await self.memory.add(msg)
return msg
关键点:
- 提示消息(hint)使用后立即清除,不污染记忆
- 支持流式输出和 TTS 语音合成
- 用户中断时会伪造工具结果以保持消息格式一致性
行动阶段 _acting()
async def _acting(self, tool_call: ToolUseBlock) -> dict | None:
# 创建工具结果消息容器
tool_res_msg = Msg("system", [ToolResultBlock(...)], "system")
# 执行工具调用
tool_res = await self.toolkit.call_tool_function(tool_call)
# 异步流式处理工具输出
async for chunk in tool_res:
tool_res_msg.content[0]["output"] = chunk.content
await self.print(tool_res_msg, chunk.is_last)
await self.memory.add(tool_res_msg)
return structured_output if 是结构化输出函数 else None
内存压缩机制
长对话是 Agent 应用的普遍痛点。一个复杂任务可能需要几十轮交互,Token 很快就爆了。业界的常见做法包括:
- 截断:简单粗暴,但会丢失关键上下文
- 滑动窗口:保留最近 N 条,远古记忆全丢
- 摘要压缩:用 LLM 生成摘要,但摘要质量参差不齐
AgentScope 的方案是结构化摘要压缩——不是让 LLM 自由发挥写摘要,而是用 Pydantic Schema 约束输出格式,确保关键信息不丢失:
class CompressionConfig(BaseModel):
trigger_threshold: int # 触发阈值
keep_recent: int = 3 # 保留最近 N 条消息
summary_schema: Type[BaseModel] = SummarySchema # 结构化摘要模型
class SummarySchema(BaseModel):
task_overview: str # 任务概览
current_state: str # 当前状态
important_discoveries: str # 重要发现
next_steps: str # 下一步
context_to_preserve: str # 需要保留的上下文
压缩策略亮点:
- 保留工具调用的 ID 对应关系,确保消息完整性
- 使用结构化输出生成高质量摘要
- 支持配置独立的压缩模型(可以用便宜的模型做压缩)
RAG 知识检索
async def _retrieve_from_knowledge(self, msg):
# 可选:查询重写(将 "yesterday" 具体化为实际日期)
if self.enable_rewrite_query:
res = await self.model(rewrite_prompt, structured_model=_QueryRewriteModel)
query = res.metadata["rewritten_query"]
# 从所有知识库检索
docs = []
for kb in self.knowledge:
docs.extend(await kb.retrieve(query=query))
# 按相关性排序并添加到记忆
docs = sorted(docs, key=lambda doc: doc.score, reverse=True)
await self.memory.add(retrieved_msg)
A2A:Agent 间通信协议
想象一个场景:你的团队用 AgentScope 构建了一个代码审查 Agent,隔壁团队用 LangChain 搞了一个安全扫描 Agent,领导想让它们协作。怎么办?
在 A2A 协议出现之前,答案是——改代码、写适配器、祈祷别出 bug。
A2A (Agent-to-Agent) 是 Google 提出的 Agent 间通信协议,类似于微服务领域的 gRPC——定义了 Agent 如何发现彼此、如何交换消息、如何管理任务生命周期。AgentScope 是首批完整实现 A2A 的框架之一。
A2AAgent 设计
class A2AAgent(AgentBase):
"""支持与远程 Agent 通信的客户端实现"""
def __init__(self, agent_card: AgentCard, client_config=None):
self.agent_card = agent_card # 远程 Agent 的描述卡片
self._a2a_client_factory = ClientFactory(config=client_config)
self.formatter = A2AChatFormatter() # 消息格式转换器
self._observed_msgs = [] # 本地观察消息缓存
核心流程
async def reply(self, msg) -> Msg:
# 1. 合并观察消息与输入消息
msgs_list = self._observed_msgs + [msg]
# 2. 创建 A2A 客户端
client = self._a2a_client_factory.create(card=self.agent_card)
# 3. 格式转换:内部 Msg → A2A Message
a2a_message = await self.formatter.format(msgs_list)
# 4. 发送并处理响应流
async for item in client.send_message(a2a_message):
if isinstance(item, A2AMessage):
response_msg = await self.formatter.format_a2a_message(item)
elif isinstance(item, tuple): # (Task, artifacts)
response_msg = await self.formatter.format_a2a_task(task)
self._observed_msgs.clear() # 处理完成后清除
return response_msg
A2A Formatter
A2AChatFormatter 负责双向格式转换:
class A2AChatFormatter:
async def format(self, msgs: list[Msg]) -> A2AMessage:
"""AgentScope Msg → A2A Message"""
parts = []
for msg in msgs:
for block in msg.get_content_blocks():
if block["type"] == "text":
parts.append(TextPart(text=block["text"]))
elif block["type"] == "image":
parts.append(FilePart(file=...)) # base64 或 URL
return A2AMessage(parts=parts, role=...)
async def format_a2a_message(self, name: str, msg: A2AMessage) -> Msg:
"""A2A Message → AgentScope Msg"""
content = []
for part in msg.parts:
if isinstance(part, TextPart):
content.append(TextBlock(type="text", text=part.text))
# ...
return Msg(name=name, content=content, role="assistant")
限制说明:
- A2A 协议不支持结构化输出
- 当前仅支持单用户-单助手的对话场景
Memory:工作记忆与长期记忆双轨制
如果你用过 ChatGPT,一定体验过这种挫败感:聊了几十轮后告诉它"按照我们之前讨论的方案来",它一脸懵逼地问"请问是哪个方案?"
这是因为大多数 Agent 框架只有工作记忆——本质上就是一个消息列表,塞进上下文窗口。一旦对话变长,要么截断丢信息,要么 Token 爆炸。
人类的记忆不是这样工作的。我们有工作记忆(当前正在想什么)和长期记忆(过去的经验、知识),两者协同工作。AgentScope 模仿了这个结构:
工作记忆 MemoryBase
工作记忆存储当前会话的对话历史:
class MemoryBase(StateModule):
_compressed_summary: str = "" # 压缩后的历史摘要
async def add(self, memories, marks=None): ...
async def delete(self, msg_ids): ...
async def get_memory(self, mark=None, exclude_mark=None, prepend_summary=True): ...
async def update_messages_mark(self, new_mark, old_mark=None, msg_ids=None): ...
实现方式:
InMemoryMemory:内存列表存储,适合简单场景RedisMemory:Redis 存储,支持分布式SQLAlchemyMemory:数据库存储,支持持久化
Mark 机制: 消息可以打上标记(mark),用于过滤和批量操作:
await memory.add(hint_msg, marks=_MemoryMark.HINT) # 打标记
await memory.delete_by_mark(mark=_MemoryMark.HINT) # 按标记删除
await memory.get_memory(exclude_mark="compressed") # 排除已压缩的消息
长期记忆 LongTermMemoryBase
长期记忆用于跨会话的信息持久化:
class LongTermMemoryBase(StateModule):
# 开发者接口:框架自动调用
async def record(self, msgs: list[Msg]): ...
async def retrieve(self, msg, limit=5) -> str: ...
# Agent 工具接口:作为工具函数暴露给 Agent
async def record_to_memory(self, thinking, content) -> ToolResponse: ...
async def retrieve_from_memory(self, keywords, limit=5) -> ToolResponse: ...
两种控制模式:
long_term_memory_mode: Literal["agent_control", "static_control", "both"]
# agent_control: 将 record/retrieve 注册为工具函数,由 Agent 自主调用
# static_control: 框架在 reply 开始/结束时自动检索/记录
# both: 同时启用两种模式
实现方式:
- Mem0 实现:自动提取对话中的关键信息,支持语义搜索
- ReMe 实现:细分为三种记忆类型
- 个人记忆(Personal):用户偏好、个人信息
- 任务记忆(Task):执行经验
- 工具记忆(Tool):工具使用模式
Plan:任务规划系统
"帮我写一个电商网站"——这种请求,单靠 ReAct 循环是搞不定的。Agent 需要把大任务拆成小任务,一步步完成。
业界有两种主流思路:
- 前置规划(AutoGPT 风格):先让 LLM 生成完整计划,然后严格执行
- 动态规划(AgentScope 风格):边做边调整,计划是活的
前置规划的问题是,LLM 很难一次性规划出完美方案——它不知道执行过程中会遇到什么坑。AgentScope 的 PlanNotebook 采用动态规划:计划随时可以修改、子任务可以增删、进度实时追踪。
数据模型
class SubTask(BaseModel):
name: str
description: str
expected_outcome: str
state: Literal["todo", "in_progress", "done", "abandoned"]
outcome: str | None = None
class Plan(BaseModel):
name: str
description: str
expected_outcome: str
subtasks: list[SubTask]
state: Literal["todo", "in_progress", "done", "abandoned"]
提供的工具函数
def list_tools(self) -> list[Callable]:
return [
# 子任务相关
self.view_subtasks, # 查看子任务详情
self.update_subtask_state, # 更新子任务状态
self.finish_subtask, # 完成子任务(需提供具体成果)
# 计划相关
self.create_plan, # 创建新计划
self.revise_current_plan, # 修改计划(增/改/删子任务)
self.finish_plan, # 完成或放弃计划
# 历史计划
self.view_historical_plans, # 查看历史计划
self.recover_historical_plan, # 恢复历史计划
]
提示消息生成
PlanNotebook 根据当前计划状态动态生成引导提示:
class DefaultPlanToHint:
no_plan: str = "如果用户查询复杂,需要先创建计划..."
at_the_beginning: str = "当前计划:{plan}\n你的选项包括:标记第一个子任务为进行中..."
when_a_subtask_in_progress: str = "子任务 {subtask_name} 正在进行中..."
when_no_subtask_in_progress: str = "前 {index} 个子任务已完成,没有进行中的任务..."
at_the_end: str = "所有子任务已完成,调用 finish_plan..."
关键约束
- 顺序执行:子任务必须按顺序完成,不能跳跃
- 单一进行中:同时只能有一个
in_progress状态的子任务 - 完成需成果:
finish_subtask必须提供具体的产出物,不能是模糊描述
Formatter:消息格式化层
Formatter 是 AgentScope 与不同 LLM API 之间的适配层,负责将统一的 Msg 对象转换为各厂商要求的格式。
基类设计
class FormatterBase:
@abstractmethod
async def format(self, msgs: list[Msg]) -> list[dict[str, Any]]:
"""将 Msg 列表转换为 API 所需的消息格式"""
@staticmethod
def convert_tool_result_to_string(output) -> tuple[str, list]:
"""将工具结果转换为文本(用于不支持多模态工具结果的 API)"""
已实现的 Formatter
| Formatter | 厂商 | 特殊处理 |
|---|---|---|
OpenAIFormatter | OpenAI | 标准实现 |
AnthropicFormatter | Anthropic/Claude | thinking block 支持 |
GeminiFormatter | URL → base64 转换 | |
DashscopeFormatter | 阿里通义 | - |
OllamaFormatter | Ollama | 本地模型适配 |
DeepseekFormatter | DeepSeek | - |
A2AChatFormatter | A2A 协议 | Agent 间通信格式 |
多模态格式转换示例
# Gemini 需要将 URL 图片下载后转为 base64
class GeminiFormatter(FormatterBase):
async def _process_image_block(self, block: ImageBlock) -> dict:
if block["source"]["type"] == "url":
# 下载并转换
data = await download_and_encode(block["source"]["url"])
return {"inline_data": {"data": data, "mime_type": "..."}}
else:
return {"inline_data": block["source"]}
MCP:Model Context Protocol 集成
工具调用是 Agent 的核心能力,但每个框架都在重复造轮子——LangChain 有自己的 Tool 抽象,CrewAI 有自己的,OpenAI 有 Function Calling……
Anthropic 提出的 MCP (Model Context Protocol) 试图解决这个问题:定义一套标准的工具协议,让工具服务可以被任何 Agent 框架复用。
这意味着:
- 高德地图的 MCP 工具,LangChain 能用,AgentScope 也能用
- 你开发的 MCP 工具,不用为每个框架写一遍适配器
AgentScope 对 MCP 的集成非常深入——不仅能批量注册 MCP 工具,还能把单个 MCP 工具拿出来当本地函数用,方便二次封装。
MCP 客户端
支持三种传输方式:
- SSE:Server-Sent Events
- StdIO:标准输入输出(本地进程)
- HTTP:HTTP 接口
MCPToolFunction
将 MCP 工具转换为可直接调用的函数对象:
class MCPToolFunction:
name: str # 工具名称
description: str # 工具描述
json_schema: dict # 参数 JSON Schema
async def __call__(self, **kwargs) -> ToolResponse:
# 建立连接并调用
async with self.client_gen() as cli:
async with ClientSession(cli[0], cli[1]) as session:
await session.initialize()
res = await session.call_tool(self.name, arguments=kwargs)
# 转换结果格式
if self.wrap_tool_result:
return ToolResponse(
content=MCPClientBase._convert_mcp_content_to_as_blocks(res.content),
metadata=res.meta,
)
return res
Toolkit 集成
# 注册 MCP 客户端的所有工具
await toolkit.register_mcp_client(
mcp_client=my_mcp_client,
group_name="mcp_tools",
enable_funcs=["func1", "func2"], # 可选:只启用部分函数
disable_funcs=["func3"], # 可选:排除部分函数
)
# 移除 MCP 客户端的工具
await toolkit.remove_mcp_clients(["client_name"])
Embedding:多模态向量化
EmbeddingModelBase 支持多种数据类型的向量化:
class EmbeddingModelBase:
model_name: str
supported_modalities: list[str] # ["text", "image", "video"]
dimensions: int
async def __call__(self, *args) -> EmbeddingResponse: ...
class EmbeddingResponse:
embeddings: list[list[float]] # 向量列表
usage: EmbeddingUsage # token 使用统计
已实现的适配器
| 适配器 | 厂商 | 支持模态 |
|---|---|---|
OpenAIEmbedding | OpenAI | 文本 |
GeminiEmbedding | 文本 | |
OllamaEmbedding | Ollama | 文本 |
DashscopeEmbedding | 阿里 | 文本 |
DashscopeMultimodalEmbedding | 阿里 | 文本 + 图片 |
与 RAG 的配合
class KnowledgeBase:
embedding_store: VDBStoreBase # 向量存储(Milvus/Chroma/...)
embedding_model: EmbeddingModelBase # 向量化模型
async def retrieve(self, query, limit=5) -> list[Document]:
# 1. 将查询文本向量化
query_embedding = await self.embedding_model(query)
# 2. 在向量库中检索
return await self.embedding_store.search(query_embedding, limit)
async def add_documents(self, documents: list[Document]):
# 1. 向量化文档
embeddings = await self.embedding_model([d.content for d in documents])
# 2. 存入向量库
await self.embedding_store.insert(embeddings, documents)
Evaluate:基准测试框架
AgentScope 提供了完整的 Agent 评估框架。
核心概念
@dataclass
class Task:
id: str # 任务唯一标识
input: JSONSerializableObject # 输入
ground_truth: JSONSerializableObject # 标准答案
metrics: list[MetricBase] # 评估指标列表
tags: dict[str, str] | None # 分类标签
metadata: dict | None # 额外元数据(如工具函数)
async def evaluate(self, solution: SolutionOutput) -> list[MetricResult]:
return [await metric(solution) for metric in self.metrics]
评估流程
class EvaluatorBase:
benchmark: BenchmarkBase # 基准测试集
storage: EvaluatorStorageBase # 结果存储
async def run(self, solution: Callable) -> dict:
results = []
for task in self.benchmark.tasks:
# 1. 执行解决方案
output = await solution(task.input)
# 2. 评估结果
metrics = await task.evaluate(output)
results.append(metrics)
# 3. 聚合统计
return self.aggregate(results)
存储结构
- Solution:单次任务的输入输出
- Evolution:同一任务的多次尝试历史
- Aggregation:整体统计结果
Model:LLM 适配层
ChatModelBase 为不同 LLM 提供统一接口:
class ChatModelBase:
model_name: str
stream: bool # 是否流式输出
async def __call__(
self,
prompt: list[dict],
tools: list[dict] | None = None,
tool_choice: str | None = None,
structured_model: Type[BaseModel] | None = None,
) -> ChatResponse | AsyncGenerator[ChatResponse, None]: ...
class ChatResponse:
content: list[ContentBlock] # 内容块列表
metadata: dict | None # 结构化输出存放在此
usage: ModelUsage # token 使用统计
已适配的模型
| Model | 厂商 | 特性 |
|---|---|---|
OpenAIModel | OpenAI | GPT-4/3.5, 支持 function calling |
AnthropicModel | Anthropic | Claude, 支持 extended thinking |
GeminiModel | Gemini Pro/Flash | |
DashscopeModel | 阿里 | 通义千问全系列 |
OllamaModel | Ollama | 本地模型运行 |
TrinityModel | 携程内部 | 内部模型服务 |
结构化输出
所有模型统一支持 Pydantic BaseModel 的结构化输出:
class MyOutput(BaseModel):
summary: str
confidence: float
response = await model(prompt, structured_model=MyOutput)
# response.metadata = {"summary": "...", "confidence": 0.95}
消息模型:Msg 类
Msg 是 AgentScope 中所有消息的统一抽象:
class Msg:
id: str # 唯一标识 (shortuuid)
name: str # 发送者名称
role: Literal["user", "assistant", "system"]
content: str | list[ContentBlock] # 支持多模态
metadata: dict | None # 结构化输出、额外信息
timestamp: str
def get_content_blocks(self, block_type=None) -> list[ContentBlock]: ...
def get_text_content(self) -> str | None: ...
def has_content_blocks(self, block_type) -> bool: ...
内容块类型
TextBlock = {"type": "text", "text": str}
ThinkingBlock = {"type": "thinking", "thinking": str} # Claude extended thinking
ImageBlock = {"type": "image", "source": {"type": "url"|"base64", ...}}
AudioBlock = {"type": "audio", "source": {...}}
VideoBlock = {"type": "video", "source": {...}}
ToolUseBlock = {"type": "tool_use", "id": str, "name": str, "input": dict}
ToolResultBlock = {"type": "tool_result", "id": str, "name": str, "output": ...}
Toolkit:工具管理系统
Toolkit 是 AgentScope 中管理工具函数的核心模块:
class Toolkit(StateModule):
tools: dict[str, RegisteredToolFunction] # 已注册的工具
groups: dict[str, ToolGroup] # 工具分组
skills: dict[str, AgentSkill] # Agent 技能
核心功能
1. 工具注册
toolkit.register_tool_function(
tool_func=my_function,
group_name="basic", # 分组
preset_kwargs={"api_key": x}, # 预设参数(不暴露给 LLM)
namesake_strategy="rename", # 同名策略:raise/override/skip/rename
)
2. 分组管理
toolkit.create_tool_group("web_tools", description="网页相关工具")
toolkit.update_tool_groups(["web_tools"], active=True)
# 元工具:让 Agent 自己管理工具激活状态
toolkit.register_tool_function(toolkit.reset_equipped_tools)
3. MCP 集成
await toolkit.register_mcp_client(mcp_client)
4. Agent Skills
toolkit.register_agent_skill("/path/to/skill_dir")
# skill_dir 必须包含 SKILL.md(带 YAML front matter)
后记
目前的AS还有很多局限的地方,一方面是目前没有较好的解决方案,另一方面是工作量非常大,但整体来说,已经算是一个比较可靠的Agent框架了