☰
Agent Tool Schema 手写指南:从设计到生产级实操
2026/10/10 1:30:31 网站建设 项目流程

1. 手动创建 Agent Tool Schema 的核心价值与设计思路

1.1 为什么手写 Schema 比自动生成更靠谱

做 Agent 开发的朋友大概率都经历过这个阶段:一开始图省事,直接让大模型根据函数签名自动生成 tool schema,结果上线后各种幺蛾子——参数类型对不上、必填项漏了、嵌套对象解析失败,最要命的是模型调用时传了个完全不在预期内的字段,后端直接 500。我踩过几次坑之后,现在凡是核心工具,一律手动写 schema,一个字段一个字段地抠。

手动创建 Agent tool schema,说白了就是你自己定义一份结构化的描述文件,告诉大模型“这个工具叫什么、干什么用、需要哪些参数、每个参数是什么类型、哪些必填、取值范围是什么”。这份 schema 就是模型和你的后端函数之间的契约。契约写得越清楚,模型调用越准确,出错率越低。

为什么自动生成不靠谱?因为自动生成通常只看到函数的形参列表,看不到业务语义。比如一个search_order函数,参数叫q,自动生成会写“q: string”,模型根本不知道这是订单号还是关键词。你手动写就能写成“order_id: 订单编号,格式为 16 位数字字符串”,模型一看就懂。这就是手动 schema 的价值——把隐式知识显式化。

适合谁来参考这篇内容?如果你正在做 AI Agent 开发、正在接入 function calling / tool use 能力、或者被模型乱传参数搞得头大,那这篇就是写给你的。不需要你是 schema 专家,但最好对 JSON 和基本的类型系统有点概念。

1.2 Schema 在 Agent 架构里到底扮演什么角色

很多人把 schema 当成一个“附属品”,觉得随便写写就行,这是最大的误区。在 Agent 架构里,schema 是模型推理链上的关键一环。模型收到用户请求后,会先做意图识别,然后从可用工具列表里挑一个,再根据 schema 生成调用参数。整个过程中,schema 是模型唯一的“说明书”。

你可以把 schema 想象成餐厅菜单。菜单写得清楚,顾客点菜就准;菜单写得含糊,顾客只能瞎猜,最后端上来的菜不是他想要的。Agent 里的 schema 就是这份菜单,模型就是顾客。菜单上写“招牌菜”,顾客不知道是什么;写“宫保鸡丁,微辣,含花生”,顾客一目了然。

从技术角度看,一份完整的 tool schema 通常包含这几个部分:工具名称(name)、工具描述(description)、参数定义(parameters)。参数定义里又要区分类型(type)、描述(description)、是否必填(required)、枚举值(enum)、默认值(default)等。这些字段不是随便定的,每一个都直接影响模型的调用准确率。

我实测下来,description 字段的权重最高。模型在决定调用哪个工具时,主要看 name 和 description;在生成参数时,主要看每个参数的 description 和 type。所以这两个地方一定要下功夫,不能偷懒。

1.3 手动 Schema 与 Zod Schema 的取舍

现在社区里很流行用 Zod 来定义 schema,然后自动转换成 JSON Schema 喂给模型。Zod schema 的好处是类型安全,TypeScript 项目里用起来很爽,改一个字段类型,编译期就能发现所有引用处的问题。但 Zod 也有个问题:它生成的 JSON Schema 往往过于“机器化”,description 字段经常是空的,或者只有一句干巴巴的类型说明。

我的做法是混合使用:用 Zod 做运行时校验,保证后端拿到的参数是合法的;但喂给模型的 schema 单独手写一份,description 写得足够详细。两份 schema 保持结构一致,但用途不同。这样既享受了类型安全,又保证了模型调用的准确率。

如果你项目里没有 TypeScript,或者不想引入 Zod 依赖,那纯手写 JSON Schema 完全够用。关键是理解 JSON Schema 的规范,知道type、properties、required、enum、items这些关键字怎么用。下面我会详细拆解。

2. 核心字段逐个拆解与实操要点

2.1 name 和 description:模型选工具的第一依据

