首页 /文章 /函数调用与结构化输出——可靠性工程实践

函数调用与结构化输出——可靠性工程实践

函数调用与结构化输出的可靠性工程。从训练、提示、解码三层说明实现机制,归纳六类失败模式,给出运行时校验、重试与兜底方案及评测指标体系。

函数调用结构化输出可靠性工程
分类:应用开发 › Agent 与工具调用 发布于 2026-09-22 16 次浏览

一 问题定义

让模型"调用正确的函数、填正确的参数、输出合法的 JSON",是 Agent 工程里最基础的一颗螺丝。业界对它的关注从"能不能"转向"够不够稳":工具选择准确率、参数 schema 合规率、结构化输出的可解析率,三者合起来决定一条 Agent 链能否无人值守。本文梳理从工具描述设计、约束解码到评测闭环的工程实践。

核心矛盾:模型的"自由生成"能力与下游系统的"严格契约"需求天然冲突。可靠性工程就是在这两者之间架桥——要么约束生成过程,要么兜底生成结果。

二 函数调用的三种实现层

层级机制保障强度典型形态
训练层RLHF / 指令微调让模型学会工具调用分布概率性(最常见失败仍在这里)GPT / Claude / Gemini 的原生 function calling
提示层工具 schema 以 JSON Schema 注入系统提示,引导输出格式较弱(长上下文下易漂移)prompt 内嵌 tools 定义 + 示例(few-shot)
解码层结构化输出 / 约束解码(grammar-constrained decoding),在采样阶段屏蔽不合法 token强(格式 100% 合法,语义仍需校验)OpenAI structured outputs、Outlines、guidance、SGLang 结构化

生产系统普遍是三层叠加:训练层保证"懂",提示层保证"知道当前用哪个",解码层保证"格式一定对"。其中解码层的价值被低估——它把"格式错误"这类本可工程消除的问题从模型概率域挪到确定性域,是成本最低的一层保险。

三 失败模式分类

失败类型现象根因
选错工具调用了语义相近但错误的函数(search_user 调成 search_order)工具描述语义重叠、缺少区分性 affordance
参数幻觉参数名 / 枚举值凭空捏造schema 约束未入解码层,或描述过于简略
参数忠实度不足参数值与上下文事实不符(订单号抄错、时间算错)模型"填表"而非"取数",无交叉验证
格式漂移长对话后 JSON 不闭合、混入散文上下文稀释 + 未开约束解码
过度调用不需要调工具也调了,或重复调用缺少"不调用"的负例训练与提示约束
嵌套 / 多工具编排失败工具链中间步参数传递错链式 error 累积、中间状态未显式约束

四 工具描述工程

  • description 写"做什么 + 何时用",不写"怎么做":模型需要的是边界判断(哪个工具适用),不是内部实现。"查询用户的未读订单列表(status=pending)"比"调用 order 服务"信息密度高。
  • 参数描述写取值来源:每个参数的 description 里指明值从哪来("从用户消息中的订单号提取"),显著降低参数幻觉。
  • 枚举必给、闭集必写全:开放集合用正则 + 说明;枚举值全列,禁止"等"。
  • 相似工具加区分字段:search_user / search_order 这类易混对,在 description 中显式写"仅当目标是用户档案时使用;订单相关用 search_order"。
  • 参数数量控制:经验上单工具参数超过 10 个,漏填率开始上升。优先把低频参数收进 object 子结构,或用 "params" 分片。
  • 默认值即契约:可选参数一律给默认值并在描述中说明,避免模型省略后下游崩溃。
反模式:把 20 个工具一起塞给模型。工具越多,选择准确率越低(工具数与混淆率正相关)。按任务阶段动态暴露工具子集(progressive disclosure)是当前主流做法。

五 结构化输出工程

