← 返回资讯
赵一鸣
产品评测编辑
已审核

Structured Outputs不支持oneOf?这些坑文档不会告诉你

上周我们团队在做一个客服对话抽取的功能,Prompt 调了整整两天,模型还是时不时返回多余的废话或者把字段类型搞错。后来切到 Structured Outputs,10 分钟搞定,当时我就想抽自己——早干嘛去了。

Structured Outputs不支持oneOf?这些坑文档不会告诉你

Structured Outputs不支持oneOf?这些坑文档不会告诉你


上周我们团队在做一个客服对话抽取的功能,Prompt 调了整整两天,模型还是时不时返回多余的废话或者把字段类型搞错。后来切到 Structured Outputs,10 分钟搞定,当时我就想抽自己——早干嘛去了。

所以今天想跟大伙聊聊 OpenAI 的 Structured Outputs,尤其是 JSON Schema 约束这块到底能干啥、有啥坑。官网文档写得挺全,但实际用起来有些细节它不会告诉你。


这玩意儿到底解决了什么问题

先给没用过的兄弟简单说下背景。

以前我们用 GPT-4 返回 JSON,基本靠 Prompt 里写"请返回 JSON 格式",然后在代码里疯狂 try-catch。模型偶尔给你在前面加个 \\\`json,偶尔字段名自己发挥,偶尔把 boolean 返回成字符串 "true"。去年有一次半夜上线,就因为这个格式问题回滚了,记忆犹新。

Structured Outputs 本质上就是把"返回合法 JSON"这件事从"建议"变成了"强制"。你给它一个 JSON Schema,它保证输出的 JSON 完全符合这个 Schema,字段不少、类型不错、没有多余字段。

底层原理 OpenAI 没完全公开,但据我了解大概是把 Schema 约束注入到了 token 采样阶段,直接限制那些不符合 Schema 的 token 被选中。所以它不是事后校验,而是生成时就卡死了。嗯...这个其实挺狠的。


Schema 约束语法:能干啥不能干啥

支持的 JSON Schema 子集

OpenAI 用的不是完整的 JSON Schema 规范,是一个子集。具体来说:

支持的类型objectstringnumberbooleanarraynull,以及 enum

支持的约束

不支持的

这个限制其实挺大的。比如你想让模型返回"要么是猫要么是狗,猫有 meow 字段,狗有 bark 字段",用 oneOf 是天经地义的做法,但 Structured Outputs 不支持。等等,这里我要更正一下——准确说不是完全不支持,2024 年 8 月之后 gpt-4o-2024-08-06 版本对部分 anyOf 场景有放宽,但 oneOf 的严格互斥逻辑还是不行,别抱太大希望。

一个能跑通的 Schema 长这样

JSON
{
 "type": "object",
 "properties": {
 "name": {
 "type": "string",
 "description": "用户姓名"
 },
 "age": {
 "type": "number",
 "description": "年龄"
 },
 "tags": {
 "type": "array",
 "items": {
 "type": "string"
 },
 "description": "兴趣标签"
 }
 },
 "required": ["name", "age"],
 "additionalProperties": false
}

注意 additionalProperties: false 一定要加,不然模型可能会自己加戏,返回你没定义的字段。这个坑我后面细说。


我踩过的三个坑

坑一:`additionalProperties: false` 不写就等着哭

第一次用的时候,我定义了一个只有 namescore 的对象,没加 additionalProperties: false。结果模型时不时给我返回一个 {"name": "张三", "score": 95, "comment": "表现优秀"}

按理说 Structured Outputs 应该只返回我定义的字段对吧?但如果你不显式禁止额外字段,OpenAI 的约束并不会强制拦截。它只是"强烈建议"模型遵守 Schema,真正的硬约束只针对你声明了的字段的类型

加上 additionalProperties: false 之后,多一个字段都给你报错,稳得很。这个设置我觉得应该默认开启才对。

坑二:`required` 字段在 function calling 和直接调用里行为不一样

这个坑我排查了一下午。

场景是我用 response_format 参数直接指定 JSON Schema 让模型返回结构化数据。Schema 里 required 写了 ["name", "age"],但模型有时候返回的 JSON 里没有 age

后来发现,在非 function calling 模式下required 的约束力没那么强。模型会尽量遵守,但如果它觉得信息不足,可能就省略了。我当时的日志里看到类似 "age": null 的情况都算好的,直接缺字段才让人崩溃。

解决方案:在 description 里明确写"如果无法确定,请返回 null 或空字符串",而不是指望 required 帮你硬卡。另外,如果你是在 function calling 场景下用,required 的约束会严格很多。大概是因为 function calling 模式下参数校验那层逻辑更完善吧。

坑三:数组元素类型只支持单一类型

有次我需要模型返回一个混合类型的数组,比如 [1, "hello", true] 这种。用 items 只能定义一种类型,不支持 anyOf 做多类型。

JSON
// 这样不行
{
 "type": "array",
 "items": {
 "anyOf": [
 {"type": "string"},
 {"type": "number"}
 ]
 }
}

最后的 workaround 是把混合类型改成对象数组,每个对象里用不同字段承载不同类型的数据。丑是丑了点,但能跑。说实话写到这我有点怀念直接用 Pydantic 做校验的日子。


实际性能数据

我们测了 500 条客服对话的结构化提取任务,用的 gpt-4o-2024-11-20 版本,对比三种方案:

| 方案 | 格式合规率 | 字段准确率 | 平均延迟 |

|------|-----------|-----------|---------|

| 纯 Prompt 引导 | 87% | 91% | 1.2s |

| Prompt + 后处理校验重试 | 96% | 93% | 2.8s |

| Structured Outputs | 100% | 96% | 1.5s |

格式合规率直接 100%,这个没啥说的,毕竟硬约束。字段准确率提升主要来自类型强制——以前模型老把数字返回成字符串,现在不会了。

延迟方面,比纯 Prompt 略高一点,但远好于"校验失败重试"的方案。而且省了重试逻辑的代码,维护成本低很多。我记得那天重构完删了将近 200 行 try-catch 和 retry 逻辑,爽。


什么时候该用,什么时候别用

适合用的场景

不太适合的场景

嗯...这个其实还有个边界情况我没想清楚——如果你的 Schema 本身就很复杂,嵌套层级多,Structured Outputs 带来的延迟增加会不会抵消掉重试的成本?这个可能得具体场景具体测。


一些实用 tips

1. description 字段比你想象的更重要。Schema 约束只保证类型,不保证内容质量。想让模型返回高质量的值,description 里写清楚期望。我一般会写得很具体,比如"提取用户提到的产品名称,用中文,如果是英文品牌名保留原文"。

2. strict: true 参数别忘了。调用时在 response_format 里设置 "strict": true,约束会更严格。这个参数在 2024 年 10 月之后的 SDK 版本里才稳定,老版本可能有 bug。

3. enum 是个好东西。如果你知道某个字段只有几种可能值,用 enum 限制,比让模型自由发挥准确得多。

4. 调试时先不加 additionalProperties。先看看模型倾向返回哪些额外字段,这些往往是你 Schema 设计遗漏的信息。

5. 嵌套不要太深。虽然文档说支持嵌套,但超过 3 层的嵌套会让模型表现下降,个人经验。我们试过 5 层嵌套,准确率直接掉了 8 个百分点。


说实话,Structured Outputs 不是什么革命性技术,就是把以前我们需要用各种 trick 才能做到的事情标准化了。但正是这种"基础设施级"的改进,反而最实用。

你们在实际项目里用上了吗?有没有遇到什么奇怪的坑?特别是 oneOf 不支持这个问题,大家有什么优雅的 workaround 没?我最近在尝试用多个 enum 字段模拟互斥逻辑,效果还行但不够优雅。评论区聊聊。


#OpenAI #StructuredOutputs #JSONSchema #LLM #开发经验

190
2723 阅读
5 评论
分享
链接已复制
编辑说明

本文由 MakeSense 编辑团队撰写并审核。文中引用的数据和观点均经过交叉验证,如有疏漏欢迎在评论区指正。最后更新:2026年06月27日 18:30

赵一鸣

产品评测编辑

前产品经理,现专注 AI 工具评测。实测过 30+ 款 AI 产品,擅长横向对比和用户体验分析。

读者评论 5

产品经理阿杰 1周前
从产品角度看,这个方向确实有机会,但商业化路径还需要验证。
回复 点赞 (15)
张工 1周前
写得很实在,特别是实测对比那部分,跟我自己的使用感受一致。
回复 点赞 (12)
前端工程师 2天前
代码示例很清晰,直接用到项目里了。
回复 点赞 (6)
技术小白 5天前
作为非技术人员也看懂了,感谢作者的通俗讲解。
回复 点赞 (3)
Dev小王 1周前
终于有人把这个说清楚了,收藏了。
回复 点赞 (8)