← 大模型应用基础

大模型输出的 JSON 不合法时应该如何修复?

高频 中等 结构化信息抽取 · 第 2 / 3 问 更新于 2026/09/30
大模型JSON结构化输出容错
本题落地项目AI智能简历优化系统

简化版

JSON 修复要先区分语法错误和语义缺失:多余逗号、代码围栏、引号不匹配可以用确定性解析或受限修复;缺少金额、枚举值非法、字段彼此矛盾不能靠修复模型猜。优先使用原生结构化输出或 Function Calling,服务端再做 Schema 与业务校验;修复次数设小上限,保留原始输出,失败后重新生成、降级或转人工。

详细版

推荐流水线是:提取候选 JSON → 严格解析 → 安全的确定性规范化 → JSON Schema 校验 → 业务规则校验。只有可证明不改变含义的修改才自动做,例如去掉 Markdown 围栏或 UTF-8 BOM;补全缺失字段属于语义生成,必须带原输入重新调用模型并明确缺口。

raw output
 -> extract one candidate
 -> strict parse
 -> bounded syntax repair
 -> schema validate
 -> business validate
 -> accept / regenerate / reject

避免正则贪婪截取第一个 { 到最后一个 },它会被解释文本和嵌套对象破坏。解析器应限制输入大小、嵌套深度和数字范围,防止资源攻击。每次记录错误类型、修复 diff、尝试次数和最终状态;高风险字段不能静默默认。

完整版教学

一、先把“JSON 不合法”拆成不同问题

输出可能根本不是 JSON,也可能语法合法但不符合 Schema,或 Schema 合法却违反业务规则。三类失败的修复方式完全不同。

例如 {"amount":100,} 是语法错误;{"amount":"一百"} 可能是类型错误;{"amount":1000} 在最多退款 500 元的业务中是规则错误。只调用一个“JSON 修复器”会把它们混在一起。

记忆钩子:修括号是语法,补字段是生成,判金额是业务;三层不能互相冒充。

二、源头上优先减少自由格式生成

若平台支持受 Schema 约束的结构化输出,应优先使用;工具调用场景则用 Function Calling。它们能显著减少围栏、解释文字和括号错误,但仍不保证字段事实正确。

提示中给出明确 Schema、枚举和一个正例也有帮助。不要同时要求“先详细解释推理,再只返回 JSON”,冲突指令容易让解释混进输出。

即使供应商宣称严格模式,客户端仍应解析和校验,因为网络截断、版本变化和业务约束仍可能失败。

三、候选提取不能靠贪婪正则

输出可能包含“结果如下:”和 Markdown 围栏,也可能有字符串内部的花括号。\{.*\} 的贪婪或非贪婪匹配都不了解 JSON 字符串转义与嵌套层级。

更稳的做法是使用流式 JSON 解码器从候选起点解析一个完整值,或要求协议层直接返回结构化对象。若输出包含多个对象,应根据契约明确拒绝,而不是随意选第一个。

bad:  explanation {"text":"a } b"} trailing
                 ^ 字符串里的 } 不能结束对象

四、自动语法修复必须保守

删除 BOM、剥离明确代码围栏、标准化换行通常不改变语义。把单引号替换成双引号则可能破坏文本中的撇号;自动补括号也可能掩盖响应被截断。

错误可否自动修原因
UTF-8 BOM可以不改变数据
明确 JSON 围栏可以只去展示包装
尾逗号谨慎可定位时含义通常明确
缺失右括号通常重生成可能是传输或长度截断
缺少必填字段不可猜缺少业务事实

修复后保存 diff,让监控知道系统修了什么,而不是只记录最终成功。

五、Schema 验证负责结构契约

Schema 校验必填字段、类型、枚举、长度和附加字段。例如把 additionalProperties 设为 false 可防止模型返回未预期字段,但兼容升级时要管理 Schema 版本。

{
  "type": "object",
  "required": ["category", "score"],
  "properties": {
    "category": {"enum": ["spam", "normal"]},
    "score": {"type": "number", "minimum": 0, "maximum": 1}
  },
  "additionalProperties": false
}

Schema 错误应以字段路径反馈给重生成模型,如 /score must be <= 1,比笼统说“JSON 错了”更容易修正。

六、语义校验不能用默认值掩盖

字段齐全不代表关系正确。开始时间必须早于结束时间,百分比之和可能要求等于 100%,退款金额不能超过原支付。这些规则由领域代码或权威服务执行。

若模型漏了 currency,自动填 CNY 只有在业务上下文明确保证时才安全;否则默认值会把“不知道”变成错误事实。可选字段也要区分“未提供”和“明确为空”。

高风险数据校验失败后应停止,不因修复次数用完就绕过规则。

修复之后仍然失败时,该填默认值还是直接报错,见「模型输出解析失败时,应该填默认值继续,还是直接报错?」。

七、重生成要携带原任务和精准错误

让修复模型只看坏 JSON,可能不知道缺失值从哪里来。重生成请求应包含原输入、原 Schema、坏输出和精简的验证错误,并要求仅纠正指定问题。

