怎么让模型稳定输出合法 JSON?结构化输出的几种实现与兜底策略?

Q1-10结构化输出高频结构化输出约束解码JSON Schema校验兜底

谁在问:一二面·工程向;平台组必问

口语化问法

  • 你怎么保证模型返回的 JSON 一定能解析?
  • 约束解码和在提示词里写『只返回 JSON』有什么区别?
  • 都用上结构化输出了,你还写校验吗?

考察意图

第一层考你知不知道有约束解码这条路(现在还答「让它返回 JSON 然后正则提取」的,说明技术栈停在 2023)。

第二层才是重点:你知不知道它保证的只是语法。 很多团队上了结构化输出之后反而放松了校验,把一个格式契约当成了业务保证——而这个误解造成的事故,通常比 parse 失败贵得多。

参考答案

图 2 · 60 分与 90 分差在哪:代价、演进、怎么验证

60

60 分答案(及格线)

有几种做法,可靠性递增:

  1. 在提示词里要求只返回 JSON,配合失败重试和容错解析——最不可靠;
  2. JSON mode:保证输出是合法 JSON,但不保证符合我的 schema;
  3. 结构化输出 / 约束解码:把 JSON Schema 编译成语法,在生成每个 token 时屏蔽掉会违反结构的候选,从机制上保证输出符合 schema;工具调用侧有对应的严格模式约束参数。

兜底上会做 schema 校验、失败重试、以及解析失败时的降级处理。

90

90 分答案(有生产经验的回答)

补三层:

第一,机制上的区别是「请求」和「封路」。 提示词是叮嘱模型尽量别越界,约束解码是把所有违规的岔路都封死——模型不是更听话了,是物理上吐不出违反结构的 token。

第二,它保证的只有语法,而且 schema 只支持 JSON Schema 的一个子集。 截至 2026-08,官方明确不支持递归 schema、外部 $refminimum/maximumminLength/maxLength 等数值与长度约束,additionalProperties 只能是 false;同时有整体复杂度上限,可选参数是复杂度大户。所以数值范围、字符串长度、日期是否真实存在、金额是否在权限内——这些语法层根本表达不了,必须活在代码里

我们线上是三层校验:语法层交给约束解码;值域层用代码校验枚举越界、数值范围、日期真实性、格式正则;业务层用代码校验权限、与来源一致性、审批阈值。原则是:能用 schema 表达的交给 schema,不能表达的必须写代码,绝不写进提示词指望模型自觉。

第三,一个反直觉的副作用:结构化输出不降低幻觉率,只是把幻觉变成格式合法的幻觉。以前 parse 报错还能当一道天然告警,现在这道告警没了,所以第 2、3 层校验只会更重要,不会更不重要。

顺带一提:预填 { 逼模型直接吐 JSON 这个流传很广的老技巧,截至 2026-08 在 Claude Opus 4.7 及以后已经返回 400,官方要求改用结构化输出。

追问链

图 1 · 五层追问树:面试官会往哪儿挖
问的不是怎么生成 JSON,是谁来管 JSON 里的值

  1. 约束解码和「在提示词里要求返回 JSON」有什么本质区别?

    期望前者在采样阶段屏蔽非法 token,是机制保证;后者只是概率上的倾向,模型可能加寒暄、缺字段、类型飘。加分项:说得出 schema 被编译成语法、编译产物会被缓存,因此首次调用有额外延迟、高频可忽略
    信号说得出「在 token 采样层面封死」 → 理解了机制;只说「结构化输出更可靠」 → 知道结论不知道原因
  2. 有了约束解码,还需要校验吗?为什么?

    期望需要 —— 它管形状不管内容。举得出具体例子最好:"2026-02-30" 是合法字符串但这个日期不存在;金额字段是合法整数但数值离谱
    信号本题最重要的分水岭:答「不用了,schema 已经保证了」 → 直接掉档
  3. schema 能表达的和不能表达的分别是什么?

    期望能表达结构 —— 字段有无、类型、嵌套形状、枚举取值;表达不了数值范围、字符串长度、正则、递归结构、跨字段一致性。所以枚举是特别值钱的设计:唯一一类「语法层能顺便管住语义」的字段,能枚举就别让模型自由发挥
    信号主动点出「枚举优先于自由文本」这条设计原则 → 真设计过 schema
  4. schema 越来越复杂,编译直接报错了,你怎么办?

    期望按官方给的顺序改:只给关键工具加严格模式 → 可选参数改必填(它显著放大语法状态空间、是复杂度大户,可用一个显式「未知」枚举值替代字段缺失)→ 拍平嵌套 → 实在不行拆到多个请求。加分项:限制是所有严格 schema 合起来算的,单个看着简单也可能超
    信号知道「可选参数是复杂度大户」 → 一定亲手撞过这个报错
  5. 返回的 JSON 全部合法,但一批订单退款金额明显不合理、下游已打款,复盘一下

    期望先止血:关自动执行改待审队列、已打款分档对账、加硬阈值 → ② 锅在架构不在模型:拿语法保证当业务保证,maximum 本就不归约束解码管 → ③ 补值域层与业务层:上下限、原价、权限、审批 → ④ 能代码判的用代码判 → 能可逆的变可逆 → 剩下人工 → ⑤ 高危动作授权检查独立于模型输出 → ⑥ 关键字段建异常值监控,补回 parse 不报错丢的告警
    信号说「不是模型的锅是架构的锅」、把退款金额归到「本就该代码判」 → 优秀;答「加强提示词」或「schema 里加 maximum」 → 没读过限制清单
一句「"2026-02-30" 是合法字符串」就把「用过」和「设计过」切开了。第 2 层是最重的分水岭 —— 语法不等于语义;第 5 层看你把锅归给架构还是归给模型。

评分要点

  1. 知道约束解码及其机制(编译成语法、采样层屏蔽)
  2. 能区分 JSON mode 与 schema 约束
  3. 明确它保证语法、不保证语义
  4. 说得出 schema 至少两条表达不了的约束
  5. 有分层校验的设计(语法 / 值域 / 业务)
  6. 知道枚举优先于自由文本
  7. 知道 schema 复杂度上限与优化顺序
  8. 高危动作的判断权收回代码,不依赖模型输出

常见错误

仍然用「让模型返回 JSON + 正则提取 + 重试」当主方案。
认为开了结构化输出就不用校验了。
分不清 JSON mode 和 schema 约束的区别。
以为在 schema 里写 maximum 就能管住数值。
还在推荐 assistant 预填 { 这个已失效的技巧。
出事后第一反应是加强提示词,而不是补校验层。
含糊标志词:「schema 定好就行了」「模型一般不会填错」「加个 try-catch 兜一下」。

关联学习