Constrained Decoding
受约束解码会在每个生成步骤屏蔽无效 token,因此 LLM 只能输出允许的标签、符合正则表达式的内容或符合架构要求的 JSON。
受约束解码是一种文本生成技术,它会限制语言模型在每一步可以生成哪些 token,从而保证最终输出符合指定格式:固定标签集合中的一个标签、正则表达式、语法或 JSON Schema。模型仍会为词汇表中的每个 token 计算分数。在选定 token 之前,解码器会移除所有会破坏格式的选项。需要解析模型输出的应用,例如 API 后端、AI 智能体和数据提取流水线,会使用这项技术来确保每个响应都能一次解析成功。
屏蔽无效 Token#
大型语言模型一次生成一个token。每一步都会为词汇表中的每个 token 生成一个分数,即 logit,然后由 softmax 将这些分数转换为概率。受约束解码会在采样之前增加一个操作:无法导向有效输出的 token 会被赋予负无穷的 logit,因此其概率为零;剩余 token 的概率则会重新归一化。
import torch
# Raw next-token scores from a model over a toy vocabulary
vocab = ["approved", "rejected", "review", "maybe", "{", "}"]
logits = torch.tensor([1.2, 0.4, 0.9, 2.5, 0.1, 0.3])
# The schema allows only the three status labels at this position
allowed = torch.tensor([True, True, True, False, False, False])
masked_logits = logits.masked_fill(~allowed, float("-inf"))
# Softmax renormalizes probability over the valid tokens only
for name, raw, masked in zip(vocab, logits.softmax(-1), masked_logits.softmax(-1)):
print(f"{name:>9}: {raw:.2f} -> {masked:.2f}")未加约束的模型将 56% 的概率分配给“maybe”。应用掩码后,“maybe”的概率降为零,三个允许的标签则按原始分数比例共享概率,因此“approved”的概率从 15% 上升至 46%。
生产环境中的推理引擎会在生成过程中跟踪约束状态。固定选项列表或正则表达式会被编译为有限状态机。JSON 和其他嵌套格式需要带栈的语法,因为只有出现匹配的左大括号后,右大括号才有效。每生成一个 token,解码器都会推进状态并重新计算允许的选项。分词会生成长度各异的子词片段,因此单个 token(如 "},)就可能跨越多个语法步骤。因此,库会预先计算每种状态下哪些词汇表条目合法;即使词汇表超过 100,000 个 token,这也能将每个 token 的计算成本控制在较低水平。Brandon Willard 和 Rémi Louf 于 2023 年在论文 Efficient Guided Generation for Large Language Models 中介绍了针对正则表达式和上下文无关语法的这种索引方法;这篇论文也是 Outlines 库的基础。
选择约束类型#
合适的约束应与应用实际使用的输出相匹配。分类和路由适合使用选项列表,因为答案必须是少数几个字符串中的一个。正则表达式可用于日期、ID 和电话号码等简短结构化值。上下文无关语法可以描述 SQL、代码和领域特定语言,llama.cpp 的 GBNF 语法格式就是一个广泛使用的例子。对于具有命名字段的记录,JSON Schema 可以指定必需键、类型、枚举和嵌套结构。像 OpenAI Structured Outputs 这样的托管 API 接受 schema,并在生成过程中强制执行;它们通常支持完整 JSON Schema 规范中有文档说明的子集。
受约束解码经常与一些相近技术混淆:
- 结构化输出:机器可读响应这一更广泛的目标,可以通过生成时的受约束解码实现,也可以在生成后验证输出并在失败时重试。
- JSON 模式:将输出限制为语法有效、形状不限的 JSON,因此仍需检查键、类型和值。
- 提示工程:在指令中要求特定格式,模型大多数时候都会遵循。使用 schema 约束的请求通常也会在提示中描述字段,让模型知道每个字段的含义。
- 函数调用:工具名称和参数是最常见的 schema 约束目标之一,因为调用代码要求字段名称完全准确。
实际应用中的权衡#
格式有保证,不代表内容有保证。Schema 可以强制要求 {"total": 1290.00} 是一个数字,但这个数字仍可能错误;受约束的模型也可能在有效字段内流畅地产生幻觉。应用程序仍需在生成后验证业务规则。
约束也可能降低回答质量,因为它会让模型偏离自然生成的文本。如果 schema 要求把最终答案放在第一个字段,就没有空间容纳中间推理,因此 schema 通常会把自由文本推理或备注字段放在答案字段之前。也要留意输出长度:如果生成在对象中途达到 token 上限,无论约束如何,结果都会无效。因此,结构化请求会设置足够宽裕的最大长度,确保容纳完整结构。非常大或递归层级很深的 schema 编译耗时更长,这对于每个请求都动态构建新 schema 的系统尤其重要。
当多模态模型必须返回图像相关字段时,视觉应用也会使用相同机制。Ultralytics LLM 接口会将请求参数原样转发给兼容 OpenAI 的 API,因此,在图像请求中传入 JSON Schema,就能将视觉语言模型的回答限制为 hazard 和 severity 等字段,便于与同一帧中的 YOLO26 检测结果结合。