最多尝试一到两次;同类错误重复出现说明模型或契约不适合,继续循环只会烧 token。第一次输出 95% 可用、第二次修复 80% 剩余失败时,总成功率约为:

95% + 5% × 80% = 99%

再多轮的边际收益很小,却增加延迟和不可预测修改。

八、安全与可观测性不能遗漏

限制原始输出大小、嵌套深度、数组长度和数值范围,防止极端 JSON 耗尽解析资源。解析后使用普通数据对象,禁止反序列化成可执行类型或把字段直接拼 SQL、命令和模板。

监控解析失败率、Schema 失败率、业务失败率、修复成功率、平均尝试数和被修改字段。模型或 Prompt 更新后按错误类别比较,而不是只看最终 JSON 成功率。

日志保留原始输出需脱敏;生产秘密不应因一次解析异常进入错误平台。

九、常见误区与追问

  • 误区:用正则提取第一对花括号就行。 正则不理解嵌套与字符串转义。
  • 误区:JSON 能解析就可以进入业务。 还需 Schema 和业务不变量校验。
  • 误区:缺字段时填默认值最稳。 默认值可能把未知变成错误事实。
  • 误区:让模型无限修到成功。 应限制次数,重复失败后降级或人工处理。
  • 误区:结构化输出模式无需客户端验证。 网络截断与语义错误仍然存在。
  • 追问:什么时候可自动补括号? 只有能证明响应完整且修复不改变含义时;长度截断应重生成。
  • 追问:修复模型要看什么? 原任务、Schema、坏输出和精确字段错误,避免凭空补事实。
  • 追问:如何防止修复改变正确字段? 比较修复 diff,锁定已通过字段,并重新执行全部验证。

十、加强记忆

JSON 修复记住“三层关卡”:解析器管语法,Schema 管结构,领域规则管语义。先用结构化输出减少错误,再做保守、可记录的确定性清理;缺失事实不能靠补括号式修复,而要带原任务精准重生成。限制次数、输入规模和嵌套深度,保留原文与 diff,并在任何修复后重新跑完整验证。

项目实战落地

项目里怎么做的

《AI智能简历助手》的诊断评分要从模型回答里解析出 score、level、analysis。评分 Prompt 末尾已经追加了「请严格返回 JSON,不要返回 Markdown 代码块」,但解析前仍然先清理一遍:

String text = StrUtil.blankToDefault(content, "").trim();
if (text.startsWith("```")) {
    text = text.replaceFirst("^```json", "")
            .replaceFirst("^```", "")
            .replaceFirst("```$", "")
            .trim();
}
if (!text.startsWith("{")) {
    int start = text.indexOf('{');
    int end = text.lastIndexOf('}');
    if (start >= 0 && end > start) {
        text = text.substring(start, end + 1);
    }
}

两层清理对应模型的两种常见习惯:把 JSON 包进代码块,以及在 JSON 前后加一段说明。

《AI个人学习计划助手》的知识点提取要求返回 JSON 数组,按同样的思路截取第一个 [ 到最后一个 ];解析用的 Jackson ObjectMapper 关闭了 FAIL_ON_TRAILING_TOKENS,读完第一个完整的数组就停。

《AI面试官与刷题训练平台》的 AI 辅助出题要从回答里拿到一个题目数组,清理多了两步:

  • 逐个试候选片段。 剥掉代码围栏后先整体解析;不行就从每个 [ 或 { 出发,按括号配对找到它的结尾(引号里的括号不算,字符串里转义过的引号也不会被当成结尾),截出一段段候选依次解析,第一个解析成功、又能找到题目数组的就用它;
  • 认几种外层包装。 模型可能直接返回数组,也可能包一层对象,代码依次在 questions、items、data、list、records 字段里找数组。

为什么这样取舍

  • Prompt 只是请求,不是约束。 模型不保证每次都听话,即使 Prompt 写明不要代码块,后端也要兼容;能靠清理救回来的就不报错。
  • 截取范围会带进多余内容。 模型在数组后面补的说明文字里也可能带 ],截出来的字符串尾部就多出一段;Jackson 3 默认把尾部多余内容判为非法 JSON,关掉这个开关后尾部内容被忽略。

面试官还会追问

  • 模型输出撞上长度上限、只返回了半截 JSON,怎么在解析之前就发现?
  • 清理之后仍然解析失败,为什么不给分数填个默认值继续,而是直接报错?

学完《AI智能简历助手》,上面这些追问你都会迎刃而解。

本题落地项目小试牛刀AI智能简历优化系统基于大模型完成简历上传解析、AI评分、问题诊断、优化建议、内容改写、Word下载、模拟面试题和生成记录管理,覆盖从简历诊断到求职准备的完整流程,并沉淀Prompt模板和改写策略。SpringbootSpringAILLMPromptSSE源码+SQL喂饭学习教程配套面试文档环境安装文档项目运行文档 学习这个项目 也可以学AI个人学习计划与资料助手小试牛刀 查看项目 也可以学AI面试官与刷题训练平台登峰造极 查看项目