ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

面试官问:“给大模型套上 JSON Schema,它会变笨吗?“

面试官问:“给大模型套上 JSON Schema,它会变笨吗?“ 面试官问“给大模型套上 JSON Schema它会变笨吗”“3 年 AI 应用开发经验主导过订单抽取、工单分类等多个结构化输出场景的落地”看到这份简历我先问了个送分题你怎么保证模型返回的一定是合法 JSON候选人答得很流畅上了 strict 模式schema 保证 100% 合规解析失败率从 3% 降到 0。我接着问那准确率呢开 schema 之前和之后同一批数据抽出来的字段值对得上吗他停了几秒应该……也变好了吧格式都规范了。这一停暴露的是整个结构化输出领域最贵的一个误会。合法和正确是两件事而约束解码只负责前一件。有研究测过一个极端情况同一个模型、同一批数学题从自然语言输出切成 JSON 约束输出准确率从 86.51% 掉到 23.44%。今天这场面试把 JSON Schema 背后的那层机制讲透。Round 1三种保证 JSON 的方式你用的是哪一种面试官“你怎么保证模型输出的一定是合法 JSON”候选人“在 prompt 里写清楚只返回 JSON、不要解释然后加 try-except解析失败就重试一次。现在线上基本不出错。”正解这个回答里其实混了三种完全不同的东西它们的保证强度差了两个数量级。第一种是格式指令也就是在 prompt 里写上请输出 JSON。这只是一个请求模型可以听也可以不听。典型的不听表现是给你裹一层 markdown 代码块或者在 JSON 前面加一句客套话。研究文献里把这类叫 format-restricting instruction它不改变解码过程只改变输入。第二种是 JSON modeOpenAI 的response_format里那个json_object类型。它保证吐出来的东西能被json.loads解析但不保证字段名对、不保证字段齐、不保证类型对。模型可以给你一个语法完美的空对象。第三种才是 strict 模式的 JSON Schema。OpenAI 这边是response_format里带json_schema且strict: trueClaude 这边是output_config.format指定json_schema或者在工具定义上打strict: true。这一种会真正改写解码过程下一轮细说。30 秒验证法复制下面这段 schema给score字段加上minimum和maximum两个约束开 strict 发一次请求看控制台返回什么。​​​schema { type: object, properties: { score: {type: integer, minimum: 0, maximum: 100} }, required: [score], additionalProperties: False, }这段 schema 在两家的 strict 路径上都不会按你想的方式生效。Claude 官方文档把minimum、maximum、multipleOf、minLength、maxLength明确列为不支持直接用会收到一个 400错误信息里会写明是哪个关键字。它的 SDK 还有个更隐蔽的行为自动把这类不支持的约束从 schema 里摘掉然后把约束信息追加到字段的 description 里。摘掉之后会发生什么值得多想一秒。你的 Pydantic 模型里写着Field(ge0, le100)看起来是硬约束经过 SDK 转换后它变成了描述文字里的一句提示。模型大概率会照做但没有任何机制拦着它写出 150。真正的值域校验还得在你自己的代码里做一遍。要点速记三层保证强度prompt 指令模型可以不听 JSON mode只保语法合法 strict json_schema约束解码json_object模式允许模型返回一个语法完美的空对象字段一个都没有Claude strict 不支持 minimum / maximum / multipleOf / minLength / maxLengthminItems 只支持 0 和 1Pydantic 的 ge / le 在 strict 模式下会被 SDK 移出 schema、写进 description从硬约束降级成软提示Round 2stricttrue 打开后底层到底多做了什么面试官“打开 strict 之后模型那边发生了什么变化”候选人“应该是针对 schema 做过专门训练吧或者内部帮我把 schema 又拼到 prompt 里强调了一遍让它更听话。”正解模型权重一个字节都没变被改的是采样那一步能落笔的候选集。把 schema 变成约束中间要过一道编译。一个 JSON Schema 描述的所有合法字符串构成一个形式语言编译器把它翻译成一台状态机。JSON 有嵌套光靠有限状态机不够用所以 xgrammar 这类引擎用的是下推自动机靠一个栈来记住当前嵌套到第几层、还欠几个右括号。生成的时候流程是这样的第一步看当前状态。模型刚写完左花括号加上scor这几个字符状态机知道现在处在字段名中间且已经匹配上了score这个字段名的前缀。第二步算允许集合。词表里十万个 token哪些接上去之后这个字符串仍然可能走向一个合法结果状态机遍历出来得到一个 bitmask长度等于整个词表。第三步压概率。模型正常前向传播算出 logits引擎把 bitmask 里不允许的位置全部置成负无穷。过一遍 softmax这些 token 的概率变成 0。第四步正常采样。temperature、top-p 该怎么作用还怎么作用只不过作用在一个被裁剪过的分布上。理解了这四步三个看起来无关的现象就串起来了。首次请求为什么慢。编译要时间schema 越复杂语法越大编译越久。OpenAI 文档的原话是用某个 schema 的第一次请求会有额外延迟后续用同一个 schema 的请求不会再有。编译结果为什么要缓存又为什么会失效。Claude 把编译好的语法缓存 24 小时从最后一次使用开始算。缓存失效的条件写得很具体schema 结构变了会失效请求里的工具集合变了也会失效而只改工具的 name 或 description 不会失效。这个区分很说明问题前两者会改变状态机本身后者不会。递归 schema 在两家那里结论相反。一个能无限自我嵌套的结构状态机要靠栈来展开实现复杂度和编译开销都上一个台阶。OpenAI 选择支持文档里给了两种写法用$ref指向根节点或者在$defs里显式自引用Claude 把递归 schema 明确列为不支持送过去直接 400。同一份评论树、同一份组织架构 schema换个厂商就得重写。跨厂商的服务想省事把树形数据拍平成带 parent_id 的列表两边都能跑。还有一个更微妙的坑叫分词歧义。左花括号和紧跟的引号这两个字符在词表里可能合成一个 token也可能是两个不同的切法对应状态机里不同的路径。引擎必须在 token 粒度上处理字符粒度的语法这中间的错位是约束解码实现里最容易出 bug 的地方也是同一个 schema 在不同后端上行为略有差异的原因。要点速记strict 不改权重只在采样前把非法 token 的 logit 置为负无穷JSON 嵌套需要栈xgrammar 用下推自动机而非有限状态机Claude 编译后的语法缓存 24 小时schema 结构变或工具集合变则失效仅改 name / description 不失效递归 schemaOpenAI 支持$ref指根或$defs自引用Claude 不支持直接 400跨厂商用 parent_id 拍平Round 3既然想法没变答案为什么会变差面试官“既然模型的想法没被改只是不让它落非法的字那套上 schema 之后答案的准确率会变吗”候选人“不会吧内容还是那个内容只是换了个格式装而已。”正解EMNLP 2024 Industry Track 有一篇专门测这件事的论文Tam et al., arXiv 2408.02442。在 GSM8K 数学推理上2024 年那批模型从自然语言输出切到 JSON-mode 约束输出一个从 86.51% 掉到 23.44%另外两个从 75.99% 和 75.13% 掉到 49.25% 和 48.90%。真正有意思的是对照组。同样要求输出 JSON但只在 prompt 里说、不开约束解码成绩几乎没掉分别是 86.99% 和 74.70%。一个说了要 JSON 但不强制一个强制差了 63 个百分点。掉的不是模型的推理能力是它写字的顺序。自回归生成只有一个方向每个 token 落下去就不能改。schema 里字段的生成顺序就是模型做决定的顺序。当你的 schema 长这样​​​{answer: ..., reasoning: ...}模型必须先把answer的内容写完才轮到reasoning。它做出答案判断的那一刻上下文里只有题目没有任何自己推导出来的中间结果。后面那段reasoning不再是推理是对一个已经定死的答案做事后解释。链式思考之所以有效靠的就是把中间步骤写进上下文供后续 token 参考字段顺序一倒这条链直接断了。顺序这件事在 Gemini 上尤其值得查一眼自己的代码。Gemini 的结构化输出文档到今天还写着一句默认情况下 API 按字母序排列属性不保留你定义属性时的顺序只是官方 SDK 可能会替你保留。2025 年 11 月的一次更新又加了隐式属性排序公告说从 2.5 那一代往后的模型开始API 会沿用 schema 里的 key 顺序OpenAI 兼容端点也覆盖。两句话同时挂在官网上意味着最终生成顺序取决于三件事你用的模型是哪一代、走的是原生接口还是 OpenAI 兼容端点、schema 是 SDK 帮你转的还是手写的字典。而字母序一旦生效answer的 a 排在reasoning的 r 前面你在 Pydantic 类里把 reasoning 写第一个也没用。schema 校验全绿解析零失败准确率悄悄掉一截日志里什么都看不出来。想确定就显式写propertyOrdering它是专门干这件事的字段OpenAI 那边没有对应物因为 OpenAI 的文档写明按你提供的 schema 顺序生成。顺序本身就是干货这也是 OpenAI 官方那个数学推理示例把steps数组放在final_answer前面的原因。反过来的证据同样结实少了这一半上面的结论很容易被用歪。约束解码在抽取和分类类任务上是净收益。SqueezeBits 在 2025 年 9 月发布的一组实测里用结构复杂的 schema 做抽取不开约束解码时正确率低到 61.1%开了之后绝对值提升 20 到 25 个百分点结构简单的那组从 90% 出头提到 98.2%。前面那篇论文测分类任务时也是同样的方向JSON-mode 表现反而最好。分界线在于这个任务需不需要模型边想边写。需要推导的任务约束会掐断它的思考路径把已知信息填进格子的任务约束只会挡掉格式错误不挡思考因为根本没有思考要挡。要点速记GSM8K 上从自然语言切到 JSON-mode 约束输出最大一例 86.51% → 23.44%Tam et al., EMNLP 2024只在 prompt 里要求 JSON 不开约束解码成绩几乎不掉86.99% / 74.70%差距来自解码约束而非格式本身字段生成顺序就是决策顺序answer 排在 reasoning 前面等于先答后想Gemini 文档写明默认按字母序排列属性2025-11 起又加了隐式保留 schema 顺序实际顺序取决于模型代次与接口路径显式写propertyOrdering才确定OpenAI 侧文档写明按提供的 schema 顺序生成官方数学推理示例就是steps在前、final_answer在后抽取类任务方向相反复杂 schema 场景约束解码带来 20-25 个百分点的绝对提升SqueezeBits, 2025-09Round 4账单和延迟你测过吗面试官“你们线上的 schema 长什么样上了 strict 之后账单和延迟有变化吗”候选人“理论上约束解码只是在采样前加个 mask计算量可以忽略我们没专门测过。”正解mask 本身确实便宜贵的是它周边那一圈。输入 token 会变多。Claude 的文档写得很直白启用结构化输出时会自动注入一段系统提示来说明期望的输出格式这段提示和你自己写的 system prompt 一样计费。schema 越大这段注入越长。prompt cache 会被打掉。同一份文档改一次output_config.format这条会话线上的 prompt 缓存就失效。做多阶段抽取的人很容易踩这个一轮抽基本信息、一轮抽条目明细、一轮抽金额三个 schema 轮着换每一轮的长上下文都按全价重算。Claude Sonnet 5 的输入价是 $2/M一个 40K token 的合同上下文单轮全价 input 就是 $0.08三轮 schema 轮换下来 $0.24 全按原价走。同样三轮如果共用一个 schema后两轮的这部分本来可以吃到缓存价。编译缓存有过期时间。Claude 的语法缓存是 24 小时从最后一次使用算起。高频 schema 永远是热的那些一天只跑几次的长尾 schema每次来都在重新编译。required 全字段这条规则是幻觉的制造现场。OpenAI 的 strict 模式要求properties里的每个字段都出现在required里想表达可选唯一的办法是把类型写成 union​​​# 逼模型编造{“phone”: {“type”: “string”}}给出口{“phone”: {“type”: [“string”, “null”]}}差别在于第一种写法下一份没留电话的合同模型也必须在phone位置填点什么。它不能停笔不能跳过状态机要求这里出现一个字符串。于是它编一个看起来像电话号码的数字。模型在这里没有别的选择你的 schema 里压根没有一个能装下没有这个结论的格子。schema 有硬上限。Azure 的结构化输出文档2026 年 8 月更新写得很直接一个 schema 最多 100 个对象属性最多 5 层嵌套。另外还有一组针对属性名与 enum 取值的字符总量限制各家数值不同用之前去对自己那家的文档。撞上限的常见场景是把一张宽表的几十个字段一次性塞进一个 schema解法是拆成两次调用先用一个小 schema 路由出该抽哪几组再用窄 schema 抽。自部署这边有个改名要注意。vLLM 从 v0.12.0 起移除了guided_json这一族参数统一换成structured_outputs​​​# 旧写法已移除SamplingParams(guided_jsonschema)现在SamplingParams(structured_outputsStructuredOutputsParams(jsonschema))后端选择上xgrammar 靠缓存吃饭适合少量 schema 高频复用、输出较长的场景guidance 按 token 现算约束首字延迟更好适合每个请求 schema 都不一样的多租户场景。SqueezeBits 那组测试还有个容易被忽略的结论vLLM 上开约束解码后batch size 到 8 以上相对 baseline 有明显的吞吐下降单请求测下来没感觉的开销在并发上会放大。项目托管 APIOpenAI / Claude自部署vLLM参数json_schemastrict/output_config.formatstructured_outputs.json首次编译有额外延迟同 schema 后续无有xgrammar 缓存复用缓存周期Claude 24 小时进程内随服务重启失效属性上限OpenAI 100 个 / 5 层嵌套无硬上限受编译耗时约束并发影响厂商侧吸收batch ≥ 8 吞吐明显下降要点速记结构化输出会自动注入格式说明的 system prompt按正常 input token 计费切换output_config.format会让该会话的 prompt cache 失效多阶段抽取按全价重算长上下文OpenAI strict 要求所有字段进 required可选字段的类型要写成 string 与 null 的联合否则等于逼模型编值schema 上限Azure 文档给的是 100 个对象属性、5 层嵌套撞上限就拆成路由加抽取两次调用vLLM v0.12.0 起guided_json移除改用structured_outputsbatch ≥ 8 时吞吐下降明显Round 5enum 限死了类别就没有幻觉了吗面试官“工单分类这种场景你怎么保证模型输出的类别一定在你给的 12 个里面”候选人“我会在 prompt 里把 12 个类别和判断标准都列清楚让它输出 JSON然后用 Pydantic 校验一遍不在列表里就重试重试两次还不行就打到人工队列。”正解问的是怎么保证答的是校验失败之后怎么补救中间那一层被跳过了。enum 就是为这件事准备的。写进 schema 之后模型在那个位置物理上落不出表外的 token重试逻辑和兜底队列可以直接删掉。分类任务也是约束解码收益最干净的场景前面提到的论文里分类题上 JSON-mode 的表现反而优于自由输出。代价在另一个地方。模型内部算完概率最高的那个选项如果是这 12 类都不像而你的 enum 里没有这个格子mask 会把这条路堵死它只能在 12 个里挑概率次高的那个交卷。输出 100% 合法语义上是猜的而且这个猜没有任何外在痕迹校验器看不出来日志里也看不出来。enum 的取值怎么命名也比看上去重要。一个类别名会被切成好几个 token模型选哪一条分支靠的就是这些 token 本身携带的语义。billing_refund和billing_dispute这样的命名模型读得懂换成cat_07和cat_12token 层面没有任何语义可依它只能从 description 里那段文字去反推映射关系多绕一道。历史系统里的数字编码落到 enum 里之前先翻译成有意义的英文标识映射回编码这一步放在你自己的代码里做。所以 enum 里还要留一个出口​​​{category: { enum: [billing, bug, feature_request, ..., unclear], description: 证据不足以判定时返回 unclear不要在其余类别中勉强选择 }}约束解码负责让模型说不出表外的话留出口负责让它有地方交代自己没把握。两件事都做了那条打到人工的队列才是真的有效信号而不是被 12 选 1 硬猜之后的沉默误分类。类别体系大的场景还要注意 enum 本身的规模。各家对 enum 取值数量和字符总量都设了上限商品类目、ICD 编码这类动辄上千项的体系一定会撞墙而且几百个取值编译出来的语法本身就大首次请求的编译延迟很难看。通行做法是两段式先用一个十几项的粗分 enum 定大类再用大类对应的窄 enum 定细类。分两次调用每次的 schema 都小编译快、缓存命中率也高。要点速记enum 约束解码让表外类别在采样层就落不下去重试和兜底逻辑可以删掉代价是模型最高概率的判断若是都不像会被迫在给定类别里挑次高的猜得毫无痕迹enum 取值用有语义的英文标识而非 cat_07 这类编码token 本身就是模型的判断依据enum 里留 unclear / other并在 description 里写清触发条件各家对 enum 取值数量与字符总量都有上限大类目体系用粗分加细分两段式编译更快缓存更稳把 unclear 的占比做成监控指标它异常走低通常意味着模型在硬猜面试官点评这位候选人的工程直觉不差知道用 strict、知道加校验、知道兜底到人工。问题出在他把 schema 当成了输出层的一个开关没意识到它同时也是模型的决策顺序表和候选集裁剪器。解析失败率从 3% 降到 0 是真实的收益但这个指标只覆盖了 schema 影响的一半。另一半在字段顺序、在 required 的写法、在 enum 有没有留出口这些地方出问题不会报错只会让准确率安静地掉。给三条能立刻做的打开你线上的 schema看字段顺序。有推理性质的字段reasoning、evidence、steps必须排在结论字段前面。用 Gemini 的话显式写propertyOrdering别信默认顺序。找出所有业务上可选、类型却写死成 string 的字段把类型改成 string 与 null 的联合。这一条改完抽取任务的字段级幻觉通常会掉一截。拿 200 条有标注的数据跑一次 A/B同一个 prompt一组走 strict schema一组走自由文本加正则抽取比字段值的准确率。这个数据你现在大概率没有。学AI大模型的正确顺序千万不要搞错了2026年AI风口已来各行各业的AI渗透肉眼可见超多公司要么转型做AI相关产品要么高薪挖AI技术人才机遇直接摆在眼前有往AI方向发展或者本身有后端编程基础的朋友直接冲AI大模型应用开发转岗超合适就算暂时不打算转岗了解大模型、RAG、Prompt、Agent这些热门概念能上手做简单项目也绝对是求职加分王给大家整理了超全最新的AI大模型应用开发学习清单和资料手把手帮你快速入门学习路线:✅大模型基础认知—大模型核心原理、发展历程、主流模型GPT、文心一言等特点解析✅核心技术模块—RAG检索增强生成、Prompt工程实战、Agent智能体开发逻辑✅开发基础能力—Python进阶、API接口调用、大模型开发框架LangChain等实操✅应用场景开发—智能问答系统、企业知识库、AIGC内容生成工具、行业定制化大模型应用✅项目落地流程—需求拆解、技术选型、模型调优、测试上线、运维迭代✅面试求职冲刺—岗位JD解析、简历AI项目包装、高频面试题汇总、模拟面经以上6大模块看似清晰好上手实则每个部分都有扎实的核心内容需要吃透我把大模型的学习全流程已经整理好了抓住AI时代风口轻松解锁职业新可能希望大家都能把握机遇实现薪资/职业跃迁这份完整版的大模型 AI 学习资料已经上传CSDN朋友们如果需要可以微信扫描下方CSDN官方认证二维码免费领取【保证100%免费】
返回列表