结构化输出怎么才不翻车:JSON Schema 约束的实战方法
让模型稳定吐出合法 JSON 是工程刚需。本文对比提示约束、Schema 校验、函数调用三种方案,给出解析失败的重试与兜底设计。
当模型输出要被程序解析时,“大致是对的”就是错的。一个多余的逗号、一句客套话,都能让下游崩掉。结构化输出是把 LLM 接进生产系统的第一道门槛。
一、三种约束方案,从弱到强
1. 纯提示约束
在提示词里写”只输出 JSON,不要任何解释”,并给出示例。
- 优点:零额外依赖,任何模型可用。
- 缺点:模型偶尔仍会加解释、用单引号、少大括号。
- 适用:内部工具、对人类可容忍的场景。
2. 函数调用 / 工具模式
利用模型的 function calling,把目标结构定义成函数的参数 schema。
- 优点:模型被训练成优先输出合法参数,成功率显著高于裸提示。
- 缺点:需要模型支持,且语义上是用”工具”承载了”格式”。
- 适用:主流的正确做法,推荐优先采用。
3. 原生 JSON Schema 强制
部分接口支持 response_format 直接传 JSON Schema,在解码层强制合法。
- 优点:几乎杜绝语法错误。
- 缺点:支持的模型和字段子集有限。
- 适用:对稳定性要求极高的生产链路。
二、Schema 设计要收敛
宽松 schema 等于没约束。注意:
- 必填字段全列,别指望模型总给。
- 枚举代替自由文本:状态用
"pending" | "done",别让它自由发挥。 - 禁止额外字段(additionalProperties: false),防模型加戏。
- 层级别太深:嵌套过深时模型容易漏层,能扁平就扁平。
- 给字段写描述:schema 里的 description 就是给模型的微型提示。
三、出错必须重试,不能硬解析
即使有约束,也要假设会失败:
- 解析失败:把错误信息原样回喂给模型,“你的输出报错 X,请修正”。
- 校验失败:Schema 不通过时,指出具体哪个字段错。
- 重试上限:2–3 次仍失败,降级到规则解析或转人工,别死循环烧钱。
四、兜底与可观测
- 超时与次数保护:给重试加最大次数和耗时上限。
- 记录失败样本:把解析失败的原文存下来,定期分析模式。
- 幂等处理:重试的副作用要可回滚,避免重复写入。
- 版本化 schema:结构变更要能让上下游平滑过渡。
五、最小可用模板
实践中把提示写成这样最稳:
- 顶部:角色与任务。
- 中部:完整的 JSON Schema(字段名、类型、枚举、描述)。
- 尾部:一两句”只输出 JSON,不要 Markdown 代码块之外的内容”。
结构化输出不是”提示词玄学”,而是schema 设计 + 重试兜底 + 监控三件套。把它工程化,AI 功能才能真正稳定上线。