第一次把 LLM 接进订单解析流程时,我写了两百多行防御代码:正则抽 JSON、去掉 Markdown 代码围栏、补全尾逗号、失败重试三次。上线第一周成功率是 96%,剩下 4% 每天往告警群里扔几十条。后来改成 schema 约束,那两百行代码基本删完了。这件事本身没什么好说的,2026 年这已经是默认操作。真正值得聊的是约束解码的边界:它在什么任务上省钱,在什么任务上会让你悄悄丢掉准确率。
约束解码到底改了什么
自回归模型每一步输出一个 token,模型本质上只做一件事:给词表里的每个 token 打分。约束解码不改模型,只在采样前把不符合语法的 token 概率压到零,再从剩下的有效 token 里取 argmax 或采样。JSON Schema 先被编译成有限状态机或下推自动机,生成过程中状态跟着已输出字符推进,合法字符集也随之变化——逗号后面该是引号还是右括号,状态机说了算。
这套流程在工程上早已不新鲜。MLC-AI 的 XGrammar 现在是 vLLM、SGLang 和 TensorRT-LLM 里的事实标准,做法是把词表拆成上下文无关和上下文相关两部分,能预计算的预计算,每步只需检查少量 token。据其公开数据,相比早期逐 token 查词表的实现有最高百倍加速。微软的 llguidance 走另一条路,用 Rust 写,128K 词表下每个 token 约 50 微秒 CPU 时间,相对 GPU 推理延迟基本看不出来。
这里有个反直觉的点:加了约束不一定更慢。JSON 生成里大量位置的 token 是确定的——输出 {"name": " 之后,闭引号几乎是唯一选择,引擎可以跳过采样直接落字。约束收缩了搜索空间,采样本身变便宜了。
API 层已经收敛,自托管最划算
云上三家各有各的做法。OpenAI 用 response_format: { type: "json_schema" },服务端做约束解码,支持递归 schema 和可选字段,代价是 schema 要随请求传、首次请求多一次编译延迟。Anthropic 在 2025 年底给 Claude 上了结构化输出,通过 output_format 支持 JSON Schema,工具调用侧也有严格模式。Google Gemini 走 response_mime_type 加 schema 约束,但有一个明确的坑:严格 schema 下微调模型的质量可能下降,文档里写着,别忽略。
自托管侧更简单,vLLM 和 SGLang 收一个 JSON schema 参数就行,编码时把 schema 编译结果缓存住。高 QPS 下不缓存的话,编译开销会以 P99 抖动的形式出现在监控里。
它会占用模型的推理预算
这是我从项目里学到的教训。有个工单分类任务,模型需要先想清楚再输出标签,我图省事直接加了 enum 约束。结果是模型不再写解释,直接吐标签,歧义样本的准确率比自由生成再抽取低了几个点。
这不是孤例。有研究(一篇匿名 ACL 投稿)报告强制结构化输出让创造性任务平均下降 17%,最差情况 26%;另一项覆盖十二个场景的研究里有十个出现性能下降。机制并不神秘:模型把一部分计算分给了格式合规,语法把模型推离它偏好的 token 时,语义就会出错。一个有记录的案例是,把国家字段约束为小写枚举值后,模型给巴黎输出了 spain——France 因为大写被屏蔽,而训练数据里 france 很少出现。
所以我把任务分成两档。数据抽取、分类、工具调用参数这类“输出即数据”的场景,直接用约束,解析失败率归零,剩下的失败全是语义问题,监控反而更干净。需要开放推理、长文生成、多因素权衡的场景,改成两阶段:第一次调用不加约束让模型自由推理,第二次用便宜的模型调结构化输出,从自由文本里抽字段。第二次调用的成本很低,但保住了第一次的思考空间。
三个容易踩的工程细节
第一,schema 当 API 契约管。线上 schema 改动和数据库迁移是一个量级的事,下游消费者会静默挂掉。要版本号、要兼容性检查。一个高频模型带五步调用,每步解析成功率 97%,端到端只剩 86%;在 Agent 链路里这个数放大得更快,步骤一多 2% 的失败率也不能忍。
第二,给字段留出“不知道”的出口。表单里没抽到的字段,如果 schema 强制要求非空字符串,模型会编一个。改成可选或允许 null,宁可拿到空值也不要拿假值。这不是模型能力问题,是你给了它一个没有退路的契约。
第三,语法保证不等于语义正确。一条情绪完全负面的评论,结构化输出的 sentiment 字段照样可能是 positive。schema 只保证你能把它解析出来,业务校验、分类准确率评测一样不能省。
约束解码消除的是解析脆弱性这一类故障,不是质量问题。它把错误处理从 try/catch 变成业务逻辑之后,评估工作的重心才真正转移到输出对不对上。
适用性上我给一个粗糙的判据:如果你的输出格式需要下游程序逐字段读取,加约束;如果输出主要是给人看的文字,只在前置一层抽关键字段就够。Agent 工具调用是目前收益最高的一处,多步链路里每个未解析的 JSON 都是一个隐性故障点。
最后提醒一点,别把配置项当保险箱用。schema 写得越窄,模型能表达的空间越小,窄过了头就是在拿语义换格式。
转载请注明出处: 皮哈皮阿
本文的链接地址: https://blog.phpat.com/ai-dev/612.html
微信或手机浏览器扫一扫,随时随地随心阅读与分享
-
上下文工程:从 Prompt 到 Context 的工程化实践
客服 Agent 答错时,团队第一反应是换模型。把那次请求的上下文打印出来才发现,模型看到的是一份过期政策、两份互相矛盾的条款,还有一长串无关日志。上下文工程要解决的,就是这类问题。
2026/10/06
-
RAG 的下一站:Agentic Retrieval
用户问“我们去年买的套餐现在还能退吗”,经典 RAG 检索出一段通用退款政策就结束了。可这个问题至少要拆成订单时间、地区、套餐版本三件事。Agentic Retrieval 要解决的,就是这种“一次检索不够用”的场景。
2026/10/12
-
约束解码让 JSON 不再崩,但它会改坏推理
约束解码让 JSON 解析失败率归零,工程师可以删掉一堆重试和修复代码。但它会挤占模型的推理预算:强制格式在部分任务上带来10%以上的准确率下降。文章梳理 OpenAI、Anthropic、Gemini 和其他自托管引擎的现状,以及 schema 设计、两阶段模式与编译缓存几个实操要点。
17小时前
京公网安备11011402053654 
@muffin:链接已更新,分类图像功能...
AI网址导航模版图标库更换指南
作者大大,图标库邀请链接失效了,麻烦更新...
AI网址导航模版图标库更换指南
太好看了,快点更新!
友情链接
@戴墨镜的刘备:哈喽,路过点赞。
vue.js组件之手写签名板vue-signature-simple
太好看了,快点更新!太棒了!👍真的很赞!
vue.js组件之手写签名板vue-signature-simple
你写得非常清晰明了,让我很容易理解你的观...
Emlog插件RSS订阅器发布