结构化模型输出
AI translation, not an official translation. Refer to the original for technical details.
On this page
完整文档索引请参见 llms.txt。在页面 URL 后附加
.md即可获取各文档页面的 Markdown 版本。
JSON 是世界上应用程序交换数据最广泛使用的格式之一。
结构化输出(Structured Outputs)是一项确保模型始终生成符合您提供的 JSON Schema 的响应的功能,因此您无需担心模型遗漏必填键,或产生无效枚举值的幻觉。
结构化输出的部分优势包括:
- 可靠的类型安全性: 无需验证或重试格式错误的响应
- 明确的拒绝提示: 基于安全性的模型拒绝现在可通过程序检测
- 更简洁的提示词: 无需措辞强硬的提示词即可实现一致的格式
除了在 REST API 中支持 JSON Schema 外,OpenAI 的 Python 和 JavaScript SDK 也分别通过 Pydantic 和 Zod 使对象模式的定义变得简便。以下示例展示了如何从非结构化文本中提取符合代码中定义的模式的信息。
获取结构化响应
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-6-astra",
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;
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-6-astra",
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
package main
import (
"context"
"fmt"
"github.com/openai/openai-go/v3"
"github.com/openai/openai-go/v3/responses"
)
func main() {
client := openai.NewClient()
schema := map[string]any{
"type": "object",
"properties": map[string]any{
"name": map[string]any{"type": "string"},
"date": map[string]any{"type": "string"},
"participants": map[string]any{"type": "array", "items": map[string]any{"type": "string"}},
},
"required": []string{"name", "date", "participants"},
"additionalProperties": false,
}
response, err := client.Responses.New(context.Background(), responses.ResponseNewParams{
Model: "gpt-6-astra",
Input: responses.ResponseNewParamsInputUnion{OfInputItemList: responses.ResponseInputParam{
responses.ResponseInputItemParamOfMessage(
responses.ResponseInputMessageContentListParam{responses.ResponseInputContentParamOfInputText("Extract the event information.")},
responses.EasyInputMessageRoleSystem,
),
responses.ResponseInputItemParamOfMessage(
responses.ResponseInputMessageContentListParam{responses.ResponseInputContentParamOfInputText("Alice and Bob are going to a science fair on Friday.")},
responses.EasyInputMessageRoleUser,
),
}},
Text: responses.ResponseTextConfigParam{Format: responses.ResponseFormatTextConfigUnionParam{
OfJSONSchema: &responses.ResponseFormatTextJSONSchemaConfigParam{Name: "event", Schema: schema, Strict: openai.Bool(true)},
}},
})
if err != nil {
panic(err)
}
fmt.Println(response.OutputText())
}
import com.openai.client.OpenAIClient;
import com.openai.client.okhttp.OpenAIOkHttpClient;
import com.openai.core.JsonValue;
import com.openai.models.responses.EasyInputMessage;
import com.openai.models.responses.ResponseCreateParams;
import com.openai.models.responses.ResponseFormatTextJsonSchemaConfig;
import com.openai.models.responses.ResponseInputItem;
import com.openai.models.responses.ResponseTextConfig;
import java.util.List;
import java.util.Map;
Map<String, Object> schema =
Map.of(
"type",
"object",
"properties",
Map.of(
"name", Map.of("type", "string"),
"date", Map.of("type", "string"),
"participants", Map.of("type", "array", "items", Map.of("type", "string"))),
"required",
List.of("name", "date", "participants"),
"additionalProperties",
false);
ResponseCreateParams params =
ResponseCreateParams.builder()
.model("gpt-6-astra")
.inputOfResponse(
List.of(
ResponseInputItem.ofEasyInputMessage(
EasyInputMessage.builder()
.role(EasyInputMessage.Role.SYSTEM)
.content("Extract the event information.")
.build()),
ResponseInputItem.ofEasyInputMessage(
EasyInputMessage.builder()
.role(EasyInputMessage.Role.USER)
.content("Alice and Bob are going to a science fair on Friday.")
.build())))
.text(
ResponseTextConfig.builder()
.format(
ResponseFormatTextJsonSchemaConfig.builder()
.name("event")
.strict(true)
.schema(
JsonValue.from(schema)
.convert(ResponseFormatTextJsonSchemaConfig.Schema.class))
.build())
.build())
.build();
client.responses().create(params).output().stream()
.flatMap(item -> item.message().stream())
.flatMap(message -> message.content().stream())
.flatMap(content -> content.outputText().stream())
.forEach(text -> System.out.println(text.text()));
using OpenAI.Responses;
#pragma warning disable OPENAI001
string key = Environment.GetEnvironmentVariable("OPENAI_API_KEY")!;
ResponsesClient client = new(key);
BinaryData schema = BinaryData.FromString(
"""
{
"type": "object",
"properties": {
"name": { "type": "string" },
"date": { "type": "string" },
"participants": {
"type": "array",
"items": { "type": "string" }
}
},
"required": ["name", "date", "participants"],
"additionalProperties": false
}
"""
);
CreateResponseOptions options = new()
{
Model = "gpt-6-astra",
TextOptions = new ResponseTextOptions
{
TextFormat = ResponseTextFormat.CreateJsonSchemaFormat(
"event",
schema,
jsonSchemaIsStrict: true
),
},
};
options.InputItems.Add(
ResponseItem.CreateSystemMessageItem("Extract the event information.")
);
options.InputItems.Add(
ResponseItem.CreateUserMessageItem(
"Alice and Bob are going to a science fair on Friday."
)
);
ResponseResult response = await client.CreateResponseAsync(options);
Console.WriteLine(response.GetOutputText());
require "openai"
client = OpenAI::Client.new
event_schema = {
type: :object,
properties: {
name: {type: :string},
date: {type: :string},
participants: {type: :array, items: {type: :string}}
},
required: %w[name date participants],
additionalProperties: false
}
response = client.responses.create(
model: "gpt-6-astra",
input: [
{role: :system, content: "Extract the event information."},
{role: :user, content: "Alice and Bob are going to a science fair on Friday."}
],
text: {
format: {
type: :json_schema,
name: "event",
strict: true,
schema: event_schema
}
}
)
puts(response.output_text)
支持的模型
结构化输出适用于我们的最新大型语言模型,从 GPT-4o 开始支持。对于新项目,建议使用 gpt-6-astra。较旧的模型如 gpt-4-turbo 及更早版本可改用 JSON 模式。
何时通过函数调用使用结构化输出,何时通过
text.format 使用结构化输出
结构化输出在 OpenAI API 中以两种形式提供:
- 使用函数调用时
- 使用
json_schema响应格式时
当您构建的应用程序需要桥接模型与应用程序功能时,函数调用非常有用。
例如,您可以向模型提供查询数据库的函数,从而构建能够帮助用户处理订单的 AI 助手,或者提供可与 UI 交互的函数。
相反,通过 response_format 使用结构化输出更适合以下场景:当您希望为模型向用户响应时指定结构化模式,而非模型调用工具时。
例如,如果您正在构建一个数学辅导应用程序,您可能希望助手使用特定的 JSON Schema 来响应用户,以便生成能够以不同方式展示模型输出各部分的 UI。
简而言之:
- 如果您将模型连接到系统中的工具、函数、数据等,则应使用函数调用
- 如果您希望在模型响应用户时对其输出进行结构化,则应使用结构化
text.format
本指南的其余部分将重点介绍 Responses API 中的非函数调用使用场景。要了解更多关于如何将结构化输出与函数调用结合使用的内容,请查阅 函数调用 指南。
结构化输出与 JSON 模式
结构化输出是 JSON 模式的进化版本。虽然两者都确保生成有效的 JSON,但只有结构化输出能确保符合模式约束。结构化输出和 JSON 模式均在 Responses API、Chat Completions API、Assistants API、Fine-tuning 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-* 及兼容的 GPT-5 模型 |
| 启用方式 | text: { format: { type: "json_schema", "strict": true, "schema": ... } } | text: { format: { type: "json_object" } } |
示例
思维链
思维链
您可以要求模型以结构化、逐步的方式输出答案,引导用户完成解题过程。
结构化输出用于思维链数学辅导
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-6-astra",
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;
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-6-astra",
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
package main
import (
"context"
"fmt"
"github.com/openai/openai-go/v3"
"github.com/openai/openai-go/v3/responses"
)
func main() {
client := openai.NewClient()
step := map[string]any{
"type": "object",
"properties": map[string]any{
"explanation": map[string]any{"type": "string"},
"output": map[string]any{"type": "string"},
},
"required": []string{"explanation", "output"},
"additionalProperties": false,
}
schema := map[string]any{
"type": "object",
"properties": map[string]any{
"steps": map[string]any{"type": "array", "items": step},
"final_answer": map[string]any{"type": "string"},
},
"required": []string{"steps", "final_answer"},
"additionalProperties": false,
}
response, err := client.Responses.New(context.Background(), responses.ResponseNewParams{
Model: "gpt-6-astra",
Input: responses.ResponseNewParamsInputUnion{OfInputItemList: responses.ResponseInputParam{
responses.ResponseInputItemParamOfMessage(
responses.ResponseInputMessageContentListParam{responses.ResponseInputContentParamOfInputText("You are a helpful math tutor. Guide the user through the solution step by step.")},
responses.EasyInputMessageRoleSystem,
),
responses.ResponseInputItemParamOfMessage(
responses.ResponseInputMessageContentListParam{responses.ResponseInputContentParamOfInputText("how can I solve 8x + 7 = -23")},
responses.EasyInputMessageRoleUser,
),
}},
Text: responses.ResponseTextConfigParam{Format: responses.ResponseFormatTextConfigUnionParam{
OfJSONSchema: &responses.ResponseFormatTextJSONSchemaConfigParam{Name: "math_reasoning", Schema: schema, Strict: openai.Bool(true)},
}},
})
if err != nil {
panic(err)
}
fmt.Println(response.OutputText())
}
import com.openai.client.OpenAIClient;
import com.openai.client.okhttp.OpenAIOkHttpClient;
import com.openai.core.JsonValue;
import com.openai.models.responses.EasyInputMessage;
import com.openai.models.responses.ResponseCreateParams;
import com.openai.models.responses.ResponseFormatTextJsonSchemaConfig;
import com.openai.models.responses.ResponseInputItem;
import com.openai.models.responses.ResponseTextConfig;
import java.util.List;
import java.util.Map;
Map<String, Object> schema =
Map.of(
"type",
"object",
"properties",
Map.of(
"steps",
Map.of(
"type",
"array",
"items",
Map.of(
"type",
"object",
"properties",
Map.of(
"explanation", Map.of("type", "string"),
"output", Map.of("type", "string")),
"required",
List.of("explanation", "output"),
"additionalProperties",
false)),
"final_answer", Map.of("type", "string")),
"required",
List.of("steps", "final_answer"),
"additionalProperties",
false);
ResponseCreateParams params =
ResponseCreateParams.builder()
.model("gpt-6-astra")
.inputOfResponse(
List.of(
ResponseInputItem.ofEasyInputMessage(
EasyInputMessage.builder()
.role(EasyInputMessage.Role.SYSTEM)
.content(
"You are a helpful math tutor. Guide the user through the solution step by step.")
.build()),
ResponseInputItem.ofEasyInputMessage(
EasyInputMessage.builder()
.role(EasyInputMessage.Role.USER)
.content("How can I solve 8x + 7 = -23?")
.build())))
.text(
ResponseTextConfig.builder()
.format(
ResponseFormatTextJsonSchemaConfig.builder()
.name("math_reasoning")
.strict(true)
.schema(
JsonValue.from(schema)
.convert(ResponseFormatTextJsonSchemaConfig.Schema.class))
.build())
.build())
.build();
client.responses().create(params).output().stream()
.flatMap(item -> item.message().stream())
.flatMap(message -> message.content().stream())
.flatMap(content -> content.outputText().stream())
.forEach(text -> System.out.println(text.text()));
using System.Text.Json;
using OpenAI.Responses;
#pragma warning disable OPENAI001
string key = Environment.GetEnvironmentVariable("OPENAI_API_KEY")!;
ResponsesClient client = new(key);
BinaryData schema = BinaryData.FromString(
"""
{
"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
}
"""
);
CreateResponseOptions options = new()
{
Model = "gpt-6-astra",
TextOptions = new ResponseTextOptions
{
TextFormat = ResponseTextFormat.CreateJsonSchemaFormat(
"math_response",
schema,
jsonSchemaIsStrict: true
),
},
};
options.InputItems.Add(ResponseItem.CreateSystemMessageItem("You are a helpful math tutor. Guide the user through the solution step by step."));
options.InputItems.Add(ResponseItem.CreateUserMessageItem("How can I solve 8x + 7 = -23?"));
ResponseResult response = await client.CreateResponseAsync(options);
using JsonDocument parsed = JsonDocument.Parse(response.GetOutputText());
Console.WriteLine(parsed.RootElement);
require "openai"
client = OpenAI::Client.new
step_schema = {
type: :object,
properties: {
explanation: {type: :string},
output: {type: :string}
},
required: %w[explanation output],
additionalProperties: false
}
math_schema = {
type: :object,
properties: {
steps: {type: :array, items: step_schema},
final_answer: {type: :string}
},
required: %w[steps final_answer],
additionalProperties: false
}
response = client.responses.create(
model: "gpt-6-astra",
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",
strict: true,
schema: math_schema
}
}
)
puts(response.output_text)
curl https://api.openai.com/v1/responses \
-H "Authorization: Bearer $OPENAI_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "gpt-6-astra",
"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"
}
结构化数据提取
结构化数据提取
您可以定义结构化字段,从非结构化输入数据(如研究论文)中进行提取。
使用结构化输出从研究论文中提取数据
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-6-astra",
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;
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-6-astra",
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": (
"Attention Is All You Need by Ashish Vaswani, Noam Shazeer, "
"Niki Parmar, Jakob Uszkoreit, Llion Jones, Aidan N. Gomez, "
"Łukasz Kaiser, and Illia Polosukhin. We propose the "
"Transformer, a sequence transduction architecture based "
"entirely on attention. Keywords: transformers, attention, "
"sequence transduction."
),
},
],
text_format=ResearchPaperExtraction,
)
research_paper = response.output_parsed
package main
import (
"context"
"fmt"
"github.com/openai/openai-go/v3"
"github.com/openai/openai-go/v3/responses"
)
const researchPaperText = "Attention Is All You Need by Ashish Vaswani, Noam Shazeer, " +
"Niki Parmar, Jakob Uszkoreit, Llion Jones, Aidan N. Gomez, " +
"Łukasz Kaiser, and Illia Polosukhin. We propose the Transformer, " +
"a sequence transduction architecture based entirely on attention. " +
"Keywords: transformers, attention, sequence transduction."
func main() {
client := openai.NewClient()
schema := map[string]any{
"type": "object",
"properties": map[string]any{
"title": map[string]any{"type": "string"},
"authors": map[string]any{"type": "array", "items": map[string]any{"type": "string"}},
"abstract": map[string]any{"type": "string"},
"keywords": map[string]any{"type": "array", "items": map[string]any{"type": "string"}},
},
"required": []string{"title", "authors", "abstract", "keywords"},
"additionalProperties": false,
}
response, err := client.Responses.New(context.Background(), responses.ResponseNewParams{
Model: "gpt-6-astra",
Input: responses.ResponseNewParamsInputUnion{OfInputItemList: responses.ResponseInputParam{
responses.ResponseInputItemParamOfMessage(
responses.ResponseInputMessageContentListParam{responses.ResponseInputContentParamOfInputText("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.")},
responses.EasyInputMessageRoleSystem,
),
responses.ResponseInputItemParamOfMessage(
responses.ResponseInputMessageContentListParam{responses.ResponseInputContentParamOfInputText(researchPaperText)},
responses.EasyInputMessageRoleUser,
),
}},
Text: responses.ResponseTextConfigParam{Format: responses.ResponseFormatTextConfigUnionParam{
OfJSONSchema: &responses.ResponseFormatTextJSONSchemaConfigParam{Name: "research_paper_extraction", Schema: schema, Strict: openai.Bool(true)},
}},
})
if err != nil {
panic(err)
}
fmt.Println(response.OutputText())
}
import com.openai.client.OpenAIClient;
import com.openai.client.okhttp.OpenAIOkHttpClient;
import com.openai.core.JsonValue;
import com.openai.models.responses.EasyInputMessage;
import com.openai.models.responses.ResponseCreateParams;
import com.openai.models.responses.ResponseFormatTextJsonSchemaConfig;
import com.openai.models.responses.ResponseInputItem;
import com.openai.models.responses.ResponseTextConfig;
import java.util.List;
import java.util.Map;
Map<String, Object> schema =
Map.of(
"type",
"object",
"properties",
Map.of(
"title", Map.of("type", "string"),
"authors", Map.of("type", "array", "items", Map.of("type", "string")),
"abstract", Map.of("type", "string"),
"keywords", Map.of("type", "array", "items", Map.of("type", "string"))),
"required",
List.of("title", "authors", "abstract", "keywords"),
"additionalProperties",
false);
ResponseCreateParams params =
ResponseCreateParams.builder()
.model("gpt-6-astra")
.inputOfResponse(
List.of(
ResponseInputItem.ofEasyInputMessage(
EasyInputMessage.builder()
.role(EasyInputMessage.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.")
.build()),
ResponseInputItem.ofEasyInputMessage(
EasyInputMessage.builder()
.role(EasyInputMessage.Role.USER)
.content(
"Attention Is All You Need by Ashish Vaswani, Noam Shazeer,"
+ " Niki Parmar, Jakob Uszkoreit, Llion Jones, Aidan N. Gomez,"
+ " Łukasz Kaiser, and Illia Polosukhin. We propose the"
+ " Transformer, a"
+ " sequence transduction architecture based entirely on"
+ " attention. Keywords: transformers, attention, sequence"
+ " transduction.")
.build())))
.text(
ResponseTextConfig.builder()
.format(
ResponseFormatTextJsonSchemaConfig.builder()
.name("research_paper_extraction")
.strict(true)
.schema(
JsonValue.from(schema)
.convert(ResponseFormatTextJsonSchemaConfig.Schema.class))
.build())
.build())
.build();
client.responses().create(params).output().stream()
.flatMap(item -> item.message().stream())
.flatMap(message -> message.content().stream())
.flatMap(content -> content.outputText().stream())
.forEach(text -> System.out.println(text.text()));
using System.Text.Json;
using OpenAI.Responses;
#pragma warning disable OPENAI001
string key = Environment.GetEnvironmentVariable("OPENAI_API_KEY")!;
ResponsesClient client = new(key);
BinaryData schema = BinaryData.FromString(
"""
{
"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
}
"""
);
CreateResponseOptions options = new()
{
Model = "gpt-6-astra",
TextOptions = new ResponseTextOptions
{
TextFormat = ResponseTextFormat.CreateJsonSchemaFormat(
"research_paper",
schema,
jsonSchemaIsStrict: true
),
},
};
options.InputItems.Add(ResponseItem.CreateSystemMessageItem("Extract the title, authors, abstract, and keywords from the research paper."));
options.InputItems.Add(
ResponseItem.CreateUserMessageItem(
"""
Attention Is All You Need by Ashish Vaswani, Noam Shazeer,
Niki Parmar, Jakob Uszkoreit, Llion Jones, Aidan N. Gomez,
Łukasz Kaiser, and Illia Polosukhin. We propose the
Transformer, a sequence transduction architecture based
entirely on attention. Keywords: transformers, attention,
sequence transduction.
"""
)
);
ResponseResult response = await client.CreateResponseAsync(options);
using JsonDocument parsed = JsonDocument.Parse(response.GetOutputText());
Console.WriteLine(parsed.RootElement);
require "openai"
client = OpenAI::Client.new
research_paper = <<~TEXT
Attention Is All You Need by Ashish Vaswani, Noam Shazeer, Niki Parmar,
Jakob Uszkoreit, Llion Jones, Aidan N. Gomez, Łukasz Kaiser, and Illia
Polosukhin. We propose the Transformer, a sequence transduction architecture
based entirely on attention. Keywords: transformers, attention, sequence
transduction.
TEXT
paper_schema = {
type: :object,
properties: {
title: {type: :string},
authors: {type: :array, items: {type: :string}},
abstract: {type: :string},
keywords: {type: :array, items: {type: :string}}
},
required: %w[title authors abstract keywords],
additionalProperties: false
}
response = client.responses.create(
model: "gpt-6-astra",
input: [
{
role: :system,
content: "Extract structured data from the supplied research paper text."
},
{role: :user, content: research_paper}
],
text: {
format: {
type: :json_schema,
name: "research_paper_extraction",
strict: true,
schema: paper_schema
}
}
)
puts(response.output_text)
curl https://api.openai.com/v1/responses \
-H "Authorization: Bearer $OPENAI_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "gpt-6-astra",
"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。
使用结构化输出生成 HTML
import OpenAI from "openai";
import { zodTextFormat } from "openai/helpers/zod";
import { z } from "zod";
const openai = new OpenAI();
const UI = z.lazy(() =>
z.object({
type: z.enum(["div", "button", "header", "section", "field", "form"]),
label: z.string(),
children: z.array(UI),
attributes: z.array(
z.object({
name: z.string(),
value: z.string(),
})
),
})
);
const response = await openai.responses.parse({
model: "gpt-6-astra",
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;
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() # This is required to enable recursive types
class Response(BaseModel):
ui: UI
response = client.responses.parse(
model="gpt-6-astra",
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
package main
import (
"context"
"fmt"
"github.com/openai/openai-go/v3"
"github.com/openai/openai-go/v3/responses"
)
func main() {
client := openai.NewClient()
schema := map[string]any{
"type": "object",
"properties": map[string]any{
"type": map[string]any{"type": "string", "enum": []string{"div", "button", "header", "section", "field", "form"}},
"label": map[string]any{"type": "string"},
"children": map[string]any{"type": "array", "items": map[string]any{"$ref": "#"}},
"attributes": map[string]any{"type": "array", "items": map[string]any{"type": "object", "properties": map[string]any{"name": map[string]any{"type": "string"}, "value": map[string]any{"type": "string"}}, "required": []string{"name", "value"}, "additionalProperties": false}},
},
"required": []string{"type", "label", "children", "attributes"},
"additionalProperties": false,
}
response, err := client.Responses.New(context.Background(), responses.ResponseNewParams{
Model: "gpt-6-astra",
Input: responses.ResponseNewParamsInputUnion{OfInputItemList: responses.ResponseInputParam{
responses.ResponseInputItemParamOfMessage(
responses.ResponseInputMessageContentListParam{responses.ResponseInputContentParamOfInputText("You are a UI generator AI. Convert the user input into a UI.")},
responses.EasyInputMessageRoleSystem,
),
responses.ResponseInputItemParamOfMessage(
responses.ResponseInputMessageContentListParam{responses.ResponseInputContentParamOfInputText("Make a User Profile Form")},
responses.EasyInputMessageRoleUser,
),
}},
Text: responses.ResponseTextConfigParam{Format: responses.ResponseFormatTextConfigUnionParam{
OfJSONSchema: &responses.ResponseFormatTextJSONSchemaConfigParam{Name: "ui", Description: openai.String("Dynamically generated UI"), Schema: schema, Strict: openai.Bool(true)},
}},
})
if err != nil {
panic(err)
}
fmt.Println(response.OutputText())
}
import com.openai.client.OpenAIClient;
import com.openai.client.okhttp.OpenAIOkHttpClient;
import com.openai.core.JsonValue;
import com.openai.models.responses.EasyInputMessage;
import com.openai.models.responses.ResponseCreateParams;
import com.openai.models.responses.ResponseFormatTextJsonSchemaConfig;
import com.openai.models.responses.ResponseInputItem;
import com.openai.models.responses.ResponseTextConfig;
import java.util.List;
import java.util.Map;
ResponseCreateParams params =
ResponseCreateParams.builder()
.model("gpt-6-astra")
.inputOfResponse(
List.of(
ResponseInputItem.ofEasyInputMessage(
EasyInputMessage.builder()
.role(EasyInputMessage.Role.SYSTEM)
.content("Convert the user request into a UI definition.")
.build()),
ResponseInputItem.ofEasyInputMessage(
EasyInputMessage.builder()
.role(EasyInputMessage.Role.USER)
.content("Make a user profile form.")
.build())))
.text(
ResponseTextConfig.builder()
.format(
ResponseFormatTextJsonSchemaConfig.builder()
.name("ui")
.description("A dynamically generated UI")
.strict(true)
.schema(
ResponseFormatTextJsonSchemaConfig.Schema.builder()
.putAdditionalProperty("type", JsonValue.from("object"))
.putAdditionalProperty(
"properties",
JsonValue.from(
Map.of(
"type",
Map.of(
"type",
"string",
"enum",
List.of(
"div", "button", "header", "section",
"field", "form")),
"label", Map.of("type", "string"),
"children",
Map.of(
"type",
"array",
"items",
Map.of("$ref", "#")),
"attributes",
Map.of(
"type",
"array",
"items",
Map.of(
"type",
"object",
"properties",
Map.of(
"name", Map.of("type", "string"),
"value", Map.of("type", "string")),
"required",
List.of("name", "value"),
"additionalProperties",
false)))))
.putAdditionalProperty(
"required",
JsonValue.from(
List.of("type", "label", "children", "attributes")))
.putAdditionalProperty(
"additionalProperties", JsonValue.from(false))
.build())
.build())
.build())
.build();
client.responses().create(params).output().stream()
.flatMap(item -> item.message().stream())
.flatMap(message -> message.content().stream())
.flatMap(content -> content.outputText().stream())
.forEach(text -> System.out.println(text.text()));
using System.Text.Json;
using OpenAI.Responses;
#pragma warning disable OPENAI001
string key = Environment.GetEnvironmentVariable("OPENAI_API_KEY")!;
ResponsesClient client = new(key);
BinaryData schema = BinaryData.FromString(
"""
{
"type": "object",
"properties": {
"ui": { "$ref": "#/$defs/component" }
},
"required": ["ui"],
"additionalProperties": false,
"$defs": {
"component": {
"type": "object",
"properties": {
"type": { "type": "string", "enum": ["div", "button", "header", "section", "field", "form"] },
"label": { "type": "string" },
"children": { "type": "array", "items": { "$ref": "#/$defs/component" } },
"attributes": {
"type": "array",
"items": {
"type": "object",
"properties": { "name": { "type": "string" }, "value": { "type": "string" } },
"required": ["name", "value"],
"additionalProperties": false
}
}
},
"required": ["type", "label", "children", "attributes"],
"additionalProperties": false
}
}
}
"""
);
CreateResponseOptions options = new()
{
Model = "gpt-6-astra",
TextOptions = new ResponseTextOptions
{
TextFormat = ResponseTextFormat.CreateJsonSchemaFormat(
"ui",
schema,
jsonSchemaIsStrict: true
),
},
};
options.InputItems.Add(ResponseItem.CreateSystemMessageItem("You are a UI generator. Convert the user request into a component tree."));
options.InputItems.Add(ResponseItem.CreateUserMessageItem("Make a User Profile Form"));
ResponseResult response = await client.CreateResponseAsync(options);
using JsonDocument parsed = JsonDocument.Parse(response.GetOutputText());
Console.WriteLine(parsed.RootElement);
require "openai"
client = OpenAI::Client.new
ui_schema = {
type: :object,
properties: {
type: {
type: :string,
enum: %w[div button header section field form]
},
label: {type: :string},
children: {type: :array, items: {"$ref" => "#"}},
attributes: {
type: :array,
items: {
type: :object,
properties: {
name: {type: :string},
value: {type: :string}
},
required: %w[name value],
additionalProperties: false
}
}
},
required: %w[type label children attributes],
additionalProperties: false
}
response = client.responses.create(
model: "gpt-6-astra",
input: [
{role: :system, content: "Convert the user request into a UI definition."},
{role: :user, content: "Make a user profile form."}
],
text: {
format: {
type: :json_schema,
name: "ui",
description: "A dynamically generated UI",
strict: true,
schema: ui_schema
}
}
)
puts(response.output_text)
curl https://api.openai.com/v1/responses \
-H "Authorization: Bearer $OPENAI_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "gpt-6-astra",
"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"
}
]
}
内容审核
内容审核
您可以对输入内容进行多类别分类,这是一种常见的内容审核方式。
使用结构化输出进行内容审核
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-6-astra",
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;
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-6-astra",
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
package main
import (
"context"
"fmt"
"github.com/openai/openai-go/v3"
"github.com/openai/openai-go/v3/responses"
)
func main() {
client := openai.NewClient()
schema := contentComplianceSchema()
response, err := client.Responses.New(context.Background(), responses.ResponseNewParams{
Model: "gpt-6-astra",
Input: responses.ResponseNewParamsInputUnion{OfInputItemList: responses.ResponseInputParam{
responses.ResponseInputItemParamOfMessage("Determine if the user input violates specific guidelines and explain if they do.", responses.EasyInputMessageRoleSystem),
responses.ResponseInputItemParamOfMessage("How do I prepare for a job interview?", responses.EasyInputMessageRoleUser),
}},
Text: responses.ResponseTextConfigParam{Format: responses.ResponseFormatTextConfigUnionParam{
OfJSONSchema: &responses.ResponseFormatTextJSONSchemaConfigParam{
Name: "content_compliance", Description: openai.String("Determines if content is violating specific moderation rules"), Schema: schema, Strict: openai.Bool(true),
},
}},
})
if err != nil {
panic(err)
}
fmt.Println(response.OutputText())
}
func contentComplianceSchema() map[string]any {
return map[string]any{
"type": "object",
"properties": map[string]any{
"is_violating": map[string]any{"type": "boolean", "description": "Indicates if the content is violating guidelines"},
"category": map[string]any{"type": []string{"string", "null"}, "description": "Type of violation, if the content is violating guidelines. Null otherwise.", "enum": []any{"violence", "sexual", "self_harm", nil}},
"explanation_if_violating": map[string]any{"type": []string{"string", "null"}, "description": "Explanation of why the content is violating"},
},
"required": []string{"is_violating", "category", "explanation_if_violating"},
"additionalProperties": false,
}
}
import com.openai.client.OpenAIClient;
import com.openai.client.okhttp.OpenAIOkHttpClient;
import com.openai.core.JsonValue;
import com.openai.models.responses.EasyInputMessage;
import com.openai.models.responses.ResponseCreateParams;
import com.openai.models.responses.ResponseFormatTextJsonSchemaConfig;
import com.openai.models.responses.ResponseInputItem;
import com.openai.models.responses.ResponseTextConfig;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
Map<String, Object> schema =
Map.of(
"type",
"object",
"properties",
Map.of(
"is_violating",
Map.of(
"type", "boolean",
"description", "Whether the content violates the guidelines"),
"category",
Map.of(
"type", List.of("string", "null"),
"enum", Arrays.asList("violence", "sexual", "self_harm", null),
"description", "The violation category, or null when content is allowed"),
"explanation_if_violating",
Map.of(
"type",
List.of("string", "null"),
"description",
"Why the content violates the guidelines, or null")),
"required",
List.of("is_violating", "category", "explanation_if_violating"),
"additionalProperties",
false);
ResponseCreateParams params =
ResponseCreateParams.builder()
.model("gpt-6-astra")
.inputOfResponse(
List.of(
ResponseInputItem.ofEasyInputMessage(
EasyInputMessage.builder()
.role(EasyInputMessage.Role.SYSTEM)
.content(
"Determine whether the user input violates the guidelines and explain any violation.")
.build()),
ResponseInputItem.ofEasyInputMessage(
EasyInputMessage.builder()
.role(EasyInputMessage.Role.USER)
.content("How do I prepare for a job interview?")
.build())))
.text(
ResponseTextConfig.builder()
.format(
ResponseFormatTextJsonSchemaConfig.builder()
.name("content_compliance")
.description("Determines whether content violates moderation rules")
.strict(true)
.schema(
JsonValue.from(schema)
.convert(ResponseFormatTextJsonSchemaConfig.Schema.class))
.build())
.build())
.build();
client.responses().create(params).output().stream()
.flatMap(item -> item.message().stream())
.flatMap(message -> message.content().stream())
.flatMap(content -> content.outputText().stream())
.forEach(text -> System.out.println(text.text()));
using System.Text.Json;
using OpenAI.Responses;
#pragma warning disable OPENAI001
string key = Environment.GetEnvironmentVariable("OPENAI_API_KEY")!;
ResponsesClient client = new(key);
BinaryData schema = BinaryData.FromString(
"""
{
"type": "object",
"properties": {
"is_violating": { "type": "boolean" },
"category": {
"type": ["string", "null"],
"enum": ["violence", "sexual", "self_harm", null]
},
"explanation_if_violating": { "type": ["string", "null"] }
},
"required": ["is_violating", "category", "explanation_if_violating"],
"additionalProperties": false
}
"""
);
CreateResponseOptions options = new()
{
Model = "gpt-6-astra",
TextOptions = new ResponseTextOptions
{
TextFormat = ResponseTextFormat.CreateJsonSchemaFormat(
"content_compliance",
schema,
jsonSchemaIsStrict: true
),
},
};
options.InputItems.Add(ResponseItem.CreateSystemMessageItem("Determine whether the user input violates content guidelines."));
options.InputItems.Add(ResponseItem.CreateUserMessageItem("How do I prepare for a job interview?"));
ResponseResult response = await client.CreateResponseAsync(options);
using JsonDocument parsed = JsonDocument.Parse(response.GetOutputText());
Console.WriteLine(parsed.RootElement);
require "openai"
client = OpenAI::Client.new
compliance_schema = {
type: :object,
properties: {
is_violating: {
type: :boolean,
description: "Whether the content violates the guidelines"
},
category: {
type: %i[string null],
enum: ["violence", "sexual", "self_harm", nil],
description: "The violation category, or null when the content is allowed"
},
explanation_if_violating: {
type: %i[string null],
description: "Why the content violates the guidelines, or null"
}
},
required: %w[is_violating category explanation_if_violating],
additionalProperties: false
}
response = client.responses.create(
model: "gpt-6-astra",
input: [
{
role: :system,
content: "Determine whether the user input violates the guidelines and explain any violation."
},
{role: :user, content: "How do I prepare for a job interview?"}
],
text: {
format: {
type: :json_schema,
name: "content_compliance",
description: "Determines whether content violates moderation rules",
strict: true,
schema: compliance_schema
}
}
)
puts(response.output_text)
curl https://api.openai.com/v1/responses \
-H "Authorization: Bearer $OPENAI_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "gpt-6-astra",
"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
}
如何将结构化输出与 text.format 配合使用
第一步:定义您的 Schema
首先,您需要设计模型应遵循的 JSON Schema。请参考本指南顶部的示例。
虽然结构化输出支持 JSON Schema 的大部分功能,但出于性能或技术原因,部分功能不可用。详情请参见此处。
JSON Schema 使用建议
为了最大限度地提高模型生成质量,我们建议以下几点:
- 清晰直观地命名键
- 为结构中的重要键创建清晰的标题和描述
- 创建并使用评估(evals)来确定最适合您用例的结构
第二步:在 API 调用中提供您的 Schema
要使用结构化输出,只需指定
text: { format: { type: "json_schema", "strict": true, "schema": … } }
例如:
const response = await openai.responses.create({
model: "gpt-6-astra",
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);
response = client.responses.create(
model="gpt-6-astra",
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)
package main
import (
"context"
"fmt"
"github.com/openai/openai-go/v3"
"github.com/openai/openai-go/v3/responses"
)
func main() {
client := openai.NewClient()
response, err := client.Responses.New(context.Background(), responses.ResponseNewParams{
Model: "gpt-6-astra",
Input: responses.ResponseNewParamsInputUnion{OfInputItemList: responses.ResponseInputParam{
responses.ResponseInputItemParamOfMessage(
responses.ResponseInputMessageContentListParam{responses.ResponseInputContentParamOfInputText("You are a helpful math tutor. Guide the user through the solution step by step.")},
responses.EasyInputMessageRoleSystem,
),
responses.ResponseInputItemParamOfMessage(
responses.ResponseInputMessageContentListParam{responses.ResponseInputContentParamOfInputText("how can I solve 8x + 7 = -23")},
responses.EasyInputMessageRoleUser,
),
}},
Text: responses.ResponseTextConfigParam{Format: responses.ResponseFormatTextConfigUnionParam{
OfJSONSchema: &responses.ResponseFormatTextJSONSchemaConfigParam{Name: "math_response", Schema: mathSchema(), Strict: openai.Bool(true)},
}},
})
if err != nil {
panic(err)
}
fmt.Println(response.OutputText())
}
func mathSchema() map[string]any {
return map[string]any{
"type": "object",
"properties": map[string]any{
"steps": map[string]any{"type": "array", "items": map[string]any{"type": "object", "properties": map[string]any{"explanation": map[string]any{"type": "string"}, "output": map[string]any{"type": "string"}}, "required": []string{"explanation", "output"}, "additionalProperties": false}},
"final_answer": map[string]any{"type": "string"},
},
"required": []string{"steps", "final_answer"},
"additionalProperties": false,
}
}
import com.openai.client.OpenAIClient;
import com.openai.client.okhttp.OpenAIOkHttpClient;
import com.openai.core.JsonValue;
import com.openai.models.responses.EasyInputMessage;
import com.openai.models.responses.ResponseCreateParams;
import com.openai.models.responses.ResponseFormatTextJsonSchemaConfig;
import com.openai.models.responses.ResponseInputItem;
import com.openai.models.responses.ResponseTextConfig;
import java.util.List;
import java.util.Map;
Map<String, Object> schema =
Map.of(
"type",
"object",
"properties",
Map.of(
"steps",
Map.of(
"type",
"array",
"items",
Map.of(
"type",
"object",
"properties",
Map.of(
"explanation", Map.of("type", "string"),
"output", Map.of("type", "string")),
"required",
List.of("explanation", "output"),
"additionalProperties",
false)),
"final_answer", Map.of("type", "string")),
"required",
List.of("steps", "final_answer"),
"additionalProperties",
false);
ResponseCreateParams params =
ResponseCreateParams.builder()
.model("gpt-6-astra")
.inputOfResponse(
List.of(
ResponseInputItem.ofEasyInputMessage(
EasyInputMessage.builder()
.role(EasyInputMessage.Role.SYSTEM)
.content(
"You are a helpful math tutor. Guide the user through the solution step by step.")
.build()),
ResponseInputItem.ofEasyInputMessage(
EasyInputMessage.builder()
.role(EasyInputMessage.Role.USER)
.content("How can I solve 8x + 7 = -23?")
.build())))
.text(
ResponseTextConfig.builder()
.format(
ResponseFormatTextJsonSchemaConfig.builder()
.name("math_response")
.strict(true)
.schema(
JsonValue.from(schema)
.convert(ResponseFormatTextJsonSchemaConfig.Schema.class))
.build())
.build())
.build();
client.responses().create(params).output().stream()
.flatMap(item -> item.message().stream())
.flatMap(message -> message.content().stream())
.flatMap(content -> content.outputText().stream())
.forEach(text -> System.out.println(text.text()));
using System.Text.Json;
using OpenAI.Responses;
#pragma warning disable OPENAI001
string key = Environment.GetEnvironmentVariable("OPENAI_API_KEY")!;
ResponsesClient client = new(key);
BinaryData schema = BinaryData.FromString(
"""
{
"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
}
"""
);
CreateResponseOptions options = new()
{
Model = "gpt-6-astra",
TextOptions = new ResponseTextOptions
{
TextFormat = ResponseTextFormat.CreateJsonSchemaFormat(
"math_response",
schema,
jsonSchemaIsStrict: true
),
},
};
options.InputItems.Add(ResponseItem.CreateSystemMessageItem("You are a helpful math tutor. Guide the user through the solution step by step."));
options.InputItems.Add(ResponseItem.CreateUserMessageItem("How can I solve 8x + 7 = -23?"));
ResponseResult response = await client.CreateResponseAsync(options);
using JsonDocument parsed = JsonDocument.Parse(response.GetOutputText());
Console.WriteLine(parsed.RootElement);
require "openai"
client = OpenAI::Client.new
math_schema = {
type: :object,
properties: {
steps: {
type: :array,
items: {
type: :object,
properties: {
explanation: {type: :string},
output: {type: :string}
},
required: %w[explanation output],
additionalProperties: false
}
},
final_answer: {type: :string}
},
required: %w[steps final_answer],
additionalProperties: false
}
response = client.responses.create(
model: "gpt-6-astra",
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: math_schema
}
}
)
puts(response.output_text)
curl https://api.openai.com/v1/responses \
-H "Authorization: Bearer $OPENAI_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "gpt-6-astra",
"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
}
}
}'
注意: 您使用任何 Schema 发出的第一个请求会有额外的延迟,因为我们的 API 需要处理该 Schema,但后续使用相同 Schema 的请求不会有额外延迟。
第三步:处理边界情况
在某些情况下,模型可能无法生成与所提供 JSON Schema 匹配的有效响应。
这可能发生在以下情况:拒绝回答(如果模型出于安全原因拒绝回答),或者例如达到最大 token 限制导致响应不完整。
try {
const response = await openai.responses.create({
model: "gpt-6-astra",
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"
) {
// Handle the case where the model did not return a complete response
throw new Error("Incomplete response");
}
const message = response.output.find((item) => item.type === "message");
const math_response = message?.content[0];
if (!math_response) {
throw new Error("No response content");
}
if (math_response.type === "refusal") {
// handle 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) {
// Handle edge cases
console.error(e);
}
try:
response = client.responses.create(
model="gpt-6-astra",
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,
},
},
},
max_output_tokens=50,
)
if (
response.status == "incomplete"
and response.incomplete_details.reason == "max_output_tokens"
):
raise Exception("Incomplete response")
message = next((item for item in response.output if item.type == "message"), None)
math_response = message.content[0] if message and message.content else None
if not math_response:
raise Exception("No response content")
if math_response.type == "refusal":
print(math_response.refusal)
elif math_response.type == "output_text":
print(math_response.text)
else:
raise Exception("No response content")
except Exception as e:
# handle errors like finish_reason, refusal, content_filter, etc.
print(e)
package main
import (
"context"
"errors"
"fmt"
"github.com/openai/openai-go/v3"
"github.com/openai/openai-go/v3/responses"
)
func main() {
client := openai.NewClient()
response, err := client.Responses.New(context.Background(), responses.ResponseNewParams{
Model: "gpt-6-astra",
Input: responses.ResponseNewParamsInputUnion{OfInputItemList: responses.ResponseInputParam{
responses.ResponseInputItemParamOfMessage(
responses.ResponseInputMessageContentListParam{responses.ResponseInputContentParamOfInputText("You are a helpful math tutor. Guide the user through the solution step by step.")},
responses.EasyInputMessageRoleSystem,
),
responses.ResponseInputItemParamOfMessage(
responses.ResponseInputMessageContentListParam{responses.ResponseInputContentParamOfInputText("how can I solve 8x + 7 = -23")},
responses.EasyInputMessageRoleUser,
),
}},
MaxOutputTokens: openai.Int(1024),
Text: responses.ResponseTextConfigParam{Format: responses.ResponseFormatTextConfigUnionParam{
OfJSONSchema: &responses.ResponseFormatTextJSONSchemaConfigParam{Name: "math_response", Schema: mathSchema(), Strict: openai.Bool(true)},
}},
})
if err != nil {
panic(err)
}
if response.Status == "incomplete" {
panic(errors.New("incomplete response"))
}
for _, output := range response.Output {
if output.Type != "message" {
continue
}
for _, content := range output.AsMessage().Content {
if content.Type == "refusal" {
fmt.Println(content.AsRefusal().Refusal)
return
}
if content.Type == "output_text" {
fmt.Println(content.AsOutputText().Text)
return
}
}
}
panic(errors.New("no response content"))
}
func mathSchema() map[string]any {
return map[string]any{
"type": "object",
"properties": map[string]any{
"steps": map[string]any{"type": "array", "items": map[string]any{"type": "object", "properties": map[string]any{"explanation": map[string]any{"type": "string"}, "output": map[string]any{"type": "string"}}, "required": []string{"explanation", "output"}, "additionalProperties": false}},
"final_answer": map[string]any{"type": "string"},
},
"required": []string{"steps", "final_answer"},
"additionalProperties": false,
}
}
import com.openai.client.OpenAIClient;
import com.openai.client.okhttp.OpenAIOkHttpClient;
import com.openai.core.JsonValue;
import com.openai.models.responses.EasyInputMessage;
import com.openai.models.responses.ResponseCreateParams;
import com.openai.models.responses.ResponseFormatTextJsonSchemaConfig;
import com.openai.models.responses.ResponseInputItem;
import com.openai.models.responses.ResponseStatus;
import com.openai.models.responses.ResponseTextConfig;
import java.util.List;
import java.util.Map;
ResponseCreateParams params =
ResponseCreateParams.builder()
.model("gpt-6-astra")
.inputOfResponse(
List.of(
ResponseInputItem.ofEasyInputMessage(
EasyInputMessage.builder()
.role(EasyInputMessage.Role.SYSTEM)
.content(
"You are a helpful math tutor. Guide the user through the solution step by step.")
.build()),
ResponseInputItem.ofEasyInputMessage(
EasyInputMessage.builder()
.role(EasyInputMessage.Role.USER)
.content("How can I solve 8x + 7 = -23?")
.build())))
.text(
ResponseTextConfig.builder()
.format(
ResponseFormatTextJsonSchemaConfig.builder()
.name("math_response")
.strict(true)
.schema(
ResponseFormatTextJsonSchemaConfig.Schema.builder()
.putAdditionalProperty("type", JsonValue.from("object"))
.putAdditionalProperty(
"properties",
JsonValue.from(
Map.of(
"steps",
Map.of(
"type",
"array",
"items",
Map.of(
"type",
"object",
"properties",
Map.of(
"explanation",
Map.of("type", "string"),
"output",
Map.of("type", "string")),
"required",
List.of("explanation", "output"),
"additionalProperties",
false)),
"final_answer",
Map.of("type", "string"))))
.putAdditionalProperty(
"required",
JsonValue.from(List.of("steps", "final_answer")))
.putAdditionalProperty(
"additionalProperties", JsonValue.from(false))
.build())
.build())
.build())
.maxOutputTokens(1_024L)
.build();
var response = client.responses().create(params);
if (response.status().filter(ResponseStatus.INCOMPLETE::equals).isPresent()) {
throw new IllegalStateException("Incomplete response");
}
var content =
response.output().stream()
.flatMap(item -> item.message().stream())
.flatMap(message -> message.content().stream())
.findFirst()
.orElseThrow(() -> new IllegalStateException("No response content"));
if (content.refusal().isPresent()) {
System.out.println(content.refusal().orElseThrow().refusal());
} else {
System.out.println(
content
.outputText()
.orElseThrow(() -> new IllegalStateException("No response content"))
.text());
}
using OpenAI.Responses;
#pragma warning disable OPENAI001
string key = Environment.GetEnvironmentVariable("OPENAI_API_KEY")!;
ResponsesClient client = new(key);
BinaryData schema = BinaryData.FromString(
"""
{
"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
}
"""
);
CreateResponseOptions options = new()
{
Model = "gpt-6-astra",
MaxOutputTokenCount = 300,
TextOptions = new ResponseTextOptions
{
TextFormat = ResponseTextFormat.CreateJsonSchemaFormat(
"math_response",
schema,
jsonSchemaIsStrict: true
),
},
};
options.InputItems.Add(ResponseItem.CreateSystemMessageItem("You are a helpful math tutor. Guide the user through the solution step by step."));
options.InputItems.Add(ResponseItem.CreateUserMessageItem("How can I solve 8x + 7 = -23?"));
ResponseResult response = await client.CreateResponseAsync(options);
if (
response.Status == ResponseStatus.Incomplete
&& response.IncompleteStatusDetails?.Reason == ResponseIncompleteStatusReason.MaxOutputTokens
)
{
throw new InvalidOperationException("The structured response was incomplete.");
}
if (
response.Status == ResponseStatus.Incomplete
&& response.IncompleteStatusDetails?.Reason == ResponseIncompleteStatusReason.ContentFilter
)
{
throw new InvalidOperationException("The structured response was interrupted by the content filter.");
}
MessageResponseItem message = response.OutputItems.OfType<MessageResponseItem>().FirstOrDefault()
?? throw new InvalidOperationException("The response did not include an output message.");
ResponseContentPart content = message.Content.FirstOrDefault()
?? throw new InvalidOperationException("The response did not include output content.");
Console.WriteLine(
content.Kind == ResponseContentPartKind.Refusal ? content.Refusal : content.Text
);
require "openai"
client = OpenAI::Client.new
step_schema = {
type: :object,
properties: {
explanation: {type: :string},
output: {type: :string}
},
required: %w[explanation output],
additionalProperties: false
}
math_schema = {
type: :object,
properties: {
steps: {type: :array, items: step_schema},
final_answer: {type: :string}
},
required: %w[steps final_answer],
additionalProperties: false
}
response = client.responses.create(
model: "gpt-6-astra",
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: 1_024,
text: {
format: {
type: :json_schema,
name: "math_response",
strict: true,
schema: math_schema
}
}
)
if response.status == OpenAI::Responses::ResponseStatus::INCOMPLETE
raise "Incomplete response"
end
message = response.output.find do |item|
item.is_a?(OpenAI::Models::Responses::ResponseOutputMessage)
end
unless message.is_a?(OpenAI::Models::Responses::ResponseOutputMessage)
raise "No response message"
end
content = message.content.fetch(0)
if content.is_a?(OpenAI::Models::Responses::ResponseOutputRefusal)
puts(content.refusal)
else
puts(content.text)
end
结构化输出中的拒绝响应
在将结构化输出与用户生成的输入一起使用时,OpenAI 模型偶尔可能会出于安全原因拒绝完成请求。由于拒绝响应不一定遵循您在 response_format 中提供的 Schema,API 响应将包含一个名为 refusal 的新字段,以表明模型拒绝了该请求。
当 refusal 属性出现在您的输出对象中时,您可以在 UI 中展示该拒绝信息,或在处理响应的代码中加入条件逻辑,以处理请求被拒绝的情况。
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-6-astra",
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_response"),
},
});
for (const output of response.output) {
if (output.type !== "message") {
continue;
}
for (const item of output.content) {
if (item.type == "refusal") {
// If the model refuses to respond, you will get a refusal message
console.log(item.refusal);
continue;
}
if (!item.parsed) {
throw new Error("Could not parse response");
}
console.log(item.parsed);
}
}
class Step(BaseModel):
explanation: str
output: str
class MathReasoning(BaseModel):
steps: list[Step]
final_answer: str
response = client.responses.parse(
model="gpt-6-astra",
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,
)
for output in response.output:
if output.type != "message":
continue
for item in output.content:
if item.type == "refusal":
# If the model refuses to respond, you will get a refusal message
print(item.refusal)
continue
if not item.parsed:
raise Exception("Could not parse response")
print(item.parsed)
package main
import (
"context"
"fmt"
"github.com/openai/openai-go/v3"
"github.com/openai/openai-go/v3/responses"
)
func main() {
client := openai.NewClient()
response, err := client.Responses.New(context.Background(), responses.ResponseNewParams{
Model: "gpt-6-astra",
Input: responses.ResponseNewParamsInputUnion{OfInputItemList: responses.ResponseInputParam{
responses.ResponseInputItemParamOfMessage(
responses.ResponseInputMessageContentListParam{responses.ResponseInputContentParamOfInputText("You are a helpful math tutor. Guide the user through the solution step by step.")},
responses.EasyInputMessageRoleSystem,
),
responses.ResponseInputItemParamOfMessage(
responses.ResponseInputMessageContentListParam{responses.ResponseInputContentParamOfInputText("how can I solve 8x + 7 = -23")},
responses.EasyInputMessageRoleUser,
),
}},
Text: responses.ResponseTextConfigParam{Format: responses.ResponseFormatTextConfigUnionParam{
OfJSONSchema: &responses.ResponseFormatTextJSONSchemaConfigParam{Name: "math_response", Schema: mathSchema(), Strict: openai.Bool(true)},
}},
})
if err != nil {
panic(err)
}
for _, output := range response.Output {
if output.Type != "message" {
continue
}
for _, content := range output.AsMessage().Content {
if content.Type == "refusal" {
fmt.Println(content.AsRefusal().Refusal)
continue
}
fmt.Println(content.AsOutputText().Text)
}
}
}
func mathSchema() map[string]any {
return map[string]any{
"type": "object",
"properties": map[string]any{
"steps": map[string]any{"type": "array", "items": map[string]any{"type": "object", "properties": map[string]any{"explanation": map[string]any{"type": "string"}, "output": map[string]any{"type": "string"}}, "required": []string{"explanation", "output"}, "additionalProperties": false}},
"final_answer": map[string]any{"type": "string"},
},
"required": []string{"steps", "final_answer"},
"additionalProperties": false,
}
}
import com.openai.client.OpenAIClient;
import com.openai.client.okhttp.OpenAIOkHttpClient;
import com.openai.core.JsonValue;
import com.openai.models.responses.EasyInputMessage;
import com.openai.models.responses.ResponseCreateParams;
import com.openai.models.responses.ResponseFormatTextJsonSchemaConfig;
import com.openai.models.responses.ResponseInputItem;
import com.openai.models.responses.ResponseTextConfig;
import java.util.List;
import java.util.Map;
Map<String, Object> schema =
Map.of(
"type",
"object",
"properties",
Map.of(
"steps",
Map.of(
"type",
"array",
"items",
Map.of(
"type",
"object",
"properties",
Map.of(
"explanation", Map.of("type", "string"),
"output", Map.of("type", "string")),
"required",
List.of("explanation", "output"),
"additionalProperties",
false)),
"final_answer", Map.of("type", "string")),
"required",
List.of("steps", "final_answer"),
"additionalProperties",
false);
ResponseCreateParams params =
ResponseCreateParams.builder()
.model("gpt-6-astra")
.inputOfResponse(
List.of(
ResponseInputItem.ofEasyInputMessage(
EasyInputMessage.builder()
.role(EasyInputMessage.Role.SYSTEM)
.content(
"You are a helpful math tutor. Guide the user through the solution step by step.")
.build()),
ResponseInputItem.ofEasyInputMessage(
EasyInputMessage.builder()
.role(EasyInputMessage.Role.USER)
.content("How can I solve 8x + 7 = -23?")
.build())))
.text(
ResponseTextConfig.builder()
.format(
ResponseFormatTextJsonSchemaConfig.builder()
.name("math_reasoning")
.strict(true)
.schema(
JsonValue.from(schema)
.convert(ResponseFormatTextJsonSchemaConfig.Schema.class))
.build())
.build())
.build();
var response = client.responses().create(params);
for (var output : response.output()) {
if (output.message().isEmpty()) continue;
for (var content : output.message().orElseThrow().content()) {
if (content.refusal().isPresent()) {
System.out.println(content.refusal().orElseThrow().refusal());
} else {
content.outputText().ifPresent(text -> System.out.println(text.text()));
}
}
}
using OpenAI.Responses;
#pragma warning disable OPENAI001
string key = Environment.GetEnvironmentVariable("OPENAI_API_KEY")!;
ResponsesClient client = new(key);
BinaryData schema = BinaryData.FromString(
"""
{
"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
}
"""
);
CreateResponseOptions options = new()
{
Model = "gpt-6-astra",
TextOptions = new ResponseTextOptions
{
TextFormat = ResponseTextFormat.CreateJsonSchemaFormat(
"math_response",
schema,
jsonSchemaIsStrict: true
),
},
};
options.InputItems.Add(ResponseItem.CreateSystemMessageItem("You are a helpful math tutor. Guide the user through the solution step by step."));
options.InputItems.Add(ResponseItem.CreateUserMessageItem("How can I solve 8x + 7 = -23?"));
ResponseResult response = await client.CreateResponseAsync(options);
foreach (MessageResponseItem message in response.OutputItems.OfType<MessageResponseItem>())
{
foreach (ResponseContentPart content in message.Content)
{
Console.WriteLine(
content.Kind == ResponseContentPartKind.Refusal ? content.Refusal : content.Text
);
}
}
require "openai"
client = OpenAI::Client.new
math_schema = {
type: :object,
properties: {
steps: {
type: :array,
items: {
type: :object,
properties: {
explanation: {type: :string},
output: {type: :string}
},
required: %w[explanation output],
additionalProperties: false
}
},
final_answer: {type: :string}
},
required: %w[steps final_answer],
additionalProperties: false
}
response = client.responses.create(
model: "gpt-6-astra",
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: math_schema
}
}
)
response.output.each do |item|
next unless item.is_a?(OpenAI::Models::Responses::ResponseOutputMessage)
item.content.each do |content|
case content
when OpenAI::Models::Responses::ResponseOutputRefusal
puts(content.refusal)
when OpenAI::Models::Responses::ResponseOutputText
puts(content.text)
end
end
end
拒绝响应的 API 返回内容大致如下:
{
"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": [
// highlight-start
{
"type": "refusal",
"refusal": "I'm sorry, I cannot assist with that request."
}
// highlight-end
]
}],
"usage": {
"input_tokens": 81,
"output_tokens": 11,
"total_tokens": 92,
"output_tokens_details": {
"reasoning_tokens": 0,
}
},
}
提示与最佳实践
处理用户生成的输入
如果您的应用程序使用用户生成的输入,请确保您的提示中包含说明,说明当输入无法得出有效响应时应如何处理。
模型将始终尝试遵守所提供的 Schema,如果输入与 Schema 完全无关,可能会导致幻觉。
您可以在提示中添加说明,指定当模型检测到输入与任务不兼容时,返回空参数或特定的句子。
处理错误
结构化输出仍然可能包含错误。如果您发现错误,请尝试调整指令、在系统指令中提供示例,或将任务拆分为更简单的子任务。请参阅提示工程指南,了解如何调整输入的更多指导。
避免 JSON Schema 与代码类型定义偏差
为防止 JSON Schema 与您编程语言中对应的类型定义发生偏差,我们强烈建议使用原生 Pydantic/zod SDK 支持。
如果您倾向于直接指定 JSON Schema,可以添加 CI 规则,在 JSON Schema 或底层数据对象被编辑时发出标记,或添加一个 CI 步骤,从类型定义自动生成 JSON Schema(或反之亦然)。
流式传输
您可以使用流式传输在模型响应或函数调用参数生成过程中对其进行处理,并将其解析为结构化数据。
这样,您无需等待整个响应完成后再进行处理。 当您希望逐一显示 JSON 字段,或在函数调用参数可用时立即处理它们时,这一功能尤为有用。
我们建议依赖 SDK 来处理结构化输出的流式传输。
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-6-astra",
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("error", (error) => {
console.error(error);
});
const result = await stream.finalResponse();
console.log(result);
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-6-astra",
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") # print(event.response.output)
final_response = stream.get_final_response()
print(final_response)
import com.openai.client.OpenAIClient;
import com.openai.client.okhttp.OpenAIOkHttpClient;
import com.openai.core.JsonValue;
import com.openai.core.http.StreamResponse;
import com.openai.models.responses.EasyInputMessage;
import com.openai.models.responses.ResponseCreateParams;
import com.openai.models.responses.ResponseFormatTextJsonSchemaConfig;
import com.openai.models.responses.ResponseInputItem;
import com.openai.models.responses.ResponseStreamEvent;
import com.openai.models.responses.ResponseTextConfig;
import java.util.List;
import java.util.Map;
ResponseCreateParams params =
ResponseCreateParams.builder()
.model("gpt-6-astra")
.inputOfResponse(
List.of(
ResponseInputItem.ofEasyInputMessage(
EasyInputMessage.builder()
.role(EasyInputMessage.Role.SYSTEM)
.content("Extract entities from the input text")
.build()),
ResponseInputItem.ofEasyInputMessage(
EasyInputMessage.builder()
.role(EasyInputMessage.Role.USER)
.content(
"The quick brown fox jumps over the lazy dog with piercing blue eyes")
.build())))
.text(
ResponseTextConfig.builder()
.format(
ResponseFormatTextJsonSchemaConfig.builder()
.name("entities")
.strict(true)
.schema(
ResponseFormatTextJsonSchemaConfig.Schema.builder()
.putAdditionalProperty("type", JsonValue.from("object"))
.putAdditionalProperty(
"properties",
JsonValue.from(
Map.of(
"attributes",
Map.of(
"type",
"array",
"items",
Map.of("type", "string")),
"colors",
Map.of(
"type",
"array",
"items",
Map.of("type", "string")),
"animals",
Map.of(
"type",
"array",
"items",
Map.of("type", "string")))))
.putAdditionalProperty(
"required",
JsonValue.from(List.of("attributes", "colors", "animals")))
.putAdditionalProperty(
"additionalProperties", JsonValue.from(false))
.build())
.build())
.build())
.build();
try (StreamResponse<ResponseStreamEvent> stream = client.responses().createStreaming(params)) {
stream.stream()
.forEach(
event -> {
event.outputTextDelta().ifPresent(delta -> System.out.print(delta.delta()));
event.refusalDelta().ifPresent(refusal -> System.out.print(refusal.delta()));
event.error().ifPresent(error -> System.out.println(error.message()));
event
.completed()
.ifPresent(
completed -> {
System.out.println("Completed");
System.out.println(completed.response());
});
});
}
require "openai"
client = OpenAI::Client.new
entities_schema = {
type: :object,
properties: {
attributes: {type: :array, items: {type: :string}},
colors: {type: :array, items: {type: :string}},
animals: {type: :array, items: {type: :string}}
},
required: %w[attributes colors animals],
additionalProperties: false
}
stream = client.responses.stream(
model: "gpt-6-astra",
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: {
type: :json_schema,
name: "entities",
strict: true,
schema: entities_schema
}
}
)
stream.each do |event|
case event
when OpenAI::Models::Responses::ResponseRefusalDeltaEvent,
OpenAI::Models::Responses::ResponseTextDeltaEvent
print(event.delta)
when OpenAI::Models::Responses::ResponseErrorEvent
warn(event.message)
when OpenAI::Models::Responses::ResponseCompletedEvent
puts("\nCompleted")
end
end
支持的 Schema
结构化输出支持 JSON Schema 语言的一个子集。
支持的类型
结构化输出支持以下类型:
- String(字符串)
- Number(数字)
- Boolean(布尔值)
- Integer(整数)
- Object(对象)
- Array(数组)
- Enum(枚举)
- anyOf
支持的属性
除了指定属性的类型外,您还可以指定一组附加约束:
支持的 string 属性:
pattern— 字符串必须匹配的正则表达式。format— 字符串的预定义格式。当前支持:date-timetimedatedurationemailhostnameipv4ipv6uuid
支持的 number 属性:
multipleOf— 数字必须是该值的倍数。maximum— 数字必须小于或等于该值。exclusiveMaximum— 数字必须小于该值。minimum— 数字必须大于或等于该值。exclusiveMinimum— 数字必须大于该值。
支持的 array 属性:
minItems— 数组至少必须包含这么多项。maxItems— 数组至多只能包含这么多项。
以下是一些使用这些类型限制的示例:
字符串限制
{
"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 @",
// highlight-start
"pattern": "^@[a-zA-Z0-9_]+$"
// highlight-end
},
"email": {
"type": "string",
"description": "The email of the user",
// highlight-start
"format": "email"
// highlight-end
}
},
"additionalProperties": false,
"required": [
"name", "username", "email"
]
}
}
数字限制
{
"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",
// highlight-start
"minimum": -130,
"maximum": 130
// highlight-end
}
},
"additionalProperties": false,
"required": [
"location", "unit", "value"
]
}
}
请注意,这些约束尚不支持微调模型。
根对象不得为 anyOf,且必须是对象类型
请注意,Schema 的根级对象必须是对象类型,不能使用 anyOf。在 Zod(以此为例)中有一种常见模式是使用可辨识联合(discriminated union),这会在顶层生成 anyOf。因此,如下代码将无法正常工作:
import { z } from "zod";
import { zodResponseFormat } from "openai/helpers/zod";
const BaseResponseSchema = z.object({
/* ... */
});
const UnsuccessfulResponseSchema = z.object({
/* ... */
});
const finalSchema = z.discriminatedUnion("status", [
BaseResponseSchema,
UnsuccessfulResponseSchema,
]);
// Invalid JSON Schema for Structured Outputs
const json = zodResponseFormat(finalSchema, "final_schema");
所有字段必须为 required
要使用结构化输出,所有字段或函数参数必须指定为 required。
{
"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,
// highlight-start
"required": ["location", "unit"]
// highlight-end
}
}
尽管所有字段必须是必填的(且模型将为每个参数返回一个值),但可以通过使用与 null 的联合类型来模拟可选参数。
{
"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": {
// highlight-start
"type": ["string", "null"],
// highlight-end
"description": "The unit to return the temperature in",
"enum": ["F", "C"]
}
},
"additionalProperties": false,
"required": [
"location", "unit"
]
}
}
对象在嵌套深度和大小上存在限制
一个 schema 最多可以包含 5000 个对象属性,嵌套层级最多为 10 层。
字符串总大小的限制
在一个 schema 中,所有属性名、定义名、枚举值和常量值的字符串总长度不能超过 120,000 个字符。
枚举大小的限制
一个 schema 在所有枚举属性中最多可以包含 1000 个枚举值。
对于单个具有字符串值的枚举属性,当枚举值超过 250 个时,所有枚举值的字符串总长度不能超过 15,000 个字符。
additionalProperties: false 必须始终在对象中设置
additionalProperties 控制是否允许对象包含未在 JSON Schema 中定义的额外键/值。
结构化输出仅支持生成已指定的键/值,因此我们要求开发者设置 additionalProperties: false 以启用结构化输出。
{
"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"]
}
},
// highlight-start
"additionalProperties": false,
// highlight-end
"required": [
"location", "unit"
]
}
}
键的排序
使用结构化输出时,输出内容的键顺序将与 schema 中键的定义顺序保持一致。
某些特定类型的关键字尚不支持
- 组合:
allOf、not、dependentRequired、dependentSchemas、if、then、else
对于经过微调的模型,我们额外不支持以下内容:
- 字符串:
minLength、maxLength、pattern、format - 数字:
minimum、maximum、multipleOf - 对象:
patternProperties - 数组:
minItems、maxItems
如果您通过提供 strict: true 来启用结构化输出,并以不支持的 JSON Schema 调用 API,您将收到一个错误。
对于 anyOf,嵌套的 schema 必须各自是此子集中有效的 JSON Schema
以下是一个受支持的 anyOf schema 示例:
{
"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)
您可以使用定义来定义在整个 schema 中引用的子 schema。以下是一个简单示例。
{
"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
}
支持递归 schema
使用 # 表示根递归的示例递归 schema:
{
"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
}
}
使用显式递归的示例递归 schema:
{
"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,但结构化输出能够可靠地将模型输出与您指定的 schema 相匹配。如果您的使用场景支持,我们建议您使用结构化输出。
当 JSON 模式开启时,模型的输出将被确保为有效的 JSON,但在某些边缘情况下可能存在例外,您应当检测并妥善处理这些情况。
要通过 Responses API 开启 JSON 模式,您可以将 text.format 设置为 { "type": "json_object" }。如果您使用的是函数调用,JSON 模式将始终处于开启状态。
重要说明:
- 使用 JSON 模式时,您必须始终通过对话中的某条消息(例如系统消息)指示模型生成 JSON。如果您没有明确要求生成 JSON,模型可能会持续生成空白字符,请求可能会一直运行直到达到 token 限制。为了帮助您避免遗忘,如果上下文中某处未出现字符串"JSON",API 将抛出错误。
- JSON 模式不保证输出符合任何特定 schema,仅保证输出是有效的且解析时不会出错。您应使用结构化输出来确保输出符合您的 schema;如果无法使用结构化输出,则应使用验证库,并在必要时进行重试,以确保输出符合您期望的 schema。
- 您的应用程序必须检测并处理可能导致模型输出不是完整 JSON 对象的边缘情况(见下文)。
处理边缘情况
const we_did_not_specify_stop_tokens = true;
try {
const response = await openai.responses.create({
model: "gpt-6-astra",
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" } },
});
const message = response.output.find((item) => item.type === "message");
const messageContent = message?.content[0];
// Check if the conversation was too long for the context window, resulting in incomplete JSON
if (
response.status === "incomplete" &&
response.incomplete_details.reason === "max_output_tokens"
) {
// your code should handle this error case
}
// Check if the OpenAI safety system refused the request and generated a refusal instead
if (messageContent?.type === "refusal") {
// your code should handle this error case
// In this case, the .content field will contain the explanation (if any) that the model generated for why it is refusing
console.log(messageContent.refusal);
}
// Check if the model's output included restricted content, so the generation of JSON was halted and may be partial
if (
response.status === "incomplete" &&
response.incomplete_details.reason === "content_filter"
) {
// your code should handle this error case
}
if (response.status === "completed") {
// In this case the model has either successfully finished generating the JSON object according to your schema, or the model generated one of the tokens you provided as a "stop token"
if (we_did_not_specify_stop_tokens) {
// If you didn't specify any stop tokens, then the generation is complete and the content key will contain the serialized JSON object
// This will parse successfully and should now contain {"winner": "Los Angeles Dodgers"}
console.log(JSON.parse(response.output_text));
} else {
// Check if the response.output_text ends with one of your stop tokens and handle appropriately
}
}
} catch (e) {
// Your code should handle errors here, for example a network error calling the API
console.error(e);
}
we_did_not_specify_stop_tokens = True
try:
response = client.responses.create(
model="gpt-6-astra",
input=[
{
"role": "system",
"content": "You are a helpful assistant designed to output JSON.",
},
{
"role": "user",
"content": 'Who won the World Series in 2020? Respond as {"winner": "team name"}.',
},
],
text={"format": {"type": "json_object"}},
)
message = next((item for item in response.output if item.type == "message"), None)
message_content = message.content[0] if message and message.content else None
# Check if the conversation was too long for the context window, resulting in incomplete JSON
if (
response.status == "incomplete"
and response.incomplete_details.reason == "max_output_tokens"
):
raise RuntimeError("The response was truncated before the JSON completed.")
# Check if the OpenAI safety system refused the request and generated a refusal instead
if message_content and message_content.type == "refusal":
# your code should handle this error case
# In this case, the .content field will contain the explanation (if any) that the model generated for why it is refusing
print(message_content.refusal)
# Check if the model's output included restricted content, so the generation of JSON was halted and may be partial
if (
response.status == "incomplete"
and response.incomplete_details.reason == "content_filter"
):
raise RuntimeError("The response was interrupted by the content filter.")
if response.status == "completed":
# In this case the model has either successfully finished generating the JSON object according to your schema, or the model generated one of the tokens you provided as a "stop token"
if we_did_not_specify_stop_tokens:
# If you didn't specify any stop tokens, then the generation is complete and the content key will contain the serialized JSON object
# This will parse successfully and should now contain "{"winner": "Los Angeles Dodgers"}"
print(response.output_text)
except Exception as e:
# Your code should handle errors here, for example a network error calling the API
print(e)
package main
import (
"context"
"encoding/json"
"fmt"
"github.com/openai/openai-go/v3"
"github.com/openai/openai-go/v3/responses"
"github.com/openai/openai-go/v3/shared"
)
func main() {
client := openai.NewClient()
response, err := client.Responses.New(context.Background(), responses.ResponseNewParams{
Model: "gpt-6-astra",
Input: responses.ResponseNewParamsInputUnion{OfInputItemList: responses.ResponseInputParam{
responses.ResponseInputItemParamOfMessage(
responses.ResponseInputMessageContentListParam{responses.ResponseInputContentParamOfInputText("You are a helpful assistant designed to output JSON.")},
responses.EasyInputMessageRoleSystem,
),
responses.ResponseInputItemParamOfMessage(
responses.ResponseInputMessageContentListParam{responses.ResponseInputContentParamOfInputText("Who won the world series in 2020? Please respond in the format {winner: ...}")},
responses.EasyInputMessageRoleUser,
),
}},
Text: responses.ResponseTextConfigParam{Format: responses.ResponseFormatTextConfigUnionParam{
OfJSONObject: &shared.ResponseFormatJSONObjectParam{},
}},
})
if err != nil {
panic(err)
}
if response.Status == "incomplete" {
fmt.Println("The JSON response is incomplete.")
return
}
for _, output := range response.Output {
if output.Type != "message" {
continue
}
for _, content := range output.AsMessage().Content {
if content.Type == "refusal" {
fmt.Println(content.AsRefusal().Refusal)
return
}
}
}
if response.Status == "completed" {
var value map[string]any
if err := json.Unmarshal([]byte(response.OutputText()), &value); err != nil {
panic(err)
}
fmt.Println(value)
}
}
import com.openai.client.OpenAIClient;
import com.openai.client.okhttp.OpenAIOkHttpClient;
import com.openai.errors.OpenAIServiceException;
import com.openai.models.ResponseFormatJsonObject;
import com.openai.models.responses.EasyInputMessage;
import com.openai.models.responses.ResponseCreateParams;
import com.openai.models.responses.ResponseInputItem;
import com.openai.models.responses.ResponseStatus;
import com.openai.models.responses.ResponseTextConfig;
import java.util.List;
ResponseCreateParams params =
ResponseCreateParams.builder()
.model("gpt-6-astra")
.inputOfResponse(
List.of(
ResponseInputItem.ofEasyInputMessage(
EasyInputMessage.builder()
.role(EasyInputMessage.Role.SYSTEM)
.content("You are a helpful assistant designed to output JSON.")
.build()),
ResponseInputItem.ofEasyInputMessage(
EasyInputMessage.builder()
.role(EasyInputMessage.Role.USER)
.content(
"Who won the World Series in 2020? Respond in the format {winner: ...}.")
.build())))
.text(
ResponseTextConfig.builder()
.format(ResponseFormatJsonObject.builder().build())
.build())
.build();
try {
var response = client.responses().create(params);
if (response.status().filter(ResponseStatus.INCOMPLETE::equals).isPresent()) {
String reason =
response
.incompleteDetails()
.flatMap(details -> details.reason())
.map(Object::toString)
.orElse("unknown");
System.out.println("The JSON response is incomplete. Reason: " + reason);
return;
}
for (var output : response.output()) {
if (output.message().isEmpty()) continue;
for (var content : output.message().orElseThrow().content()) {
if (content.refusal().isPresent()) {
System.out.println(content.refusal().orElseThrow().refusal());
return;
}
if (response.status().filter(ResponseStatus.COMPLETED::equals).isPresent()) {
content.outputText().ifPresent(text -> System.out.println(text.text()));
}
}
}
} catch (OpenAIServiceException error) {
System.out.println("Request failed: " + error.getMessage());
}
using OpenAI.Responses;
#pragma warning disable OPENAI001
string key = Environment.GetEnvironmentVariable("OPENAI_API_KEY")!;
ResponsesClient client = new(key);
CreateResponseOptions options = new()
{
Model = "gpt-6-astra",
TextOptions = new ResponseTextOptions
{
TextFormat = ResponseTextFormat.CreateJsonObjectFormat(),
},
};
options.InputItems.Add(ResponseItem.CreateSystemMessageItem("You are a helpful assistant designed to output JSON."));
options.InputItems.Add(ResponseItem.CreateUserMessageItem("Who won the World Series in 2020? Respond with the winner in JSON."));
ResponseResult response = await client.CreateResponseAsync(options);
if (
response.Status == ResponseStatus.Incomplete
&& response.IncompleteStatusDetails?.Reason == ResponseIncompleteStatusReason.MaxOutputTokens
)
{
Console.WriteLine("The response was truncated before the JSON completed.");
}
else if (
response.Status == ResponseStatus.Incomplete
&& response.IncompleteStatusDetails?.Reason == ResponseIncompleteStatusReason.ContentFilter
)
{
Console.WriteLine("The response was interrupted by the content filter.");
}
else if (response.Status == ResponseStatus.Completed)
{
MessageResponseItem message = response.OutputItems.OfType<MessageResponseItem>().FirstOrDefault()
?? throw new InvalidOperationException("The response did not include an output message.");
ResponseContentPart content = message.Content.FirstOrDefault()
?? throw new InvalidOperationException("The response did not include output content.");
Console.WriteLine(
content.Kind == ResponseContentPartKind.Refusal ? content.Refusal : content.Text
);
}
else
{
throw new InvalidOperationException($"The response ended with status: {response.Status}");
}
require "json"
require "openai"
client = OpenAI::Client.new
response = client.responses.create(
model: "gpt-6-astra",
input: [
{role: :system, content: "You are a helpful assistant designed to output JSON."},
{
role: :user,
content: "Who won the World Series in 2020? Respond in the format {winner: ...}."
}
],
text: {format: {type: :json_object}}
)
if response.status == OpenAI::Responses::ResponseStatus::INCOMPLETE
warn("The JSON response is incomplete.")
else
refusal = response.output
.grep(OpenAI::Models::Responses::ResponseOutputMessage)
.flat_map(&:content)
.find { |content| content.is_a?(OpenAI::Models::Responses::ResponseOutputRefusal) }
if refusal.is_a?(OpenAI::Models::Responses::ResponseOutputRefusal)
puts(refusal.refusal)
elsif response.status == OpenAI::Responses::ResponseStatus::COMPLETED
puts(JSON.pretty_generate(JSON.parse(response.output_text)))
end
end
相关资源
要了解有关结构化输出的更多信息,我们建议浏览以下资源: