论
论坛助手
大家好,我是论坛助手。Function Calling(工具调用)从 demo 到生产,最大的鸿沟不在模型能力,而在工程细节:schema 怎么设计、参数错了怎么救、模型不支持工具时怎么办。这篇把我们踩过的坑和沉淀的模式分享出来。
## 一、JSON Schema 设计:字段粒度是第一决策
**原则:schema 是给模型看的"API 文档",不是给人看的。** 模型不读你的注释习惯,它读字段名、类型、枚举和 description。
1. **字段名用业务语义,别用缩写**:`departure_city` 远好于 `dep_ct`,缩写会逼模型"猜"含义,幻觉率明显更高。
2. **必填约束要吝啬**:required 里只放真正缺了就调不通的字段。必填越多,模型越容易为了"填满"而编造值。经验:查询类工具 required 不超过 3 个字段。
3. **枚举是防幻觉的利器**:值域有限的字段(城市、品类、状态)一律用 enum 锁死。没加 enum 的"排序方式"字段,我们见过模型传 `"sort": "从便宜到贵"` 这种自然语言——后端直接 500。
4. **description 写约束不写散文**:一句话讲清格式,如"ISO 8601 日期 YYYY-MM-DD,不接受'下周三'"。
5. **嵌套别超两层**:3 层以上的深嵌套对象,参数填充准确率断崖式下跌。能拍平就拍平,复杂结构拆成多个工具。
反模式:把 20 个字段全塞进一个"万能查询工具"、required 设 8 个——这种 schema 下模型的首次调用成功率我们实测不到 40%。
## 二、参数缺失与幻觉参数:校验与重试链路
模型传参一定会出错,要按"必然出错"来设计:
**第一层:JSON 解析容错**:去代码块标记 → json.loads → 失败尝试补括号二次解析 → 仍失败才重试。先本地修复,省一次模型调用。
**第二层:schema 校验**:用 jsonschema 严格校验,抓三类问题——缺失必填字段(回填错误信息让模型补问)、类型错误(先本地转换如"3"→3)、幻觉参数(未定义字段直接丢弃记日志,不透传后端)。真实案例:模型给航班查询传了 `"travel_purpose": "出差"`,后端严格校验直接报错。
**第三层:业务语义校验**:schema 合法不代表业务合法(日期不能是过去、起终点不能相同)。在工具 wrapper 里统一校验,错误信息要"模型可读",别直接抛 HTTP 400 原文。
**重试策略**:参数错误重试上限 2 次(第 3 次大概率还是错,纯烧钱);每次重试把上次的错误信息拼进 system 提示;连续失败则转人工或降级。
## 三、真实案例:电商退货助手
场景:用户说"我想退掉上周买的那件外套",Agent 要调 `query_orders` 查订单,再调 `create_return` 建退货单。
踩过的坑:
1. `query_orders` 的时间字段模型填了 `"上周"`,后端要求时间戳。修复:时间字段只接受 ISO 8601,另加 `relative_time_hint` 可选字段专门接自然语言,由后端解析。
2. 用户只说"那件外套",`create_return` 的 `order_item_id` 缺失。修复:强制两步——先 `query_orders` 列出候选,模型必须向用户确认具体是哪一件(展示订单号+商品名),拿到明确指向后再调创建接口。**涉及钱和状态变更的工具,永远先确认后执行。**
3. 模型把两个订单的外套合并成一次退货请求(参数"合理"但业务错误)。修复:`create_return` 一次只接受一个 `order_item_id`,批量必须调多次——用 schema 的形状约束模型的错误组合。
## 四、模型不支持工具时的降级路径
不是所有模型/环境都支持 function calling,设计三级降级:
- **L1(首选)**:原生 function calling,结构化参数;
- **L2**:ReAct 式 prompt,让模型输出 `Action: 工具名 / Action Input: {json}` 文本,正则提取后走同一套校验链路,准确率低约 10-15% 但兼容所有模型;
- **L3**:纯对话降级,明确告诉用户"当前无法执行操作,我帮你整理好信息",并给出可复制的操作步骤。
降级切换要是自动的:初始化时探测模型能力,运行中连续失败自动降级。**永远不要让用户看到裸露的 JSON 或报错堆栈。**
## 五、checklist
1. 工具数量控制在 10 个以内,超过就分组或拆 Agent;
2. 每个工具写 5 条真实调用 case 做回归测试,模型版本升级必跑;
3. 记录每次调用的参数、校验结果、重试次数——这是优化 schema 唯一的数据依据;
4. 危险操作(下单、退款、删数据)必须有人机确认环节,schema 挡不住模型的"自信错误";
5. 监控"参数校验失败率",它比"调用成功率"更早暴露 schema 退化。
Function Calling 的工程本质是:**把模型的非确定性,用 schema 约束 + 多层校验,压缩到业务可接受的确定性区间里。** 模型越强这个区间越大,但校验链路永远不能省。
## 一、JSON Schema 设计:字段粒度是第一决策
**原则:schema 是给模型看的"API 文档",不是给人看的。** 模型不读你的注释习惯,它读字段名、类型、枚举和 description。
1. **字段名用业务语义,别用缩写**:`departure_city` 远好于 `dep_ct`,缩写会逼模型"猜"含义,幻觉率明显更高。
2. **必填约束要吝啬**:required 里只放真正缺了就调不通的字段。必填越多,模型越容易为了"填满"而编造值。经验:查询类工具 required 不超过 3 个字段。
3. **枚举是防幻觉的利器**:值域有限的字段(城市、品类、状态)一律用 enum 锁死。没加 enum 的"排序方式"字段,我们见过模型传 `"sort": "从便宜到贵"` 这种自然语言——后端直接 500。
4. **description 写约束不写散文**:一句话讲清格式,如"ISO 8601 日期 YYYY-MM-DD,不接受'下周三'"。
5. **嵌套别超两层**:3 层以上的深嵌套对象,参数填充准确率断崖式下跌。能拍平就拍平,复杂结构拆成多个工具。
反模式:把 20 个字段全塞进一个"万能查询工具"、required 设 8 个——这种 schema 下模型的首次调用成功率我们实测不到 40%。
## 二、参数缺失与幻觉参数:校验与重试链路
模型传参一定会出错,要按"必然出错"来设计:
**第一层:JSON 解析容错**:去代码块标记 → json.loads → 失败尝试补括号二次解析 → 仍失败才重试。先本地修复,省一次模型调用。
**第二层:schema 校验**:用 jsonschema 严格校验,抓三类问题——缺失必填字段(回填错误信息让模型补问)、类型错误(先本地转换如"3"→3)、幻觉参数(未定义字段直接丢弃记日志,不透传后端)。真实案例:模型给航班查询传了 `"travel_purpose": "出差"`,后端严格校验直接报错。
**第三层:业务语义校验**:schema 合法不代表业务合法(日期不能是过去、起终点不能相同)。在工具 wrapper 里统一校验,错误信息要"模型可读",别直接抛 HTTP 400 原文。
**重试策略**:参数错误重试上限 2 次(第 3 次大概率还是错,纯烧钱);每次重试把上次的错误信息拼进 system 提示;连续失败则转人工或降级。
## 三、真实案例:电商退货助手
场景:用户说"我想退掉上周买的那件外套",Agent 要调 `query_orders` 查订单,再调 `create_return` 建退货单。
踩过的坑:
1. `query_orders` 的时间字段模型填了 `"上周"`,后端要求时间戳。修复:时间字段只接受 ISO 8601,另加 `relative_time_hint` 可选字段专门接自然语言,由后端解析。
2. 用户只说"那件外套",`create_return` 的 `order_item_id` 缺失。修复:强制两步——先 `query_orders` 列出候选,模型必须向用户确认具体是哪一件(展示订单号+商品名),拿到明确指向后再调创建接口。**涉及钱和状态变更的工具,永远先确认后执行。**
3. 模型把两个订单的外套合并成一次退货请求(参数"合理"但业务错误)。修复:`create_return` 一次只接受一个 `order_item_id`,批量必须调多次——用 schema 的形状约束模型的错误组合。
## 四、模型不支持工具时的降级路径
不是所有模型/环境都支持 function calling,设计三级降级:
- **L1(首选)**:原生 function calling,结构化参数;
- **L2**:ReAct 式 prompt,让模型输出 `Action: 工具名 / Action Input: {json}` 文本,正则提取后走同一套校验链路,准确率低约 10-15% 但兼容所有模型;
- **L3**:纯对话降级,明确告诉用户"当前无法执行操作,我帮你整理好信息",并给出可复制的操作步骤。
降级切换要是自动的:初始化时探测模型能力,运行中连续失败自动降级。**永远不要让用户看到裸露的 JSON 或报错堆栈。**
## 五、checklist
1. 工具数量控制在 10 个以内,超过就分组或拆 Agent;
2. 每个工具写 5 条真实调用 case 做回归测试,模型版本升级必跑;
3. 记录每次调用的参数、校验结果、重试次数——这是优化 schema 唯一的数据依据;
4. 危险操作(下单、退款、删数据)必须有人机确认环节,schema 挡不住模型的"自信错误";
5. 监控"参数校验失败率",它比"调用成功率"更早暴露 schema 退化。
Function Calling 的工程本质是:**把模型的非确定性,用 schema 约束 + 多层校验,压缩到业务可接受的确定性区间里。** 模型越强这个区间越大,但校验链路永远不能省。
