JSON 是世界上应用程序交换数据最广泛使用的格式之一。
结构化输出是一项功能,可确保模型始终生成遵循您提供的 JSON Schema ,因此你不必担心模型会遗漏必需的键,或凭空产生无效的枚举值。
结构化输出的部分优势包括:
可靠的类型安全: 无需验证或重试格式不正确的响应
明确的拒绝: 基于安全考虑的模型拒绝现在可通过编程方式检测
更简单的提示词: 无需使用措辞强烈的提示词来实现一致的格式
除了在 REST API 中支持 JSON Schema 之外,适用于 Python and JavaScript 的 OpenAI SDK 也让使用 Pydantic and Zod 。在下文中,你可以了解如何从非结构化文本中提取符合代码中所定义 Schema 的信息。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import OpenAI from "openai" ;
import { zodResponseFormat } 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()),
});
const completion = await openai.chat.completions.parse({
model : "gpt-4o-2024-08-06" ,
messages : [
{ role : "system" , content : "Extract the event information." },
{ role : "user" , content : "Alice and Bob are going to a science fair on Friday." },
],
response_format : zodResponseFormat(CalendarEvent, "event" ),
});
const event = completion.choices[ 0 ].message.parsed; 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
from pydantic import BaseModel
from openai import OpenAI
client = OpenAI()
class CalendarEvent ( BaseModel ):
name: str
date: str
participants: list [ str ]
completion = client.chat.completions.parse(
model= "gpt-4o-2024-08-06" ,
messages=[
{ "role" : "system" , "content" : "Extract the event information." },
{ "role" : "user" , "content" : "Alice and Bob are going to a science fair on Friday." },
],
response_format=CalendarEvent,
)
event = completion.choices[ 0 ].message.parsed
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
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()),
});
const response = await openai.responses.parse({
model : "gpt-4o-2024-08-06" ,
input : [
{ role : "system" , content : "Extract the event information." },
{
role : "user" ,
content : "Alice and Bob are going to a science fair on Friday." ,
},
],
text : {
format : zodTextFormat(CalendarEvent, "event" ),
},
});
const event = response.output_parsed; 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
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" : "Extract the event information." },
{
"role" : "user" ,
"content" : "Alice and Bob are going to a science fair on Friday." ,
},
],
text_format=CalendarEvent,
)
event = response.output_parsed
Structured Outputs 可在我们的 最新大型语言模型中使用 ,从 GPT-4o 开始支持。较早的模型如 gpt-4-turbo and earlier may use JSON 模式 instead.
何时使用通过函数调用实现 Structured Outputs 与通过
response_format
何时使用通过函数调用实现 Structured Outputs 与通过
text.format
Structured Outputs 在 OpenAI API 中提供两种形式:
当使用 函数调用
当使用 json_schema 响应格式
当你正在构建一个连接模型与应用功能的应用程序时,函数调用会非常有用。
例如,你可以让模型访问查询数据库的函数,从而构建一个能帮助用户处理订单的 AI 助手;或者让它访问可以与 UI 交互的函数。
相反,通过 response_format 当你希望指定一个结构化 schema,用于模型响应用户而非调用工具时,更为适合。
例如,如果你正在构建一个数学辅导应用程序,你可能希望助手使用特定的 JSON Schema 来响应用户,以便你能生成一个 UI,以不同的方式展示模型输出的不同部分。
简而言之:
如果你要在系统中将模型连接到工具、函数、数据等,则应使用函数调用 - 如果你希望对模型响应用户时的输出进行结构化,则应使用结构化
response_format
如果你要在系统中将模型连接到工具、函数、数据等,则应使用函数调用 - 如果你希望对模型响应用户时的输出进行结构化,则应使用结构化
text.format
本指南的其余部分将重点介绍 Chat Completions API 中的非函数调用用例。要了解有关如何在函数调用中使用 Structured Outputs 的更多信息,请查看
函数调用
guide.
本指南的其余部分将重点介绍 Responses API 中的非函数调用用例。要了解有关如何在函数调用中使用 Structured Outputs 的更多信息,请查看
函数调用
guide.
Structured Outputs 是以下功能的演进: JSON 模式 。虽然两者都能确保生成有效的 JSON,但只有结构化输出能确保严格遵循 schema。结构化输出和 JSON 模式在 Responses API、Chat Completions API、Assistants API、Fine-tuning API 和 Batch API 中均受支持。
我们建议在可能的情况下,始终使用 Structured Outputs 而非 JSON 模式。
然而,带有以下功能的 Structured Outputs response_format: {type: "json_schema", ...} 仅受 gpt-4o-mini, gpt-4o-mini-2024-07-18,且 gpt-4o-2024-08-06 模型快照及更高版本支持。
结构化输出 JSON 模式 输出有效的 JSON 是 是 遵循 schema 是 (参见 受支持的 schema ) No 兼容模型 gpt-4o-mini, gpt-4o-2024-08-06及后续gpt-3.5-turbo, gpt-4-* and gpt-4o-* 视觉启用 response_format: { type: "json_schema", json_schema: {"strict": true, "schema": ...} }response_format: { type: "json_object" }
结构化输出 JSON 模式 输出有效的 JSON 是 是 遵循 schema 是 (参见 受支持的 schema ) No 兼容模型 gpt-4o-mini, gpt-4o-2024-08-06及后续gpt-3.5-turbo, gpt-4-* and gpt-4o-* 视觉启用 text: { format: { type: "json_schema", "strict": true, "schema": ... } }text: { format: { type: "json_object" } }
思维链
思维链
你可以要求模型以结构化、分步的方式输出答案,从而引导用户理清解决方案。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
import OpenAI from "openai" ;
import { z } from "zod" ;
import { zodResponseFormat } from "openai/helpers/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 completion = await openai.chat.completions.parse({
model : "gpt-4o-2024-08-06" ,
messages : [
{ role : "system" , content : "You are a helpful math tutor. Guide the user through the solution step by step." },
{ role : "user" , content : "how can I solve 8x + 7 = -23" },
],
response_format : zodResponseFormat(MathReasoning, "math_reasoning" ),
});
const math_reasoning = completion.choices[ 0 ].message.parsed; 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
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" : "You are a helpful math tutor. Guide the user through the solution step by step." },
{ "role" : "user" , "content" : "how can I solve 8x + 7 = -23" }
],
response_format=MathReasoning,
)
math_reasoning = completion.choices[ 0 ].message.parsed 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
curl https://api.openai.com/v1/chat/completions \
-H "Authorization: Bearer $OPENAI_API_KEY " \
-H "Content-Type: application/json" \
-d '{
"model": "gpt-4o-2024-08-06",
"messages": [
{
"role": "system",
"content": "You are a helpful math tutor. Guide the user through the solution step by step."
},
{
"role": "user",
"content": "how can I solve 8x + 7 = -23"
}
],
"response_format": {
"type": "json_schema",
"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
}
}
}'
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
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" ,
input : [
{
role : "system" ,
content :
"You are a helpful math tutor. Guide the user through the solution step by step." ,
},
{ role : "user" , content : "how can I solve 8x + 7 = -23" },
],
text : {
format : zodTextFormat(MathReasoning, "math_reasoning" ),
},
});
const math_reasoning = response.output_parsed; 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
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" : "You are a helpful math tutor. Guide the user through the solution step by step." ,
},
{ "role" : "user" , "content" : "how can I solve 8x + 7 = -23" },
],
text_format=MathReasoning,
)
math_reasoning = response.output_parsed 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
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",
"input": [
{
"role": "system",
"content": "You are a helpful math tutor. Guide the user through the solution step by step."
},
{
"role": "user",
"content": "how can I solve 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" : "Start with the equation 8x + 7 = -23." ,
"output" : "8x + 7 = -23"
},
{
"explanation" : "Subtract 7 from both sides to isolate the term with the variable." ,
"output" : "8x = -23 - 7"
},
{
"explanation" : "Simplify the right side of the equation." ,
"output" : "8x = -30"
},
{
"explanation" : "Divide both sides by 8 to solve for x." ,
"output" : "x = -30 / 8"
},
{
"explanation" : "Simplify the fraction." ,
"output" : "x = -15 / 4"
}
],
"final_answer" : "x = -15 / 4"
} 结构化数据提取
你可以定义结构化字段,以便从非结构化输入数据(例如研究论文)中提取信息。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import OpenAI from "openai" ;
import { z } from "zod" ;
import { zodResponseFormat } from "openai/helpers/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 completion = await openai.chat.completions.parse({
model : "gpt-4o-2024-08-06" ,
messages : [
{ role : "system" , content : "You are an expert at structured data extraction. You will be given unstructured text from a research paper and should convert it into the given structure." },
{ role : "user" , content : "..." },
],
response_format : zodResponseFormat(ResearchPaperExtraction, "research_paper_extraction" ),
});
const research_paper = completion.choices[ 0 ].message.parsed; 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
from pydantic import BaseModel
from openai import OpenAI
client = OpenAI()
class ResearchPaperExtraction ( BaseModel ):
title: str
authors: list [ str ]
abstract: str
keywords: list [ str ]
completion = client.chat.completions.parse(
model= "gpt-4o-2024-08-06" ,
messages=[
{ "role" : "system" , "content" : "You are an expert at structured data extraction. You will be given unstructured text from a research paper and should convert it into the given structure." },
{ "role" : "user" , "content" : "..." }
],
response_format=ResearchPaperExtraction,
)
research_paper = completion.choices[ 0 ].message.parsed 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
curl https://api.openai.com/v1/chat/completions \
-H "Authorization: Bearer $OPENAI_API_KEY " \
-H "Content-Type: application/json" \
-d '{
"model": "gpt-4o-2024-08-06",
"messages": [
{
"role": "system",
"content": "You are an expert at structured data extraction. You will be given unstructured text from a research paper and should convert it into the given structure."
},
{
"role": "user",
"content": "..."
}
],
"response_format": {
"type": "json_schema",
"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
}
}
}'
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
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" ,
input : [
{
role : "system" ,
content :
"You are an expert at structured data extraction. You will be given unstructured text from a research paper and should convert it into the given structure." ,
},
{ role : "user" , content : "..." },
],
text : {
format : zodTextFormat(ResearchPaperExtraction, "research_paper_extraction" ),
},
});
const research_paper = response.output_parsed; 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
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" : "You are an expert at structured data extraction. You will be given unstructured text from a research paper and should convert it into the given structure." ,
},
{ "role" : "user" , "content" : "..." },
],
text_format=ResearchPaperExtraction,
)
research_paper = response.output_parsed 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
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",
"input": [
{
"role": "system",
"content": "You are an expert at structured data extraction. You will be given unstructured text from a research paper and should convert it into the given structure."
},
{
"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" : "Application of Quantum Algorithms in Interstellar Navigation: A New Frontier" ,
"authors" : [ "Dr. Stella Voyager" , "Dr. Nova Star" , "Dr. Lyra Hunter" ],
"abstract" : "This paper investigates the utilization of quantum algorithms to improve interstellar navigation systems. By leveraging quantum superposition and entanglement, our proposed navigation system can calculate optimal travel paths through space-time anomalies more efficiently than classical methods. Experimental simulations suggest a significant reduction in travel time and fuel consumption for interstellar missions." ,
"keywords" : [
"Quantum algorithms" ,
"interstellar navigation" ,
"space-time anomalies" ,
"quantum superposition" ,
"quantum entanglement" ,
"space travel"
]
} UI 生成
UI 生成
你可以通过将 HTML 表示为带有约束(例如枚举)的递归数据结构,来生成有效的 HTML。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
import OpenAI from "openai" ;
import { z } from "zod" ;
import { zodResponseFormat } from "openai/helpers/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 completion = await openai.chat.completions.parse({
model : "gpt-4o-2024-08-06" ,
messages : [
{
role : "system" ,
content : "You are a UI generator AI. Convert the user input into a UI." ,
},
{ role : "user" , content : "Make a User Profile Form" },
],
response_format : zodResponseFormat(UI, "ui" ),
});
const ui = completion.choices[ 0 ].message.parsed; 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
from enum import Enum
from typing import List
from pydantic import BaseModel
from openai import OpenAI
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
completion = client.chat.completions.parse(
model= "gpt-4o-2024-08-06" ,
messages=[
{ "role" : "system" , "content" : "You are a UI generator AI. Convert the user input into a UI." },
{ "role" : "user" , "content" : "Make a User Profile Form" }
],
response_format=Response,
)
ui = completion.choices[ 0 ].message.parsed
print (ui) 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
curl https://api.openai.com/v1/chat/completions \
-H "Authorization: Bearer $OPENAI_API_KEY " \
-H "Content-Type: application/json" \
-d '{
"model": "gpt-4o-2024-08-06",
"messages": [
{
"role": "system",
"content": "You are a UI generator AI. Convert the user input into a UI."
},
{
"role": "user",
"content": "Make a User Profile Form"
}
],
"response_format": {
"type": "json_schema",
"json_schema": {
"name": "ui",
"description": "Dynamically generated UI",
"schema": {
"type": "object",
"properties": {
"type": {
"type": "string",
"description": "The type of the UI component",
"enum": ["div", "button", "header", "section", "field", "form"]
},
"label": {
"type": "string",
"description": "The label of the UI component, used for buttons or form fields"
},
"children": {
"type": "array",
"description": "Nested UI components",
"items": {"$ref": "#"}
},
"attributes": {
"type": "array",
"description": "Arbitrary attributes for the UI component, suitable for any element",
"items": {
"type": "object",
"properties": {
"name": {
"type": "string",
"description": "The name of the attribute, for example onClick or className"
},
"value": {
"type": "string",
"description": "The value of the attribute"
}
},
"required": ["name", "value"],
"additionalProperties": false
}
}
},
"required": ["type", "label", "children", "attributes"],
"additionalProperties": false
},
"strict": true
}
}
}'
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
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" ,
input : [
{
role : "system" ,
content : "You are a UI generator AI. Convert the user input into a UI." ,
},
{
role : "user" ,
content : "Make a User Profile Form" ,
},
],
text : {
format : zodTextFormat(UI, "ui" ),
},
});
const ui = response.output_parsed; 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
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" : "You are a UI generator AI. Convert the user input into a UI." ,
},
{ "role" : "user" , "content" : "Make a User Profile Form" },
],
text_format=Response,
)
ui = response.output_parsed 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
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",
"input": [
{
"role": "system",
"content": "You are a UI generator AI. Convert the user input into a UI."
},
{
"role": "user",
"content": "Make a User Profile Form"
}
],
"text": {
"format": {
"type": "json_schema",
"name": "ui",
"description": "Dynamically generated UI",
"schema": {
"type": "object",
"properties": {
"type": {
"type": "string",
"description": "The type of the UI component",
"enum": ["div", "button", "header", "section", "field", "form"]
},
"label": {
"type": "string",
"description": "The label of the UI component, used for buttons or form fields"
},
"children": {
"type": "array",
"description": "Nested UI components",
"items": {"$ref": "#"}
},
"attributes": {
"type": "array",
"description": "Arbitrary attributes for the UI component, suitable for any element",
"items": {
"type": "object",
"properties": {
"name": {
"type": "string",
"description": "The name of the attribute, for example onClick or className"
},
"value": {
"type": "string",
"description": "The value of the attribute"
}
},
"required": ["name", "value"],
"additionalProperties": false
}
}
},
"required": ["type", "label", "children", "attributes"],
"additionalProperties": false
},
"strict": true
}
}
}'
示例响应
{
"type" : "form" ,
"label" : "User Profile Form" ,
"children" : [
{
"type" : "div" ,
"label" : "" ,
"children" : [
{
"type" : "field" ,
"label" : "First Name" ,
"children" : [],
"attributes" : [
{
"name" : "type" ,
"value" : "text"
},
{
"name" : "name" ,
"value" : "firstName"
},
{
"name" : "placeholder" ,
"value" : "Enter your first name"
}
]
},
{
"type" : "field" ,
"label" : "Last Name" ,
"children" : [],
"attributes" : [
{
"name" : "type" ,
"value" : "text"
},
{
"name" : "name" ,
"value" : "lastName"
},
{
"name" : "placeholder" ,
"value" : "Enter your last name"
}
]
}
],
"attributes" : []
},
{
"type" : "button" ,
"label" : "Submit" ,
"children" : [],
"attributes" : [
{
"name" : "type" ,
"value" : "submit"
}
]
}
],
"attributes" : [
{
"name" : "method" ,
"value" : "post"
},
{
"name" : "action" ,
"value" : "/submit-profile"
}
]
} 审核
审核
你可以对输入进行多类别分类,这是执行内容审核的一种常见方法。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import OpenAI from "openai" ;
import { z } from "zod" ;
import { zodResponseFormat } from "openai/helpers/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 completion = await openai.chat.completions.parse({
model : "gpt-4o-2024-08-06" ,
messages : [
{ role : "system" , content : "Determine if the user input violates specific guidelines and explain if they do." },
{ role : "user" , content : "How do I prepare for a job interview?" },
],
response_format : zodResponseFormat(ContentCompliance, "content_compliance" ),
});
const compliance = completion.choices[ 0 ].message.parsed; 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
from enum import Enum
from typing import Optional
from pydantic import BaseModel
from openai import OpenAI
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 ]
completion = client.chat.completions.parse(
model= "gpt-4o-2024-08-06" ,
messages=[
{ "role" : "system" , "content" : "Determine if the user input violates specific guidelines and explain if they do." },
{ "role" : "user" , "content" : "How do I prepare for a job interview?" }
],
response_format=ContentCompliance,
)
compliance = completion.choices[ 0 ].message.parsed 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
curl https://api.openai.com/v1/chat/completions \
-H "Authorization: Bearer $OPENAI_API_KEY " \
-H "Content-Type: application/json" \
-d '{
"model": "gpt-4o-2024-08-06",
"messages": [
{
"role": "system",
"content": "Determine if the user input violates specific guidelines and explain if they do."
},
{
"role": "user",
"content": "How do I prepare for a job interview?"
}
],
"response_format": {
"type": "json_schema",
"json_schema": {
"name": "content_compliance",
"description": "Determines if content is violating specific moderation rules",
"schema": {
"type": "object",
"properties": {
"is_violating": {
"type": "boolean",
"description": "Indicates if the content is violating guidelines"
},
"category": {
"type": ["string", "null"],
"description": "Type of violation, if the content is violating guidelines. Null otherwise.",
"enum": ["violence", "sexual", "self_harm"]
},
"explanation_if_violating": {
"type": ["string", "null"],
"description": "Explanation of why the content is violating"
}
},
"required": ["is_violating", "category", "explanation_if_violating"],
"additionalProperties": false
},
"strict": true
}
}
}'
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
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" ,
input : [
{
"role" : "system" ,
"content" : "Determine if the user input violates specific guidelines and explain if they do."
},
{
"role" : "user" ,
"content" : "How do I prepare for a job interview?"
}
],
text : {
format : zodTextFormat(ContentCompliance, "content_compliance" ),
},
});
const compliance = response.output_parsed; 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
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" : "Determine if the user input violates specific guidelines and explain if they do." ,
},
{ "role" : "user" , "content" : "How do I prepare for a job interview?" },
],
text_format=ContentCompliance,
)
compliance = response.output_parsed 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
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",
"input": [
{
"role": "system",
"content": "Determine if the user input violates specific guidelines and explain if they do."
},
{
"role": "user",
"content": "How do I prepare for a job interview?"
}
],
"text": {
"format": {
"type": "json_schema",
"name": "content_compliance",
"description": "Determines if content is violating specific moderation rules",
"schema": {
"type": "object",
"properties": {
"is_violating": {
"type": "boolean",
"description": "Indicates if the content is violating guidelines"
},
"category": {
"type": ["string", "null"],
"description": "Type of violation, if the content is violating guidelines. Null otherwise.",
"enum": ["violence", "sexual", "self_harm"]
},
"explanation_if_violating": {
"type": ["string", "null"],
"description": "Explanation of why the content is violating"
}
},
"required": ["is_violating", "category", "explanation_if_violating"],
"additionalProperties": false
},
"strict": true
}
}
}'
示例响应
{
"is_violating" : false ,
"category" : null ,
"explanation_if_violating" : null
}
如何将结构化输出与 response_format 您可以将结构化输出与新的 SDK 辅助工具结合使用,将模型的输出解析为您所需的格式,或者您也可以直接指定 JSON schema。
Note: 对于微调模型,使用任何 schema 发起的首次请求都会产生额外的延迟,因为我们的 API 需要处理该 schema,但后续使用相同 schema 的请求将不会产生额外延迟。其他模型不受此限制。
SDK 对象
首先,您必须定义一个对象或数据结构,以表示模型应遵循并受其约束的 JSON Schema。请参阅本 示例 指南顶部的参考。
虽然结构化输出支持大部分 JSON Schema 功能,但由于性能或技术原因,某些功能不可用。请参阅 此处 for more details.
例如,您可以像这样定义一个对象:
1
2
3
4
5
6
7
8
9
from pydantic import BaseModel
class Step ( BaseModel ):
explanation: str
output: str
class MathResponse ( BaseModel ):
steps: list [Step]
final_answer: str 1
2
3
4
5
6
7
8
9
10
11
12
import { z } from "zod" ;
import { zodResponseFormat } from "openai/helpers/zod" ;
const Step = z.object({
explanation : z.string(),
output : z.string(),
});
const MathResponse = z.object({
steps : z.array(Step),
final_answer : z.string(),
}); 数据结构设计技巧 为了最大化模型生成的质量,我们建议如下:
清晰直观地命名键
为结构中的重要键创建清晰的标题和描述
创建并使用评估 (evals) 以确定最适合您用例的结构
图像生成端点 parse 方法,以自动将 JSON 响应解析为您定义的对象。
在底层,SDK 负责提供与您的数据结构相对应的 JSON schema,然后将响应解析为对象。
1
2
3
4
5
6
7
8
completion = client.chat.completions.parse(
model= "gpt-4o-2024-08-06" ,
messages=[
{ "role" : "system" , "content" : "You are a helpful math tutor. Guide the user through the solution step by step." },
{ "role" : "user" , "content" : "how can I solve 8x + 7 = -23" }
],
response_format=MathResponse
) 1
2
3
4
5
6
7
8
const completion = await openai.chat.completions.parse({
model : "gpt-4o-2024-08-06" ,
messages : [
{ role : "system" , content : "You are a helpful math tutor. Guide the user through the solution step by step." },
{ role : "user" , content : "how can I solve 8x + 7 = -23" },
],
response_format : zodResponseFormat(MathResponse, "math_response" ),
});
在某些情况下,模型可能无法生成与提供的 JSON schema 匹配的有效响应。
这种情况可能发生在拒绝响应时(例如,模型出于安全原因拒绝回答),或者在达到最大 token 限制导致响应不完整时。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
try {
const completion = await openai.chat.completions.create({
model : "gpt-4o-2024-08-06" ,
messages : [{
role : "system" ,
content : "You are a helpful math tutor. Guide the user through the solution step by step." ,
},
{
role : "user" ,
content : "how can I solve 8x + 7 = -23"
},
],
store : true ,
response_format : {
type : "json_schema" ,
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 ,
},
},
max_tokens : 50 ,
});
if (completion.choices[ 0 ].finish_reason === "length" ) {
throw new Error ( "Incomplete response" );
}
const math_response = completion.choices[ 0 ].message;
if (math_response.refusal) {
console .log(math_response.refusal);
} else if (math_response.content) {
console .log(math_response.content);
} else {
throw new Error ( "No response content" );
}
} catch (e) {
console .error(e);
} 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
try :
response = client.chat.completions.create(
model= "gpt-4o-2024-08-06" ,
messages=[
{
"role" : "system" ,
"content" : "You are a helpful math tutor. Guide the user through the solution step by step." ,
},
{ "role" : "user" , "content" : "how can I solve 8x + 7 = -23" },
],
response_format={
"type" : "json_schema" ,
"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:
pass 手动 schema
首先,您必须设计模型应遵循并受其约束的 JSON Schema。请参阅 示例 指南顶部的参考。
虽然结构化输出支持大部分 JSON Schema 功能,但由于性能或技术原因,某些功能不可用。请参阅 此处 for more details.
JSON Schema 设计技巧 为了最大化模型生成的质量,我们建议如下:
清晰直观地命名键
为结构中的重要键创建清晰的标题和描述
创建并使用评估 (evals) 以确定最适合您用例的结构
第 2 步:在 API 调用中提供您的 schema
要使用结构化输出,只需指定
response_format: { "type" : "json_schema" , "json_schema" : … , "strict" : true }
text: { format : { type : "json_schema" , "strict" : true , "schema" : … } }
For example:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
response = client.chat.completions.create(
model= "gpt-4o-2024-08-06" ,
messages=[
{ "role" : "system" , "content" : "You are a helpful math tutor. Guide the user through the solution step by step." },
{ "role" : "user" , "content" : "how can I solve 8x + 7 = -23" }
],
response_format={
"type" : "json_schema" ,
"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.choices[ 0 ].message.content) 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
const response = await openai.chat.completions.create({
model : "gpt-4o-2024-08-06" ,
messages : [
{ role : "system" , content : "You are a helpful math tutor. Guide the user through the solution step by step." },
{ role : "user" , content : "how can I solve 8x + 7 = -23" }
],
store : true ,
response_format : {
type : "json_schema" ,
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.choices[ 0 ].message.content); 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
curl https://api.openai.com/v1/chat/completions \
-H "Authorization: Bearer $OPENAI_API_KEY " \
-H "Content-Type: application/json" \
-d '{
"model": "gpt-4o-2024-08-06",
"messages": [
{
"role": "system",
"content": "You are a helpful math tutor. Guide the user through the solution step by step."
},
{
"role": "user",
"content": "how can I solve 8x + 7 = -23"
}
],
"response_format": {
"type": "json_schema",
"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
}
}
}'
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
response = client.responses.create(
model= "gpt-4o-2024-08-06" ,
input =[
{ "role" : "system" , "content" : "You are a helpful math tutor. Guide the user through the solution step by step." },
{ "role" : "user" , "content" : "how can I solve 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) 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
const response = await openai.responses.create({
model : "gpt-4o-2024-08-06" ,
input : [
{ role : "system" , content : "You are a helpful math tutor. Guide the user through the solution step by step." },
{ role : "user" , content : "how can I solve 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); 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
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",
"input": [
{
"role": "system",
"content": "You are a helpful math tutor. Guide the user through the solution step by step."
},
{
"role": "user",
"content": "how can I solve 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
}
}
}' Note: 使用任何 schema 发起的首次请求都会产生额外的延迟,因为我们的 API 需要处理该 schema,但后续使用相同 schema 的请求将不会产生额外延迟。
在某些情况下,模型可能无法生成与提供的 JSON schema 匹配的有效响应。
这种情况可能发生在拒绝响应时(例如,模型出于安全原因拒绝回答),或者在达到最大 token 限制导致响应不完整时。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
try {
const completion = await openai.chat.completions.create({
model : "gpt-4o-2024-08-06" ,
messages : [{
role : "system" ,
content : "You are a helpful math tutor. Guide the user through the solution step by step." ,
},
{
role : "user" ,
content : "how can I solve 8x + 7 = -23"
},
],
store : true ,
response_format : {
type : "json_schema" ,
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 ,
},
},
max_tokens : 50 ,
});
if (completion.choices[ 0 ].finish_reason === "length" ) {
throw new Error ( "Incomplete response" );
}
const math_response = completion.choices[ 0 ].message;
if (math_response.refusal) {
console .log(math_response.refusal);
} else if (math_response.content) {
console .log(math_response.content);
} else {
throw new Error ( "No response content" );
}
} catch (e) {
console .error(e);
} 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
try :
response = client.chat.completions.create(
model= "gpt-4o-2024-08-06" ,
messages=[
{
"role" : "system" ,
"content" : "You are a helpful math tutor. Guide the user through the solution step by step." ,
},
{ "role" : "user" , "content" : "how can I solve 8x + 7 = -23" },
],
response_format={
"type" : "json_schema" ,
"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:
pass
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
try {
const response = await openai.responses.create({
model : "gpt-4o-2024-08-06" ,
input : [{
role : "system" ,
content : "You are a helpful math tutor. Guide the user through the solution step by step." ,
},
{
role : "user" ,
content : "how can I solve 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 ( "Incomplete response" );
}
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 ( "No response content" );
}
} catch (e) {
console .error(e);
} 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
try :
response = client.responses.create(
model= "gpt-4o-2024-08-06" ,
input =[
{
"role" : "system" ,
"content" : "You are a helpful math tutor. Guide the user through the solution step by step." ,
},
{ "role" : "user" , "content" : "how can I solve 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:
pass
通常,在使用结构化输出时,您会在编程语言的类型系统中拥有一个类型或类,将 JSON Schema 表示为一个对象。
确认收到保证与你所请求的 schema 匹配的 JSON 后,你现在可以安全地将其解析为相应的类型。
For example:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
from pydantic import BaseModel, ValidationError
from typing import List
class Step ( BaseModel ):
explanation: str
output: str
class Solution ( BaseModel ):
steps: List [Step]
final_answer: str
...
try :
solution = Solution.parse_raw(response.choices[ 0 ].message.content)
print (solution)
except ValidationError as e:
print (e.json()) 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
type Step = {
explanation : string;
output: string;
};
type Solution = {
steps : Step[];
final_answer: string;
};
...
const solution = JSON .parse(response.choices[ 0 ].message.content)) as Solution
首先,您必须设计模型应遵循并受其约束的 JSON Schema。请参阅 示例 指南顶部的参考。
虽然结构化输出支持大部分 JSON Schema 功能,但由于性能或技术原因,某些功能不可用。请参阅 此处 for more details.
JSON Schema 设计技巧 为了最大化模型生成的质量,我们建议如下:
清晰直观地命名键
为结构中的重要键创建清晰的标题和描述
创建并使用评估 (evals) 以确定最适合您用例的结构
第 2 步:在 API 调用中提供您的 schema
要使用结构化输出,只需指定
response_format: { "type" : "json_schema" , "json_schema" : … , "strict" : true }
text: { format : { type : "json_schema" , "strict" : true , "schema" : … } }
For example:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
response = client.chat.completions.create(
model= "gpt-4o-2024-08-06" ,
messages=[
{ "role" : "system" , "content" : "You are a helpful math tutor. Guide the user through the solution step by step." },
{ "role" : "user" , "content" : "how can I solve 8x + 7 = -23" }
],
response_format={
"type" : "json_schema" ,
"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.choices[ 0 ].message.content) 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
const response = await openai.chat.completions.create({
model : "gpt-4o-2024-08-06" ,
messages : [
{ role : "system" , content : "You are a helpful math tutor. Guide the user through the solution step by step." },
{ role : "user" , content : "how can I solve 8x + 7 = -23" }
],
store : true ,
response_format : {
type : "json_schema" ,
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.choices[ 0 ].message.content); 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
curl https://api.openai.com/v1/chat/completions \
-H "Authorization: Bearer $OPENAI_API_KEY " \
-H "Content-Type: application/json" \
-d '{
"model": "gpt-4o-2024-08-06",
"messages": [
{
"role": "system",
"content": "You are a helpful math tutor. Guide the user through the solution step by step."
},
{
"role": "user",
"content": "how can I solve 8x + 7 = -23"
}
],
"response_format": {
"type": "json_schema",
"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
}
}
}'
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
response = client.responses.create(
model= "gpt-4o-2024-08-06" ,
input =[
{ "role" : "system" , "content" : "You are a helpful math tutor. Guide the user through the solution step by step." },
{ "role" : "user" , "content" : "how can I solve 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) 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
const response = await openai.responses.create({
model : "gpt-4o-2024-08-06" ,
input : [
{ role : "system" , content : "You are a helpful math tutor. Guide the user through the solution step by step." },
{ role : "user" , content : "how can I solve 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); 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
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",
"input": [
{
"role": "system",
"content": "You are a helpful math tutor. Guide the user through the solution step by step."
},
{
"role": "user",
"content": "how can I solve 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
}
}
}' Note: 使用任何 schema 发起的首次请求都会产生额外的延迟,因为我们的 API 需要处理该 schema,但后续使用相同 schema 的请求将不会产生额外延迟。
在某些情况下,模型可能无法生成与提供的 JSON schema 匹配的有效响应。
这种情况可能发生在拒绝响应时(例如,模型出于安全原因拒绝回答),或者在达到最大 token 限制导致响应不完整时。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
try {
const completion = await openai.chat.completions.create({
model : "gpt-4o-2024-08-06" ,
messages : [{
role : "system" ,
content : "You are a helpful math tutor. Guide the user through the solution step by step." ,
},
{
role : "user" ,
content : "how can I solve 8x + 7 = -23"
},
],
store : true ,
response_format : {
type : "json_schema" ,
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 ,
},
},
max_tokens : 50 ,
});
if (completion.choices[ 0 ].finish_reason === "length" ) {
throw new Error ( "Incomplete response" );
}
const math_response = completion.choices[ 0 ].message;
if (math_response.refusal) {
console .log(math_response.refusal);
} else if (math_response.content) {
console .log(math_response.content);
} else {
throw new Error ( "No response content" );
}
} catch (e) {
console .error(e);
} 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
try :
response = client.chat.completions.create(
model= "gpt-4o-2024-08-06" ,
messages=[
{
"role" : "system" ,
"content" : "You are a helpful math tutor. Guide the user through the solution step by step." ,
},
{ "role" : "user" , "content" : "how can I solve 8x + 7 = -23" },
],
response_format={
"type" : "json_schema" ,
"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:
pass
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
try {
const response = await openai.responses.create({
model : "gpt-4o-2024-08-06" ,
input : [{
role : "system" ,
content : "You are a helpful math tutor. Guide the user through the solution step by step." ,
},
{
role : "user" ,
content : "how can I solve 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 ( "Incomplete response" );
}
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 ( "No response content" );
}
} catch (e) {
console .error(e);
} 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
try :
response = client.responses.create(
model= "gpt-4o-2024-08-06" ,
input =[
{
"role" : "system" ,
"content" : "You are a helpful math tutor. Guide the user through the solution step by step." ,
},
{ "role" : "user" , "content" : "how can I solve 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:
pass
通常,在使用结构化输出时,您会在编程语言的类型系统中拥有一个类型或类,将 JSON Schema 表示为一个对象。
确认收到保证与你所请求的 schema 匹配的 JSON 后,你现在可以安全地将其解析为相应的类型。
For example:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
from pydantic import BaseModel, ValidationError
from typing import List
class Step ( BaseModel ):
explanation: str
output: str
class Solution ( BaseModel ):
steps: List [Step]
final_answer: str
...
try :
solution = Solution.parse_raw(response.choices[ 0 ].message.content)
print (solution)
except ValidationError as e:
print (e.json()) 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
type Step = {
explanation : string;
output: string;
};
type Solution = {
steps : Step[];
final_answer: string;
};
...
const solution = JSON .parse(response.choices[ 0 ].message.content)) as Solution
在将结构化输出用于用户生成的输入时,出于安全原因,OpenAI 模型可能会偶尔拒绝处理该请求。由于拒绝的响应不一定会遵循你在 response_format,API 响应将包含一个名为 refusal 中提供的 schema,因此我们会在响应中添加一个额外的字符串属性,以指示模型拒绝处理该请求。
当 refusal 属性出现在你的输出对象中时,你可以在 UI 中展示该拒绝信息,或者在使用该响应的代码中加入条件逻辑,以处理请求被拒绝的情况。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
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" : "You are a helpful math tutor. Guide the user through the solution step by step." },
{ "role" : "user" , "content" : "how can I solve 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) 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
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 : "You are a helpful math tutor. Guide the user through the solution step by step." },
{ role : "user" , content : "how can I solve 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 响应大概如下所示:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
{
"id" : "chatcmpl-9nYAG9LPNonX8DAyrkwYfemr3C8HC" ,
"object" : "chat.completion" ,
"created" : 1721596428 ,
"model" : "gpt-4o-2024-08-06" ,
"choices" : [
{
"index" : 0 ,
"message" : {
"role" : "assistant" ,
"refusal" : "I'm sorry, I cannot assist with that request."
},
"logprobs" : null ,
"finish_reason" : "stop"
}
],
"usage" : {
"prompt_tokens" : 81 ,
"completion_tokens" : 11 ,
"total_tokens" : 92 ,
"completion_tokens_details" : {
"reasoning_tokens" : 0 ,
"accepted_prediction_tokens" : 0 ,
"rejected_prediction_tokens" : 0
}
},
"system_fingerprint" : "fp_3407719c7f"
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
{
"id" : "resp_1234567890" ,
"object" : "response" ,
"created_at" : 1721596428 ,
"status" : "completed" ,
"completed_at" : 1721596429 ,
"error" : null ,
"incomplete_details" : null ,
"input" : [],
"instructions" : null ,
"max_output_tokens" : null ,
"model" : "gpt-4o-2024-08-06" ,
"output" : [{
"id" : "msg_1234567890" ,
"type" : "message" ,
"role" : "assistant" ,
"content" : [
{
"type" : "refusal" ,
"refusal" : "I'm sorry, I cannot assist with that request."
}
]
}],
"usage" : {
"input_tokens" : 81 ,
"output_tokens" : 11 ,
"total_tokens" : 92 ,
"output_tokens_details" : {
"reasoning_tokens" : 0 ,
}
},
}
如果你的应用使用了用户生成的输入,请确保你的提示词包含有关如何处理输入无法生成有效响应情况的说明。
模型将始终尝试遵循提供的 schema,如果输入与 schema 完全无关,则可能会导致幻觉。
你可以在提示词中加入指令,指定如果模型检测到输入与任务不兼容,则返回空参数或特定的句子。
结构化输出仍可能包含错误。如果你发现错误,请尝试调整指令、在系统指令中提供示例,或将任务拆分为更简单的子任务。有关如何调整输入的更多指导,请参阅 提示词工程指南 有关如何调整输入的更多指导。
为了防止 JSON Schema 与编程语言中相应的类型发生偏差,我们强烈建议使用原生的 Pydantic/zod SDK 支持。
如果你倾向于直接指定 JSON schema,可以添加 CI 规则,在 JSON schema 或底层数据对象被修改时发出警告,或者添加一个 CI 步骤,从类型定义自动生成 JSON Schema(或反向操作)。
你可以使用流式传输来处理正在生成的模型响应或函数调用参数,并将其解析为结构化数据。
这样,你无需等待整个响应完成即可对其进行处理。如果你想逐个显示 JSON 字段,或者在函数调用参数可用时立即对其进行处理,此功能尤为有用。
我们建议依赖 SDK 来处理结构化输出的流式传输。
你可以找到一个关于如何在不使用 SDK 的情况下流式传输函数调用参数的示例 stream 助手在 函数调用指南 .
以下是如何使用 stream helper:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
from typing import List
from pydantic import BaseModel
from openai import OpenAI
class EntitiesModel ( BaseModel ):
attributes: List [ str ]
colors: List [ str ]
animals: List [ str ]
client = OpenAI()
with client.beta.chat.completions.stream(
model= "gpt-4.1" ,
messages=[
{ "role" : "system" , "content" : "Extract entities from the input text" },
{
"role" : "user" ,
"content" : "The quick brown fox jumps over the lazy dog with piercing blue eyes" ,
},
],
response_format=EntitiesModel,
) as stream:
for event in stream:
if event. type == "content.delta" :
if event.parsed is not None :
print ( "content.delta parsed:" , event.parsed)
elif event. type == "content.done" :
print ( "content.done" )
elif event. type == "error" :
print ( "Error in stream:" , event.error)
final_completion = stream.get_final_completion()
print ( "Final completion:" , final_completion) 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
import OpenAI from "openai" ;
import { zodResponseFormat } from "openai/helpers/zod" ;
import { z } from "zod" ;
export const openai = new OpenAI();
const EntitiesSchema = z.object({
attributes : z.array(z.string()),
colors : z.array(z.string()),
animals : z.array(z.string()),
});
const stream = openai.beta.chat.completions
.stream({
model : "gpt-4.1" ,
messages : [
{ role : "system" , content : "Extract entities from the input text" },
{
role : "user" ,
content :
"The quick brown fox jumps over the lazy dog with piercing blue eyes" ,
},
],
response_format : zodResponseFormat(EntitiesSchema, "entities" ),
})
.on( "refusal.done" , () => console .log( "request refused" ))
.on( "content.delta" , ( { snapshot, parsed } ) => {
console .log( "content:" , snapshot);
console .log( "parsed:" , parsed);
console .log();
})
.on( "content.done" , ( props ) => {
console .log(props);
});
await stream.done();
const finalCompletion = await stream.finalChatCompletion();
console .log(finalCompletion); 您还可以在创建深度研究请求时使用 stream 用于解析函数调用参数的辅助工具:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
from pydantic import BaseModel
import openai
from openai import OpenAI
class GetWeather ( BaseModel ):
city: str
country: str
client = OpenAI()
with client.beta.chat.completions.stream(
model= "gpt-4.1" ,
messages=[
{
"role" : "user" ,
"content" : "What's the weather like in SF and London?" ,
},
],
tools=[
openai.pydantic_function_tool(GetWeather, name= "get_weather" ),
],
parallel_tool_calls= True ,
) as stream:
for event in stream:
if event. type == "tool_calls.function.arguments.delta" or event. type == "tool_calls.function.arguments.done" :
print (event)
print (stream.get_final_completion()) 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
import { zodFunction } from "openai/helpers/zod" ;
import OpenAI from "openai/index" ;
import { z } from "zod" ;
const GetWeatherArgs = z.object({
city : z.string(),
country : z.string(),
});
const client = new OpenAI();
const stream = client.beta.chat.completions
.stream({
model : "gpt-4.1" ,
messages : [
{
role : "user" ,
content : "What's the weather like in SF and London?" ,
},
],
tools : [zodFunction({ name : "get_weather" , parameters : GetWeatherArgs })],
})
.on( "tool_calls.function.arguments.delta" , ( props ) =>
console .log( "tool_calls.function.arguments.delta" , props)
)
.on( "tool_calls.function.arguments.done" , ( props ) =>
console .log( "tool_calls.function.arguments.done" , props)
)
.on( "refusal.delta" , ( { delta } ) => {
process.stdout.write(delta);
})
.on( "refusal.done" , () => console .log( "request refused" ));
const completion = await stream.finalChatCompletion();
console .log( "final completion:" , completion);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
from typing import List
from openai import OpenAI
from pydantic import BaseModel
class EntitiesModel ( BaseModel ):
attributes: List [ str ]
colors: List [ str ]
animals: List [ str ]
client = OpenAI()
with client.responses.stream(
model= "gpt-4.1" ,
input =[
{ "role" : "system" , "content" : "Extract entities from the input text" },
{
"role" : "user" ,
"content" : "The quick brown fox jumps over the lazy dog with piercing blue eyes" ,
},
],
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 ( "Completed" )
final_response = stream.get_final_response()
print (final_response) 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
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" ,
input : [
{ role : "user" , content : "What's the weather like in Paris today?" },
],
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 language.
支持的类型
结构化输出支持以下类型:
字符串
数字
布尔值
整数
对象
数组
枚举
anyOf
支持的属性
除了指定属性的类型外,你还可以指定一系列附加约束:
支持 string properties:
pattern — 字符串必须匹配的正则表达式。
format — 字符串的预定义格式。目前支持:
date-time
time
date
duration
email
hostname
ipv4
ipv6
uuid
支持 number properties:
multipleOf — 该数字必须是此值的倍数。
maximum — 该数字必须小于或等于此值。
exclusiveMaximum — 该数字必须小于此值。
minimum — 该数字必须大于或等于此值。
exclusiveMinimum — 该数字必须大于此值。
支持 array properties:
minItems — 该数组必须至少包含此数量的项。
maxItems — 该数组最多包含此数量的项。
以下是关于如何使用这些类型限制的一些示例:
字符串限制
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
{
"name" : "user_data" ,
"strict" : true ,
"schema" : {
"type" : "object" ,
"properties" : {
"name" : {
"type" : "string" ,
"description" : "The name of the user"
},
"username" : {
"type" : "string" ,
"description" : "The username of the user. Must start with @" ,
"pattern" : "^@[a-zA-Z0-9_]+$"
},
"email" : {
"type" : "string" ,
"description" : "The email of the user" ,
"format" : "email"
}
},
"additionalProperties" : false ,
"required" : [
"name" , "username" , "email"
]
}
} 数字限制
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
{
"name" : "weather_data" ,
"strict" : true ,
"schema" : {
"type" : "object" ,
"properties" : {
"location" : {
"type" : "string" ,
"description" : "The location to get the weather for"
},
"unit" : {
"type" : [ "string" , "null" ],
"description" : "The unit to return the temperature in" ,
"enum" : [ "F" , "C" ]
},
"value" : {
"type" : "number" ,
"description" : "The actual temperature value in the location" ,
"minimum" : -130 ,
"maximum" : 130
}
},
"additionalProperties" : false ,
"required" : [
"location" , "unit" , "value"
]
}
}
根对象不得为 anyOf 并且必须是一个对象
请注意,schema 的根级别对象必须是一个对象,并且不得在顶层使用 anyOf。在 Zod(作为一个示例)中出现的一种模式是使用可辨识联合(discriminated union),它会产生一个 anyOf 。因此,如下所示的代码将无法运行:
1
2
3
4
5
6
7
8
9
10
11
12
13
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,
]);
const json = zodResponseFormat(finalSchema, 'final_schema' );
所有字段必须为 required
要使用 Structured Outputs,所有字段或函数参数必须指定为 required.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
{
"name" : "get_weather" ,
"description" : "Fetches the weather in the given location" ,
"strict" : true ,
"parameters" : {
"type" : "object" ,
"properties" : {
"location" : {
"type" : "string" ,
"description" : "The location to get the weather for"
},
"unit" : {
"type" : "string" ,
"description" : "The unit to return the temperature in" ,
"enum" : [ "F" , "C" ]
}
},
"additionalProperties" : false ,
"required" : [ "location" , "unit" ]
}
}
尽管所有字段都必须是必需的(并且模型会为每个参数返回一个值),但可以通过使用带有以下类型的联合类型来模拟可选参数: null.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
{
"name" : "get_weather" ,
"description" : "Fetches the weather in the given location" ,
"strict" : true ,
"parameters" : {
"type" : "object" ,
"properties" : {
"location" : {
"type" : "string" ,
"description" : "The location to get the weather for"
},
"unit" : {
"type" : [ "string" , "null" ],
"description" : "The unit to return the temperature in" ,
"enum" : [ "F" , "C" ]
}
},
"additionalProperties" : false ,
"required" : [
"location" , "unit"
]
}
}
对象在嵌套深度和大小上有限制
一个 schema 最多可包含 5000 个对象属性,且嵌套层级最多为 10 层。
总字符串大小的限制
在一个 schema 中,所有属性名称、定义名称、枚举值和 const 值的总字符串长度不能超过 120,000 个字符。
枚举大小的限制
一个 schema 中的所有枚举属性最多可包含 1000 个枚举值。
对于包含字符串值的单个枚举属性,当枚举值超过 250 个时,所有枚举值的总字符串长度不能超过 15,000 个字符。
additionalProperties: false 必须在对象中设置
additionalProperties 控制是否允许对象包含未在 JSON Schema 中定义的额外键/值。
结构化输出仅支持生成指定的键/值,因此我们要求开发者设置 additionalProperties: false 以选择启用结构化输出。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
{
"name" : "get_weather" ,
"description" : "Fetches the weather in the given location" ,
"strict" : true ,
"schema" : {
"type" : "object" ,
"properties" : {
"location" : {
"type" : "string" ,
"description" : "The location to get the weather for"
},
"unit" : {
"type" : "string" ,
"description" : "The unit to return the temperature in" ,
"enum" : [ "F" , "C" ]
}
},
"additionalProperties" : false ,
"required" : [
"location" , "unit"
]
}
}
键名排序
使用结构化输出时,输出的顺序将与模式中键名的顺序保持一致。
暂不支持某些特定类型的关键字
Composition: allOf, not, dependentRequired, dependentSchemas, if, then, else
对于微调模型,我们还不支持以下功能:
For strings: minLength, maxLength, pattern, format
For numbers: minimum, maximum, multipleOf
For objects: patternProperties
For arrays: minItems, maxItems
如果您通过提供 strict: true 并使用不受支持的 JSON Schema 调用 API,您将收到一个错误。
For anyOf,嵌套模式必须各自符合此子集的有效 JSON Schema
以下是一个受支持的 anyOf 模式示例:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
{
"type" : "object" ,
"properties" : {
"item" : {
"anyOf" : [
{
"type" : "object" ,
"description" : "The user object to insert into the database" ,
"properties" : {
"name" : {
"type" : "string" ,
"description" : "The name of the user"
},
"age" : {
"type" : "number" ,
"description" : "The age of the user"
}
},
"additionalProperties" : false ,
"required" : [
"name" ,
"age"
]
},
{
"type" : "object" ,
"description" : "The address object to insert into the database" ,
"properties" : {
"number" : {
"type" : "string" ,
"description" : "The number of the address. Eg. for 123 main st, this would be 123"
},
"street" : {
"type" : "string" ,
"description" : "The street name. Eg. for 123 main st, this would be main st"
},
"city" : {
"type" : "string" ,
"description" : "The city of the address"
}
},
"additionalProperties" : false ,
"required" : [
"number" ,
"street" ,
"city"
]
}
]
}
},
"additionalProperties" : false ,
"required" : [
"item"
]
}
支持使用定义
您可以使用定义来定义在整个模式中被引用的子模式。以下是一个简单的示例。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
{
"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
}
支持递归模式
使用以下方式的递归模式示例 # to indicate root recursion.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
{
"name" : "ui" ,
"description" : "Dynamically generated UI" ,
"strict" : true ,
"schema" : {
"type" : "object" ,
"properties" : {
"type" : {
"type" : "string" ,
"description" : "The type of the UI component" ,
"enum" : [ "div" , "button" , "header" , "section" , "field" , "form" ]
},
"label" : {
"type" : "string" ,
"description" : "The label of the UI component, used for buttons or form fields"
},
"children" : {
"type" : "array" ,
"description" : "Nested UI components" ,
"items" : {
"$ref" : "#"
}
},
"attributes" : {
"type" : "array" ,
"description" : "Arbitrary attributes for the UI component, suitable for any element" ,
"items" : {
"type" : "object" ,
"properties" : {
"name" : {
"type" : "string" ,
"description" : "The name of the attribute, for example onClick or className"
},
"value" : {
"type" : "string" ,
"description" : "The value of the attribute"
}
},
"additionalProperties" : false ,
"required" : [ "name" , "value" ]
}
}
},
"required" : [ "type" , "label" , "children" , "attributes" ],
"additionalProperties" : false
}
}
使用显式递归的递归模式示例:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
{
"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,但在某些边缘情况下可能并非如此,您需要自行检测并妥善处理。
要开启 Chat Completions 的 JSON 模式,请设置 response_format to { "type": "json_object" }。如果您正在使用函数调用,JSON 模式将始终处于开启状态。
要开启 Responses API 的 JSON 模式,您可以设置 text.format to { "type": "json_object" }。如果您正在使用函数调用,JSON 模式将始终处于开启状态。
重要提示:
在使用 JSON 模式时,你必须始终通过对话中的某条消息(例如系统消息)指示模型生成 JSON。如果不包含生成 JSON 的明确指令,模型可能会生成无休止的空格流,并且请求可能会持续运行,直到达到 token 限制。为了帮助你避免遗忘,如果上下文中没有出现字符串“JSON”,API 将会抛出错误。
JSON 模式不能保证输出符合任何特定 schema,只能保证它是有效的并且能无错解析。你应该使用结构化输出来确保其匹配你的 schema;如果无法做到,则应使用验证库并视情况配合重试,以确保输出符合所需的 schema。
你的应用必须检测并处理模型输出不是完整 JSON 对象的边缘情况(见下文)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
const we_did_not_specify_stop_tokens = true ;
try {
const response = await openai.chat.completions.create({
model : "gpt-3.5-turbo-0125" ,
messages : [
{
role : "system" ,
content : "You are a helpful assistant designed to output JSON." ,
},
{ role : "user" , content : "Who won the world series in 2020? Please respond in the format {winner: ...}" },
],
store : true ,
response_format : { type : "json_object" },
});
if (response.choices[ 0 ].message.finish_reason === "length" ) {
}
if (response.choices[ 0 ].message[ 0 ].refusal) {
console .log(response.choices[ 0 ].message[ 0 ].refusal)
}
if (response.choices[ 0 ].message.finish_reason === "content_filter" ) {
}
if (response.choices[ 0 ].message.finish_reason === "stop" ) {
if (we_did_not_specify_stop_tokens) {
console .log( JSON .parse(response.choices[ 0 ].message.content))
} else {
}
}
} catch (e) {
console .error(e)
} 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
we_did_not_specify_stop_tokens = True
try :
response = client.chat.completions.create(
model= "gpt-3.5-turbo-0125" ,
messages=[
{ "role" : "system" , "content" : "You are a helpful assistant designed to output JSON." },
{ "role" : "user" , "content" : "Who won the world series in 2020? Please respond in the format {winner: ...}" }
],
response_format={ "type" : "json_object" }
)
if response.choices[ 0 ].message.finish_reason == "length" :
pass
if response.choices[ 0 ].message[ 0 ].get( "refusal" ):
print (response.choices[ 0 ].message[ 0 ][ "refusal" ])
if response.choices[ 0 ].message.finish_reason == "content_filter" :
pass
if response.choices[ 0 ].message.finish_reason == "stop" :
if we_did_not_specify_stop_tokens:
print (response.choices[ 0 ].message.content)
else :
pass
except Exception as e:
print (e)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
const we_did_not_specify_stop_tokens = true ;
try {
const response = await openai.responses.create({
model : "gpt-3.5-turbo-0125" ,
input : [
{
role : "system" ,
content : "You are a helpful assistant designed to output JSON." ,
},
{ role : "user" , content : "Who won the world series in 2020? Please respond in the format {winner: ...}" },
],
text : { format : { type : "json_object" } },
});
if (response.status === "incomplete" && response.incomplete_details.reason === "max_output_tokens" ) {
}
if (response.output[ 0 ].content[ 0 ].type === "refusal" ) {
console .log(response.output[ 0 ].content[ 0 ].refusal)
}
if (response.status === "incomplete" && response.incomplete_details.reason === "content_filter" ) {
}
if (response.status === "completed" ) {
if (we_did_not_specify_stop_tokens) {
console .log( JSON .parse(response.output_text))
} else {
}
}
} catch (e) {
console .error(e)
} 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
we_did_not_specify_stop_tokens = True
try :
response = client.responses.create(
model= "gpt-3.5-turbo-0125" ,
input =[
{ "role" : "system" , "content" : "You are a helpful assistant designed to output JSON." },
{ "role" : "user" , "content" : "Who won the world series in 2020? Please respond in the format {winner: ...}" }
],
text={ "format" : { "type" : "json_object" }}
)
if response.status == "incomplete" and response.incomplete_details.reason == "max_output_tokens" :
pass
if response.output[ 0 ].content[ 0 ]. type == "refusal" :
print (response.output[ 0 ].content[ 0 ][ "refusal" ])
if response.status == "incomplete" and response.incomplete_details.reason == "content_filter" :
pass
if response.status == "completed" :
if we_did_not_specify_stop_tokens:
print (response.output_text)
else :
pass
except Exception as e:
print (e)
如需了解更多关于结构化输出的信息,我们建议浏览以下资源: