模型 API 的结构化输出如何保证结果符合 JSON Schema?
未标记
考查重点:约束生成与异常完成。严格模式在生成时屏蔽不符合支持 Schema 的 token,正常完成可保结构;拒绝、截断和业务含义仍需处理
本题目录
参考答案
核心回答
支持严格结构化输出的 API,通常通过模型对格式的训练,加上推理时的约束解码,让正常完成的输出符合其支持的 JSON Schema 子集。约束发生在生成过程中;应用层收到结果后再解析、校验或重试,是另一层机制。
生成时怎样约束
以 vLLM 配合 XGrammar 这类公开实现为例,可以分成四步:
- 接收并检查 Schema。 核对字段类型、必填项、枚举、对象和数组结构,拒绝或按文档处理不支持的约束。Schema 写进普通提示词,与通过专门参数开启严格模式,作用不同。
- 构建语法约束。 将支持的 Schema 转成可用于解码的语法或解析状态,结合 tokenizer 判断哪些 token 能合法延续当前前缀。嵌套对象和数组需要维护相应状态,不能只靠检查一对大括号。
- 逐步屏蔽非法 token。 模型产生 logits 后,把不能延续合法结果的候选屏蔽,再在剩余候选中选择或采样。选中 token 后更新解析状态,下一步重新计算允许集合。
- 完成后交付结果。 只有达到完整、可接受的结束状态,才是一份成功的结构化结果;拒绝、超时、长度截断和连接中断需要走相应的异常分支。
若当前允许的 token 集合为 A_t,可以把约束写成:
修正后 logit z̃_i = z_i,若 i 属于允许集合 A_t
= −∞,若 i 不属于 A_t
p_t = softmax(z̃)
这说明为什么强约束比“请只输出 JSON”更可靠。允许集合受完整前缀和语法状态影响;token 可能包含多个字符,实际实现还要处理 tokenizer 与语法的匹配,而非逐字符简单判断。
这是对公开约束解码机制的说明,具体闭源 API 采用哪种编译器、自动机或缓存策略,应以其公开资料为准。
JSON 模式和 Schema 模式有什么区别
普通 JSON 模式主要保证可解析的 JSON,例如 {"status":"maybe"} 依然是合法 JSON;若 Schema 规定 status 只能为 ok 或 failed,它就不符合约定。
Schema 中,properties 描述字段,required 决定哪些字段必须出现,additionalProperties: false 禁止额外字段。字段允许 null 与字段可以省略也是两种不同要求。严格模式通常只能实现标准的一部分,且不同服务商、模型和版本的支持范围可能不同;不能把“接口接受了 Schema”直接等同于“所有关键字都被强制执行”。
为什么还要做应用层校验
Schema 能约束类型、枚举与结构,不能自动保证事实、授权和业务规则成立。例如订单号满足字符串类型,不代表订单真实存在、属于当前用户或允许退款。这些条件仍需查询真实系统并验证。
应用应检查响应是否正常完成,解析完整 JSON,验证约定的结构,再执行跨字段关系、事实依据和业务权限检查。流式传来半个 JSON 时,可以缓存和展示进度,不能凭未完成的工具参数触发有副作用的操作。
如果不支持原生约束,可以采用提示词、解析器、错误反馈和有限重试,但应把它视为生成后的修复流程。给残缺结果补括号、自动填默认值后就执行,可能改变原意,也不能证明模型原本遵循了 Schema。
对应教程
- 14-输出解析器:理解解析、结构化输出和运行时校验的边界,进一步区分格式与业务正确。
参考资料
- 国内:阿里云百炼:结构化输出:比较合法 JSON 与严格 Schema 模式,说明服务商所支持的 Schema 子集如何限制可用约束。
- 国内:DeepSeek:JSON Output:参考仅保证合法 JSON 的接口约定,解释正文中合法 JSON 仍可能违反枚举等 Schema 要求的例子。
- 国内:zero2Agent:工具管理:参数校验与工具路由:借鉴服务端结构约束与应用端业务校验的分工,说明正文中订单号合法仍需验证事实和权限的原因。
- 国外:vLLM:Structured output:XGrammar backend 与 token mask:通过开源实现说明 Schema 如何转换为语法、生成时如何应用 token 掩码,以及如何处理不支持的特性。
- 国外:JSON Schema:Understanding JSON Schema:object:依据 Schema 关键字的语义,解释正文中字段定义、必填、可空和禁止额外字段之间的区别。
