结构化输出为什么总失败:五个最常见的原因和修法

📅 2026/4/26 ✍️ 小文 📖 约 1 分钟

开了 JSON mode 和 schema 校验,模型还是吐坏 JSON。从 schema 设计、字段顺序、长文本陷阱到重试策略,逐条给出修复方案。

结构化输出是工程上最实用的能力之一,也是失败率最难解释的能力之一——明明开了严格模式,还是偶尔出问题。五个原因按实际出现频率排列。

一、schema 太复杂

模型生成长 JSON 时是在逐 token「记忆」自己写过的结构。层级越深、枚举越多,出错概率越高。

典型坏味道:嵌套 4 层以上(data.items[].attributes[].value)、一个对象 20+ 字段、大量 anyOf 或递归结构。

修法:拆成多次调用。先抽主体信息,再针对每个主体单独抽明细。多一次调用的成本,远低于解析失败重试的成本。

二、字段顺序被序列化打乱

如果 schema 从无序 dict/HashMap 生成,每次请求字段顺序可能不同。影响两个:提示缓存命不中(成本),输出稳定性受轻微影响(质量)。

修法:定义时固定顺序,并把它放在提示的固定位置。

三、在长文本里顺手输出结构

「读完这 30 页报告后输出 10 个要点」失败率很高,因为模型要在长上下文末尾精确控制格式,注意力已经分散。两段式:先让它自由总结,再用第二次调用专门格式化。第二次输入短、任务单纯,几乎不出错。适合长文档抽取时,也可以用分块边读边抽再合并。

四、必填字段没有兜底

业务上「这字段必须有」,但数据里就是没有。模型被强要求填,就只能编。

修法:所有可能缺失的字段设计成可空,并在 description 里写明「无法确定时返回 null,不要猜测」,业务层单独处理 null。

这条最常被忽略。强制必填不是提高质量,是提高幻觉率。 宁可让下游收到 null,也不要收到一个看起来很合理的假值。

五、校验和重试策略错了

失败就整段重试是最差的做法——同样输入大概率同样失败。分类型处理:

失败类型处理方式
JSON 语法错重试一次,温度降到 0
缺字段把校验错误信息回灌,让模型补
字段类型错本地转换(“5” → 5),别浪费调用
枚举越界映射到最近合法值,或置 null

关键点:把校验器的错误信息回灌给模型。很多实现只重试不反馈,白白浪费机会。

六、上线前检查清单

  1. 层级是否 ≤ 3 层?
  2. 必填字段是否有真实的业务保证?
  3. 可能缺失的字段是否可空?
  4. 枚举值是否都写了含义?
  5. 解析失败是否有结构化回退,而不是直接报错给用户?

做完这五条,稳定性通常能从 95% 提到 99.5% 以上。剩下的 0.5%,靠兜底而不是靠提示词。

📤 分享到