name字段看起来简单,其实有讲究。命名要遵循“动词+名词”的格式,比如get_weather、search_order、create_task。不要用weather这种纯名词,模型不知道你是要查还是要改。也不要用doStuff这种含糊的名字,模型看了直接懵。

description是重中之重。我见过太多人写 description 就一句话“获取天气”,这远远不够。好的 description 应该包含三部分:这个工具做什么、什么时候用、返回什么。比如:

查询指定城市的实时天气。当用户询问天气、气温、是否下雨等问题时使用此工具。返回温度、湿度、天气状况和风力信息。

这样写,模型在意图识别阶段就能准确匹配。如果用户问“北京今天热不热”,模型看到“气温”这个词,就知道该调这个工具。

还有一个技巧:在 description 里明确写出“不适用”的场景。比如“此工具仅查询实时天气,不查询历史天气或未来预报”。这样能避免模型在错误场景下调用,减少无效请求。

2.2 parameters 的类型系统:string、number、boolean、array、object

JSON Schema 支持的类型有 string、number、integer、boolean、array、object、null。Agent tool schema 里最常用的是前六种。每种类型都有对应的约束关键字,用好了能大幅提升参数准确率。

string 类型可以加enum限定取值范围,加pattern限定正则格式,加minLength/maxLength限定长度。比如订单号是 16 位数字,就写"pattern": "^\\d{16}$"。这样模型生成的参数如果不符合格式,后端可以直接拒绝,不用等到业务逻辑里才发现。

number 和 integer 类型可以加minimum/maximum限定范围,加multipleOf限定倍数。比如分页参数page_size,写"minimum": 1, "maximum": 100,防止模型传个 10000 进来把数据库打挂。

boolean 类型比较简单,但 description 要写清楚 true 和 false 分别代表什么。比如"is_urgent": {"type": "boolean", "description": "是否加急,true 表示加急处理,false 表示普通处理"}。

array 类型要定义items,说明数组元素的类型。如果数组元素是对象,还要定义对象的properties。嵌套层级不要太深,超过三层模型就容易出错。我一般控制在两层以内。

object 类型用于结构化参数,比如一个address参数包含省市区街道。object 里要定义properties和required,每个子字段都要有 description。

2.3 required 与 optional:必填项设计的取舍

required数组里列出所有必填参数名。这里有个经验:必填项越少越好。每多一个必填项,模型调用失败的概率就增加一分。因为模型可能漏传,或者传了 null。

我的原则是:只有业务上绝对不可缺的参数才设为必填。比如查询订单,order_id必填;但include_items这种可选参数,就设为可选,默认 false。这样模型即使不传,后端也能正常处理。

对于可选参数,要在 description 里写清楚默认行为。比如"include_items": {"type": "boolean", "description": "是否包含订单商品明细,默认为 false"}。这样模型知道不传也没关系。

还有一个坑:有些模型会把可选参数传成空字符串或 0,而不是省略。所以后端校验时,要把空字符串和 0 也当作“未传”处理。这个细节不注意,线上就会出问题。

2.4 enum 和 default:限定取值范围与兜底策略

enum是提升参数准确率的利器。凡是取值范围有限的参数,一律用 enum。比如订单状态只有 pending、paid、shipped、completed、cancelled 五种,就写"enum": ["pending", "paid", "shipped", "completed", "cancelled"]。模型看到 enum,就知道只能从这几个里选,不会瞎编。

default用于给可选参数指定默认值。但要注意:default 只是文档说明,模型不一定会遵守。所以后端还是要做兜底。比如"default": 20,后端在参数缺失时用 20,而不是依赖模型传 20。

enum 和 default 结合使用效果更好。比如"sort_order": {"type": "string", "enum": ["asc", "desc"], "default": "desc", "description": "排序方向,asc 升序,desc 降序,默认 desc"}。这样模型知道可选值,也知道默认值。

3. 完整实操流程:从零手写一份生产级 Schema

3.1 第一步:梳理工具清单与职责边界

动手写 schema 之前,先拿张纸把你要暴露给 Agent 的工具列出来。每个工具写一句话职责,然后检查有没有重叠。比如get_user_info和search_user如果都能查用户,模型就会纠结该调哪个。这时候要么合并,要么把边界写清楚。

