上一节我们的 Tool:
@dataclass
class Tool:
name: str
description: str
func: Callable
现在很自然可以加:
schema: dict
但是更好的方式不是手写:
schema = {...}
而是在注册时自动:
schema = function_to_schema(func)
这样 Tool 定义只写一次。
理想流程
Python Function
↓
@tool
↓
Registry.register
↓
自动提取:
- name
- description
- signature
- type hints
↓
生成 Tool Schema
↓
保存 Tool
以后:
registry.list_schemas()
直接给 Provider。
执行:
registry.execute(tool_call)
也是同一 Registry。
这就形成了单一事实来源。
把 Registry 和 Schema 合在一起以后,系统里就不应该再出现两套彼此独立的 Tool 定义。可以把下面这张图理解成“一份 Tool,两条出口”:一条通过 list_schemas() 去模型侧,另一条通过 execute() 去真实函数侧。
![图片[1]-小节三:让 Schema 与 Registry 合体——一个 Tool 只定义一次,模型与 Executor 共用同一份信息-大赛人网](https://www.dsrw.com/wp-content/uploads/2026/11/image-1479.png)
这样做真正省掉的不是几行代码,而是配置漂移。函数参数一旦变化,只要 Schema 从真实函数生成,模型看到的协议和 Harness 最终调用的 Callable 就更不容易错位。
完整 Tool + Registry + Schema 实现
下面是一段非常重要的完整代码。
建议你保存为:
tool_registry_schema_demo.py
它不依赖任何第三方库。
这一段代码最值得理解什么?
不是 inspect API。
而是:
@tool
↓
Registry
├─ 保存真实 func
└─ 自动生成 schema
从此以后:
模型知道什么
和:
Harness 能执行什么
来自同一个 Tool。
这会极大减少配置漂移。
Schema 要不要直接存 Registry?
可以。
也可以只在需要时动态生成。
两种都合理。
课程里先存起来,更直观。
真实项目如果函数定义不会变化,注册时生成一次就够。
Tool Schema 与 Provider 的关系
我们内部定义:
registry.list_schemas()
Provider 可能还需要包装成特定 API 形式。
例如内部是:
{
"name": "...",
"description": "...",
"parameters": {...}
}
某个 Provider 可能要求外面再套一层。
这属于 Provider Adapter 的职责。
所以边界是:
Registry:
内部统一 Tool Schema
Provider:
转换成目标模型 API 的 Tool 格式
这样 Registry 不依赖具体模型厂商。
这和上一部分的 Provider 解耦正好接上。
例如,我们内部保留:
{
"name": "read_file",
"description": "读取指定文本文件",
"parameters": {
"type": "object",
"properties": {}
}
}
OpenAI Compatible Provider 再按接口要求包装成:
{
"type": "function",
"function": {
"name": "read_file",
"description": "读取指定文本文件",
"parameters": {
"type": "object",
"properties": {}
}
}
}
注意,外层 type 和 function 是传输格式,不应该反过来污染 Registry 的内部模型。将来切换 Provider 时,我们只换包装方式,不必重写所有 Tool。
这里可以把 Provider Adapter 看成一个“翻译层”。Registry 保存的是课程内部统一协议,到了不同模型厂商那里,再按各自 API 要求套外壳。下面这张图把这个边界放进完整调用链里看,会更容易理解为什么 Registry 不应该直接绑定某一家 SDK。
![图片[2]-小节三:让 Schema 与 Registry 合体——一个 Tool 只定义一次,模型与 Executor 共用同一份信息-大赛人网](https://www.dsrw.com/wp-content/uploads/2026/11/image-1480.png)
换句话说,Schema 的业务含义属于 Tool 系统,厂商需要的包装格式属于 Provider。 两层分开以后,换模型时主要调整 Adapter,而不是回头修改每个工具。
回到配套项目看一遍
当前项目的 ToolSpec 已经保存了 name、description、parameters 和真实 func,Registry.schemas() 会把内部 Schema 统一列出来。阶段项目 03 为了让结构更直观,仍然手写 parameters,本节的 function_to_schema() 是我们接下来可以接入的增强方案,两者不要误认为已经自动连在一起。
在项目根目录运行:
python3 --version
python3 projects/03_tool_registry_schema/main.py
第一行应显示 Python 3.9.x;随后会打印 add 工具的 Schema,并输出执行结果 5。这一步先确认“登记—导出—执行”链路畅通,至于自动生成和执行前校验,我们分别在本节示例与后续 Harness 中补齐。

















请登录后查看评论内容