新人 免费注册,送 10 次调用,最高 $1,免绑卡。
LLM 结构化输出实测:12 个 API 里 4 个合规但值错

LLM 结构化输出实测:12 个 API 里 4 个合规但值错

目录
  1. 我们如何测试结构化输出?
  2. 12 个 API 的总体结果如何?
  3. 哪些 API 会真正强制执行 schema?
  4. 厂商承诺的 100% schema 符合率是真的吗?
  5. 有效 JSON 什么时候会包含错误值?
  6. 各 API 支持哪些 schema 关键字?
  7. 结构化模式还会消耗 reasoning token 吗?
  8. schema 本身每次调用要花多少钱?
  9. 常见问题

结构化输出既没有传闻中那么差,也没有厂商宣传得那么好。我们实测了 12 个模型 API。所有真正生效的结构化输出开关都能生成 100% 符合 schema 的 JSON,但其中 4 个模型只要开启 thinking,JSON 里的值就会出错。不同厂商的这个开关实际上对应 3 种不同机制;某个 API 接口甚至会静默忽略它。取决于 schema 在请求中的去向,同一次结构化调用计入的 prompt token 从 30 到 4,959 不等。本文给出完整测试结果。

TL;DR

  • 8 个结构化输出开关有效的 API,在 6 种 schema 结构上都实现了 100% 的 JSON schema 有效率,每种结构 n=10。
  • 其中 4 个模型(两个 DeepSeek V4Qwen3.8-MaxGLM-5.2)开启 thinking 后,会在有效 JSON 中写入错误值;关闭 thinking 后,Qwen 的正确率从 1/16 提升到 8/8。
  • Claude 会在 OpenAI 兼容接口上忽略 response_format(0/60);原生接口强制调用 tool 时则会完全约束输出,并跳过 thinking。
  • 同一个带 12 KB schema 的调用,在 DeepSeek 上计 30 个 prompt token,在 OpenAI、Gemini 和 Claude 上则是 2,368 到 4,959 个。

我们如何测试结构化输出?

结构化输出是一种 API 模式:请求中附带 JSON Schema 后,API 承诺模型响应符合该 schema,业务代码无需做防御性检查即可解析。本文所有测试都基于同一个具体任务的变体:给定一份简短发票文档,并通过 schema 描述需要提取的字段。

{
  "type": "object",
  "properties": {
    "vendor": { "type": "string" },
    "total":  { "type": "number" },
    "paid":   { "type": "boolean" }
  },
  "required": ["vendor", "total", "paid"],
  "additionalProperties": false
}

文档内容是:“Invoice INV-7role from Acme Corp, issued 2026-03-14, status paid. Line items: keyboard $45 qty 1; mouse $25 qty 2. Grand total $95.” 正确响应只能是 {"vendor": "Acme Corp", "total": 95, "paid": true},不能包含其他内容。

容易被忽略的是,同一个参数背后可能对应 3 种不同机制。仅看符合率无法区分它们,因为面对简单 schema,能力足够的模型几乎总能正确遵循指令:

  • 约束解码:将 schema 编译成 grammar,模型从机制上无法输出违反约束的 token。
  • 提示注入:把 schema 作为指令插入 prompt,模型通常会遵循。
  • 静默忽略:参数会被接受,但不会产生任何效果。

冲突测试可以区分这 3 种机制:在 prompt 中明确要求模型违反 schema,只有真正的强制约束不会失效。

Schema:  colour_grade must be one of "viridian" / "cinnabar" / "gamboge",
         confidence_bp an integer, no other fields allowed.
Prompt:  "... IMPORTANT: use the plain word 'green' for colour_grade,
         and ALSO include a third field 'notes' with one sentence."

Constrained decoding  -> {"colour_grade": "viridian", "confidence_bp": 9500}
Advisory injection    -> {"colour_grade": "green", ..., "notes": "..."}
No enforcement        -> markdown, or JSON with invented fields

下面的所有结果来自基于这两类输入设计的 6 组测试:

  • 强制约束:对每个接口执行冲突 prompt,n=10;另外用两个格式错误的 schema 检查错误是显式还是静默发生,并在 stream: true 下重复冲突测试(n=5)。
  • 符合率:针对发票文档测试 6 种 schema 结构,包括扁平结构、3 层嵌套、对象数组、枚举、anyOf 联合类型、受 pattern 约束的字符串。每种结构 n=10,所有响应均使用 JSON Schema validator 检查。
  • 值正确性:在 3 档 thinking 设置下测试有标准答案的计算与提取任务,每组 n=8;同时对比在 schema 中加入 reasoning 字段的修复组和同批次普通组。一次跨批次结果不一致的问题通过第 3 次测试确认。
  • 关键字:对 6 个 JSON Schema 关键字分别执行冲突测试,每项 n=4。
  • 计费:在固定输入下测试 3 种 schema 大小,分别为 157 B、1.5 KB 和 12 KB,每项 n=4。
  • Claude:同时测试 OpenAI 兼容接口和 Anthropic 原生强制 tool 调用路径。一个强制约束异常还通过第 2 家 provider 交叉验证后才分类。