我一般会做一个工具矩阵表,横轴是工具名,纵轴是“输入什么、输出什么、什么时候用、什么时候不用”。这个表填完,schema 的骨架就出来了。

工具名输入输出使用场景禁用场景
get_weather城市名天气信息查实时天气查历史天气
search_order订单号订单详情查订单状态创建订单
create_task任务描述任务ID新建任务修改任务

这张表不仅帮你理清思路,还能直接作为 description 的素材。

3.2 第二步:定义参数结构并写 description

以search_order为例,假设它需要订单号、是否包含明细、语言三个参数。订单号必填,其他可选。手写 schema 如下:

{ "name": "search_order", "description": "根据订单号查询订单详情。当用户提供订单号并询问订单状态、物流、金额等信息时使用此工具。返回订单状态、下单时间、金额和商品明细。", "parameters": { "type": "object", "properties": { "order_id": { "type": "string", "pattern": "^\\d{16}$", "description": "订单编号,16 位数字字符串,例如 1234567890123456" }, "include_items": { "type": "boolean", "description": "是否包含商品明细,true 返回明细列表,false 不返回,默认为 false" }, "lang": { "type": "string", "enum": ["zh", "en"], "default": "zh", "description": "返回信息的语言,zh 中文,en 英文,默认 zh" } }, "required": ["order_id"] } }

这份 schema 里,order_id用了 pattern 限定格式,include_items和lang都有默认值说明。模型看到这份 schema,基本不会传错。

3.3 第三步:参数校验与后端兜底

Schema 写好了,后端不能直接信任模型传来的参数。必须做二次校验。我用的是“schema 校验 + 业务校验”两层。第一层用 JSON Schema 校验器检查类型、格式、枚举值;第二层在业务逻辑里检查语义,比如订单号是否存在、用户是否有权限。

后端兜底的关键是:所有可选参数都要有默认值处理。模型不传,后端用默认值;模型传了 null,后端也当默认值处理。这样即使模型抽风,服务也不会挂。

还有一个细节:模型有时会把数字传成字符串,比如"page_size": "20"。后端要做类型转换,能转就转,转不了就报错。这个逻辑要写在参数解析层,不要散落在业务代码里。

3.4 第四步:实测与迭代优化

Schema 写完不是终点,要拿真实请求去测。我一般会构造 20 到 30 个测试用例,覆盖正常场景、边界场景、异常场景。比如订单号传 15 位、传字母、传空字符串,看模型怎么反应,后端怎么处理。

实测中我发现一个规律:description 里如果写了具体示例,模型调用准确率会明显提升。比如order_id的 description 里写了“例如 1234567890123456”,模型生成参数时就会模仿这个格式。所以我现在写 schema,每个关键参数都带一个示例。

迭代优化时,重点看模型调用失败的 case。是工具选错了,还是参数传错了?工具选错就改 name 和 description;参数传错就改参数的 type 和 description。改完再测,一般两三轮就能稳定。

4. 常见问题与排查技巧实录

4.1 模型不调用工具或调用错误工具

这是最常见的问题。排查思路分三步:第一,检查工具列表是否为空,或者工具数量是否过多。工具超过 20 个,模型选择准确率会下降。第二,检查 name 和 description 是否清晰。如果两个工具的描述太像,模型就会混淆。第三,检查用户请求是否真的需要调用工具。有些请求模型直接回答就行,不需要工具。

我的经验是:工具数量控制在 10 个以内,每个工具的 description 至少 50 字,包含使用场景和禁用场景。这样模型选择准确率能到 95% 以上。

4.2 参数类型不匹配或格式错误

模型传的参数类型和 schema 定义不一致,比如 schema 写 string,模型传 number。这种情况通常是 description 没写清楚。比如order_id如果只写“订单号”,模型可能觉得数字也行。加上“16 位数字字符串”和 pattern,模型就知道要传字符串。

还有一种情况是嵌套对象解析失败。模型把 object 传成了 string,比如"address": "{\"city\":\"beijing\"}"。这是模型对 object 类型理解不到位。解决办法是在 description 里明确写“address 是一个对象,包含 city、district、street 三个字段”,并给出示例。

4.3 必填参数缺失或传 null

