如何让大模型稳定输出 JSON?Prompt、JSON Mode 和 Structured Outputs 有什么区别?
简化版
三种手段保证强度递增:纯 Prompt 只能要求模型「尽量」输出 JSON,仍可能加解释、漏字段、语法错;JSON Mode 通常保证「语法上是合法 JSON」,但不保证字段符合你的 Schema;Structured Outputs / 严格模式 Function Calling 能约束输出匹配指定 JSON Schema(字段、类型、枚举、必填)。但无论哪种,字段值的业务正确性仍要程序校验——「解析成功」不等于「内容正确」。
详细版
| 方案 | 保证什么 | 不保证什么 |
|---|---|---|
| 文本 Prompt + 示例 | 尽量像 JSON | 可能多解释、漏字段、无效 JSON |
| JSON Mode | 可解析为 JSON(语法) | 字段名/类型/必填是否符合预期 |
| Structured Outputs | 匹配受支持的 JSON Schema | 值的业务正确性 |
| Function Calling (strict) | 工具参数符合 Schema | 操作是否已授权 |
Schema 要清晰描述字段语义、枚举、是否允许 null、附加属性。调用端还要处理拒答、截断、超时、Schema 不支持、语义错误、重试——别把「解析成功」等同「业务正确」。
完整版教学
一、为什么「只输出 JSON」不够(失败示例)
普通生成的目标是预测自然语言,所以模型经常在 JSON 上翻车:
你要的:{"name": "张三", "age": 30}
模型可能输出:
好的,这是结果: ← 多了前言
```json
{"name": "张三", "age": "30"} ← age 被写成字符串
``` ← 包在 markdown 代码块里
// 希望对你有帮助 ← 多了注释
即使语法合法,也可能数字写成字符串、漏必填字段、发明新字段。Few-shot 示例能改善格式,但给不了严格保证。
二、JSON Mode 的能力边界
JSON Mode 约束输出为有效 JSON,解决的是「语法可解析性」。但它通常不理解你的完整业务 Schema——所以「输出了一个 JSON 对象」和「精确符合预期结构」是两回事:
JSON Mode 保证:能 JSON.parse()
JSON Mode 不保证:{"naem": 30, "extra": true} ← 字段名拼错、类型错、多字段,但语法合法
如果平台支持 Structured Outputs,优先提供 Schema;不支持就用验证库检查 + 有限重试。
三、Structured Outputs 为什么更可靠
严格 Schema 约束的实现,会把 JSON Schema 转成解码约束——生成时只允许产生符合结构的 token 序列(constrained decoding):
Schema: { status: enum["pending","paid","failed"], amount: number }
约束解码:生成 status 时,只允许从三个枚举值里选;生成 amount 时只允许数字 token
→ 从源头杜绝字段名错、类型错、枚举越界
它能控制对象字段、类型、枚举、必填关系,显著减少格式错误。但注意边界:不同平台只支持 JSON Schema 的子集,Schema 过深或过于动态可能用不了;模型也可能拒答或因输出长度不足被截断,应用必须处理这些状态。
四、结构正确 ≠ 内容正确(最关键)
这是最容易被忽略的红线。Schema 能保证「形状」,但保证不了「内容」:
Schema 保证:amount 是数字 → 但不保证这个金额来自正确的发票
Schema 保证:status 是合法枚举 → 但不保证模型选对了状态
以下仍需业务层验证:数值范围和字段间关系、ID 是否真实存在、用户是否有权限、日期和单位是否合理、内容是否由证据支持。约束解码只管形状,求真靠程序。
五、Function Calling 与结构化回答的区别
- 结构化回答:返回程序可消费的数据;
- Function Calling:让模型建议调用某个工具及参数。
关键安全认知:即使开启严格模式、参数符合 Schema,“模型产生了调用”也不代表”操作已获授权”。应用仍要验证:工具名、参数语义、当前用户权限、风险等级,通过后才执行。而且工具返回值属于不可信外部数据,不能直接升级成高优先级指令(间接注入风险)。
六、Schema 设计与错误恢复
Schema 设计:字段名表达业务语义(别用模糊缩写)、用 description 说明来源和判定规则、能用 enum 就不用自由文本、明确 required 和 nullable、禁止多余附加字段、结构扁平少嵌套、给版本号防上下游不兼容。
错误恢复:先区分三类错误,只对可修复的重试:
解析错误(语法坏) → 可重试,把错误信息作为受控反馈
Schema 错误(缺字段)→ 可重试
语义错误(值不对) → 不能靠重试猜,转人工或拒绝
+ 设最大重试次数,避免死循环
七、常见误区与追问
- 误区:JSON Mode 保证符合我的 Schema。 只保证语法合法,字段/类型/必填仍可能不符。
- 误区:Structured Outputs 保证内容对。 只保证形状(类型/枚举/必填),值的业务正确性要程序验。
- 误区:模型给了工具调用就能执行。 严格模式只保证参数形状,授权/权限/风险仍要应用校验。
- 追问:Structured Outputs 底层怎么实现? 把 Schema 转成解码约束,只允许生成符合结构的 token。
- 追问:为什么 Schema 正确还会错? 它管形状不管真值——金额是数字≠金额来自正确发票。
- 追问:工具返回值能直接信吗? 不能,是不可信外部数据,别升级为高优先级指令。
- 追问:什么错误该重试、什么不该? 解析/Schema 错可重试(有限次),语义错转人工,别让模型反复猜。
八、加强记忆
三种强度记「口头要求 / 保证像合法表格 / 保证表头类型符合模板」:Prompt(尽量)< JSON Mode(语法合法)< Structured Outputs(匹配 Schema,靠约束解码只生成合规 token)。最红线的一条钉死:结构正确 ≠ 内容正确——Schema 管形状(类型/枚举/必填),值是否真实、是否有权限仍要业务程序验。Function Calling 严格模式只保证参数形状、不代表已授权;工具返回值是不可信数据。Schema 要语义化字段 + enum + 版本号,错误恢复只对语法/Schema 错重试、语义错转人工。