结构化输出并非经过验证的输出
你的团队启用模式约束解码(schema-constrained decoding)的那一天感觉像是一个里程碑。解析错误停止了。JSONDecodeError 警报消失了。从文本中抓取字段的脆弱正则表达式也被删除了。有人在站会上说“模型现在返回有效的 JSON 了”,结构化输出的任务单随之关闭。
那句话正是麻烦的开始。“模型现在返回有效的 JSON 了”是正确性工作的开始,而不是结束。JSON 模式和约束解码保证了响应的形状(shape)——即 quantity 是一个整数,status 是三个枚举值之一,对象包含你要求的键。它们完全无法保证 quantity 是否是正确的数字,status 是否反映了真实发生的情况,或者 sku 字段是否指向了目录中存在的商品。
模式(schema)只是一个类型签名。它告诉你函数返回一个 int。它并没有告诉你这个 int 是正确的。将通过模式检查等效于通过正确性检查,是结构化输出流水线将“格式正确的胡言乱语”推向生产环境最常见的方式——而且因为这些胡言乱语格式正确,你的解析器、类型检查器和仪表板在问题发 生时都会显示为绿色。
模式到底证明了什么
约束解码通过掩码(masking)Token 来工作。在每个生成步骤中,解码器计算哪些下一个 Token 能让输出保持在仍能满足语法的路径上,将所有其他 Token 的概率设为零,并进行重新归一化。模型字面上无法在错误的地方产生花括号,也无法在模式要求数字的地方产生字符串。
这是一个真正的保证,值得拥有。但请注意它涵盖的具体范围:结构一致性。语法知道 price 必须是一个数字。它不知道这个产品的价格是 49.99。它知道 currency 必须是一个三个字母的枚举值。它不知道订单是以欧元结算的。约束作用于 Token 语法;而正确性存在于语法从未获得的语义中。
掩码机制中还隐藏着一个更微妙的问题。模型对下一个 Token 的概率计算是在不感知约束的情况下进行的。解码器在事后才应用掩码。因此,当模型“想要”说一些语法禁止的内容时,约束解码并不会让它重新考虑——它只是强迫模型选择概率最高的被允许的 Token。强制执行约束不仅会改变答案的格式,还会改变其内容。如果让模型自由发挥,它可能会对一个确实无法确定的字段写下 "unknown",但在约束下,它可能会被迫选择一个具体的枚举值,因为 "unknown" 不在枚举中,而语法必须在那里填入某些内容。你得到了一个干净的模式,作为交换,你得到了一个自信的错误答案。
最典型的例子是数字字段。你将 speed 定义为一个数字。模型已经内化了答案是“fast”——这是一个描述性概念,而非测量值。如果没有约束,它会写下 {"speed": "fast"}。有了约束,它做不到这一点,于是它输出了 {"speed": 9999} 或 {"speed": 0}——这是一个数字,模式有效,但毫无意义。你以前能捕获的格式错误,现在变成了你无法察觉的语义错误。
读时模式(Schema-on-read)陷阱
这是我最常看到的失败模式。团队采用了结构化输出,将响应直接接入 Pydantic 模型或 TypeScript 接口,而在反序列化成功的那一刻,数据就被视为可信的。验证器和解析器被默默地合并成了一个步骤。解析成功,因此数据就是好的。
但解析只能证明字节匹配类型。这是最松散意义上的“读时模式”:你将字段读取为字符串,然后你就相信了它。我们将这类 Bug 称为“格式正确的胡言乱语”。每个值都是正确的类型。每个必需的键都存在。每个枚举都是合法的。但记录仍然是错误的:
sku是一个格式完美的字符串——"PRD-44182"——但在产品表中匹配不到任何行。ship_date是一个有效的 ISO-8601 日期——2026-02-30——但在日历上并不存在。discount_pct是一个数字140,而有意义的范围仅为 0 到 100。assignee是你提示词中列出的有效枚举成员,但下游服务在上季度已停用,不再路由到该成员。total是一个数字,且它不等于sum(line_items),因为模型是独立计算它的。
- https://news.ycombinator.com/item?id=46345333
- https://mbrenndoerfer.com/writing/constrained-decoding-structured-llm-output
- https://dev.to/pockit_tools/llm-structured-output-in-2026-stop-parsing-json-with-regex-and-do-it-right-34pk
- https://www.promptfoo.dev/docs/guides/evaluate-json/
- https://developers.redhat.com/articles/2025/06/03/structured-outputs-vllm-guiding-ai-responses
- https://letsdatascience.com/blog/structured-outputs-making-llms-return-reliable-json