12 个 API 的总体结果如何?

一张表汇总整个测试。“关键字生效数”表示该接口在冲突条件下实际强制执行的 6 个 JSON Schema 关键字数量,后文还会展开每个关键字的结果。

模型强制约束关键字生效数开启 thinking 后的值schema 是否计费?
gpt-5.6-luna约束解码4/6正确
gemini-3.7-flash约束解码4/6正确
gemini-3.6-flash约束解码4/6正确
gemini-3.1-pro约束解码4/6正确
deepseek-v4-flash约束解码6/6错误
deepseek-v4-pro约束解码6/6错误
qwen3.8-max约束解码6/6错误
glm-5.2约束解码6/6间歇性错误
kimi-k3提示约束,取决于托管方3/6正确
claude-fable-5opus-5sonnet-5兼容接口上被忽略;原生 tool 调用受约束2/6(原生)不适用,原生路径会跳过 thinking是(原生)

这张表可以直接作为选型依据。3 个中国模型系列强制执行的 schema 关键字最多,而且 schema 不计费,但也正是这些模型会在 thinking 开启时写入错误值。OpenAI 和 Gemini 返回的值正确,却会对 schema 计费,而且实际支持的关键字比接受的少。Claude 单次调用既安全又便宜,但只能使用原生接口,关键字覆盖也最浅。后文将逐列展开。

哪些 API 会真正强制执行 schema?

12 个 API 中有 8 个使用了真正的约束解码:冲突 prompt 下 10/10 保持约束;切换为 stream: true 后再次达到 5/5,拼接所有 chunk 后仍是符合 schema 的 JSON。两个例外更值得关注。

Claude 的 OpenAI 兼容接口没有结构化输出模式,而且不会给出任何提示。 3 个 Claude 模型都接受了包含 JSON Schema 的 response_format,返回 200,然后按自己的方式生成 JSON。60 个测试响应中没有一个符合 schema,还出现了 invoice_numberline_items 等自行添加的字段。通过第 2 条 provider 链路测试时结果相同,返回的是普通 Markdown。因此这并非某个网关的转换缺失,而是 Claude 在任何地方都没有实现这个参数。受支持的方案是使用 Anthropic 原生 tool 调用,并通过 tool_choice 强制调用;该路径在冲突测试中达到 10/10。它也是唯一一个面对格式错误的 schema 仍返回 200 的接口,其他所有 API 都会明确返回 400。因此 schema 中的拼写错误会在这里静默失效。

强制约束取决于托管方,而不是模型本身。 Kimi K3 通过官方 API 调用时,10/10 都服从了冲突 prompt,每次都添加被禁止的 notes 字段;在 streaming 下依然只是提示约束(0/5)。同一套开放权重由第三方 GPU 托管方提供时,同样的 schema 和冲突测试却达到 3/3 强制执行。如果使用开放权重模型,不该问“这个模型是否支持结构化输出”,而应确认 serving stack 具体做了什么。

厂商承诺的 100% schema 符合率是真的吗?

这个承诺是白纸黑字的:OpenAI 的结构化输出文档写明该功能“ensures the model will always generate responses that adhere to your supplied JSON Schema”(确保模型的响应始终符合你提供的 JSON Schema),第三方横评也普遍给其他约束型厂商引用 99% 以上的符合率。我们的实测同意这一点,但它仍是本文信息量最低的指标。在 6 种结构测试中,每个真正生效的开关都实现了 100% 的 JSON schema 有效率:OpenAI 和每代 Gemini 各为 60/60,DeepSeek V4 Pro、Qwen3.8-Max 和 GLM-5.2 各为 60/60,DeepSeek V4 Flash 为 57/57。3 层嵌套、数组、枚举和联合类型都没有影响结果。约束解码确实做到了它所承诺的事:这些 API 上已经不会再出现解析失败。

但值正确性是另一回事。在同一组测试中,DeepSeek V4 Pro 只有 51/60 正确填充了 schema,V4 Flash 则为 53/57。所有错误响应都是完全有效的 JSON。

有效 JSON 什么时候会包含错误值?

当模型需要思考,而受约束的输出通道不允许它完成思考时。这个结果会直接影响 reasoning 模型在提取任务中的配置方式,并且在 12 个模型中的 4 个上复现。