除"调用工具"外,让模型输出严格 JSON(分类结果、抽取字段、UI 数据)是同一问题的另一面。实践要点:

  • schema 即接口文档:字段名用名词单数、平铺优先少嵌套;每个字段 description 一句话说清语义,必填用 required 显式声明,可选的给 default。
  • 用联合类型显式建模"结果分支":如 "match" / "no_match" / "ambiguous" 三态,比让模型自由输出"没找到"稳健得多;歧义态单独建模,下游可走人工或追问。
  • 枚举 + 正则双重约束:状态字段用 enum,日期 / 编号字段用 pattern,解码层直接拦截非法值。
  • 禁止字符串内嵌 JSON:把 JSON 作为字段值再序列化是解析失败的主要来源;下游需要就拆字段。
  • 长输出用流式 + 增量 parse:大 schema 分阶段输出(先骨架后详情)可降低中途截断损失。

解码层选型上,约束解码在无温度(temperature=0)任务下应默认开启;开启后"格式类失败"趋近于零,剩余失败转为"语义类",评测关注点也随之转移。

六 运行时防护:校验、重试与兜底

  • 服务端再次校验:不信任模型侧的"已 schema 校验"。接收 JSON 后再过一次 JSON Schema 校验(jsonschema 库),失败直接走重试,不进入业务逻辑。
  • 重试策略分级:格式错误 → 原样重试(可附错误信息提示);参数非法 → 带错误信息的定向重试("字段 X 应匹配枚举 [...]");语义可疑(值与上下文不符)→ 换模型或降级人工。重试上限 2-3 次,防止死循环与成本失控。
  • 修复而非重跑:轻微格式错误(缺引号、尾逗号)用规则 / 小模型修复,比重跑整条链便宜一个数量级。
  • 兜底态显式建模:所有链路都有"无法调用 / 信息不足"的出口,且这个出口是业务设计的一部分(追问用户、取默认值、人工队列),不是 try-except 里的 pass。
  • 幂等与可重入:写操作带 idempotency key;同一意图重复调用时靠 key 去重,防止"过度调用"造成重复副作用。

七 评测体系:三个核心指标

指标定义测量方法
工具选择准确率给定 query,选中 ground-truth 工具的比例构造工具选择测试集(含"不该调用"负例),逐条比对
参数正确率选中正确工具前提下,参数与标注值等价的比例参数级比对:枚举精确匹配、数值容差、字符串归一化后匹配
可解析率 / schema 合规率输出能被解析且通过 schema 校验的比例全量输出过 jsonschema,统计通过率(约束解码下应 ≈100%,否则查配置)

测试集设计三原则:覆盖所有工具(含易混对)、覆盖边界参数(空值 / 极值 / 多值)、覆盖负例(模糊 query、无关 query、多工具并列)。评测集随工具演进版本化,每次 schema 变更都回归跑一遍——工具调用是"契约",契约变更没有回归测试就是事故。

八 安全交叉点:注入与工具调用

工具调用是提示注入的主要"爆炸出口"(详见本站《Agent 提示注入攻击》一文)。工程上要做的:高危工具默认人工确认;工具参数里的自由文本字段(如邮件正文、搜索词)过注入检测;禁止把用户原文整体透传进工具参数(先抽取结构化字段再填入);参数白名单校验(URL 域名、路径前缀、命令动词)。这条线与本章的可靠性工程是同一套管道——契约即安全边界。

九 选型与落地清单

  • 模型原生 function calling + 服务端 schema 双校验(基线,任何栈都该有)
  • 严格 JSON 输出任务开约束解码(structured outputs / outlines / guidance 任选其一)
  • 工具按阶段暴露,单轮可见工具 ≤10 个
  • 写操作幂等键 + 高危工具人工确认队列
  • 三指标评测集 + schema 变更必回归
  • 失败分类日志(选错 / 参数 / 格式 / 过度调用),月度看分布,反哺工具描述改进

成熟度判据:可解析率长期 ≥99.5% 时,工程重心应从"修格式"转向"语义正确率"——那一层没有银弹,只能靠测试集迭代 + 失败样本复盘。

关键词 函数调用结构化输出可靠性工程 000052