记忆点:JSON Mode 只管语法,Structured Outputs 管 Schema 字段,Constrained Decoding 管整个语言结构。
💡 答案要点
三者的本质区别在于「约束层级」不同:
┌───────────────────────────────────────────────────────┐
│ Layer 1: JSON Mode │
│ → 只保证输出是合法 JSON │
│ → 不保证字段名、类型、必填项 │
│ → 代价:最低 │
├───────────────────────────────────────────────────────┤
│ Layer 2: Structured Outputs (OpenAI) │
│ → JSON + 严格 Schema 校验 │
│ → 模型训练时学习了 Schema 的结构 │
│ → 代价:中等 │
├───────────────────────────────────────────────────────┤
│ Layer 3: Constrained Decoding │
│ → CFG(上下文无关文法)/ Regex 驱动 token-by-token │
│ → 在采样阶段就禁止非法 token │
│ → 不依赖模型能力,纯解码器侧约束 │
│ → 代价:最高(需要编译 Grammar) │
└───────────────────────────────────────────────────────┘Constrained Decoding 的核心原理:
传统解码:
候选词: ["价格", "价钱", "cost", "$", ...]
softmax → 选 top-k → 可能选出 "$"
约束解码(CFG 语法: Number -> Int | Float | Dollar):
候选词: ["价格", "价钱", "cost"] ← "$" 被直接排除!
softmax + 掩码 → 只在合法词中选主流实现方案:
python
# 方案1: Outlines - 基于 EBNF 语法的约束解码
import outlines
from outlines import generate
date_pattern = r"\d{4}-\d{2}-\d{2}"
regex_schema = f"""
date: {date_pattern}
status: "success" | "pending" | "failed"
message: "[^""]*"
"""
response = outlines.generate.regex(llm, regex_schema)(prompt)
# 方案2: LMQL - Query Language for constrained generation
from lmql import query, args
@query(returns=f"{{int}}")
def answer(question: str) -> int:
"""强制返回整数"""
"""LMQL
{ response := random({question}) }
return response >= 0
"""
# 方案3: Guidance (Microsoft)
import guidance
guide = """
{{#\system}}{{user}}Calculate the sum of 23+45.
{{#assistant}}The result is {{num|gen(regex=r'\d+', max_tokens=2)}}.
{{/assistant}}{{/user}}{{/system}}
"""
result = guidance.llm(guide, max_tokens=10)选型决策树:
只需要合法 JSON? → JSON Mode
需要 Schema 字段校验?→ Structured Outputs
需要嵌套复杂格式/自定义语言?→ Constrained Decoding
需要确保数学/逻辑推理结果格式?→ Constrained Decoding
需要与传统 AI 系统集成(Java/C++ 等不支持新 API)?→ Constrained Decoding面试加分点:
- Constrained Decoding 的优势是不依赖模型能力——即使用很小的模型也能输出正确格式
- 缺点是编译 Grammar 有成本,且某些复杂结构难以表达为 CFG
- 工业实践中经常采用双层策略:先用 Structured Outputs 生成,再用 Post-parse 验证兜底
面试话术:
"JSON Mode 只管语法合法性,Structured Outputs 进一步做了 Schema 约束,而 Constrained Decoding 是在 token 级做语法约束。三层方案层层加码,约束力越来越强但延迟也越高。我在项目里用过 Outlines 处理复杂的嵌套 JSON,准确率接近 100%,但 Grammar 编写成本需要评估。生产上推荐 Structured Outputs 为主、Constrained Decoding 兜底的策略。"