JSON 是全球应用程序交换数据时最广泛使用的格式之一。
结构化输出(Structured Outputs)是一项确保模型始终生成符合您所提供 JSON 架构 响应的功能,因此您不必担心模型遗漏必需的键或臆造出无效的枚举值。
结构化输出的一些优势包括
可靠的类型安全: 无需验证或重试格式错误的响应
明确的拒绝: 基于安全原因的模型拒绝现在可以通过编程方式检测到
更简单的提示词: 无需使用强硬的提示词来实现一致的格式
除了在 REST API 中支持 JSON 架构外,OpenAI 的 Python 和 JavaScript SDK 也分别通过 Pydantic 和 Zod 轻松定义对象架构。在下文中,您可以看到如何从非结构化文本中提取符合代码中定义架构的信息。
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
结构化输出适用于我们的最新大语言模型 ,从 GPT-4o 开始。像 gpt-4-turbo 及更早期的旧模型可能会改用 JSON 模式 。
何时通过函数调用与通过 response_format 使用结构化输出
何时通过函数调用与通过 text.format 使用结构化输出
OpenAI API 中有两种形式的结构化输出
当使用函数调用 时
当使用 json_schema 响应格式时
当您构建一个连接模型与应用程序功能的应用程序时,函数调用非常有用。
例如,您可以为模型提供查询数据库的函数,从而构建一个能帮助用户处理订单的 AI 助手,或者提供能与 UI 交互的函数。
相反,当您希望在模型响应用户时(而不是调用工具时)指定一个结构化架构,通过 response_format 使用结构化输出更为合适。
例如,如果您正在构建一个数学辅导应用,您可能希望助手使用特定的 JSON 架构来回复用户,这样您就可以生成一个 UI,以不同的方式展示模型输出的不同部分。
简而言之
如果您正在将模型连接到系统中的工具、函数、数据等,那么您应该使用函数调用 - 如果您想在模型响应用户时对其输出进行结构化,则应使用结构化的 response_format
如果您正在将模型连接到系统中的工具、函数、数据等,那么您应该使用函数调用 - 如果您想在模型响应用户时对其输出进行结构化,则应使用结构化的 text.format
本指南的其余部分将重点介绍 Chat Completions API 中非函数调用的使用场景。要了解关于如何在函数调用中使用结构化输出的更多信息,请查看
函数调用
指南。
本指南的其余部分将重点介绍 Responses API 中非函数调用的使用场景。要了解关于如何在函数调用中使用结构化输出的更多信息,请查看
函数调用
指南。
结构化输出是 JSON 模式 的演进版。虽然两者都确保生成有效的 JSON,但只有结构化输出能确保遵循架构。结构化输出和 JSON 模式均在 Responses API、Chat Completions API、Assistants API、微调 API 和 Batch API 中得到支持。
我们建议尽可能始终使用结构化输出代替 JSON 模式。
然而,带有 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-* 模型启用方式 response_format: { type: "json_schema", json_schema: {"strict": true, "schema": ...} }response_format: { type: "json_object" }
结构化输出 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" } }
思维链
思维链
您可以要求模型以结构化、循序渐进的方式输出答案,以引导用户完成解决方案。
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 架构。
注意: 对于微调模型,您首次使用任何架构发起的请求会有额外的延迟,因为我们的 API 需要处理该架构,但后续使用相同架构的请求将不会有额外延迟。其他模型没有此限制。
SDK 对象
首先,您必须定义一个对象或数据结构来表示模型应受约束遵循的 JSON 架构。请参考本指南顶部的示例 。
虽然结构化输出支持 JSON 架构的大部分内容,但出于性能或技术原因,某些功能尚不可用。有关更多详细信息,请参阅此处 。
例如,您可以像这样定义一个对象
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 架构,然后将响应解析为对象。
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 架构的有效响应。
这可能发生在拒绝的情况下(如果模型出于安全原因拒绝回答),或者例如当您达到最大 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 手动架构
首先,您必须设计模型应受约束遵循的 JSON 架构。请参考本指南顶部的示例 。
虽然结构化输出支持 JSON 架构的大部分内容,但出于性能或技术原因,某些功能尚不可用。有关更多详细信息,请参阅此处 。
JSON 架构的建议 为了最大化模型生成的质量,我们建议采取以下措施
清晰且直观地命名键
为结构中的重要键创建清晰的标题和描述
创建并使用评估 (evals) 来确定最适合您用例的结构
要使用结构化输出,只需指定
response_format: { "type" : "json_schema" , "json_schema" : … , "strict" : true }
text: { format : { type : "json_schema" , "strict" : true , "schema" : … } }
例如
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
}
}
}' 注意: 您首次使用任何架构发起的请求会有额外的延迟,因为我们的 API 需要处理该架构,但后续使用相同架构的请求将不会有额外延迟。
在某些情况下,模型可能不会生成符合所提供 JSON 架构的有效响应。
这可能发生在拒绝的情况下(如果模型出于安全原因拒绝回答),或者例如当您达到最大 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 架构。
一旦确认您已收到保证符合所请求架构的 JSON,您现在就可以安全地将其解析为对应的类型。
例如
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 架构。请参考本指南顶部的示例 。
虽然结构化输出支持 JSON 架构的大部分内容,但出于性能或技术原因,某些功能尚不可用。有关更多详细信息,请参阅此处 。
JSON 架构的建议 为了最大化模型生成的质量,我们建议采取以下措施
清晰且直观地命名键
为结构中的重要键创建清晰的标题和描述
创建并使用评估 (evals) 来确定最适合您用例的结构
要使用结构化输出,只需指定
response_format: { "type" : "json_schema" , "json_schema" : … , "strict" : true }
text: { format : { type : "json_schema" , "strict" : true , "schema" : … } }
例如
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
}
}
}' 注意: 您首次使用任何架构发起的请求会有额外的延迟,因为我们的 API 需要处理该架构,但后续使用相同架构的请求将不会有额外延迟。
在某些情况下,模型可能不会生成符合所提供 JSON 架构的有效响应。
这可能发生在拒绝的情况下(如果模型出于安全原因拒绝回答),或者例如当您达到最大 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 架构。
一旦确认您已收到保证符合所请求架构的 JSON,您现在就可以安全地将其解析为对应的类型。
例如
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 的新字段,以指示模型拒绝满足请求。
当 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 ,
}
},
}
如果您的应用正在使用用户生成的输入,请确保您的提示词包含关于如何处理输入无法产生有效响应的情况的说明。
模型将始终尝试遵循提供的架构,如果输入与架构完全不相关,这可能导致幻觉。
如果模型检测到输入与任务不兼容,您可以在提示词中加入说明,指定您希望返回空参数或特定句子。
结构化输出仍可能包含错误。如果您发现错误,请尝试调整说明、在系统指令中提供示例,或将任务拆分为更简单的子任务。有关如何调整输入的更多指导,请参考提示工程指南 。
为了防止您的 JSON 架构与编程语言中的对应类型产生分歧,我们强烈建议使用原生 Pydantic/Zod SDK 支持。
如果您倾向于直接指定 JSON 架构,您可以添加 CI 规则,在 JSON 架构或底层数据对象被编辑时进行标记,或添加一个从类型定义自动生成 JSON 架构(反之亦然)的 CI 步骤。
您可以使用流式传输来处理正在生成的模型响应或函数调用参数,并将它们解析为结构化数据。
这样,您就不必等待整个响应完成即可处理它。如果您想逐个显示 JSON 字段,或者在函数调用参数可用时立即处理它们,这将非常有用。
我们建议依靠 SDK 来处理带有结构化输出的流式传输。
您可以在函数调用指南 中找到关于如何在不使用 SDK stream 助手的情况下流式传输函数调用参数的示例。
以下是如何使用 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
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 架构 语言的子集。
支持的类型
结构化输出支持以下类型
字符串
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 — 数组最多包含此数量的项目。
以下是关于如何使用这些类型限制的一些示例
字符串限制
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 且必须为对象
请注意,架构的根级别对象必须是对象,且不能使用 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 (必需的)
要使用结构化输出,必须将所有字段或函数参数指定为 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"
]
}
}
对象在嵌套深度和大小上有局限性
一个架构最多可包含 5000 个对象属性,嵌套层级最多 10 层。
字符串总大小限制
在架构中,所有属性名、定义名、枚举值和常量值的总字符串长度不能超过 120,000 个字符。
枚举大小限制
一个架构在所有枚举属性中最多可包含 1000 个枚举值。
对于单个具有字符串值的枚举属性,当枚举值超过 250 个时,所有枚举值的总字符串长度不能超过 15,000 个字符。
对象中必须始终设置 additionalProperties: false
additionalProperties 控制对象是否允许包含 JSON 架构中未定义的额外键/值。
结构化输出仅支持生成指定的键/值,因此我们要求开发者设置 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"
]
}
}
键排序
使用结构化输出时,输出生成的顺序将与架构中键的顺序一致。
某些特定于类型的关键字尚不支持
组合: allOf, not, dependentRequired, dependentSchemas, if, then, else
对于微调模型,我们额外不支持以下内容
对于字符串: minLength, maxLength, pattern, format
对于数字: minimum, maximum, multipleOf
对于对象: patternProperties
对于数组: minItems, maxItems
如果您通过提供 strict: true 开启结构化输出并使用不受支持的 JSON 架构调用 API,将会收到错误。
对于 anyOf,嵌套的架构必须各自是符合此子集的有效 JSON 架构
这是一个支持的 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"
]
}
支持定义 (Definitions)
您可以使用定义来定义在整个架构中引用的子架构。以下是一个简单的示例。
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
}
支持递归架构
使用 # 表示根递归的递归架构示例。
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 设置为 { "type": "json_object" }。如果您正在使用函数调用,JSON 模式始终处于开启状态。
要在 Responses API 中开启 JSON 模式,您可以将 text.format 设置为 { "type": "json_object" }。如果您正在使用函数调用,JSON 模式始终处于开启状态。
重要说明
使用 JSON 模式时,您必须始终通过对话中的某条消息(例如通过您的系统消息)指示模型生成 JSON。如果您未包含生成 JSON 的明确说明,模型可能会生成无休止的空白流,并且请求可能会持续运行直到达到 Token 限制。为了帮助确保您不会忘记,如果字符串 “JSON” 没有出现在上下文的某个位置,API 将抛出错误。
JSON 模式不能保证输出匹配任何特定架构,仅保证它是有效的且解析时不会出错。您应使用结构化输出以确保其匹配您的架构,如果无法做到,则应使用验证库并可能采取重试机制,以确保输出匹配您所需的架构。
您的应用程序必须检测并处理可能导致模型输出不是完整 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)
要了解关于结构化输出的更多信息,我们建议浏览以下资源