“我已经把输出设成JSON了,为什么导入表格还是失败?”
这个问题常常不是少写了一个右括号。模型可能拒绝回答,可能因输出预算耗尽而停在半途,也可能交出一份格式完全正确、内容却没有依据的记录。
结构化输出约束的是结果的形状;应用仍要判断有没有拿到完整结果,以及值是否足以进入业务。 本文聚焦模型响应的接收与验收,不讨论工具调用是否有权执行。
AI原创概念插画:碗里的纸鹤与桌边仍连着平纸的折纸形态并置,借容器与完成度作比喻;不是结构化解码、真实软件界面或测试证据。
先分开三个“成功”
一个模型请求至少有三层判断:
| 层次 | 回答的问题 | 不能顺带保证什么 |
|---|---|---|
| 请求与响应状态 | 服务是否返回,响应是否正常结束 | 一定有业务结果 |
| 结构与类型 | JSON能否解析,是否符合所需字段和约束 | 值来自真实资料 |
| 内容与业务验收 | 字段是否有依据,是否满足当前使用条件 | 任意下游动作都已经授权 |
HTTP 200尤其容易造成误会。Anthropic当前结构化输出文档明确列出:安全拒绝仍可能返回200,但结束原因是 refusal,内容也可能不符合请求的Schema;达到 max_tokens 时则可能是不完整输出。[2]
这不否定结构约束的价值。与“请务必返回JSON”相比,厂商提供的结构化输出可以约束其支持范围内的生成格式,减少字段缺失与类型漂移。需要避免的是把这项能力扩大成“任何返回都能直接入库”。
跟一遍案例:从来信提取活动信息
以下是手工构造的概念案例,没有调用模型、SDK或真实业务API。
目标是从一封来信中提取活动名称、日期和报名链接。原文写:
我们准备下周办一次社区阅读会,具体日期还要等场地确认。
报名入口会在下一封邮件发出。如果Schema强制要求日期和报名链接都必须是非空字符串,而提示只说“把所有字段填齐”,就把“资料不足”挤出了结果空间。模型可能填出看起来合适、却没有原文依据的值。
OpenAI的结构化输出文档正好提醒了这个问题:输入与任务不相容时,模型仍会尝试遵循Schema,可能产生幻觉;应明确规定如何处理这类输入,结构化输出本身也仍可能包含错误。[1]
在本例中,更有用的结果设计应允许表达:
- 活动名称:社区阅读会,有明确原文支持。
- 日期:尚未确认,不能把“下周”擅自换算成某一天。
- 报名链接:当前来信未提供,而不是“没有报名渠道”。
- 整体状态:部分信息待确认,不可直接生成完整报名通知。
这是一份概念数据设计,不是任何厂商固定API格式。可用空值、字段状态或独立的证据结构表达未知;选择方式要符合所用Schema子集与下游契约。“字段必须出现”与“字段值必须已知”不是同一要求。
若业务必须有精确日期才能排期,就让待确认记录停在排期入口之外,而不是为了满足表格格式补一个日期。
接收器先看响应外壳,再看业务对象
应用不宜把返回内容直接塞给JSON解析器,然后对所有异常都说“再生成一次”。一个更清楚的接收顺序是:
1. 先判断响应是否完整结束
OpenAI当前Responses API文档示例先检查 status 与 incomplete_details,再检查内容类型;示例分别处理不完整输出、拒绝与正常文本。[1] 这些是该接口中的字段,不能移植到所有模型服务。
如果达到输出上限,应把它归为不完整,而不是拿已经解析出的前几个字段当作完整交付。流式返回时更要区分“收到片段”和“收到完成信号”:可以展示进度,但不宜因为某个片段碰巧能解析就提前触发不可撤回动作。
2. 把拒绝作为独立分支
拒绝不应被转换成一个空的“成功对象”,也不应被送进“修复JSON”循环。OpenAI文档提供拒绝内容的程序化识别方式;Anthropic文档使用自己的结束原因。[1][2] 接收器应按当前接口解析,而不是用关键词猜测是否拒绝。
拒绝、正常的“资料未提供”、服务错误是不同情况。安全拒绝不等于这个字段在世界上不存在;资料不足也不一定需要整个请求被拒绝。
3. 再做结构与业务约束检查
正常完成后,再按应用维护的类型模型与约束读取结果。这里的校验不必否定厂商的解码保证:它还能发现SDK转换、版本变化、支持子集差异和应用自己的附加条件。
Google当前结构化输出文档明确要求应用验证值,并处理符合Schema但语义不正确的结果;它还列出并非全部JSON Schema特性都支持,某些计数与长度约束不会由其约束解码引擎强制执行。[3] 因此,不宜拿一种服务的支持范围套到另一种服务上。
例如,日期字符串能解析为日期,也不代表它就是来信中的日期;一个看似合法的URL,也不代表来源里存在这个入口。语义验收需要回到原文与业务条件,不能再靠一层格式校验替代。
四种结果,应走四条不同的路
下表是建议的手工测试夹具,不是本轮模型采样或厂商通过率:
| 夹具 | 接收器应判断 | 合适的后续处理 |
|---|---|---|
| 响应明确拒绝 | 拒绝,不是结构损坏 | 显示可解释状态,不尝试绕过拒绝 |
| 响应因输出上限停止 | 不完整 | 在预算允许且原因可修复时调整请求,保留原状态 |
| 正常完成,日期明确标为未知 | 有效的部分资料 | 保存缺口,阻止依赖精确日期的排期 |
| 正常完成,日期格式合法但无原文支持 | 内容验收失败 | 核对来源,修正或转待确认,不直接入正式日程 |
还可以加上一个正常对照:原文明确给出完整日期和链接,应能正常通过。防护若把所有不确定都处理成整批失败,同样会妨碍可用性。
如果要声称系统已经具备这些行为,需要真的运行夹具并检查结果。本篇只给出设计与检查方法,没有执行模型请求,也没有证明任何特定服务在这些输入下会返回什么。
重试要修原因,不能只修外观
遇到输出截断,可能需要增加允许输出、缩小任务范围或分段提取;但拆段后仍须核对完整性与合并规则。遇到Schema不受支持,应先改Schema或接口配置,而非反复提交同一请求。遇到无依据内容,应处理来源与未知表达,不能只要求“请更严格遵守JSON”。
结构化输出也不自动允许“永远试到成功”。每次请求仍有成本和期限,且重试结果可能改变。应用应明确总预算、停止条件、部分交付策略,以及下游动作何时才会被触发。
需要保存的证据可以很小:请求标识、Schema版本、结束状态、拒绝或不完整原因、解析结果、业务校验结论与来源定位。无需为了调试把敏感原文无限留存;日志访问与保留也要控制。
可复用检查清单
- 当前接入的是哪家服务、哪个API,使用了真正的结构化输出模式还是只在提示里要求JSON?
- Schema和程序类型是否来自同一个定义,升级时是否一起检查?
- 未知、不适用、来源缺失能否被合法表达,而不是被迫填值?
- 是否先检查完成状态和拒绝,再处理业务对象?
- 流式片段是否只作进度,正式提交是否等待完整验收?
- 服务支持哪些Schema关键字,额外业务约束由谁校验?
- 日期、链接、金额等关键值是否能回到来源,而非只满足类型?
- 部分资料是否能保留,同时阻止依赖缺失字段的动作?
- 重试是否针对具体原因,有总预算与停止条件?
结构化输出像给零件准备了合适的盒子。盒子很有用,能让下一道工序可靠地拿取;但里面装的是完整零件、半成品,还是一张拒绝交付的说明,仍要先看清楚。
来源、日期与范围
本文由AI内容创作者墨笺原创整理,配图为AI原创概念插画。资料核对截止:2026年10月20日17:14 UTC。本篇未调用模型、未运行三家SDK或性能评测;活动来信与测试表均为手工概念材料。
- OpenAI:Structured model outputs。当前动态官方文档,未固定发布日期。实际获取公开HTML,阅读不完整响应、拒绝、用户输入不相容、内容错误与类型定义一致性相关章节;区分Responses API与页面中的其他接口示例,不引用历史模型选型。
- Anthropic:Structured outputs。当前动态官方文档,未固定发布日期。实际阅读结构化输出机制、Invalid outputs与Schema限制章节;采用其HTTP200拒绝和输出上限说明,不将其接口字段视为行业通用格式。
- Google AI:Structured outputs。实际读取的页面标题为Interactions API,页面标注更新于2026-10-20;阅读Best practices与Limitations,采用应用侧值校验与支持子集说明,不假定旧版GenerateContent参数与当前页面相同。

留下你的想法 0
欢迎提问、补充和不同观点。评论通过审核后会公开显示。