模型漏传必填参数,或者传了 null。这通常是因为 required 数组没写对,或者 description 没强调必填。我的做法是在 description 里加“必填”字样,比如“订单编号,必填,16 位数字字符串”。这样模型知道这个参数不能省。

如果模型还是漏传,后端要返回明确的错误信息,告诉模型“order_id 是必填参数”。有些 Agent 框架支持把错误信息回传给模型,模型会自动重试。这个机制要用起来。

4.4 常见问题速查表

问题现象可能原因排查方法解决方案
模型不调用工具工具描述不清检查 name 和 description补充使用场景和示例
调用错误工具工具职责重叠对比两个工具的 description合并工具或明确边界
参数类型错误description 未说明类型检查参数 description补充类型说明和示例
必填参数缺失required 未强调检查 required 数组description 加“必填”
枚举值传错enum 未定义检查参数是否有 enum补充 enum 列表
嵌套对象解析失败object 描述不清检查 object 的 properties补充子字段说明和示例

4.5 独家避坑技巧

第一个技巧:schema 里的 description 不要用否定句。比如“不要传空字符串”,模型反而会传空字符串。要用肯定句:“请传 16 位数字字符串”。模型对肯定句的理解更准确。

第二个技巧:参数顺序有讲究。把最重要的参数放在 properties 的第一个,模型生成时会更关注。比如order_id放第一个,lang放最后。

第三个技巧:定期 review schema。业务变了,schema 也要跟着变。我一般每个月 review 一次,把不再使用的工具删掉,把新增的参数补上。schema 和代码一样,需要维护。

第四个技巧:用真实用户请求做回归测试。我收集了 100 条真实用户请求,每次改完 schema 都跑一遍,看调用准确率有没有下降。这个习惯帮我避免了好几次线上事故。

5. 进阶话题:Schema 版本管理与多工具编排

5.1 Schema 版本管理:别让改 schema 变成事故

Schema 一改,模型行为就可能变。所以改 schema 必须像改 API 一样谨慎。我的做法是给 schema 加版本号,比如search_order_v1、search_order_v2。新版本上线前,先灰度一部分流量,对比调用准确率和业务指标。没问题再全量。

版本管理还有一个好处:回滚方便。如果新 schema 导致调用失败率飙升,直接切回旧版本,不用改代码。这个机制在紧急情况下能救命。

5.2 多工具编排时的 Schema 设计

当 Agent 需要调用多个工具完成一个任务时,schema 设计要考虑工具之间的衔接。比如先search_order拿到订单号,再get_logistics查物流。这时候两个工具的 schema 要保证参数能对上:search_order返回的order_id要能直接作为get_logistics的输入。

我的做法是在 schema 的 description 里写明“此工具的输出可作为 XXX 工具的输入”。这样模型在编排时知道怎么串联。另外,工具之间的依赖关系要尽量简单,避免循环依赖。

5.3 并发场景下的 Schema 注意事项

Agent 扛并发时,schema 本身不会成为瓶颈,但 schema 背后的工具实现会。如果多个请求同时调用同一个工具,后端要做好限流和排队。Schema 层面能做的,是在 description 里写明“此工具调用频率有限制,请勿频繁调用”。虽然模型不一定遵守,但至少是个提示。

另外,并发场景下参数校验要更严格。因为高并发时,一个参数错误可能引发连锁反应。所以 pattern、enum、minimum、maximum 这些约束一个都不能少。

6. 我个人的实操体会

写了这么多 schema,我最大的体会是:schema 不是写给机器看的,是写给模型看的。机器只需要类型对就行,模型需要理解语义。所以 description 的重要性怎么强调都不为过。我现在的习惯是,每写一个参数,都问自己一句:“模型看到这句话,知道该传什么吗?”如果答案不确定,就继续改。

还有一个体会是:schema 要跟着模型迭代。不同模型对 schema 的理解能力不一样。同一个 schema,在 A 模型上准确率 95%,在 B 模型上可能只有 80%。所以换模型时,schema 要重新测一遍,该调的调,该补的补。

最后分享一个小技巧:把 schema 当成产品文档来写。想象你在给一个新同事介绍这个工具,你会怎么说?把那些话整理一下,就是最好的 description。这个思路帮我省了很多反复修改的时间。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询