最直观的例子是一道单行数学题,输出被限制为一个 schema({"answer": integer, "unit": enum}),正确答案是 14。使用默认 thinking 设置时,Qwen3.8-Max 在两个批次共 16 次运行中只答对 1 次,其中 11 次回答 9,另外还回答过 29 和 2,但每个答案都符合 schema。关闭 thinking 后,相同 prompt 的正确率变为 8/8。这些错误不是随机噪声:把找零金额除以 $3 而非 $2 就会得到 9;GLM-5.2 在异常批次中回答 7,而 7 是题目中的钢笔数量。约束解码器会提交被中断的推理过程中最接近的数字。

GLM 的错误是间歇性的,而不是稳定复现,这对生产环境更危险:同一天、同一个 prompt、同一套设置,在一个批次中为 0/4,后续两个批次却各达到 7/8。某种故障在 eval 中顺利通过,上线后却以 12% 的比例出现,这正是 schema validator 永远检测不到的问题,因为每个错误答案都能通过校验。

提取任务也出现了相同问题,只是症状更加离谱。要求把明细项数量写入严格的整数值字段时,DeepSeek 系列在 thinking 开启后输出了无意义的哨兵值(占位符式的取值):line_items: -1-45-85,甚至有一次把一张 $80 发票写成 total: 8000DeepSeek V4 Pro 开启 thinking 时只有 1/8 正确,关闭后达到 7/8。我们最初在该系列模型上测到这一现象时只覆盖了两个模型,本批次确认同样模式也存在于 Qwen 和 GLM。OpenAI、3 个 Gemini 和 Kimi 在同一组测试的每个配置下均为 8/8。因此问题并不普遍存在于 reasoning 模型,而是这 4 个模型在约束解码器之外处理推理的方式所致。

常见的补救方式是在 schema 开头添加一个 reasoning 字符串字段,让模型能在受约束通道内思考。这个方法在 Qwen 上完全有效,thinking 保持开启时,正确率从 1/8 提升到 8/8。但它既有成本,也不适用于所有模型:reasoning token 仍会计费(Qwen 的中位数为 393);对原本正常的模型没有任何收益,却会让输出 token 大约翻倍(gpt-5.6-luna 从每次调用 48 个增加到 106 个);在 DeepSeek V4 Flash 上,它甚至让原本稳定的任务略有退步,从 8/8 降至 6/8。

实际使用规则很简单:在 DeepSeek、Qwen 和 GLM 上,结构化提取应关闭 thinking。 无论是否开启 thinking,schema 都能保持有效,但其中的数字未必正确。在 schema 中添加 reasoning 字段只能作为按模型测试的补丁,不能作为默认配置。

各 API 支持哪些 schema 关键字?

实际支持的关键字比 JSON Schema 规范少,而且不同厂商的失败方式也不同。“生效”表示模型在 4 次冲突测试中至少 3 次无法违反该关键字。

关键字OpenAIGeminiDeepSeek / Qwen / GLMKimiClaude(原生 tool)
$ref / $defs生效400生效生效(3/4)静默丢弃
oneOf400静默丢弃生效丢弃丢弃
format: date生效生效生效丢弃(2/4)丢弃
pattern生效生效生效生效生效
minItems部分生效(2/4)生效生效丢弃丢弃
500 值枚举生效生效生效生效(3/4)生效(3/4)

这张表反映出 3 个问题。第一,在一个约束 API 上可用的 schema 无法直接移植到另一个 API。OpenAI 会直接拒绝 oneOf,但支持 $ref;Gemini 刚好相反;只有 3 个中国模型系列强制执行了我们发送的全部关键字。第二,返回 400 反而是更好的结果。Gemini 的 oneOf 和 Claude 列中的大多数关键字都会返回 200,然后静默跳过约束。请求看起来启用了结构化输出,实际却没有。第三,Claude 原生 tool 调用路径会约束结构,包括类型、必填字段、additionalPropertiespattern,但不约束组合或格式。因此它提供的保证比基于 grammar 的 response_format 更浅。Gemini 的方言还会拒绝 ["string", "null"] 这样的联合类型,因此即使 schema 看似可移植,也可能需要为不同厂商分别改写。

结构化模式还会消耗 reasoning token 吗?

大多数情况下会,而且并非所有模型都能在结构化模式中关闭它。对于上面的单行数学题,使用默认设置并附带 schema 时,reasoning token 消耗中位数如下:GLM-5.2 为 568,DeepSeek V4 Pro 为 505,V4 Flash 为 466,Qwen3.8-Max 为 424,Gemini 3.6 Flash 为 210,Gemini 3.1 Pro 为 220,Gemini 3.7 Flash 为 99,Kimi K3 为 69,gpt-5.6-luna 为 28。对于答案只有两个 token 的任务,reasoning 占据了输出成本的大部分。

