登录
推荐 文章 Go 技术 课程 下载 专题 AI
首页 >  科技周边 >  人工智能

OpenAI Responses API 怎样用结构化输出约束 JSON 形状

来源:17golang原创

时间:2026-10-24 20:14:06 168浏览 收藏

我第一次把一个已有的 JSON 抽取调用迁到 Responses API 时,最容易混淆的不是 Schema 本身,而是约束参数的位置:旧的 Chat Completions 写在 response_format,Responses API 则写在 text.format。如果还把旧的 json_schema 外壳原样搬过来,请求就会在参数层面走偏。

官方地址:https://developers.openai.com/api/docs/guides/structured-outputs

在 Responses API 中,使用 text.format.type = "json_schema",把名称、Schema 和 strict: true 放到同一层;严格对象通常还要写全 required 和 additionalProperties: false。这样约束的是输出形状,不是业务字段的真实性。

从旧请求迁移时,先改参数层级

OpenAI 官方把 Structured Outputs 和旧 JSON mode 区分开:两者都能产生合法 JSON,但只有 Structured Outputs 会按提供的 Schema 约束形状。Responses API 的结构化文本输出使用 text.format,因此迁移时应做一次字段对照。

Chat Completions response_format 迁移到 Responses API text.format 的字段关系说明图
图1:参数迁移说明图,展示旧 response_format 与 Responses API text.format 的对应边界。
旧写法Responses API 写法迁移注意
response_formattextResponses API 把输出配置放进 text
json_schema.nametext.format.name名称必须是可用的短标识
json_schema.schematext.format.schemaSchema 内容本身可以继续复用
json_schema.stricttext.format.strict严格模式只支持 JSON Schema 的一部分能力

这里的“复用 Schema”指复用 properties、required 等设计,不是把包含 name、schema、strict 的旧包装对象整体嵌套到 text.format 里。

严格 Schema 要把可选性写成数据类型

严格模式下,我会先把输出对象画成一张小表:字段名、类型、是否允许为空、允许的枚举值。对象字段写进 required,同时关闭额外属性;业务上“可能没有值”的字段仍然可以是必填字段,但类型声明为包含 null 的联合类型。

const ticketSchema = {
  type: "object",
  properties: {
    category: {
      type: "string",
      enum: ["billing", "technical", "other"]
    },
    priority: {
      type: "string",
      enum: ["low", "normal", "high"]
    },
    summary: { type: "string" },
    customer_id: {
      // 没有客户编号时返回 null,但字段仍然必须出现
      type: ["string", "null"]
    }
  },
  // 严格对象把所有可返回字段明确列出,避免模型临时添加键
  required: ["category", "priority", "summary", "customer_id"],
  additionalProperties: false
};

这个 Schema 解决的是“返回哪些键、每个键是什么类型”。它不能保证 summary 的内容真实,也不能替业务系统完成权限、金额或状态校验;这些仍要在应用层处理。

把 Schema 放进 Responses API 的 text.format

下面是 Node.js SDK 风格的最小调用。示例只展示请求结构,密钥从环境变量读取;response.output_text 是供应用继续处理的文本结果,拿到后仍要根据响应状态和拒答信息决定是否解析。

import OpenAI from "openai";

const client = new OpenAI({ apiKey: process.env.OPENAI_API_KEY });

const response = await client.responses.create({
  model: "gpt-4o-mini",
  input: [
    {
      role: "system",
      content: "把工单归类并返回结构化结果。"
    },
    {
      role: "user",
      content: "用户说:发票下载失败,但订单已经完成。"
    }
  ],
  text: {
    format: {
      type: "json_schema",
      name: "support_ticket",
      strict: true,
      schema: ticketSchema
    }
  }
});

// 正常完成后才把结构化文本交给业务层解析
const ticket = JSON.parse(response.output_text);
console.log(ticket.category, ticket.priority);

如果项目采用的 SDK 版本支持更高层的解析辅助,也可以使用对应 SDK 的类型化入口;但迁移的核心仍然是请求体中的 text.format 形状。模型是否支持 Structured Outputs、Schema 子集是否被接受,也应作为部署前的兼容性检查项。

拒答和不完整响应不能直接 JSON.parse

结构化输出并不意味着每一次响应都必然是业务对象。官方文档特别说明,模型拒答时可能返回不符合给定 Schema 的 refusal;响应状态也可能是 incomplete。因此,生产代码应把“请求成功”“模型愿意回答”“输出完整”“文本可解析”拆成几层判断。

Schema 约束、拒答、不完整响应与业务解析边界的静态关系图
图2:响应边界结构图,说明 Schema 约束并不替代拒答、不完整状态和业务校验处理。
function parseStructuredResponse(response) {
  // 不完整响应先返回可诊断状态,不把残缺文本当作 JSON
  if (response.status !== "completed") {
    return { ok: false, reason: `response-${response.status}` };
  }

  // 拒答属于模型决策分支,不应强行按业务 Schema 解析
  const refusal = response.output
    ?.flatMap((item) => item.content ?? [])
    .find((part) => part.type === "refusal");
  if (refusal) {
    return { ok: false, reason: "refusal", message: refusal.refusal };
  }

  try {
    // JSON 语法正确仍需由应用层检查枚举、权限和业务含义
    return { ok: true, value: JSON.parse(response.output_text) };
  } catch (error) {
    return { ok: false, reason: "invalid-json", error };
  }
}

上面的代码只负责分流,不代表 Schema 已经覆盖所有业务规则。比如 category 是允许的枚举值,不等于工单真的属于该分类;落库前仍应做白名单、长度、权限和状态机检查。

我会用这张清单做迁移回归

  1. 把旧请求中的 response_format 改为 Responses API 的 text.format,不要保留多余的 json_schema 包装层。
  2. 确认 type 是 json_schema,并给格式定义设置稳定名称;需要严格形状时显式使用 strict: true。
  3. 逐个检查对象的 required 和 additionalProperties: false;业务可选值用 null 表达。
  4. 把拒答、不完整、空输出、JSON 解析失败分别记录,不把它们统一归类为“字段缺失”。
  5. 对旧模型、当前目标模型和实际 SDK 版本做一次兼容性确认,尤其关注 Strict Schema 支持子集。
  6. 最后再做业务校验:枚举白名单、字符串长度、身份权限、金额或状态转换不能交给 JSON Schema 单独承担。

对我来说,结构化输出最有价值的地方不是让模型“看起来像 JSON”,而是把接口边界前移到请求定义里。迁移时只要先改参数层级,再收紧 Schema,最后补齐失败分支,通常比在下游不断修补字符串解析更稳。

相关问题

Responses API 的 JSON mode 和 Structured Outputs 有什么区别?

JSON mode 主要保证结果是合法 JSON;Structured Outputs 还会按提供的 JSON Schema 约束形状。能使用 Schema 时,优先选择 json_schema。

严格模式下怎样表示可选字段?

可以让字段出现在 required 中,同时把类型写成例如 ["string", "null"],用 null 表示没有值。

Schema 严格通过后还要做业务校验吗?

要。Schema 约束类型和形状,不能替代权限、真实性、数值范围和业务状态检查。

参考地址:https://developers.openai.com/api/docs/guides/structured-outputs

声明:本文转载于:17golang原创 如有侵犯,请联系study_golang@163.com删除
相关阅读
更多>
最新阅读
更多>
课程推荐
更多>