题目 1:为什么只告诉模型“你有一个 read_file 工具”还不够?
请从 Tool Name、参数名、参数类型、必填字段、用途描述几个角度说明。如果没有 Schema,模型可能出现哪些典型错误?
只知道 Tool Name,模型只能靠自然语言经验猜调用方式。它可能把参数写成
filename而不是path,漏掉必填参数,把整数传成字符串,或者根本不知道什么时候应该选择这个 Tool。Tool Schema 把 name、description、parameters、required 等信息结构化后,模型能在明确协议内产生 Tool Call。这样既减少模型猜测,也让 Harness 后续校验有统一依据。
题目 2:判断题——Python 参数有默认值,就通常不应该放进 required,对吗?
请结合 read_file(path: str, encoding: str = "utf-8") 解释。
通常对。
path没有默认值,函数调用时必须提供,所以应该出现在required;encoding有默认值,即使模型不传,Python 也能使用"utf-8",因此通常不需要标为 required。自动生成 Schema 时可以通过inspect.Parameter.empty判断参数是否存在默认值。不过业务设计上仍要确认默认值是否真的适合 Tool Calling 场景。
题目 3:代码阅读——为什么下面 Schema 仍然可能导致模型乱传值?
{
"metric": {
"type": "string"
}
}
后端实际上只接受 revenue、request、click。应该怎么改?
因为
type: string只限制“必须是字符串”,没有限制字符串取值范围。模型仍可能输出“收入”“income”“sales”等后端不认识的值。更好的 Schema 应增加enum,例如["revenue", "request", "click"]。Python 侧还可以使用Literal["revenue", "request", "click"],再由 Schema Generator 自动转换成 enum。这样模型动作空间会更明确。
题目 4:编程实现——根据 Python 函数自动生成基础 Tool Schema
请使用 inspect.signature() 完成一个 function_to_schema(),至少支持 str、int、float、bool,并自动生成 required。
下面是一种完整实现:
这个版本已经能自动从函数签名生成基础 Schema。后续可以继续加入 list、Optional、Literal、description 等能力。
题目 5:综合应用——为什么 Schema 应该尽量从 Registry 中的 Tool 自动生成?
假设 Python 函数已经把参数 filename 改成 path,但手工维护的 Schema 忘了更新,会发生什么?如何避免?
如果函数签名已经改成
path,而 Schema 仍告诉模型参数叫filename,模型会按旧协议生成 Tool Call,Harness 执行时就会出现unexpected keyword argument。这就是多份事实来源导致的配置漂移。更稳的方式是 Registry 注册 Tool 时直接读取真实函数签名自动生成 Schema,让模型看到的参数定义与 Executor 实际调用的函数保持一致。人工只补充描述和额外业务约束。
题目 6:对比分析——Tool Schema、参数校验、Middleware 三者分别负责什么?
请用 read_file(path) 的路径逃逸例子说明为什么三者不能互相替代。
Tool Schema 主要告诉模型
path是一个字符串、是否必填,以及它的用途;参数校验负责确认 Tool Call 的结构与类型符合协议;Middleware 则负责执行层安全,例如把路径解析后检查是否仍位于 workspace 内。模型即使完全遵守type: string,仍可能传入../../etc/passwd,所以 Schema 不能替代安全检查。三层分别负责“生成正确结构”“验证结构”“控制真实行为”。
题目 7:概念理解——为什么说 Tool Schema 是 Agent 与程序之间的协议?
请从模型端和 Harness 端两个方向解释,而不是只回答“因为它是 JSON”。
模型端通过 Schema 了解有哪些 Tool、每个 Tool 的用途、参数名、类型和必填规则,从而按协议生成 Tool Call;Harness 端则可以使用同一套定义验证 Tool Call 是否符合预期,再通过 Registry 找到真实函数执行。也就是说,Schema 同时定义了“模型应该怎么请求”和“程序愿意接收什么请求”。它的本质是双方约定的机器可读契约,而不是因为使用了 JSON 就天然成为协议。
进一步阅读
- JSON Schema 基础资料:重点理解 object、properties、required、array、enum、minimum、maximum 等常用约束。
- Python
inspect模块官方文档:用于读取函数签名、默认值与参数信息。 - Python
typing模块官方文档:重点关注get_origin、get_args、Literal、Optional等类型结构。 - API Contract / Interface Contract 相关资料:帮助理解 Tool Schema 为什么本质上是一份机器可读协议。
- OpenAPI / JSON Schema 相关思想:可以类比普通后端 API 如何用结构化协议描述参数。
- Input Validation 相关资料:理解 Schema 与真实运行时校验的边界。
- Capability Security 相关资料:为后续 Tool 权限和 Middleware 做准备。
- Prompt / Tool Description 设计资料:理解为什么工具描述会直接影响模型选择 Tool 的质量。
术语表
- 工具模式(Tool Schema):描述 Tool 名称、用途和参数结构的机器可读协议。它既帮助模型生成正确 Tool Call,也可以为 Harness 参数校验提供依据。
- JSON Schema:一种描述 JSON 数据结构和约束的规范思想,可表达对象、字符串、整数、数组、必填字段、枚举和值范围等。Tool Schema 通常会借鉴这套结构。
- 属性集合(Properties):Tool 参数对象中的字段定义,例如
path、limit、keyword,每个属性可以继续声明类型和其他约束。 - 必填字段(Required):调用 Tool 时必须提供的参数集合。Python 中没有默认值的参数通常可以映射为 required。
- 枚举(Enum):把参数允许值限制在固定集合内,例如日志级别只能是
debug、info、warning、error。它可以显著减少模型自由发挥。 - 类型标注(Type Hint):Python 函数签名中的
str、int、list[str]、Literal[...]等类型信息,是自动生成 Tool Schema 的重要来源。 - 模式生成器(Schema Generator):读取 Python 函数签名、类型标注和描述,并自动构建 Tool Schema 的程序组件。
- 接口契约(Contract):调用方与执行方共同遵守的约定。在 Tool Calling 中,模型按 Schema 产生请求,Harness 按 Schema 接收和校验,因此 Schema 就承担了契约角色。
本章总结
这一节我们把 Tool 系统从:
Harness 知道有哪些函数
推进到了:
模型也知道每个函数应该怎么调用
上一节 Tool Registry 解决,“有哪些 Tool?真实 Python Callable 在哪里?”
这一节 Tool Schema 解决,“这些 Tool 怎么描述给模型?参数怎么传?”
我们从最简单的:
def read_file(
path: str,
):
"""读取指定文件"""
自动生成:
{
"name": "read_file",
"description": "读取指定文件",
"parameters": {
"type": "object",
"properties": {
"path": {
"type": "string"
}
},
"required": [
"path"
]
}
}
真正值得记住的不是 JSON 结构,而是,Tool Schema 本质上是 Agent 与程序之间的协议。
模型按协议表达:
我想调用什么
参数是什么
Harness 再按同一协议判断:
工具是否存在
参数结构是否正确
能否真正执行
我们还亲手实现了:
inspect.signature
↓
读取参数
↓
读取 Type Hint
↓
判断默认值
↓
生成 properties
↓
生成 required
并继续扩展到:
list
Optional
Literal
enum
最重要的是,我们没有把 Schema 单独做成一份手工 JSON。
而是让:
Python Function
↓
@tool
↓
Registry
↓
Schema Generator
形成一个统一入口。
这样模型看到的 Tool 定义,和 Harness 真正执行的 Tool,不容易失去同步。
这一节也必须记住三个边界:
第一,自动生成不等于自动设计。
糟糕的函数名、参数名、docstring,照样会生成糟糕 Schema。
第二,Schema 不等于安全。
它可以告诉模型 path 是 string,但不能阻止 ../../etc/passwd。真实安全仍然要靠 Middleware 与路径校验。
第三,Schema 不是越复杂越好。
真正好的 Tool Schema 应该清晰、约束准确、描述简洁,让模型容易选对 Tool、传对参数,同时不要无谓消耗 Context。
如果你想验证自己是否真正掌握,可以做三件事:
1. 写一个 function_to_schema()
2. 支持 str / int / bool / list / Optional / Literal
3. 把 Registry 中所有 Tool 自动转换成 list_schemas()
当你能做到:
registry.list_tools()
给 Harness 看真实 Tool,
同时:
registry.list_schemas()
给模型看调用协议,
我们的 Tool 系统就真正开始成形了。
下一节,我们会继续把这个能力真正用起来。
我们将一次性打造 Agent 最常用的一组基础工具:
read_file
write_file
edit_file
list_files
search_files
run_python
run_shell
从下一节开始,Agent 不只是“理论上能调用 Tool”,而会真正开始操作一个受控项目环境。
















请登录后查看评论内容