← 返回技术博客

OpenAI Structured Outputs 完整指南:如何让 GPT 稳定输出符合 JSON Schema 的 JSON 数据?

OpenAI Structured Outputs 完整指南:如何让 GPT 稳定输出符合 JSON Schema 的 JSON 数据?

本文面向需要把 GPT 结果接入数据库、队列、API 或 Agent 执行器的后端开发者与数据工程师,按数据抽取、分类路由、工具参数、界面数据和生产流水线拆解 Structured Outputs 的正确用法。文章同时覆盖拒绝、截断、Schema 版本化、业务校验与回归测试,帮助团队避免把“结构合法”误判成“业务正确”。

OpenAI Structured Outputs 的正确用法是:在需要稳定结构时启用 json_schemastrict: true,而不是只依赖提示词或普通 JSON mode;同时处理 Schema 支持范围、refusal、截断和业务语义验证。 这样可以约束 JSON 的结构,但不能保证日期、金额、身份关系或分类内容一定真实。

这篇 OpenAI Structured Outputs 指南适合三类读者:

  • 后端开发者:需要把 GPT API 返回值稳定解析并写入数据库。
  • 数据工程师:需要把模型结果接入队列、批处理或数据管道。
  • Agent 工程师:需要同时约束最终响应格式和工具调用参数。

先确定 Structured Outputs 解决的边界

普通提示词只能“要求模型输出 JSON”,无法从协议层阻止模型遗漏字段、增加未知字段或改变字段类型。JSON mode 的目标主要是生成可解析的 JSON,它并不保证结果符合指定的 JSON Schema;OpenAI 官方也建议,在需要匹配特定 Schema 时优先使用 Structured Outputs。(help.openai.com)

OpenAI 对 Structured Outputs 的实现包含 Schema 约束和受限解码。官方公告中的复杂 Schema 评测显示,特定模型配置在该测试中达到 100% 的 Schema 匹配率,但这不是所有模型、所有任务或字段语义都达到 100% 正确 的承诺。(openai.com)

因此,生产系统需要把结果拆成三层:

  1. 格式层:是否是完整 JSON,是否符合 Schema。
  2. 内容层:字段值是否来自输入,是否存在幻觉或误抽取。
  3. 业务层:权限、数据库状态、金额范围和关联关系是否允许继续执行。

只处理第一层,仍然可能把格式正确但业务错误的数据写入正式系统。

数据抽取先设计可演进的 Schema

数据抽取是最适合使用 Structured Outputs 的场景之一,例如把合同、会议纪要或工单转成数据库记录。Schema 不应追求一次覆盖所有可能字段,而应先定义下游真正需要的最小对象。

一个最小抽取结构可以是:

{
  "type": "object",
  "properties": {
    "items": {
      "type": "array",
      "items": {
        "type": "object",
        "properties": {
          "name": { "type": "string" },
          "due_date": { "type": "string" },
          "owner": { "type": "string" }
        },
        "required": ["name", "due_date", "owner"],
        "additionalProperties": false
      }
    }
  },
  "required": ["items"],
  "additionalProperties": false
}

这里有三个关键决定:

  • 根对象明确声明 type: object,避免把数组、字符串误当成完整结果。
  • 数组元素再次定义对象结构,避免每一项出现不同字段。
  • requiredadditionalProperties: false 同时使用,使缺字段和多余字段更容易在接口层暴露。

仅在提示词中写“请返回 namedue_dateowner”时,模型仍可能输出说明文字、额外字段或不同命名。启用严格 Schema 后,结构约束会更明确,但日期是否真的在原文中出现,仍需要应用层核对原始文本。

OpenAI 如何保证输出符合 JSON Schema?

更准确的说法是:在支持的模型和请求配置下,strict: true 会让生成结果遵循所提供 Schema 的结构;前提是 Schema 使用了 Structured Outputs 支持的 JSON Schema 子集。Schema 不支持或不符合严格模式要求时,请求可能直接返回错误,而不是自动替开发者修改设计。(help.openai.com)

如果 Schema 变更频繁,建议在数据中保存 schema_version,并为每个版本保留输入样本、原始响应和解析结果。这样字段升级后,历史数据仍可以按旧版本回放。

分类路由使用枚举,但必须保留未知状态

分类任务经常被误写成一个自由文本字段:

{ "category": "请根据内容自行判断" }

这种设计会产生“技术支持”“技术问题”“需要支持”等语义相近但无法稳定路由的结果。更适合下游分支判断的做法,是使用有限枚举:

