OpenAI 结构化输出完全指南:json_schema、strict 模式与常见报错
让模型稳定输出可解析 JSON 的完整路径:Responses API 的 text.format 写法、strict 模式、schema 设计要点,以及只放 schema 不放 name 这类高频报错的排查。
操作步骤
定义 JSON Schema
把想要的输出形状写成 JSON Schema:顶层 type: object,用 properties 定义字段、required 标注必填项,枚举约束用 enum。字段越多,description 越要写清楚。
包进 text.format 并带 name
请求里加 text={"format": {"type": "json_schema", "name": 给配置起名, "strict": true, "schema": 你的 schema}}。name 必填——只放 schema 不放 name 会报错。
用 input 发起请求
Responses API 的消息字段是 input(数组),不是 messages。把系统指令与用户输入都放进 input。
解析 output_text 并做防御性校验
从响应取 output_text 做 json.loads;形状已由 schema 保证,但仍建议保留一层业务语义校验(枚举值是否合法、日期是否在预期范围)。
结构化输出(Structured Outputs)是 OpenAI API 的约束解码能力:开发者在请求里提供 JSON Schema,模型被约束为按该 schema 输出合法 JSON,从而省掉正则抽取与格式修复,直接 json.loads / JSON.parse 进业务代码。本教程以 Responses API 为准讲清完整写法、strict 模式的含义,以及只放 schema 不放 name 这类高频报错的排查。
说明:本文代码按官方 Structured Outputs 指南逐行核对(文档核对版),
lastTestedAt为核对日期;真机运行前建议先在测试环境跑通。
1. 快速上手:最小可用示例
Responses API 的结构化输出挂在 text 参数上,format 里三件套:type、name、schema,加上 strict 开关。
from openai import OpenAI
client = OpenAI()
schema = {
"type": "object",
"properties": {
"steps": {
"type": "array",
"items": {"type": "string"},
"description": "按顺序拆解的解题步骤",
},
"answer": {"type": "string", "description": "最终答案"},
},
"required": ["steps", "answer"],
}
resp = client.responses.create(
model="gpt-5.6-luna",
input=[
{"role": "system", "content": "你是解题助手,严格按 schema 返回。"},
{"role": "user", "content": "一道题:小明有 3 个苹果,又买了 5 个,一共几个?"},
],
text={
"format": {
"type": "json_schema",
"name": "math_response",
"strict": True,
"schema": schema,
}
},
)
data = json.loads(resp.output_text)
print(data["answer"], data["steps"])
三个最容易错的位置:消息字段是 input 不是 messages;schema 包在 text.format 里不是顶层;name 必填。官方指南的示例正是 text={"format": {"type": "json_schema", "name": "math_response", "schema": …}} 这个形状。
2. Node.js 等价写法
import OpenAI from "openai";
const client = new OpenAI();
const schema = {
type: "object",
properties: {
sentiment: { type: "string", enum: ["positive", "neutral", "negative"] },
score: { type: "number" },
},
required: ["sentiment", "score"],
};
const resp = await client.responses.create({
model: "gpt-5.6-luna",
input: [
{ role: "system", content: "对用户评论做情感分类,严格按 schema 返回。" },
{ role: "user", content: "这耳机续航真行,但佩戴一般。" },
],
text: {
format: {
type: "json_schema",
name: "sentiment_response",
strict: true,
schema,
},
},
});
const data = JSON.parse(resp.output_text);
console.log(data.sentiment, data.score);
枚举(enum)是结构化输出里最实用的约束:分类任务直接把标签空间写进 schema,模型就不可能输出标签体系之外的值。
3. strict 模式:保证形状,不保证语义
strict: true 的含义是约束解码——模型的输出严格按 schema 生成,字段存在性与类型都有保证。不写或为 false 时,模型"尽量"遵循 schema,在长文本、复杂嵌套下可能偏移出合法 JSON。
但要分清两层保证:
- 形状保证(strict 给的):字段在、类型对、枚举值在集合内。
- 语义正确(strict 不给的):
answer是对的答案、sentiment符合人类判断——这取决于提示词与模型能力。
所以生产姿势是"双保险":strict 保证 json.loads 永远不炸,业务侧再保留一层语义校验(枚举合法性、数值范围、日期格式),校验失败走重试或降级。
data = json.loads(resp.output_text)
# 形状已由 strict 保证;这层校验的是 strict 不保证的语义
assert data["sentiment"] in {"positive", "neutral", "negative"}
if not 0 <= data["score"] <= 1:
raise ValueError("score 越界,走重试或降级")
4. Schema 设计要点
- 顶层永远是 object:把所有字段挂在顶层
properties下,避免顶层裸 array——解析与校验都更简单。 - required 写全:希望出现的字段全部放进
required;strict 模式下缺失字段的处理不如显式required+ 默认值约定清晰。 - 枚举优先于自由文本:能枚举的状态(
positive/neutral/negative、low/mid/high)都用enum,把模型的自由度限制在标签空间内。 - description 写给模型看:每个字段的
description是模型理解语义约束的第一现场,格式要求(如 "YYYY-MM-DD")直接写在这里。 - 复杂校验放应用侧:正则、跨字段一致性这类高级约束不要指望 schema 表达,拿到输出后在应用层验证。
5. 常见报错与排查
| 现象 | 原因 | 修法 |
|---|---|---|
| 只传 schema 就报错 | format 里缺 name | 补 name 字段,这是必填项 |
报 unknown parameter messages | 用成了 Chat Completions 字段 | Responses API 用 input(数组) |
| 输出偶尔不合法 JSON | 没开 strict: true | 加上 strict 开关,别依赖"尽量遵循" |
| 枚举值跑出集合 | schema 里没用 enum 或 strict 未开 | 字段加 enum 并开 strict |
| 解析后字段值语义不对 | 形状对但语义偏 | 加强 description 与系统提示,应用侧加业务校验 |
| 长嵌套结构输出被截断 | 达到输出 token 上限 | 精简 schema、拆分任务,或提高输出上限 |
其中"只放 schema 不放 name"是最常见的翻车点——报错信息不一定直指 name,容易往 schema 语法上找半天。记住三件套:type、name、schema,外加 strict 开关。
6. 和 function calling 怎么选
两者共用 JSON Schema 这套描述语言,但解决的问题不同:
| 维度 | Function calling | Structured outputs |
|---|---|---|
| 解决什么 | 模型决定调用哪个工具、生成参数 | 约束最终回答的 JSON 形状 |
| 触发方 | 模型发起 function_call,你的代码执行 | 你发起请求,直接拿结果 |
| 典型场景 | 查数据库、调内部 API、执行动作 | 分类、抽取、打标、生成固定格式内容 |
| 返回流 | function_call → 执行 → function_call_output 回传 | 响应里直接是符合 schema 的文本 |
一句话:要让模型"做事"用 function calling,要让模型"按格式交作业"用 structured outputs。两者都走 Responses API 的工具与格式机制,字段声明风格一致,学会一个另一个几乎免费。
7. 常见问题
1. structured outputs 和 function calling 什么关系?
两者共用同一套 schema 机制但用途不同:function calling 让模型决定"调用哪个工具并生成参数",结构化输出约束"最终回答的 JSON 形状"。需要把答案交给下游程序消费时用 structured outputs;需要模型触发你这边的能力时用 function calling。同一请求里可以只用其一。
2. 为什么我只传了 schema 还报错?
Responses API 的 schema 必须包在 text.format 里,且 format 里必须带 name 字段——name 是这次输出配置的标识。只放 {"type": "json_schema", "schema": …} 不放 name 会直接报错。完整写法见本文第一个示例。
3. strict: true 和不写 strict 有什么区别?
strict: true 是约束解码:输出严格按 schema 生成,字段与类型都能保证。不写或为 false 时模型"尽量"按 schema 输出,长内容或复杂嵌套下可能偏移。生产代码里凡是拿输出直接 json.loads 的场景都应该开 strict。
4. schema 里能用正则或自定义格式吗?
支持的是 JSON Schema 的常用子集:object、array、string、number、enum、required 这些核心能力最稳。越冷门的特性兼容性越差,设计 schema 时优先用基础类型加 enum 表达约束,复杂校验放到应用侧做二次验证。
5. 输出合法 JSON 但字段值不对怎么办?
结构化输出保证形状不保证语义。把语义约束写进 schema 的 description 与系统提示里(枚举值给注释、日期给格式示例),并在应用侧保留一层业务校验——形状合法 + 语义校验双保险才是生产可用的姿势。
6. Chat Completions 的 response_format 还能用吗?
老项目的 response_format 写法仍然存在,但 Chat Completions 已进入 legacy 阶段,新项目统一用 Responses API(input 字段 + text.format)。本文所有示例以 Responses API 为准。
下一步
- 需要模型触发动作而不只是交作业?读 《OpenAI API 函数调用实战:Responses API 工具使用完全指南》。
- 刚接触 OpenAI API?读 《OpenAI API 入门:第一个 GPT-5.6 调用详解》。
- 想了解 Responses API 的整体设计?读 《Responses API 高级实战:structured outputs / 流式 SSE / Batch / prompt caching》。
关键要点
- Responses API 用 text={"format": {"type": "json_schema", "name": …, "strict": true, "schema": …}} 传入 schema——schema 包在 format 里,name 必填
- 只放 schema 不放 name 会直接报错——这是最高频的翻车点
- strict: true 表示严格遵循 schema 输出;省略或为 false 时模型'尽量'遵循,不保证合法
- 字段用 input(数组),不是 Chat Completions 的 messages——新项目统一走 Responses API
- function calling 与 structured outputs 是两件事:前者决定'调哪个工具',后者约束'返回什么形状'
- 拿到输出后仍要防御性解析:schema 约束的是形状,不保证业务语义正确
常见问题
官方参考
相关文章
Responses API 高级实战:structured outputs / 流式 SSE / Batch / prompt caching
Responses API 进阶用法:JSON Schema 严格模式、流式 SSE 解析、Batch API 离线降本、prompt caching 三层缓存、成本优化案例。从『能调通』到『生产级』。
阅读全文OpenAI API 错误处理与重试:401/429/5xx 实战模式
OpenAI API 在生产环境最常见的错误码(401/429/500/503/timeout)实战处理:指数退避、jitter 抖动、错误预算、上游保护、与 streaming 的特殊处理。
阅读全文OpenAI API 函数调用实战:Responses API 工具使用完全指南
函数调用(Function Calling)是让 GPT-5.6 调用你代码的核心能力。本文用 Responses API 完整走一遍:声明 tools、解析 function_call、回传结果、串联多轮工具调用。
阅读全文订阅 GPTMap Weekly
每周一封邮件,精选 OpenAI 重要更新、深度解读与最佳实践。无广告,可随时退订。