核心摘要
约束解码在大模型生成 Token 时强制执行输出语言。它可以让结果符合受支持的 JSON Schema、语法、正则或选项集合,但不能保证字段值真实或操作安全。生产系统需要完整输出契约:约束编译、拒答与截断处理、应用层校验、可观测性,以及高风险流程的失败关闭策略。
约束解码改变了什么
约束解码改变的是格式控制发生的位置。仅靠提示词,是请求模型主动配合;生成后校验,则是在模型已经输出后拒绝或修复;约束解码直接阻止不合法的下一 Token 被采样。
普通解码在第 t 步从模型概率分布采样:
P(token_t | prompt, token_1 ... token_t-1)
约束解码会把该分布与当前语法状态允许的 Token 求交集:
allowed = grammar.valid_tokens(generated_prefix)
masked_logits[token not in allowed] = -infinity
token_t = sample(masked_logits)
关键是当前语法状态。引擎不是只在最后检查字符串能否解析,而是持续判断当前前缀能否继续扩展成约束语言中的合法结果。
提示词、JSON 模式、Schema 与校验
这些机制解决的问题不同,不能互相替代。
| 机制 | 能约束什么 | 主要失败方式 |
|---|---|---|
| 提示词格式要求 | 模型遵循示例的意愿 | 出现说明文字、缺字段、类型错误 |
| JSON 模式 | 通常保证 JSON 可解析 | 可能返回任意合法形状 |
| Schema 引导解码 | 受支持的结构约束 | 结构正确但字段值错误 |
| 应用层校验 | 领域规则与跨字段规则 | 需要维护确定性逻辑 |
| 证据校验 | 主张支持与来源 | 需要来源和评估策略 |
结构化输出是应用目标,JSON 模式和约束解码是实现机制。JSON Schema 描述契约,而厂商的解码后端决定能执行哪些子集。
OpenAI Structured Outputs 文档说明了受支持模型的严格 JSON Schema 输出。NVIDIA NIM 则记录了 guided JSON、正则、上下文无关文法和固定选项,同时提示不同后端的支持范围与回退行为。因此,只说某个平台“支持结构化输出”并不足以证明兼容性。
Schema 如何变成 Token 规则
Schema 引导生成通常经历四层处理:
- 规范化约束。 解析引用,验证受支持关键字,拒绝歧义或不支持的结构。
- 编译识别器。 把 Schema 或语法转换为有限状态表示、下推自动机或优化匹配器。
- 映射到分词器 Token。 一个 Token 可能表示一个字符、多个字符或 Unicode 序列的一部分,引擎要判断其文本是否为合法延续。
- 屏蔽并推进。 每一步阻止非法 Token,完成采样后更新识别器状态。
由此会产生实际边界:
- Schema 本身合法,却超出厂商支持子集;
- 同一正则在某个后端可编译,在另一个后端失败;
- 分词器词表可能让简单约束产生较高计算成本;
- 空对象可能满足 JSON 模式,却不满足应用所需字段;
- 流式消费者收到的是暂时无法解析的前缀;
- 安全拒答或 Token 上限可能让请求没有产生 Schema 实例。
设计生产级输出契约
生产契约必须定义正常路径之外的行为。Schema 应保持狭窄,并显式表达不确定数据,不能迫使模型编造值。
{
"type": "object",
"properties": {
"ticket_id": { "type": ["string", "null"] },
"priority": {
"type": "string",
"enum": ["low", "medium", "high", "unknown"]
},
"evidence_ids": {
"type": "array",
"items": { "type": "string" }
}
},
"required": ["ticket_id", "priority", "evidence_ids"],
"additionalProperties": false
}
执行器还要完成确定性校验:
type Ticket = {
ticket_id: string | null;
priority: "low" | "medium" | "high" | "unknown";
evidence_ids: string[];
};
function validateForEscalation(
ticket: Ticket,
visibleEvidenceIds: Set<string>,
): void {
if (ticket.priority === "high" && ticket.evidence_ids.length === 0) {
throw new Error("high_priority_requires_evidence");
}
for (const id of ticket.evidence_ids) {
if (!visibleEvidenceIds.has(id)) {
throw new Error("unavailable_evidence");
}
}
}
解码器无法保证这两条规则。它不知道调用者有权查看哪些证据,Schema 也不能证明高优先级判断有事实支持。
延迟与吞吐权衡
约束解码可以减少修复重试,但也会增加推理路径工作,应同时测量收益和成本。
| 成本 | 观测指标 | 缓解方式 |
|---|---|---|
| Schema 编译 | 冷启动延迟、缓存命中率 | 规范化并缓存已审查 Schema |
| Token 屏蔽 | 每个输出 Token 的耗时 | 使用简单约束和优化后端 |
| 语法分支 | 合法 Token 集合大小 | 使用有界枚举和浅层对象 |
| 强制输出变长 | 输出 Token 与完成延迟 | 让契约保持任务专用 |
| 减少重试 | 解析与 Schema 失败率 | 比较端到端成功率 |
不要假设约束越严格就一定越快。有些后端优化了常见 JSON Schema 路径,复杂正则或语法组合则可能回退到较慢实现。测试必须覆盖实际模型、分词器、后端、Schema 家族、流式模式和生产并发。
失败模式与安全降级
以下结果必须被视为不同状态:
| 结果 | 正确处理 |
|---|---|
| 不支持的 Schema | 在部署或请求校验阶段拒绝 |
| 约束编译失败 | 返回类型明确的基础设施错误 |
| 模型拒答 | 保留为一等返回状态 |
| 达到 Token 上限 | 标记输出不完整,不能按成功解析 |
| 结构合法但语义无效 | 返回领域错误或进入人工复核 |
| 后端静默丢弃约束 | 通过一致性探针检测并失败关闭 |
对于只展示给人工的低风险草稿,降级为提示词 JSON 可能可以接受;如果结果会触发支付、权限变更、数据库写入或外部消息,则不能降级。无法执行契约时必须停止操作。
测试与可观测性
约束层测试应与模型质量测试分开。
结构一致性测试
- 最小、典型和最大合法对象;
- Unicode、转义文本、空数组和长字符串;
- 不支持的关键字与递归 Schema;
- 拒答、取消、超时和截断;
- 流式拼接与消费者中途断开;
- 后端升级与分词器变更。
语义测试
- 类型正确但值错误;
- 字段互相矛盾;
- 编造标识符;
- 引用未授权资源;
- 缺少证据;
- 对抗文本要求模型修改 Schema。
遥测应记录 Schema 版本与摘要、后端、模型修订、编译结果、首 Token 延迟、输出 Token 延迟、结束原因、拒答状态、校验结果和降级路径。默认不要记录敏感原始负载。
上线决策清单
当下游代码需要狭窄的机器可读契约,且实际后端能稳定支持时,适合使用约束解码。最终输出只是供人阅读的自然语言时,不必强行增加这层复杂度。
上线前应确认:
- 厂商支持的 Schema 或语法子集。
- 约束像生产代码一样被版本化和审查。
- 拒答、截断和不支持 Schema 的结果协议。
- 解析后继续验证领域规则与权限。
- 在生产并发下测试冷、热 Schema。
- 为后端升级添加结构一致性探针。
- 高影响操作禁止静默降级。
工具执行还要结合函数调用指南中的宿主授权模型。一般 JSON 校验可参考 JSON Schema 校验指南。
常见问题
约束解码能强迫模型回答吗?
不能。安全拒答、信息不足、取消和 Token 上限仍然存在。响应协议应显式表示这些状态,而不是把它们强塞进正常对象。
语法一定比 JSON Schema 更好吗?
取决于目标语言。JSON Schema 适合类型化应用对象;上下文无关文法适合非 JSON 的 DSL;正则只适用于有界正则语言,嵌套结构会很难维护。
应该动态生成 Schema 吗?
只应在严格边界内使用。动态 Schema 会扩大编译缓存、攻击面和兼容矩阵。优先使用经过审查的模板、有界参数、大小限制和规范化。
约束解码可以与函数调用结合吗?
可以。很多厂商用 Schema 约束生成工具参数,但模型仍只是提出操作,可信代码必须在执行前校验并授权精确调用。
如何发现厂商静默降级了约束?
运行无限制模型容易违反的反向探针,记录后端与功能开关,并独立校验每个响应。请求返回成功不代表约束确实被执行。
参考资料
- OpenAI Structured Outputs 文档,访问于 2026-07-28。
- NVIDIA NIM Structured Generation 文档,访问于 2026-07-28。
- NVIDIA Triton Guided Decoding 文档,访问于 2026-07-28。