结构化输出指南
结构化输出是一种功能,可确保模型始终生成符合您提供的 JSON Schema 的响应,因此您无需担心模型遗漏必需键或生成无效的枚举值。JSON 是全球应用程序之间交换数据的常用格式之一。
结构化输出的优势
- 可靠的类型安全性:无需验证或重试格式错误的响应。
- 明确的拒绝:基于安全性的模型拒绝现在可以程序化检测。
- 更简单的提示:无需使用强硬的提示词来实现一致的格式。
除了在 REST API 中支持 JSON Schema 外,Python 和 JavaScript 的 OpenAI SDK 还支持使用 Pydantic 和 Zod 轻松定义对象模式。以下是如何从非结构化文本中提取符合代码定义模式的结构化信息的示例。
获取结构化响应
JavaScript 示例
import OpenAI from "openai";
import { zodTextFormat } from "openai/helpers/zod";
import { z } from "zod";
const openai = new OpenAI();
const CalendarEvent = z.object({
name: z.string(),
date: z.string(),
participants: z.array(z.string()),
});
```javascript
const response = await openai.responses.parse({
model: "gpt-4o-2024-08-06",
messages: [
{ role: "system", content: "提取事件信息。" },
{
role: "user",
content: "Alice 和 Bob 将在周五参加一个科学博览会。",
},
],
text: {
format: zodTextFormat(CalendarEvent, "event"),
},
});
const event = response.output_parsed;
### Python 示例
```python
from openai import OpenAI
from pydantic import BaseModel
client = OpenAI()
class CalendarEvent(BaseModel):
name: str
date: str
participants: list[str]
response = client.responses.parse(
model="gpt-4o-2024-08-06",
input=[
{"role": "system", "content": "提取事件信息。"},
{
"role": "user",
"content": "Alice 和 Bob 将在周五参加一个科学博览会。",
},
],
text_format=CalendarEvent,
)
event = response.output_parsed
支持的模型
结构化输出适用于我们的最新大型语言模型,从 GPT-4o 开始。旧模型如 gpt-4-turbo 及更早版本可以使用 JSON 模式。
通过函数调用与 text.format 使用结构化输出的场景
结构化输出在 OpenAI API 中有两种形式:
使用函数调用时。 使用 json_schema 响应格式时。
函数调用适用于构建连接模型与应用程序功能的系统。例如,您可以让模型访问查询数据库的函数,以构建一个可以帮助用户处理订单的 AI 助手,或与用户界面交互的函数。 通过 response_format 的结构化输出更适合在模型直接响用用户时指定结构化模式。例如,如果您正在构建一个数学辅导应用程序,您可能希望助手的响应遵循特定的 JSON Schema,以便生成以不同方式显示模型输出的用户界面。 简单来说:
如果您需要将模型连接到工具、函数或数据,请使用函数调用。 如果您希望结构化模型对用户的响应,请使用结构化的 text.format。
本指南的其余部分将重点介绍在 Responses API 中非函数调用的用例。要了解更多关于如何在函数调用中使用结构化输出的信息,请查看函数调用指南。
结构化输出与 JSON 模式
结构化输出是 JSON 模式 的进化版本。两者都确保生成有效的 JSON,但只有结构化输出能确保模式一致性。结构化输出和 JSON 模式在 Responses API、Chat Completions API、Assistants API、Fine-tuning API 和 Batch API 中均受支持。
我们建议尽可能使用结构化输出。但 response_format: {type: "json_schema", ...} 的结构化输出仅在 gpt-4o-mini、gpt-4o-mini-2024-07-18 和 gpt-4o-2024-08-06 模型快照及更高版本中受支持。
| 特性 | 结构化输出 | JSON 模式 |
|---|---|---|
| 输出有效 JSON | 是 | 是 |
| 遵循模式 | 是(见支持的模式) | 否 |
| 兼容模型 | gpt-4o-mini, gpt-4o-2024-08-06 及更高版本 | gpt-3.5-turbo, gpt-4-* 和 gpt-4o-* 模型 |
| 启用方式 | text: { format: { type: "json_schema", "strict": true, "schema": ... } } | text: { format: { type: "json_object" } } |
示例
逐步推理(Chain of Thought)
您可以要求模型以结构化的、逐步的方式输出答案,以引导用户完成解决方案。
数学辅导的结构化输出
import OpenAI from "openai";
import { zodTextFormat } from "openai/helpers/zod";
import { z } from "zod";
const openai = new OpenAI();
const Step = z.object({
explanation: z.string(),
output: z.string(),
});
const MathReasoning = z.object({
steps: z.array(Step),
final_answer: z.string(),
});
const response = await openai.responses.parse({
model: "gpt-4o-2024-08-06",
messages: [
{
role: "system",
content: "您是一位有用的数学辅导老师,逐步引导用户解决问题。",
},
{ role: "user", content: "如何解决 8x + 7 = -23?" },
],
text: {
format: zodTextFormat(MathReasoning, "math_reasoning"),
},
});
const math_reasoning = response.output_parsed;
from openai import OpenAI
from pydantic import BaseModel
client = OpenAI()
class Step(BaseModel):
explanation: str
output: str
class MathReasoning(BaseModel):
steps: list[Step]
final_answer: str
response = client.responses.parse(
model="gpt-4o-2024-08-06",
input=[
{
"role": "system",
"content": "您是一位有用的数学辅导老师,逐步引导用户解决问题。",
},
{"role": "user", "content": "如何解决 8x + 7 = -23?"},
],
text_format=MathReasoning,
)
math_reasoning = response.output_parsed
curl https://api.openai.com/v1/responses \
-H "Authorization: Bearer $OPENAI_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "gpt-4o-2024-08-06",
"messages": [
{
"role": "system",
"content": "您是一位有用的数学辅导老师,逐步引导用户解决问题。"
},
{
"role": "user",
"content": "如何解决 8x + 7 = -23?"
}
],
"text": {
"format": {
"type": "json_schema",
"name": "math_reasoning",
"schema": {
"type": "object",
"properties": {
"steps": {
"type": "array",
"items": {
"type": "object",
"properties": {
"explanation": { "type": "string" },
"output": { "type": "string" }
},
"required": ["explanation", "output"],
"additionalProperties": false
}
},
"final_answer": { "type": "string" }
},
"required": ["steps", "final_answer"],
"additionalProperties": false
},
"strict": true
}
}
}'
示例响应
{
"steps": [
{
"explanation": "从方程 8x + 7 = -23 开始。",
"output": "8x + 7 = -23"
},
{
"explanation": "两边减去 7 以隔离含变量的项。",
"output": "8x = -23 - 7"
},
{
"explanation": "简化等式右边。",
"output": "8x = -30"
},
{
"explanation": "两边除以 8 以求解 x。",
"output": "x = -30 / 8"
},
{
"explanation": "简化分数。",
"output": "x = -15 / 4"
}
],
"final_answer": "x = -15 / 4"
}
### 结构化数据提取
您可以定义结构化字段以从非结构化输入数据(如研究论文)中提取信息。
#### 从研究论文中提取数据的结构化输出
```javascript
import OpenAI from "openai";
import { zodTextFormat } from "openai/helpers/zod";
import { z } from "zod";
const openai = new OpenAI();
const ResearchPaperExtraction = z.object({
title: z.string(),
authors: z.array(z.string()),
abstract: z.string(),
keywords: z.array(z.string()),
});
const response = await openai.responses.parse({
model: "gpt-4o-2024-08-06",
messages: [
{
role: "system",
content: "您是一位结构化数据提取专家。您将收到研究论文的非结构化文本,并应将其转换为给定结构。",
},
{ role: "user", content: "..." },
],
text: {
format: zodTextFormat(ResearchPaperExtraction, "research_paper_extraction"),
},
});
const research_paper = response.output_parsed;
from openai import OpenAI
from pydantic import BaseModel
client = OpenAI()
class ResearchPaperExtraction(BaseModel):
title: str
authors: list[str]
abstract: str
keywords: list[str]
response = client.responses.parse(
model="gpt-4o-2024-08-06",
input=[
{
"role": "system",
"content": "您是一位结构化数据提取专家。您将收到研究论文的非结构化文本,并应将其转换为给定结构。",
},
{"role": "user", "content": "..."},
],
text_format=ResearchPaperExtraction,
)
research_paper = response.output_parsed
curl https://api.openai.com/v1/responses \
-H "Authorization: Bearer $OPENAI_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "gpt-4o-2024-08-06",
"messages": [
{
"role": "system",
"content": "您是一位结构化数据提取专家。您将收到研究论文的非结构化文本,并应将其转换为给定结构。"
},
{
"role": "user",
"content": "..."
}
],
"text": {
"format": {
"type": "json_schema",
"name": "research_paper_extraction",
"schema": {
"type": "object",
"properties": {
"title": { "type": "string" },
"authors": {
"type": "array",
"items": { "type": "string" }
},
"abstract": { "type": "string" },
"keywords": {
"type": "array",
"items": { "type": "string" }
}
},
"required": ["title", "authors", "abstract", "keywords"],
"additionalProperties": false
},
"strict": true
}
}
}'
示例响应
{
"title": "量子算法在星际导航中的应用:新前沿",
"authors": [
"Stella Voyager 博士",
"Nova Star 博士",
"Lyra Hunter 博士"
],
"abstract": "本文研究了利用量子算法改进星际导航系统的方法。通过利用量子叠加和纠缠,我们提出的导航系统可以比经典方法更有效地计算时空异常中的最佳旅行路径。实验模拟表明,星际任务的旅行时间和燃料消耗显著减少。",
"keywords": [
"量子算法",
"星际导航",
"时空异常",
"量子叠加",
"量子纠缠",
"太空旅行"
]
}
UI 生成
您可以通过将 HTML 表示为具有约束(如枚举)的递归数据结构来生成有效的 HTML。
使用结构化输出生成 HTML
import OpenAI from "openai";
import { zodTextFormat } from "openai/helpers/zod";
import { z } from "zod";
const openai = new OpenAI();
const UI = z.lazy(() =>
z.object({
type: z.enum(["div", "button", "header", "section", "field", "form"]),
label: z.string(),
children: z.array(UI),
attributes: z.array(
z.object({
name: z.string(),
value: z.string(),
})
),
})
);
const response = await openai.responses.parse({
model: "gpt-4o-2024-08-06",
messages: [
{
role: "system",
content: "您是一位 UI 生成 AI,将用户输入转换为 UI。",
},
{
role: "user",
content: "创建一个用户资料表单",
},
],
text: {
format: zodTextFormat(UI, "ui"),
},
});
const ui = response.output_parsed;
from enum import Enum
from typing import List
from openai import OpenAI
from pydantic import BaseModel
client = OpenAI()
class UIType(str, Enum):
div = "div"
button = "button"
header = "header"
section = "section"
field = "field"
form = "form"
class Attribute(BaseModel):
name: str
value: str
class UI(BaseModel):
type: UIType
label: str
children: List["UI"]
attributes: List[Attribute]
UI.model_rebuild() # 必需以支持递归类型
class Response(BaseModel):
ui: UI
response = client.responses.parse(
model="gpt-4o-2024-08-06",
input=[
{
"role": "system",
"content": "您是一位 UI 生成 AI,将用户输入转换为 UI。",
},
{"role": "user", "content": "创建一个用户资料表单"},
],
text_format=Response,
)
ui = response.output_parsed
curl https://api.openai.com/v1/responses \
-H "Authorization: Bearer $OPENAI_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "gpt-4o-2024-08-06",
"messages": [
{
"role": "system",
"content": "您是一位 UI 生成 AI,将用户输入转换为 UI。"
},
{
"role": "user",
"content": "创建一个用户资料表单"
}
],
"text": {
"format": {
"type": "json_schema",
"name": "ui",
"description": "动态生成的 UI",
"schema": {
"type": "object",
"properties": {
"type": {
"type": "string",
"description": "UI 组件的类型",
"enum": ["div", "button", "header", "section", "field", "form"]
},
"label": {
"type": "string",
"description": "UI 组件的标签,用于按钮或表单字段"
},
"children": {
"type": "array",
"description": "嵌套的 UI 组件",
"items": {"$ref": "#"}
},
"attributes": {
"type": "array",
"description": "UI 组件的任意属性,适用于任何元素",
"items": {
"type": "object",
"properties": {
"name": {
"type": "string",
"description": "属性的名称,例如 onClick 或 className"
},
"value": {
"type": "string",
"description": "属性的值"
}
},
"required": ["name", "value"],
"additionalProperties": false
}
}
},
"required": ["type", "label", "children", "attributes"],
"additionalProperties": false
},
"strict": true
}
}
}'
示例响应
{
"type": "form",
"label": "用户资料表单",
"children": [
{
"type": "div",
"label": "",
"children": [
{
"type": "field",
"label": "名字",
"children": [],
"attributes": [
{
"name": "type",
"value": "text"
},
{
"name": "name",
"value": "firstName"
},
{
"name": "placeholder",
"value": "请输入您的名字"
}
]
},
{
"type": "field",
"label": "姓氏",
"children": [],
"attributes": [
{
"name": "type",
"value": "text"
},
{
"name": "name",
"value": "lastName"
},
{
"name": "placeholder",
"value": "请输入您的姓氏"
}
]
}
],
"attributes": []
},
{
"type": "button",
"label": "提交",
"children": [],
"attributes": [
{
"name": "type",
"value": "submit"
}
]
}
],
"attributes": [
{
"name": "method",
"value": "post"
},
{
"name": "action",
"value": "/submit-profile"
}
]
}
内容审核
您可以对输入进行多类别分类,这是内容审核的常见方式。
使用结构化输出进行内容审核
import OpenAI from "openai";
import { zodTextFormat } from "openai/helpers/zod";
import { z } from "zod";
const openai = new OpenAI();
const ContentCompliance = z.object({
is_violating: z.boolean(),
category: z.enum(["violence", "sexual", "self_harm"]).nullable(),
explanation_if_violating: z.string().nullable(),
});
const response = await openai.responses.parse({
model: "gpt-4o-2024-08-06",
messages: [
{
"role": "system",
"content": "判断用户输入是否违反特定准则,并解释原因(如果违反)。"
},
{
"role": "user",
"content": "如何准备工作面试?"
}
],
text: {
format: zodTextFormat(ContentCompliance, "content_compliance"),
},
});
const compliance = response.output_parsed;
from enum import Enum
from typing import Optional
from openai import OpenAI
from pydantic import BaseModel
client = OpenAI()
class Category(str, Enum):
violence = "violence"
sexual = "sexual"
self_harm = "self_harm"
class ContentCompliance(BaseModel):
is_violating: bool
category: Optional[Category]
explanation_if_violating: Optional[str]
response = client.responses.parse(
model="gpt-4o-2024-08-06",
input=[
{
"role": "system",
"content": "判断用户输入是否违反特定准则,并解释原因(如果违反)。",
},
{"role": "user", "content": "如何准备工作面试?"},
],
text_format=ContentCompliance,
)
compliance = response.output_parsed
curl https://api.openai.com/v1/responses \
-H "Authorization: Bearer $OPENAI_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "gpt-4o-2024-08-06",
"messages": [
{
"role": "system",
"content": "判断用户输入是否违反特定准则,并解释原因(如果违反)。"
},
{
"role": "user",
"content": "如何准备工作面试?"
}
],
"text": {
"format": {
"type": "json_schema",
"name": "content_compliance",
"description": "判断内容是否违反特定审核规则",
"schema": {
"type": "object",
"properties": {
"is_violating": {
"type": "boolean",
"description": "指示内容是否违反准则"
},
"category": {
"type": ["string", "null"],
"description": "如果内容违反准则,则为违规类型;否则为 null。",
"enum": ["violence", "sexual", "self_harm"]
},
"explanation_if_violating": {
"type": ["string", "null"],
"description": "内容违反原因的解释"
}
},
"required": ["is_violating", "category", "explanation_if_violating"],
"additionalProperties": false
},
"strict": true
}
}
}'
示例响应
{
"is_violating": false,
"category": null,
"explanation_if_violating": null
}
如何使用 text.format 的结构化输出
步骤 1:定义您的模式 首先,您需要设计模型应遵循的 JSON Schema。请参阅本指南顶部的示例以供参考。 虽然结构化输出支持大部分 JSON Schema,但出于性能或技术原因,某些功能不可用。详情请见支持的模式。 JSON Schema 的建议 为了最大化模型生成的质量,我们建议:
清晰且直观地命名键。 为重要键创建清晰的标题和描述。 创建并使用评估来确定最适合您用例的结构。
步骤 2:在 API 调用中提供您的模式
要使用结构化输出,只需指定:
text: { format: { type: "json_schema", "strict": true, "schema": … } }
示例
response = client.responses.create(
model="gpt-4o-2024-08-06",
input=[
{"role": "system", "content": "您是一位有用的数学辅导老师,逐步引导用户解决问题。"},
{"role": "user", "content": "如何解决 8x + 7 = -23?"}
],
text={
"format": {
"type": "json_schema",
"name": "math_response",
"schema": {
"type": "object",
"properties": {
"steps": {
"type": "array",
"items": {
"type": "object",
"properties": {
"explanation": {"type": "string"},
"output": {"type": "string"}
},
"required": ["explanation", "output"],
"additionalProperties": false
}
},
"final_answer": {"type": "string"}
},
"required": ["steps", "final_answer"],
"additionalProperties": false
},
"strict": true
}
}
)
print(response.output_text)
const response = await openai.responses.create({
model: "gpt-4o-2024-08-06",
messages: [
{ role: "system", content: "您是一位有用的数学辅导老师,逐步引导用户解决问题。" },
{ role: "user", content: "如何解决 8x + 7 = -23?" }
],
text: {
format: {
type: "json_schema",
name: "math_response",
schema: {
type: "object",
properties: {
steps: {
type: "array",
items: {
type: "object",
properties: {
explanation: { type: "string" },
output: { type: "string" }
},
required: ["explanation", "output"],
additionalProperties: false
}
},
final_answer: { type: "string" }
},
required: ["steps", "final_answer"],
additionalProperties: false
},
strict: true
}
}
});
console.log(response.output_text);
curl https://api.openai.com/v1/responses \
-H "Authorization: Bearer $OPENAI_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "gpt-4o-2024-08-06",
"messages": [
{
"role": "system",
"content": "您是一位有用的数学辅导老师,逐步引导用户解决问题。"
},
{
"role": "user",
"content": "如何解决 8x + 7 = -23?"
}
],
"text": {
"format": {
"type": "json_schema",
"name": "math_response",
"schema": {
"type": "object",
"properties": {
"steps": {
"type": "array",
"items": {
"type": "object",
"properties": {
"explanation": { "type": "string" },
"output": { "type": "string" }
},
"required": ["explanation", "output"],
"additionalProperties": false
}
},
"final_answer": { "type": "string" }
},
"required": ["steps", "final_answer"],
"additionalProperties": false
},
"strict": true
}
}
}'
注意:首次使用任何模式进行请求时,由于 API 处理模式,会有额外的延迟,但使用相同模式的后续请求不会产生额外延迟。
步骤 3:处理边缘情况
在某些情况下,模型可能无法生成符合提供的 JSON Schema 的有效响应。这可能发生在模型因安全原因拒绝回答,或达到最大 token 限制导致响应不完整时。
try {
const response = await openai.responses.create({
model: "gpt-4o-2024-08-06",
messages: [
{
role: "system",
content: "您是一位有用的数学辅导老师,逐步引导用户解决问题。",
},
{
role: "user",
content: "如何解决 8x + 7 = -23?"
},
],
max_output_tokens: 50,
text: {
format: {
type: "json_schema",
name: "math_response",
schema: {
type: "object",
properties: {
steps: {
type: "array",
items: {
type: "object",
properties: {
explanation: { type: "string" },
output: { type: "string" },
},
required: ["explanation", "output"],
additionalProperties: false,
},
},
final_answer: { type: "string" },
},
required: ["steps", "final_answer"],
additionalProperties: false,
},
strict: true,
},
}
});
if (response.status === "incomplete" && response.incomplete_details.reason === "max_output_tokens") {
throw new Error("响应不完整");
}
const math_response = response.output[0].content[0];
if (math_response.type === "refusal") {
console.log(math_response.refusal);
} else if (math_response.type === "output_text") {
console.log(math_response.text);
} else {
throw new Error("无响应内容");
}
} catch (e) {
console.error(e);
}
try:
response = client.responses.create(
model="gpt-4o-2024-08-06",
input=[
{
"role": "system",
"content": "您是一位有用的数学辅导老师,逐步引导用户解决问题。",
},
{"role": "user", "content": "如何解决 8x + 7 = -23?"},
],
text={
"format": {
"type": "json_schema",
"name": "math_response",
"strict": True,
"schema": {
"type": "object",
"properties": {
"steps": {
"type": "array",
"items": {
"type": "object",
"properties": {
"explanation": {"type": "string"},
"output": {"type": "string"},
},
"required": ["explanation", "output"],
"additionalProperties": False,
},
},
"final_answer": {"type": "string"},
},
"required": ["steps", "final_answer"],
"additionalProperties": False,
},
"strict": True,
},
},
)
except Exception as e:
print(e)
结构化输出的拒绝处理
在使用用户生成输入的结构化输出时,OpenAI 模型可能因安全原因偶尔拒绝请求。由于拒绝不一定遵循您提供的模式,API 响应将包含一个新的 refusal 字段,以指示模型拒绝了请求。
当输出对象中出现 refusal 属性时,您可以在 UI 中显示拒绝信息,或在处理响应的代码中添加条件逻辑以处理拒绝请求的情况。
from pydantic import BaseModel
from openai import OpenAI
client = OpenAI()
class Step(BaseModel):
explanation: str
output: str
class MathReasoning(BaseModel):
steps: list[Step]
final_answer: str
completion = client.chat.completions.parse(
model="gpt-4o-2024-08-06",
messages=[
{"role": "system", "content": "您是一位有用的数学辅导老师,逐步引导用户解决问题。"},
{"role": "user", "content": "如何解决 8x + 7 = -23?"}
],
response_format=MathReasoning,
)
math_reasoning = completion.choices[0].message
if math_reasoning.refusal:
print(math_reasoning.refusal)
else:
print(math_reasoning.parsed)
import { z } from "zod";
import OpenAI from "openai";
const openai = new OpenAI();
const Step = z.object({
explanation: z.string(),
output: z.string(),
});
const MathReasoning = z.object({
steps: z.array(Step),
final_answer: z.string(),
});
const completion = await openai.chat.completions.parse({
model: "gpt-4o-2024-08-06",
messages: [
{ role: "system", content: "您是一位有用的数学辅导老师,逐步引导用户解决问题。" },
{ role: "user", content: "如何解决 8x + 7 = -23?" },
],
response_format: zodResponseFormat(MathReasoning, "math_reasoning"),
});
const math_reasoning = completion.choices[0].message
if (math_reasoning.refusal) {
console.log(math_reasoning.refusal);
} else {
console.log(math_reasoning.parsed);
}
拒绝的 API 响应示例
{
"id": "resp_1234567890",
"object": "response",
"created_at": 1721596428,
"status": "completed",
"error": null,
"incomplete_details": null,
"messages": [],
"instructions": null,
"max_output_tokens": null,
"model": "gpt-4o-2024-08-06",
"output": [{
"id": "msg_1234567890",
"type": "message",
"role": "assistant",
"content": [
{
"type": "refusal",
"refusal": "抱歉,我无法协助处理该请求。"
}
]
}],
"usage": {
"input_tokens": 81,
"output_tokens": 11,
"total_tokens": 92,
"output_tokens_details": {
"reasoning_tokens": 0
}
}
}
提示与最佳实践
处理用户生成输入
如果您的应用程序使用用户生成输入,请确保您的提示包含如何处理无法生成有效响应的输入的说明。模型将始终尝试遵循提供的模式,如果输入与模式完全无关,可能会导致幻觉。您可以在提示中指定如果模型检测到输入与任务不兼容时,返回空参数或特定句子。
处理错误
结构化输出仍可能包含错误。如果发现错误,请尝试调整指令、在系统指令中提供示例,或将任务拆分为更简单的子任务。有关如何调整输入的更多指导,请参阅提示工程指南。
避免 JSON Schema 偏差
为防止 JSON Schema 与编程语言中的相应类型发生偏差,我们强烈建议使用原生的 Pydantic/Zod SDK 支持。如果您更喜欢直接指定 JSON Schema,可以添加 CI 规则,在 JSON Schema 或底层数据对象被编辑时发出警告,或添加一个自动从类型定义生成 JSON Schema(或反之)的 CI 步骤。
流式处理
您可以使用流式处理来实时处理模型响应或函数调用参数,并将其解析为结构化数据。这样,您无需等待整个响应完成即可处理。这对于逐一显示 JSON 字段或立即处理函数调用参数非常有用。我们建议使用 SDK 来处理结构化输出的流式处理。
from typing import List
from openai import OpenAI
from pydantic import BaseModel
client = OpenAI()
class EntitiesModel(BaseModel):
attributes: List[str]
colors: List[str]
animals: List[str]
with client.responses.stream(
model="gpt-4.1",
input=[
{"role": "system", "content": "从输入文本中提取实体"},
{
"role": "user",
"content": "快速的棕色狐狸跳过懒惰的狗,拥有锐利的蓝眼睛",
},
],
text_format=EntitiesModel,
) as stream:
for event in stream:
if event.type == "response.refusal.delta":
print(event.delta, end="")
elif event.type == "response.output_text.delta":
print(event.delta, end="")
elif event.type == "response.error":
print(event.error, end="")
elif event.type == "response.completed":
print("完成")
final_response = stream.get_final_response()
print(final_response)
import { OpenAI } from "openai";
import { zodTextFormat } from "openai/helpers/zod";
import { z } from "zod";
const EntitiesSchema = z.object({
attributes: z.array(z.string()),
colors: z.array(z.string()),
animals: z.array(z.string()),
});
const openai = new OpenAI();
const stream = openai.responses
.stream({
model: "gpt-4.1",
messages: [
{ role: "user", content: "今天巴黎的天气如何?" },
],
text: {
format: zodTextFormat(EntitiesSchema, "entities"),
},
})
.on("response.refusal.delta", (event) => {
process.stdout.write(event.delta);
})
.on("response.output_text.delta", (event) => {
process.stdout.write(event.delta);
})
.on("response.output_text.done", () => {
process.stdout.write("\n");
})
.on("response.error", (event) => {
console.error(event.error);
});
const result = await stream.finalResponse();
console.log(result);
支持的模式
结构化输出支持 JSON Schema 语言的一个子集。 支持的类型 结构化输出支持以下类型:
字符串(String) 数字(Number) 布尔值(Boolean) 整数(Integer) 对象(Object) 数组(Array) 枚举(Enum) anyOf
支持的属性 除了指定属性的类型外,您还可以指定以下附加约束: 支持的 string 属性:
pattern — 字符串必须匹配的正则表达式。 format — 字符串的预定义格式。目前支持: date-time time date duration email hostname ipv4 ipv6 uuid
支持的 number 属性:
multipleOf — 数字必须是此值的倍数。 maximum — 数字必须小于或等于此值。 exclusiveMaximum — 数字必须小于此值。 minimum — 数字必须大于或等于此值。 exclusiveMinimum — 数字必须大于此值。
支持的 array 属性:
minItems — 数组必须至少包含此数量的项。 maxItems — 数组最多包含此数量的项。
示例
字符串限制
{
"name": "user_data",
"strict": true,
"schema": {
"type": "object",
"properties": {
"name": {
"type": "string",
"description": "用户的名称"
},
"username": {
"type": "string",
"description": "用户的用户名,必须以 @ 开头",
"pattern": "^@[a-zA-Z0-9_]+$"
},
"email": {
"type": "string",
"description": "用户的电子邮件",
"format": "email"
}
},
"additionalProperties": false,
"required": ["name", "username", "email"]
}
}
数字限制
{
"name": "weather_data",
"strict": true,
"schema": {
"type": "object",
"properties": {
"location": {
"type": "string",
"description": "获取天气的地点"
},
"unit": {
"type": ["string", "null"],
"description": "返回温度的单位",
"enum": ["F", "C"]
},
"value": {
"type": "number",
"description": "该地点的实际温度值",
"minimum": -130,
"maximum": 130
}
},
"additionalProperties": false,
"required": ["location", "unit", "value"]
}
}
注意:这些约束在微调模型中尚不支持。
根对象必须是对象且不能是 anyOf
根级别的模式必须是对象,且不能使用 anyOf。例如,Zod 中常见的模式是使用区分联合,这会在顶层产生 anyOf,因此以下代码无效:
import { z } from 'zod';
import { zodResponseFormat } from 'openai/helpers/zod';
const BaseResponseSchema = z.object({/* ... */});
const UnsuccessfulResponseSchema = z.object({/* ... */});
const finalSchema = z.discriminatedUnion('status', [
BaseResponseSchema,
UnsuccessfulResponseSchema,
]);
// 结构化输出的无效 JSON Schema
const json = zodResponseFormat(finalSchema, 'final_schema');
所有字段必须是 required
要使用结构化输出,所有字段或函数参数必须指定为 required。
{
"name": "get_weather",
"description": "获取给定地点的天气",
"strict": true,
"parameters": {
"type": "object",
"properties": {
"location": {
"type": "string",
"description": "获取天气的地点"
},
"unit": {
"type": "string",
"description": "返回温度的单位",
"enum": ["F", "C"]
}
},
"additionalProperties": false,
"required": ["location", "unit"]
}
}
虽然所有字段必须是必需的(模型将为每个参数返回一个值),但可以通过使用带有 null 的联合类型来模拟可选参数。
{
"name": "get_weather",
"description": "获取给定地点的天气",
"strict": true,
"parameters": {
"type": "object",
"properties": {
"location": {
"type": "string",
"description": "获取天气的地点"
},
"unit": {
"type": ["string", "null"],
"description": "返回温度的单位",
"enum": ["F", "C"]
}
},
"additionalProperties": false,
"required": ["location", "unit"]
}
}
对象嵌套深度和大小的限制
模式最多可包含 5000 个对象属性,嵌套深度最多 10 层。
字符串总大小的限制
在模式中,所有属性名称、定义名称、枚举值和常量值的总字符串长度不得超过 120,000 个字符。
枚举大小的限制
模式中所有枚举属性的枚举值总数最多为 1000 个。对于具有字符串值的单个枚举属性,当枚举值超过 250 个时,所有枚举值的总字符串长度不得超过 15,000 个字符。
必须始终设置 additionalProperties: false
additionalProperties 控制对象是否可以包含未在 JSON Schema 中定义的额外键/值。结构化输出仅支持生成指定键/值,因此要求开发者设置 additionalProperties: false 以启用结构化输出。
{
"name": "get_weather",
"description": "获取给定地点的天气",
"strict": true,
"schema": {
"type": "object",
"properties": {
"location": {
"type": "string",
"description": "获取天气的地点"
},
"unit": {
"type": "string",
"description": "返回温度的单位",
"enum": ["F", "C"]
}
},
"additionalProperties": false,
"required": ["location", "unit"]
}
}
键顺序
使用结构化输出时,输出将按照模式中键的顺序生成。
部分类型特定关键字尚未支持
组合: allOf, not, dependentRequired, dependentSchemas, if, then, else
对于微调模型,还不支持以下内容:
- 字符串: minLength, maxLength, pattern, format
- 数字: minimum, maximum, multipleOf
- 对象: patternProperties
- 数组: minItems, maxItems
如果您启用了结构化输出(设置 strict: true)并使用不支持的 JSON Schema 调用 API,将收到错误。
anyOf 的嵌套模式必须是有效的 JSON Schema 子集
以下是一个支持的 anyOf 模式示例:
{
"type": "object",
"properties": {
"item": {
"anyOf": [
{
"type": "object",
"description": "插入数据库的用户对象",
"properties": {
"name": {
"type": "string",
"description": "用户的名称"
},
"age": {
"type": "number",
"description": "用户的年龄"
}
},
"additionalProperties": false,
"required": ["name", "age"]
},
{
"type": "object",
"description": "插入数据库的地址对象",
"properties": {
"number": {
"type": "string",
"description": "地址的编号,例如 123 main st 中的 123"
},
"street": {
"type": "string",
"description": "街道名称,例如 123 main st 中的 main st"
},
"city": {
"type": "string",
"description": "地址的城市"
}
},
"additionalProperties": false,
"required": ["number", "street", "city"]
}
]
}
},
"additionalProperties": false,
"required": ["item"]
}
支持定义
您可以使用定义来定义在模式中引用的子模式。以下是一个简单示例:
{
"type": "object",
"properties": {
"steps": {
"type": "array",
"items": {
"$ref": "#/$defs/step"
}
},
"final_answer": {
"type": "string"
}
},
"$defs": {
"step": {
"type": "object",
"properties": {
"explanation": {
"type": "string"
},
"output": {
"type": "string"
}
},
"required": ["explanation", "output"],
"additionalProperties": false
}
},
"required": ["steps", "final_answer"],
"additionalProperties": false
}
支持递归模式
以下是使用 # 表示根递归的示例递归模式:
{
"name": "ui",
"description": "动态生成的 UI",
"strict": true,
"schema": {
"type": "object",
"properties": {
"type": {
"type": "string",
"description": "UI 组件的类型",
"enum": ["div", "button", "header", "section", "field", "form"]
},
"label": {
"type": "string",
"description": "UI 组件的标签,用于按钮或表单字段"
},
"children": {
"type": "array",
"description": "嵌套的 UI 组件",
"items": {
"$ref": "#"
}
},
"attributes": {
"type": "array",
"description": "UI 组件的任意属性,适用于任何元素",
"items": {
"type": "object",
"properties": {
"name": {
"type": "string",
"description": "属性的名称,例如 onClick 或 className"
},
"value": {
"type": "string",
"description": "属性的值"
}
},
"additionalProperties": false,
"required": ["name", "value"]
}
}
},
"required": ["type", "label", "children", "attributes"],
"additionalProperties": false
}
}
以下是使用显式递归的递归模式示例:
{
"type": "object",
"properties": {
"linked_list": {
"$ref": "#/$defs/linked_list_node"
}
},
"$defs": {
"linked_list_node": {
"type": "object",
"properties": {
"value": {
"type": "number"
},
"next": {
"anyOf": [
{
"$ref": "#/$defs/linked_list_node"
},
{
"type": "null"
}
]
}
},
"additionalProperties": false,
"required": ["next", "value"]
}
},
"additionalProperties": false,
"required": ["linked_list"]
}
JSON 模式
JSON 模式是结构化输出功能的简化版本。虽然 JSON 模式确保模型输出是有效的 JSON,但结构化输出能可靠地匹配您指定的模式。我们建议在支持的情况下使用结构化输出。
启用 JSON 模式时,模型的输出将确保是有效的 JSON,但在某些边缘情况下需要检测和适当处理。
要在 Responses API 中启用 JSON 模式,可以将 text.format 设置为 { "type": "json_object" }。如果使用函数调用,JSON 模式始终启用。
重要说明:
使用 JSON 模式时,您必须始终通过对话中的某条消息(例如系统消息)指示模型生成 JSON。如果未明确指示生成 JSON,模型可能生成无限的空白流,导致请求持续运行直到达到 token 限制。为避免遗漏,API 会在上下文中未出现“JSON”字符串时抛出错误。 JSON 模式不保证输出符合任何特定模式,仅保证其有效且可解析无错误。您应使用结构化输出确保匹配您的模式,或者使用验证库和可能的多次重试以确保输出符合期望模式。 您的应用程序必须检测并处理可能导致模型输出不是完整 JSON 对象的边缘情况。
处理边缘情况
const we_did_not_specify_stop_tokens = true;
try {
const response = await openai.responses.create({
model: "gpt-3.5-turbo-0125",
messages: [
{
role: "system",
content: "您是一位有用的助手,设计用于输出 JSON。",
},
{ role: "user", content: "2020 年世界大赛谁赢了?请以 {winner: ...} 格式响应" },
],
text: { format: { type: "json_object" } },
});
if (response.status === "incomplete" && response.incomplete_details.reason === "max_output_tokens") {
// 处理因上下文窗口过长导致 JSON 不完整的情况
}
if (response.output[0].content[0].type === "refusal") {
// 处理 OpenAI 安全系统拒绝请求的情况
console.log(response.output[0].content[0].refusal);
}
if (response.status === "incomplete" && response.incomplete_details.reason === "content_filter") {
// 处理因输出受限内容导致 JSON 生成中断的情况
}
if (response.status === "completed") {
if (we_did_not_specify_stop_tokens) {
// 如果未指定停止标记,则生成完成,内容键将包含序列化的 JSON 对象
console.log(JSON.parse(response.output_text));
} else {
// 检查 response.output_text 是否以您提供的停止标记之一结尾,并适当处理
}
}
} catch (e) {
console.error(e);
}
we_did_not_specify_stop_tokens = True
try:
response = client.responses.create(
model="gpt-3.5-turbo-0125",
input=[
{"role": "system", "content": "您是一位有用的助手,设计用于输出 JSON。"},
{"role": "user", "content": "2020 年世界大赛谁赢了?请以 {winner: ...} 格式响应"}
],
text={"format": {"type": "json_object"}}
)
if response.status == "incomplete" and response.incomplete_details.reason == "max_output_tokens":
# 处理因上下文窗口过长导致 JSON 不完整的情况
pass
if response.output[0].content[0].type == "refusal":
# 处理 OpenAI 安全系统拒绝请求的情况
print(response.output[0].content[0]["refusal"])
if response.status == "incomplete" and response.incomplete_details.reason == "content_filter":
# 处理因输出受限内容导致 JSON 生成中断的情况
pass
if response.status == "completed":
if we_did_not_specify_stop_tokens:
# 如果未指定停止标记,则生成完成,内容键将包含序列化的 JSON 对象
print(response.output_text)
else:
# 检查 response.output_text 是否以您提供的停止标记之一结尾,并适当处理
pass
except Exception as e:
print(e)
资源
要了解更多关于结构化输出的信息,我们建议浏览以下资源:
查看我们的结构化输出入门手册 了解如何使用结构化输出构建多代理系统
这个页面有用吗?