JSON mode 与结构化输出:哪些中转站真的支持,怎么测

教程 发布于 2026-10-01 35 次阅读 API指南针
声明支持 JSON mode 的站很多,真正能稳定返回合法 JSON 的不多。本文给出一套分辨率极高的测试方法。

两种不同等级的能力

「结构化输出」实际包含两个差别很大的能力等级,很多站把它们混为一谈:

等级一:JSON mode(response_format: {"type": "json_object"})

只保证返回的是一段合法 JSON,不保证字段符合你的要求。

  • 你必须自己在 system prompt 里把字段结构描述清楚;
  • 模型可能多给字段、少给字段、改变类型(该是数字的给了字符串);
  • 但至少 json.loads() 不会失败。

等级二:JSON Schema(response_format: {"type":"json_schema","json_schema":{...}})

保证返回的 JSON 严格符合你给的 schema:字段齐全、类型正确、枚举值受限。

  • 这是真正意义上的「结构化输出」;
  • 实现难度比等级一高一个量级,因为它需要在上游做约束解码。

关键判断:一家站声称支持 JSON mode,不代表支持 json_schema。对你的项目来说,需要哪一个取决于你是否能容忍字段缺失。

三类常见失效表现

一、参数被静默忽略

最常见的失效。你传了 response_format,网关没报错,但也没生效 —— 模型自由输出,包含解释性文字和 markdown 代码块包裹。

症状:返回值以「好的,以下是 JSON:」开头,或者被 ``` `json `` 包住,json.loads()` 失败。

二、只在部分模型上生效

网关把 response_format 透传给上游,而上游不一定支持。表现是:同一个网关,模型 A 正常、模型 B 无效。

这本身不一定是网关的错 —— 但如果它不做兼容处理(比如对不支持的模型明确报错),就会变成静默失效。

三、schema 被降级

声明支持 json_schema,实际内部降级成 json_object。表现是:JSON 合法,但字段时有缺失或类型漂移。

这一类最难判断,因为结果「看起来对」。

一套分辨率极高的测试

测试 1:参数是否生效

curl -s https://<base_url>/v1/chat/completions \
  -H "Authorization: Bearer $KEY" -H "Content-Type: application/json" \
  -d '{
    "model": "<model>",
    "response_format": {"type": "json_object"},
    "messages": [{"role": "user",
      "content": "用一句话介绍北京。以 JSON 返回。"}]
  }'

判据:choices[0].message.content 是否是一个可以直接解析的 JSON(不含 ``` 包裹、不含前后解释文字)。

测试 2:schema 是否严格生效

给一个带必填 + 枚举 + 类型约束的 schema:

{
  "type": "json_schema",
  "json_schema": {
    "name": "city_info",
    "strict": true,
    "schema": {
      "type": "object",
      "properties": {
        "city":     {"type": "string"},
        "population": {"type": "integer"},
        "tier":     {"type": "string", "enum": ["一线", "二线", "三线"]}
      },
      "required": ["city", "population", "tier"],
      "additionalProperties": false
    }
  }
}

判据(三条都要过):

  1. 三个字段全部存在;
  2. population 是数字而不是字符串 "21540000";
  3. tier 的值在枚举范围内。

任一不过 → 不支持严格 schema,最多只做到等级一。

测试 3:抗干扰测试(最能分辨真伪)

上面两个测试,很多站能通过一次性抽查。加上干扰才看得出真实水平:

在 prompt 里主动诱导模型破坏格式:

「请以 JSON 返回。另外,在 JSON 之前先用一段中文说明你的推理过程,并在结尾加一句总结。」

判据:

  • 真正支持约束解码的实现:仍然只返回纯 JSON(约束优先级高于用户指令);
  • 只做 prompt 包装的实现:会顺从用户指令,输出变成「说明 + JSON + 总结」。

这一条是三个测试里最有分辨力的,因为它区分的是「约束解码」和「在 system prompt 里偷偷加了一句『请返回 JSON』」。

测试 4:稳定性重复

同一个请求跑 20 次,统计失败率。

  • 失败率 0% → 可用;
  • 失败率 5%–20% → 只能当「大概率可用」,代码里必须加重试与兜底解析。

单次成功没有意义 —— 结构化输出的价值在于「不需要兜底」,如果需要兜底,那它就不能作为架构依赖。

为什么这项对工程影响特别大

如果你的代码里有这样的写法:

data = json.loads(resp.choices[0].message.content)

那么一旦模型输出被 markdown 包裹,整个流程直接抛异常。生产环境里的表现是「偶发任务失败」——最难排查的一类问题。

三种可选的处理方式,按可靠性排序:

  1. 要求严格的 json_schema(最优,但依赖服务端实现);
  2. 加重试 + 健壮解析(提取第一个 { 到最后一个 } 之间的内容再解析,失败则重试);
  3. 改用函数调用(如果只是要抽取结构化数据,工具调用的参数序列化通常比 JSON mode 更稳,因为它是协议层能力而不是提示层要求)。

第 3 条是一个常被忽略的实用技巧:同样的需求,用「让模型调用一个参数就是你要的数据的工具」来实现,往往比 JSON mode 更可靠。

小结

对结构化输出的评估,按这个顺序走:

  1. 先问清你要的是等级一还是等级二;
  2. 跑测试 1、2 确认基本能力;
  3. 跑测试 3 分辨真伪(这一步不能省);
  4. 跑测试 4 看稳定性,决定代码里要不要写兜底。

本站的选型文章里反复出现同一个原则,这里同样适用:能自己测的,不要靠标称值。

这篇文章对你有帮助吗?如果你在实际使用中发现了文中没提到的情况,欢迎 提交纠错或补充,我们会核验后更新到正文里。

相关文章

视频生成接口进中转:三种形态、四个计量陷阱,以及一份验收清单

2026-10-19

MCP 经中转站:哪些能通、哪些一定不通,以及怎么在十分钟内测出来

2026-10-19

中转站选型决策树:从你的场景倒推到站点

2026-10-07

日志与对账:把 token 消耗算到项目维度

2026-10-06

灰度切换供应商:不中断业务地换掉一家 API 站

2026-10-06

自建探针:二十行脚本监控你的 API 供应商

2026-10-06

顺着看下去:本站收录的部分中转站

本文没有指向特定模型系列,下面是本站收录站点中综合评分靠前的几家,供你顺着看下去。排序依据是评分与可用率,不构成推荐。

完整清单见 中转站导航,或按 模型系列 浏览。