{
  "type": "object",
  "properties": {
    "category": {
      "type": "string",
      "enum": ["billing", "technical", "account", "unknown"]
    },
    "needs_human_review": {
      "type": "boolean"
    }
  },
  "required": ["category", "needs_human_review"],
  "additionalProperties": false
}

unknown 不是失败字段,而是生产系统必须保留的安全出口。当输入信息不足、类别重叠或模型无法判断时,系统应把记录送入人工复核,而不是通过提示词逼迫 GPT API 选择一个看似合理的类别。

Structured Outputs 和 JSON mode 有什么区别?

JSON mode 更像“输出必须是可解析 JSON”的约束;Structured Outputs 则进一步要求输出匹配指定 Schema。前者适合结构尚未固定的实验性场景,后者更适合数据库写入、固定 API 请求和自动路由。即使使用 Structured Outputs,分类标签的定义仍应足够清晰,并对 unknown 或人工复核路径做显式设计。(help.openai.com)

工具参数要严格,执行权限不能交给模型

Agent 工具调用需要区分两件事:

  • 工具参数是否符合参数 Schema;
  • 应用是否允许执行这次工具调用。

例如,模型可以生成符合 Schema 的退款参数,但这不代表订单存在,也不代表当前用户有退款权限。严格参数只能减少参数格式错误,不能代替权限系统、资源锁、库存检查或事务控制。

工具定义通常应包含:

{
  "type": "function",
  "function": {
    "name": "create_ticket",
    "description": "创建客户服务工单",
    "strict": true,
    "parameters": {
      "type": "object",
      "properties": {
        "customer_id": { "type": "string" },
        "priority": {
          "type": "string",
          "enum": ["low", "normal", "high"]
        },
        "summary": { "type": "string" }
      },
      "required": ["customer_id", "priority", "summary"],
      "additionalProperties": false
    }
  }
}

OpenAI 的 Function Calling 帮助文档明确说明,严格模式要求 Schema 使用受支持的子集,并满足严格模式条件;应用仍需自行验证工具执行条件。(help.openai.com)

在执行器中,至少应按以下顺序处理:

  1. 解析工具名称和参数。
  2. 再次使用本地 Schema 验证库校验参数。
  3. 查询用户身份、资源状态和权限。
  4. 对金额、删除、发送消息等高风险动作增加确认或人工审批。
  5. 执行事务并记录工具调用、参数、结果和错误。

此外,Structured Outputs 与并行工具调用存在兼容限制。若工具执行器无法安全处理多个同时调用,应按照官方文档关闭并行工具调用,而不是假设每次只会出现一个动作。(openai.com)

界面数据和下游 API 必须增加语义校验

字段类型正确,不代表字段内容可用。以下情况都可能通过基础 Schema 验证,却在业务上失败:

  • due_date 是合法日期字符串,但早于合同签署日期。
  • amount 是数字,但币种与订单币种不一致。
  • customer_id 格式正确,但数据库中不存在。
  • start_dateend_date 都合法,却出现结束日期早于开始日期。
  • status 属于枚举,但当前状态不允许直接跳转到目标状态。

因此,建议把验证分成两次。第一次验证 JSON 结构,第二次执行业务规则和数据库约束;只有两次都通过,才允许进入正式写入或自动执行流程。

JSON Schema 验证通过后还要做业务校验吗?

需要。JSON Schema 主要验证类型、字段、枚举和嵌套结构,无法自动知道业务系统中的权限、资源存在性、时间先后关系或金额归属。生产服务应把 Schema 验证视为“进入业务校验的门槛”,而不是最终验收结果。

对于界面生成和下游 API,字段描述也不能省略。描述应明确日期格式、单位、是否允许空值,以及“无法从输入确认时应返回什么状态”。描述越含糊,结构可能越稳定,但内容越容易漂移。

拒绝、截断和解析失败分别处理

Structured Outputs 遇到 refusal 怎么处理?

不要把 refusal 当成普通 JSON 解析错误,也不要对所有拒绝请求无限重试。OpenAI 官方说明,模型仍可能因安全原因拒绝请求,此时响应会提供拒绝信息,而不是符合业务 Schema 的对象。(openai.com)

建议将结果分成以下几类:

  • refusal:记录拒绝原因,按安全或人工处理流程结束。
  • 正常结束但本地解析失败:检查 SDK、响应路径和 Schema 版本。
  • 因长度限制提前结束:保留原始响应,判断是否需要扩大输出预算或拆分任务。
  • API 错误:记录请求标识、模型、参数和重试次数。
  • 业务校验失败:进入人工复核或补充信息流程。