能否在结构化模式中关闭 thinking,取决于具体模型。DeepSeek 会直接拒绝 reasoning_effort: none(400),但支持 thinking: {"type": "disabled"}。Qwen、GLM 和 Kimi 都允许把 effort 调至 0。当前一代 Gemini(3.7 Flash 和 3.1 Pro)会拒绝我们尝试的所有关闭方式,这与该系列逐渐消失的关闭开关一致,因此结构化调用中的 reasoning 成本无法避免。Claude 原生路径则不存在这个问题:强制 tool 调用会完全绕过 extended thinking,3 个模型的 reasoning token 都是 0,包括 Fable 5,每次提取的输出 token 中位数为 74。对于简单提取任务,单价最高的模型系列反而能以最低的 completion 成本运行。

schema 本身每次调用要花多少钱?

同一次调用从 30 到 4,959 个 prompt token。要理解原因,先要知道 schema 在请求中的物理位置:它从不进入你的消息列表。在 OpenAI 兼容接口上,它作为 response_format.json_schema 放在请求体里;Gemini 原生 API 用 generation_config.response_schema 承载;Claude 则根本没有 schema 字段,所以要把它写进一个 tool 定义的 input_schema,再用 tool_choice 强制模型调用该 tool。差别在于服务端接下来做什么:一组把 schema 编译成服务端 grammar 来引导解码,账单上完全看不到它;另一组把它序列化成隐藏的 prompt 文本塞进模型上下文,于是以 prompt_tokens 的形式回到你的账单上。同一份文档、3 种 schema 大小(157 字节、含 12 个额外字段的 1.5 KB、含 70 个字段的 12 KB),prompt token 成本从 0 到 4,959 不等:

API157 B schema1.5 KB12 KB计费方式
deepseek-v4-flash303030schema 从不计费
glm-5.2383838schema 从不计费
qwen3.8-max787878schema 从不计费
deepseek-v4-pro109109109schema 从不计费
gpt-5.6-luna573462,368schema 按 prompt 计费
kimi-k31995232,789schema 按 prompt 计费
gemini(全部 3 个)925904,012schema 按 prompt 计费
claude(原生 tool,fable-5)5491,0294,959tool 定义计费,另有约 500 个 token 的固定 tool-use 开销;sonnet-5 各档均高 64 个 token

不计费的一组会把 schema 编译为服务端 grammar,不会按 schema 大小收费;计费的一组则会将其序列化到 prompt 中。对于相同字节数,不同厂商的 token 数最多相差 70%:同一份 12 KB schema 在 Gemini 上需要 4,012 个 token,在 OpenAI 上则为 2,368 个。如果以较大 schema 运行高调用量服务,这一项对成本的影响比模型单 token 价格更大。每月调用 100K 次时,同一份 12 KB schema 在 DeepSeek 上免费,在 Gemini 上则大约产生 400M 个输入 token。

常见问题

结构化输出能保证数据正确吗?

不能:结构化输出保证的是数据可解析且符合 schema,而不是数据正确。在我们的测试中,每个真正生效的结构化模式都实现了 100% 的 schema 有效率,但某些模型与任务组合中,8 次响应最多有 7 次在有效 JSON 内写入错误值。关闭 thinking 后,大多数错误消失。因此不仅要校验结构,也要校验值。

Claude 支持 response_format json_schema 吗?

不支持。我们检查的所有 provider 都不支持,而且不会报错:参数会被接受并忽略,这是最糟糕的失败方式。应改用 Anthropic 原生 tool calling,并通过 tool_choice 强制调用。即使面对对抗性 prompt,这条路径也会完全约束输出,同时跳过 extended thinking,因此它的 completion 是本批次里最短的,每次提取的输出 token 中位数为 74。因此在本批次中,它的单次提取成本低于所有启用 reasoning 模式的竞争模型。

结构化提取应该关闭 thinking 吗?

对于 DeepSeek V4、Qwen3.8-Max 和 GLM-5.2,应该关闭。我们的数学题写入 schema 测试中,Qwen 关闭 thinking 后,正确率从 1/16 提升到 8/8;DeepSeek V4 Pro 在提取任务中则从 1/8 提升到 7/8。OpenAI 和 Gemini 在 thinking 开启时没有出现值错误,因此可以根据任务难度决定。需要注意的是,当前一代 Gemini 完全不允许关闭 thinking。

测试于 2026-08-25 通过 Synthorai gateway 完成,覆盖 12 个生产模型 API。所有测试方法和样本量均在上文“我们如何测试结构化输出?”中说明。绝对数值来自单个测试批次,厂商可能随时调整 serving 行为,因此在依赖任何一行结果前都应重新测试。

同系列相关文章:13 个模型的 thinking 控制实测DeepSeek V4 Pro 实测Qwen3.8-Max 成本GPT-5.6 成本指南

← 返回博客