工具定义的三件套里,name 和 description 回答"这个工具是什么、什么时候用",说给模型听;第三件 input_schema 回答"参数怎么填"——用 JSON Schema 这门行业标准的方言写成,告诉模型:参数叫什么名、什么类型、哪些必填、允许哪些取值。模型填参数时照着它来,所以它本质上是一份模型与你的程序之间的接口协议。
这份契约为什么值得单独写一篇?因为它是工具调用质量的第一决定因素:模型选不选这个工具看 description,填得对不对几乎全看 schema。本文逐行解剖一份真实定义,给全高频词汇表,再看进阶组合与"说话算数"的两个机制。
1、参数契约解决什么问题
模型的输出是自由文本,没有约束时让它"传两个数字和一个运算符",它可能给出 5,也可能给出 "五"、"5.0" 甚至一段解释。程序这边却是严格类型的世界:5 能进加减法,"5" 进去就是字符串拼接。中间必须有一份双方都认的约定。
JSON Schema 就是这份约定的标准写法:它是描述 JSON 数据结构的一门小语言,一门类型系统足够、又足够通用的方言。一份契约回答四件事:参数叫什么名(properties 的键)、什么类型(type)、哪些必填(required)、允许哪些取值(enum 等)。工具定义的完整形态如下:
{
"name": "calculate",
"description": "对两个数执行四则运算",
"input_schema": {
"type": "object",
"properties": {
"a": {"type": "number", "description": "第一个操作数"},
"b": {"type": "number", "description": "第二个操作数"},
"op": {"type": "string", "enum": ["add", "subtract", "multiply", "divide"],
"description": "运算类型"}
},
"required": ["a", "b", "op"]
}
}
外层的 name 与 description 管选择,input_schema 管填写——三件套各司其职,本文聚焦第三件。
2、逐行解剖工具定义
2.1、六件事各司其职
把上面的 input_schema 拆开编号看,六件事各自的位置与职责是:根类型声明整体形态是对象,所有参数打包成键值对;properties 是参数定义表,每个键就是一个参数名;每个参数用 type 约束类型,用 description 附一句给模型看的人话说明——模型选参、填参都靠它;enum 把取值锁死在白名单内,模型不可能填出 "乘";required 划定必填边界,不在名单里的参数可以省略——比如读文件工具的 offset、limit 不设必填,模型就可以只传一个 path。
两个容易低估的细节。其一,description 写在参数级同样重要:"第一个操作数" 看似废话,当工具同时有 a、b、precision 三个数值参数时,模型分清谁靠的就是这句说明。其二,required 是"最小调用"的设计:把偶尔才需要的参数放进必填,等于强迫模型每次都编一个值,反而制造垃圾参数。
2.2、number 与 integer
类型词汇里最容易混淆的一对:number 是任意数字,小数、负数都行;integer 仅限整数。读文件工具的 offset(跳过多少行)该用 integer——"跳过 3.5 行"没有意义;金额、权重这类允许小数的就用 number。类型选得越准,模型需要猜测的余地越小。
3、高频词汇表
JSON Schema 的完整关键字有几十个,工具定义里高频的就这几个:
| 关键字 | 作用 | 例 |
|---|---|---|
type |
数据类型 | string、number、boolean、array 等 |
description |
给模型看的说明 | "第一个操作数" |
enum |
取值白名单 | ["add", "subtract"] |
required |
必填参数名数组 | ["a", "b", "op"] |
properties |
对象的属性定义表 | 上文 ② |
items |
数组元素的约束 | 配 type: array 使用 |
additionalProperties |
是否禁止多余字段 | false 即锁死参数集 |
表里最后一行是严格校验的入场券,第 5 节展开。常用的 type 取值及适合的参数形态如下:
| 类型 | 含义 | 适合 |
|---|---|---|
string |
字符串 | 路径、查询词、城市名 |
number |
任意数字 | 金额、权重、温度 |
integer |
整数 | 页码、行数、数量 |
boolean |
布尔 | 开关选项 |
array |
列表 | 关键词集合、ID 列表 |
object |
对象 | 嵌套结构(少见,能不用则不用) |
两张表的共同结论:词汇不多,组合足以覆盖绝大多数工具;先用好这七个关键字,再谈长尾。
4、数组与枚举的组合
进阶一步,让一个参数收一组值。搜索工具的契约可以长这样:
{
"type": "object",
"properties": {
"keywords": {
"type": "array",
"items": {"type": "string"},
"description": "要搜索的关键词列表"
},
"scope": {"type": "string", "enum": ["all", "code", "docs"],
"description": "搜索范围"}
},
"required": ["keywords"]
}
items 声明数组里每个元素都必须是字符串,scope 用枚举锁死三选一。模型收到这份契约后,合法的调用形如 {"keywords": ["安全阀", "max_turns"], "scope": "code"}——列表里混进数字、scope 填 "代码",都会被识别为不合法。再进一层,object 里还能嵌 object:properties 套 properties 即可描述多级结构,但嵌套每深一层,模型填错的概率就高一分——参数结构能平铺就不嵌套,是工具设计的实用纪律。
5、契约为何说话算数
两个机制保证 schema 不只是建议。第一道在模型侧:schema 随请求发给模型,模型生成参数时以它为模板。这有一个一分钟就能复现的实验:把某个参数的 type 从 number 改成 string,同一句提问下,模型提交的参数立刻跟着变。对照如下:
"type": "number" → 模型提交 {"a": 5, "b": 3, "op": "add"}
"type": "string" → 模型提交 {"a": "5", "b": "3", "op": "add"}
同一道题,契约一改、输出即改——模型不是"知道"参数类型,而是照着模板生成的。第二道在接口侧:工具定义可以开启严格校验,声明 strict: true 后,不合 schema 的参数直接打回重填,不再进入执行。开启有代价:schema 必须 additionalProperties: false 且列全 required,即完全锁死参数集。契约生效的完整链路如下:
图中两道关卡一软一硬:模板引导决定"大概率填对",严格校验兜底"填错必被拦"。
6、全行业通用的钥匙
最后值得一记:JSON Schema 不是大模型圈的发明。json-schema.org 是一门有年头的标准,OpenAPI 接口规范 用它描述请求体,前端表单校验用它约束输入,配置文件校验也用它。在工具定义里学会这七个关键字,等于顺手拿到一把全行业通用的钥匙——同一个心智模型,从 agent 工具一路用到接口文档与表单。工具定义的接口规范可对照 官方工具使用文档。
7、总结
回顾全文:input_schema 是工具定义里参数部分的契约,用 JSON Schema 写成;六个高频部件——根类型、properties、type、description、enum、required——覆盖绝大多数场景;数组配 items 收一组值,结构能平铺就不嵌套;契约靠"模型照模板生成 + strict 严格校验"两道机制说话算数;而 JSON Schema 本身是 OpenAPI 与表单校验共用的行业标准。对于正在写工具的开发者,建议每个参数都补上 description、把可选参数挡在 required 之外、枚举值一律用 enum 锁死——这三件小事做到,工具调用的准确率就有八成。

