跳到正文

大模型输出JSON怎么保正确?

解码策略、提示工程、后处理与Schema约束方法详解

原题:在需要大模型输出结构化JSON格式内容的应用中,有哪些技术手段可以确保输出的语法正确性、格式稳定性和字段完整性?请结合解码策略、提示工程、后处理或Schema约束等方法进行说明。

模型微调 · 字节真题

30 秒回答

  1. 约束解码技术(如JSON Mode、Grammar-based Decoding)的原理和应用
  2. 提示工程技巧(Few-shot示例、Schema描述、输出格式指令)
  3. 后处理与验证机制(JSON修复、重试策略、Pydantic校验)
  4. 模型选型与训练层面的优化(Code模型、SFT/RLHF针对性训练)

回答与解析

答案要点

  • 约束解码技术(如JSON Mode、Grammar-based Decoding)的原理和应用
  • 提示工程技巧(Few-shot示例、Schema描述、输出格式指令)
  • 后处理与验证机制(JSON修复、重试策略、Pydantic校验)
  • 模型选型与训练层面的优化(Code模型、SFT/RLHF针对性训练)
  • 实际落地中的组合策略和容错设计

一、解码层:约束生成空间

JSON Mode / Structured Output

  • OpenAI/Claude等提供的原生能力,强制token级约束,确保括号、引号、逗号语法正确
  • 底层实现:将JSON Schema编译为上下文无关文法(CFG),用约束解码(Constrained Decoding)过滤非法token

Grammar-based Decoding

  • 开源方案:Outlines、Guidance、lm-format-enforcer
  • 核心:用FSM/正则表达式约束生成路径,例如{"name": string, "age": number}的合法序列

二、提示工程:降低歧义

技巧 做法
Schema前置 在prompt中明确定义字段类型、必填项、枚举值
Few-shot示例 提供2-3个输入→输出的完整JSON样例
输出包裹 json...标记或强制以{开头
负向指令 "不要输出markdown,不要解释,只返回JSON"

三、后处理:兜底与修复

多层校验链

原始输出 → 提取JSON块(正则/栈匹配)→ json.loads() → Pydantic校验 → 业务规则校验

失败恢复策略

  • 语法错误:用json-repair、partial-json-parser尝试修复截断输出
  • 字段缺失:补默认值或触发重试(带错误反馈的二次生成)
  • 类型错误:强制类型转换或报错重试

四、模型与训练层面

  • 选型:优先Code系列模型(CodeLlama、DeepSeek-Coder),JSON结构化能力更强
  • SFT:构造<指令, Schema, 正确JSON>数据对微调
  • RLHF/DPO:对格式错误给予低奖励,强化合规输出

五、工程实践组合

推荐分层架构:约束解码(保语法)+ 清晰Schema(保结构)+ Pydantic校验(保业务)+ 重试降级(保可用)

口语版讲法(约4分钟)

  • 问题本质:保证JSON的正确、完整、稳定
  • 解码层约束:Grammar-based Decoding保语法
  • 提示工程:Schema前置+示例降低歧义
  • 后处理兜底:修复与重试策略
  • 选型与风险:Code模型+容错设计+落地注意

这个问题其实本质是在问,怎么让大模型规规矩矩地吐出我们想要的JSON,而且每次都能稳定输出。我理解它的核心挑战是,大模型本质上是概率生成,但JSON是个严格的格式,所以需要从解码、提示、后处理、甚至模型选型几个层面合力解决。

先说解码层,这是最硬核的手段。现在像OpenAI的JSON Mode,或者开源的Outlines、Guidance这类库,都是在token级别做约束,比如生成的时候只允许合法的JSON token通过,括号引号逗号这些语法错误直接就过滤掉了。你可以把它想象成给模型戴了个脚镣,只能在JSON的文法范围内跳舞。这招对语法正确性几乎是100%保底的,但前提是Schema必须提前定义清楚,而且对生成速度有轻微影响。

但解码约束不能解决所有问题,比如字段缺失、值类型不对这些语义层面的错误。所以第二层就是提示工程。我会在prompt里把Schema写清楚,比如字段名、类型、枚举值、必填还是可选,再给两三个完整的输入输出示例。这里有个技巧,我会让模型输出先以{开头,并且在最后加一句“只返回JSON,不要任何解释”,这样能减少很多噪声。不过提示工程是软约束,模型可能不听话,所以不能完全依赖。

第三层是后处理兜底。实际线上跑的时候,模型偶尔还是会输出截断或者带markdown的JSON。我会用正则或者栈匹配把JSON块提取出来,然后走Pydantic校验。如果语法不对,就用json-repair这样的库尝试修复;如果字段缺失,就补默认值或者触发重试。重试的时候我会把上一次的错误信息塞回prompt,让模型自己修正,效果往往不错。这里有个坑:重试次数不能太多,否则延迟和成本受不了,我一般设两到三次。

再说模型选型。Code系列模型比如DeepSeek-Coder,对结构化输出的能力确实比通用模型强,因为它们训练数据里代码和JSON很多。如果预算允许,我会优先选这类模型。另外,如果业务场景很固定,也可以用SFT微调,构造一批带Schema的JSON数据让模型专门学。

真正落地的时候,我不会只用一种方法,而是分层组合:解码层保语法,提示工程降低歧义,后处理做容错,模型选型提上限。举个例子,比如做一个客服退款接口,需要模型输出{reason, amount, decision}这样的JSON。我会先用Grammar-based Decoding确保括号引号没错,然后在prompt里给一个“退款原因只能是枚举值”的Schema,最后再加一层业务规则校验,比如金额不能为负。如果校验失败,就带错误信息重试一次。

不过这里有个容易被忽略的前提:约束解码和提示工程的效果很大程度上取决于Schema设计得好不好。如果Schema本身字段定义模糊,或者枚举值范围没想清楚,模型再厉害也容易出错。所以我上线前一定会花时间打磨Schema的颗粒度和边界条件,比如哪些字段可以容忍默认值,哪些必须严格匹配。

所以整体上,我更倾向于把这件事看成系统工程,不是靠某一种技术通吃。我会优先保证解码层的语法正确性,然后通过提示和后处理补语义,最后用业务校验兜底。这样即使模型偶尔抽风,系统也不会崩。

关键一句:Schema设计的质量直接影响约束解码和提示工程的效果,需要提前打磨边界条件。

面试官还可能这样问

  1. 问法 1 · 场景切入

    我看你做过电商订单处理的场景,假设我们要让模型直接输出一个订单对象的JSON,包含必填字段和枚举值,你怎么保证它每次都能输出正确的结构?

  2. 问法 2 · 层层追问

    大模型输出结构化数据时,你遇到过格式乱掉的情况吗?……怎么确保它输出的JSON语法是对的?……如果字段缺失或者类型不匹配呢?

  3. 问法 3 · 直球架构

    请设计一个方案,确保大模型输出JSON时语法正确、字段完整、格式稳定。你会从解码策略、提示工程、后处理这些层面分别怎么做?

同模块相关题目