Skip to content

Day 5 -- Tools 设计文档

设计目标:构建可扩展的工具系统,支持通过基类继承和装饰器两种方式定义工具,自动生成 JSON Schema 参数描述,并通过注册中心统一管理。


一、核心接口设计

1.1 Tool(抽象基类)

属性/方法类型说明
namestr (abstract property)工具唯一标识
descriptionstr (abstract property)功能描述(给 LLM 看的)
parametersdict (abstract property)JSON Schema 格式的参数定义
executeasync method实际执行逻辑

1.2 ToolResult

字段类型说明
outputstr成功结果
errorOptional[str]错误信息
is_errorbool是否出错

为什么不直接返回 str?

  • 需要区分"成功但结果为空"和"执行出错"
  • 上层可以根据 is_error 做不同处理(如日志、重试)
  • 结构化返回值便于后续扩展(如添加 metadata)

1.3 @tool 装饰器

参数说明
name工具名称
description工具描述

自动推导的内容

  • 从函数签名获取参数名和类型标注
  • Python 类型到 JSON Schema 类型的映射
  • 有默认值的参数标记为非必填
  • 从 docstring 提取参数描述

1.4 ToolRegistry

方法签名说明
registerregister(tool: Tool)注册工具(name 重复则覆盖)
getget(name: str) -> Optional[Tool]按名字获取工具
list_toolslist_tools() -> List[Tool]获取所有已注册工具
get_tool_definitionsget_tool_definitions() -> List[dict]生成 OpenAI API 兼容的工具定义

二、关键流程图

@tool 装饰器的工作原理

工具调用流程(与 Agent 协作)


三、设计决策与权衡

决策 1:两种工具定义方式(基类继承 vs 装饰器)

方案适合场景优点缺点
基类继承复杂工具(需要初始化状态)灵活,可以有构造函数和内部状态样板代码多
@tool 装饰器简单工具(纯函数)极简,一个函数搞定不适合有状态的工具

选择理由:同时提供两种方式,让开发者根据需求选择。简单工具用装饰器(快),复杂工具用基类(灵活)。

决策 2:JSON Schema 自动生成

方案优点缺点
自动从类型标注推导(选择)零手工编写,减少出错复杂类型(如嵌套对象)支持有限
手动编写 JSON Schema完全控制繁琐,容易和代码不同步
Pydantic 模型定义参数强大的类型系统工具定义变重

类型映射表

Python 类型JSON Schema 类型
strstring
intinteger
floatnumber
boolboolean
listarray
dictobject
无标注string(兜底)

决策 3:工具执行异常处理

python
try:
    result = await tool.execute(**args)
except Exception as e:
    result = ToolResult(error=str(e), is_error=True)

关键:工具内部异常不向上传播,而是包装成 ToolResult。这保证了 Agent 的推理循环不会因为一个工具报错就中断。

决策 4:Registry 用 dict 而非 list

方案按名查找重复检测
Dict[name, tool](选择)O(1)自动覆盖(或可改为报错)
List[tool]O(n) 遍历需要手动检查

四、与前序章节的集成点

  • 被 Day 4 依赖:AgentRuntime 通过 ToolRegistry 获取工具定义和执行工具
  • 被 Day 6 依赖:Skill 的 required_tools 引用 ToolRegistry 中的工具名
  • 被 Day 8 依赖:MCPServer 把 ToolRegistry 的工具暴露为 MCP 服务;MCPClient 的 RemoteTool 也注册到 ToolRegistry

五、与真实生产系统的对比

维度miniOpenClaw生产级实现
参数校验JSON Schema(LLM 端校验)JSON Schema + 服务端 Pydantic 二次校验
工具发现硬编码注册动态加载(插件系统、MCP 发现)
执行安全无沙箱Docker 容器 / 沙箱环境执行
权限控制按用户/角色控制工具访问
并行执行顺序执行asyncio.gather 并行 + 依赖图调度
超时依赖 Agent 全局超时每个工具独立超时设置