官方公告指出,生成在达到 max_tokens 或其他停止条件前被截断时,结果可能无法完成 Schema。(openai.com) 这类情况不应简单地把半截 JSON 拼接后入库,也不宜不加区分地自动重试,否则可能造成重复写入或重复调用外部工具。

每次处理至少保存以下信息:

  • 原始响应;
  • finish_reason 或对应结束状态;
  • refusal 状态;
  • Schema 名称与版本;
  • 模型和 SDK 版本;
  • 本地解析错误与业务校验错误。

新 Schema 第一次请求还可能出现额外延迟,因为服务需要预处理 Schema;官方说明典型 Schema 的首次处理通常低于 10 秒,复杂 Schema 可能达到 1 分钟,后续请求可复用处理结果。(openai.com) 因此,批处理任务应尽量复用稳定 Schema,避免每条数据动态生成一份结构不同的定义。

用回归样例保护生产数据管道

Structured Outputs 的上线验收不应只拿一条“正常输入”测试。建议建立四类固定样例:

  1. 正常样例:字段齐全、表达清楚、无需人工判断。
  2. 边界样例:缺日期、多个负责人、空数组、超长文本或歧义分类。
  3. 恶意样例:输入中包含要求改变格式、泄露提示词或绕过业务规则的内容。
  4. 升级样例:旧 Schema 生成的数据能否被新服务读取,新增字段是否影响旧消费者。

可把每次请求的结果分成“结构通过”“业务通过”“人工复核”“拒绝”“截断”几个状态,而不是只统计 API 成功率。这样才能区分是 Schema 设计问题、模型拒答问题、输出长度问题,还是下游数据库约束过严。

如果团队需要持续批处理、运行本地验证脚本或接入苹果开发流水线,可以参考 nuvcloud 的帮助文档 先确认远程运行、权限和文件传输方式;需要长期运行的任务,则应进一步比较 Mac 方案与按月使用成本,不要只按单次 API 调用费用判断总成本。

上线前按这份清单验收

  • [ ] 已使用 json_schema 或工具定义中的 strict: true,没有只依赖提示词。
  • [ ] Schema 明确声明对象、数组元素、requiredadditionalProperties
  • [ ] 分类字段包含 unknown、人工复核或其他合法兜底状态。
  • [ ] 已确认当前模型和 SDK 支持所使用的 Schema 子集。
  • [ ] 本地代码会区分正常内容、refusal、截断和 API 错误。
  • [ ] Schema 验证后仍会执行权限、资源状态、日期、金额和关联字段校验。
  • [ ] 工具执行前存在二次校验、幂等控制和高风险动作审批。
  • [ ] 已保存原始响应、结束状态、Schema 版本和错误类型。
  • [ ] 已准备正常、边界、恶意和升级回归样例。
  • [ ] Schema 变更已经版本化,并通知所有下游消费者。

生产方案如何选择

不同用途不应套用同一套输出配置。最终回答需要可读性时,响应 Schema 可以保留面向界面的字段;工具参数则应尽量短小、枚举清晰,并由执行器承担权限和状态判断。

使用场景 推荐配置 必须补充的校验 主要失败处理
数据抽取写入数据库 json_schema + strict: true 字段来源、关联记录、数据库约束 业务失败进入复核
分类与队列路由 枚举 + unknown 分类置信规则、队列权限 未知状态不自动分流
Agent 工具参数 工具 Schema + strict: true 权限、资源状态、幂等和审批 拒绝执行,不盲目重试
界面或下游 API 响应 Schema 日期、金额、标识符和跨字段关系 语义错误回退人工
批量生产管道 固定版本 Schema 回归样例、日志和版本兼容 按错误类型重试或暂停

如果当前方案只是提示词加 JSON mode,真实缺点通常是:字段结构无法稳定演进、解析失败与业务失败混在一起、截断后容易误入库,并且工具参数格式正确时仍可能绕过应用层的权限判断。对于需要持续批处理或长期运行验证脚本的团队,租赁 nuvcloud 的 Mac 环境可以减少本地机器占用、临时配置和开发流水线迁移成本;但若任务是长期满负载运行、必须连接特定物理设备,或需要完全控制硬件,直接自购 Mac 可能更合适。需要临时算力或测试环境时,可先通过 nuvcloud 控制中心 验证实际运行流程,再决定采用临时还是常驻方案。

为结构化输出搭建稳定的远程 Mac 环境

使用 nuvcloud 独享裸金属 Mac,快速搭建 JSON Schema 调试、接口联调与生产流水线验证环境。

支持 SSH 与 VNC 双入口,既能运行自动化脚本和测试任务,也能按需接入完整远程桌面。

延伸阅读

限时优惠 →