JSON は、アプリケーション間でデータをやり取りする形式として、世界で最も広く使われているものの一つです。
構造化出力は、モデルが生成する応答を、指定した JSON スキーマに常に準拠させる機能です。モデルが必須キーを省略したり、列挙型に定義されていない値を生成したりする心配がありません。
構造化出力には、次のような利点があります。
- 型安全性の保証: 応答の形式を検証したり、形式が正しくないためにリクエストを再試行したりする必要がありません。
- 拒否の明示: モデルが安全上の理由でリクエストを拒否したことを、プログラムで検出できます。
- プロンプトの簡素化: 出力形式を統一するために、プロンプトで強く念を押す必要がありません。
OpenAI の REST API は JSON スキーマに対応しています。また、OpenAI の Python ライブラリと JavaScript ライブラリでは、それぞれ pydantic.BaseModel と z.object を使ってオブジェクトのスキーマを定義できます。次の例では、非構造化テキストから情報を抽出し、コードで定義したスキーマに沿った形で取得します。
Ruby SDK は Sorbet の T::Struct で定義したスキーマに対応しており、パースした結果を型付きで返します。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25import OpenAI from "openai";
import { zodResponseFormat } from "openai/helpers/zod";
import { z } from "zod";
const openai = new OpenAI();
const CalendarEvent = z.object({
name: z.string(),
date: z.string(),
participants: z.array(z.string()),
});
const completion = await openai.chat.completions.parse({
model: "gpt-6-astra",
messages: [
{ role: "system", content: "Extract the event information." },
{
role: "user",
content: "Alice and Bob are going to a science fair on Friday.",
},
],
response_format: zodResponseFormat(CalendarEvent, "event"),
});
const event = completion.choices[0].message.parsed;1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25from pydantic import BaseModel
from openai import OpenAI
client = OpenAI()
class CalendarEvent(BaseModel):
name: str
date: str
participants: list[str]
completion = client.chat.completions.parse(
model="gpt-6-astra",
messages=[
{"role": "system", "content": "Extract the event information."},
{
"role": "user",
"content": "Alice and Bob are going to a science fair on Friday.",
},
],
response_format=CalendarEvent,
)
event = completion.choices[0].message.parsed1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41package main
import (
"context"
"fmt"
"github.com/openai/openai-go/v3"
"github.com/openai/openai-go/v3/shared"
)
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,
}
completion, err := client.Chat.Completions.New(context.Background(), openai.ChatCompletionNewParams{
Model: "gpt-6-astra",
Messages: []openai.ChatCompletionMessageParamUnion{
openai.SystemMessage("Extract the event information."),
openai.UserMessage("Alice and Bob are going to a science fair on Friday."),
},
ResponseFormat: openai.ChatCompletionNewParamsResponseFormatUnion{
OfJSONSchema: &shared.ResponseFormatJSONSchemaParam{JSONSchema: shared.ResponseFormatJSONSchemaJSONSchemaParam{
Name: "event", Schema: schema, Strict: openai.Bool(true),
}},
},
})
if err != nil {
panic(err)
}
fmt.Println(completion.Choices[0].Message.Content)
}1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39import com.openai.client.OpenAIClient;
import com.openai.client.okhttp.OpenAIOkHttpClient;
import com.openai.core.JsonValue;
import com.openai.models.chat.completions.ChatCompletionCreateParams;
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);
ChatCompletionCreateParams params =
ChatCompletionCreateParams.builder()
.model("gpt-6-astra")
.addSystemMessage("Extract the event information.")
.addUserMessage("Alice and Bob are going to a science fair on Friday.")
.putAdditionalBodyProperty(
"response_format",
JsonValue.from(
Map.of(
"type",
"json_schema",
"json_schema",
Map.of("name", "event", "strict", true, "schema", schema))))
.build();
client.chat().completions().create(params).choices().stream()
.flatMap(choice -> choice.message().content().stream())
.forEach(System.out::println);1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42using OpenAI.Chat;
string key = Environment.GetEnvironmentVariable("OPENAI_API_KEY")!;
string model = "gpt-6-astra";
ChatClient client = new(model, 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
}
"""
);
ChatCompletionOptions options = new()
{
ResponseFormat = ChatResponseFormat.CreateJsonSchemaFormat(
"event",
schema,
jsonSchemaIsStrict: true
),
};
ChatCompletion completion = await client.CompleteChatAsync(
[
new SystemChatMessage("Extract the event information."),
new UserChatMessage(
"Alice and Bob are going to a science fair on Friday."
),
],
options
);
Console.WriteLine(completion.Content[0].Text);1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34# gem install openai sorbet-runtime
require "openai"
require "openai/helpers/sorbet"
class CalendarEvent < T::Struct
const :name, String
const :date, String
const :participants, T::Array[String]
end
client = OpenAI::Client.new
schema = OpenAI::StructuredOutput.from_sorbet(CalendarEvent)
completion = client.chat.completions.create(
model: "gpt-6-astra",
messages: [
{
role: :system,
content: "Extract the event information."
},
{
role: :user,
content: "Alice and Bob are going to a science fair on Friday."
}
],
response_format: schema
)
choice = completion.choices.fetch(0)
raise "Completion ended with reason: #{choice.finish_reason}" unless choice.finish_reason.to_s == "stop"
raise "The model refused the request" if choice.message.refusal
event = T.cast(choice.message.parsed, CalendarEvent)
puts(event.name, event.date, event.participants.join(", "))1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27import 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;1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25from 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_parsed1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45package 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())
}1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58import 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()));1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47using 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());1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36# gem install openai sorbet-runtime
require "openai"
require "openai/helpers/sorbet"
class CalendarEvent < T::Struct
const :name, String
const :date, String
const :participants, T::Array[String]
end
client = OpenAI::Client.new
schema = OpenAI::StructuredOutput.from_sorbet(CalendarEvent)
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: schema
)
raise "Response ended with status: #{response.status}" unless response.status == OpenAI::Responses::ResponseStatus::COMPLETED
message = response.output.grep(OpenAI::Responses::ResponseOutputMessage).fetch(0)
output_text = message.content.grep(OpenAI::Responses::ResponseOutputText).first
raise "No structured output returned (the model may have refused)" unless output_text
event = T.cast(output_text.parsed, CalendarEvent)
puts(event.name, event.date, event.participants.join(", "))対応モデル
構造化出力は、GPT-4o 以降の OpenAI の最新の大規模言語モデルで利用できます。新しいプロジェクトでは、まず gpt-6-astra を使用してください。gpt-4-turbo やそれ以前のモデルでは、代わりに JSON モードを利用できる場合があります。
構造化出力で使い分ける Function Calling と response_format
構造化出力で使い分ける Function Calling と text.format
OpenAI API では、次の 2 つの方法で構造化出力を利用できます。
- Function Calling を使う方法
json_schema応答形式を使う方法
Function Calling は、モデルとアプリケーションの機能を連携させる場合に役立ちます。
たとえば、データベースに問い合わせる関数をモデルから呼び出せるようにすれば、ユーザーからの注文に関する問い合わせに対応する AI アシスタントを構築できます。UI を操作する関数をモデルから呼び出せるようにすることもできます。
一方、モデルがツールを呼び出す際ではなく、ユーザーに回答する際のスキーマを指定したい場合は、response_format を使った構造化出力が適しています。
たとえば、数学の学習を支援するアプリケーションでは、アシスタントに特定の JSON スキーマに沿って回答させることで、モデルの出力の各部分をそれぞれ異なる形式で表示する UI を生成できます。
用途に応じて、次のように使い分けます。
- モデルをシステム内のツール、関数、データなどに接続する場合は、Function Calling を使います。ユーザーへの応答を構造化する場合は、
response_formatで構造化された応答形式を指定します。
- モデルをシステム内のツール、関数、データなどに接続する場合は、Function Calling を使います。ユーザーへの応答を構造化する場合は、
text.formatで構造化された応答形式を指定します。
以降では、Chat Completions API で Function Calling を使わずに構造化出力を利用する場合について説明します。Function Calling と構造化出力を併用する方法については、
Function Calling
ガイドを参照してください。
以降では、Responses API で Function Calling を使わずに構造化出力を利用する場合について説明します。Function Calling と構造化出力を併用する方法については、
Function Calling
ガイドを参照してください。
構造化出力と JSON モードの違い
構造化出力は、JSON モードを発展させた機能です。どちらも有効な JSON が生成されることを保証しますが、スキーマへの準拠まで保証するのは構造化出力だけです。Responses API、Chat Completions API、Assistants API、Fine-tuning API、Batch API は、いずれも構造化出力と JSON モードの両方に対応しています。
可能な場合は、常に 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-* および JSON モードに対応する GPT-5 モデル |
| 有効にする設定 | response_format: { type: "json_schema", json_schema: {"strict": true, "schema": ...} } |
response_format: { type: "json_object" } |
| 構造化出力 | JSON モード | |
|---|---|---|
| 有効な JSON の出力 | はい | はい |
| スキーマへの準拠 | はい(対応スキーマを参照) | いいえ |
| 対応モデル | gpt-4o-mini、gpt-4o-2024-08-06 およびそれ以降のモデル |
gpt-3.5-turbo、gpt-4-*、gpt-4o-* および JSON モードに対応する GPT-5 モデル |
| 有効にする設定 | text: { format: { type: "json_schema", "strict": true, "schema": ... } } |
text: { format: { type: "json_object" } } |
使用例
思考の連鎖
モデルに解答をステップごとに構造化して出力するよう指示すると、ユーザーが解き方を順にたどれるようになります。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30import OpenAI from "openai";
import { z } from "zod";
import { zodResponseFormat } from "openai/helpers/zod";
const openai = new OpenAI();
const Step = z.object({
explanation: z.string(),
output: z.string(),
});
const MathReasoning = z.object({
steps: z.array(Step),
final_answer: z.string(),
});
const completion = await openai.chat.completions.parse({
model: "gpt-6-astra",
messages: [
{
role: "system",
content:
"You are a helpful math tutor. Guide the user through the solution step by step.",
},
{ role: "user", content: "how can I solve 8x + 7 = -23" },
],
response_format: zodResponseFormat(MathReasoning, "math_reasoning"),
});
const math_reasoning = completion.choices[0].message.parsed;1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29from pydantic import BaseModel
from openai import OpenAI
client = OpenAI()
class Step(BaseModel):
explanation: str
output: str
class MathReasoning(BaseModel):
steps: list[Step]
final_answer: str
completion = client.chat.completions.parse(
model="gpt-6-astra",
messages=[
{
"role": "system",
"content": "You are a helpful math tutor. Guide the user through the solution step by step.",
},
{"role": "user", "content": "how can I solve 8x + 7 = -23"},
],
response_format=MathReasoning,
)
math_reasoning = completion.choices[0].message.parsed1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49package main
import (
"context"
"fmt"
"github.com/openai/openai-go/v3"
"github.com/openai/openai-go/v3/shared"
)
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,
}
completion, err := client.Chat.Completions.New(context.Background(), openai.ChatCompletionNewParams{
Model: "gpt-6-astra",
Messages: []openai.ChatCompletionMessageParamUnion{
openai.SystemMessage("You are a helpful math tutor. Guide the user through the solution step by step."),
openai.UserMessage("how can I solve 8x + 7 = -23"),
},
ResponseFormat: openai.ChatCompletionNewParamsResponseFormatUnion{
OfJSONSchema: &shared.ResponseFormatJSONSchemaParam{JSONSchema: shared.ResponseFormatJSONSchemaJSONSchemaParam{
Name: "math_reasoning", Schema: schema, Strict: openai.Bool(true),
}},
},
})
if err != nil {
panic(err)
}
fmt.Println(completion.Choices[0].Message.Content)
}1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54import com.openai.client.OpenAIClient;
import com.openai.client.okhttp.OpenAIOkHttpClient;
import com.openai.core.JsonValue;
import com.openai.models.chat.completions.ChatCompletionCreateParams;
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);
ChatCompletionCreateParams params =
ChatCompletionCreateParams.builder()
.model("gpt-6-astra")
.addSystemMessage(
"You are a helpful math tutor. Guide the user through the solution step by step.")
.addUserMessage("How can I solve 8x + 7 = -23?")
.putAdditionalBodyProperty(
"response_format",
JsonValue.from(
Map.of(
"type",
"json_schema",
"json_schema",
Map.of("name", "math_reasoning", "strict", true, "schema", schema))))
.build();
client.chat().completions().create(params).choices().stream()
.flatMap(choice -> choice.message().content().stream())
.forEach(System.out::println);1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46using System.Text.Json;
using OpenAI.Chat;
string key = Environment.GetEnvironmentVariable("OPENAI_API_KEY")!;
string model = "gpt-6-astra";
ChatClient client = new(model, 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
}
"""
);
ChatCompletionOptions options = new()
{
ResponseFormat = ChatResponseFormat.CreateJsonSchemaFormat(
"math_response",
schema,
jsonSchemaIsStrict: true
),
};
ChatCompletion completion = await client.CompleteChatAsync(
[new SystemChatMessage("You are a helpful math tutor. Guide the user through the solution step by step."), new UserChatMessage("How can I solve 8x + 7 = -23?")],
options
);
using JsonDocument parsed = JsonDocument.Parse(completion.Content[0].Text);
Console.WriteLine(parsed.RootElement);1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48require "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
}
completion = client.chat.completions.create(
model: "gpt-6-astra",
messages: [
{
role: :system,
content: "You are a helpful math tutor. Guide the user through the solution step by step."
},
{
role: :user,
content: "How can I solve 8x + 7 = -23?"
}
],
response_format: {
type: :json_schema,
json_schema: {
name: "math_reasoning",
strict: true,
schema: math_schema
}
}
)
puts(completion.choices.fetch(0).message.content)1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43curl https://api.openai.com/v1/chat/completions \
-H "Authorization: Bearer $OPENAI_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "gpt-6-astra",
"messages": [
{
"role": "system",
"content": "You are a helpful math tutor. Guide the user through the solution step by step."
},
{
"role": "user",
"content": "how can I solve 8x + 7 = -23"
}
],
"response_format": {
"type": "json_schema",
"json_schema": {
"name": "math_reasoning",
"schema": {
"type": "object",
"properties": {
"steps": {
"type": "array",
"items": {
"type": "object",
"properties": {
"explanation": { "type": "string" },
"output": { "type": "string" }
},
"required": ["explanation", "output"],
"additionalProperties": false
}
},
"final_answer": { "type": "string" }
},
"required": ["steps", "final_answer"],
"additionalProperties": false
},
"strict": true
}
}
}'1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32import 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;1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29from 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_parsed1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53package 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())
}1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73import 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()));1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49using 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);1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48require "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)1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43curl 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"
}構造化データの抽出
研究論文などの非構造化データから抽出したい項目を、構造化フィールドとして定義できます。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30import OpenAI from "openai";
import { z } from "zod";
import { zodResponseFormat } from "openai/helpers/zod";
const openai = new OpenAI();
const ResearchPaperExtraction = z.object({
title: z.string(),
authors: z.array(z.string()),
abstract: z.string(),
keywords: z.array(z.string()),
});
const completion = await openai.chat.completions.parse({
model: "gpt-6-astra",
messages: [
{
role: "system",
content:
"You are an expert at structured data extraction. You will be given unstructured text from a research paper and should convert it into the given structure.",
},
{ role: "user", content: "..." },
],
response_format: zodResponseFormat(
ResearchPaperExtraction,
"research_paper_extraction"
),
});
const research_paper = completion.choices[0].message.parsed;1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36from pydantic import BaseModel
from openai import OpenAI
client = OpenAI()
class ResearchPaperExtraction(BaseModel):
title: str
authors: list[str]
abstract: str
keywords: list[str]
completion = client.chat.completions.parse(
model="gpt-6-astra",
messages=[
{
"role": "system",
"content": "You are an expert at structured data extraction. You will be given unstructured text from a research paper and should convert it into the given structure.",
},
{
"role": "user",
"content": (
"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."
),
},
],
response_format=ResearchPaperExtraction,
)
research_paper = completion.choices[0].message.parsed1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48package main
import (
"context"
"fmt"
"github.com/openai/openai-go/v3"
"github.com/openai/openai-go/v3/shared"
)
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,
}
completion, err := client.Chat.Completions.New(context.Background(), openai.ChatCompletionNewParams{
Model: "gpt-6-astra",
Messages: []openai.ChatCompletionMessageParamUnion{
openai.SystemMessage("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."),
openai.UserMessage(researchPaperText),
},
ResponseFormat: openai.ChatCompletionNewParamsResponseFormatUnion{
OfJSONSchema: &shared.ResponseFormatJSONSchemaParam{JSONSchema: shared.ResponseFormatJSONSchemaJSONSchemaParam{
Name: "research_paper_extraction", Schema: schema, Strict: openai.Bool(true),
}},
},
})
if err != nil {
panic(err)
}
fmt.Println(completion.Choices[0].Message.Content)
}1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54import com.openai.client.OpenAIClient;
import com.openai.client.okhttp.OpenAIOkHttpClient;
import com.openai.core.JsonValue;
import com.openai.models.chat.completions.ChatCompletionCreateParams;
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);
ChatCompletionCreateParams params =
ChatCompletionCreateParams.builder()
.model("gpt-6-astra")
.addSystemMessage(
"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.")
.addUserMessage(
"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.")
.putAdditionalBodyProperty(
"response_format",
JsonValue.from(
Map.of(
"type",
"json_schema",
"json_schema",
Map.of(
"name",
"research_paper_extraction",
"strict",
true,
"schema",
schema))))
.build();
client.chat().completions().create(params).choices().stream()
.flatMap(choice -> choice.message().content().stream())
.forEach(System.out::println);1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49using System.Text.Json;
using OpenAI.Chat;
string key = Environment.GetEnvironmentVariable("OPENAI_API_KEY")!;
string model = "gpt-6-astra";
ChatClient client = new(model, 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
}
"""
);
ChatCompletionOptions options = new()
{
ResponseFormat = ChatResponseFormat.CreateJsonSchemaFormat(
"research_paper",
schema,
jsonSchemaIsStrict: true
),
};
ChatCompletion completion = await client.CompleteChatAsync(
[
new SystemChatMessage("Extract the title, authors, abstract, and keywords from the research paper."),
new UserChatMessage(
"""
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.
"""
),
],
options
);
using JsonDocument parsed = JsonDocument.Parse(completion.Content[0].Text);
Console.WriteLine(parsed.RootElement);1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51require "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
}
completion = client.chat.completions.create(
model: "gpt-6-astra",
messages: [
{
role: :system,
content: "Extract structured data from the supplied research paper text."
},
{
role: :user,
content: research_paper
}
],
response_format: {
type: :json_schema,
json_schema: {
name: "research_paper_extraction",
strict: true,
schema: paper_schema
}
}
)
puts(completion.choices.fetch(0).message.content)1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40curl https://api.openai.com/v1/chat/completions \
-H "Authorization: Bearer $OPENAI_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "gpt-6-astra",
"messages": [
{
"role": "system",
"content": "You are an expert at structured data extraction. You will be given unstructured text from a research paper and should convert it into the given structure."
},
{
"role": "user",
"content": "..."
}
],
"response_format": {
"type": "json_schema",
"json_schema": {
"name": "research_paper_extraction",
"schema": {
"type": "object",
"properties": {
"title": { "type": "string" },
"authors": {
"type": "array",
"items": { "type": "string" }
},
"abstract": { "type": "string" },
"keywords": {
"type": "array",
"items": { "type": "string" }
}
},
"required": ["title", "authors", "abstract", "keywords"],
"additionalProperties": false
},
"strict": true
}
}
}'1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29import 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;1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36from 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_parsed1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52package 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())
}1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69import 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()));1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51using 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);1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51require "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)1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40curl 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 の生成
HTML を再帰的なデータ構造で表し、列挙型などで値を制約することで、妥当な HTML を生成できます。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33import OpenAI from "openai";
import { z } from "zod";
import { zodResponseFormat } from "openai/helpers/zod";
const openai = new OpenAI();
const UI = z.lazy(() =>
z.object({
type: z.enum(["div", "button", "header", "section", "field", "form"]),
label: z.string(),
children: z.array(UI),
attributes: z.array(
z.object({
name: z.string(),
value: z.string(),
})
),
})
);
const completion = await openai.chat.completions.parse({
model: "gpt-6-astra",
messages: [
{
role: "system",
content: "You are a UI generator AI. Convert the user input into a UI.",
},
{ role: "user", content: "Make a User Profile Form" },
],
response_format: zodResponseFormat(UI, "ui"),
});
const ui = completion.choices[0].message.parsed;1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49from enum import Enum
from pydantic import BaseModel
from openai import OpenAI
client = OpenAI()
class UIType(str, Enum):
div = "div"
button = "button"
header = "header"
section = "section"
field = "field"
form = "form"
class Attribute(BaseModel):
name: str
value: str
class UI(BaseModel):
type: UIType
label: str
children: list["UI"]
attributes: list[Attribute]
UI.model_rebuild() # This is required to enable recursive types
class Response(BaseModel):
ui: UI
completion = client.chat.completions.parse(
model="gpt-6-astra",
messages=[
{
"role": "system",
"content": "You are a UI generator AI. Convert the user input into a UI.",
},
{"role": "user", "content": "Make a User Profile Form"},
],
response_format=Response,
)
ui = completion.choices[0].message.parsed
print(ui)1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42package main
import (
"context"
"fmt"
"github.com/openai/openai-go/v3"
"github.com/openai/openai-go/v3/shared"
)
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,
}
completion, err := client.Chat.Completions.New(context.Background(), openai.ChatCompletionNewParams{
Model: "gpt-6-astra",
Messages: []openai.ChatCompletionMessageParamUnion{
openai.SystemMessage("You are a UI generator AI. Convert the user input into a UI."),
openai.UserMessage("Make a User Profile Form"),
},
ResponseFormat: openai.ChatCompletionNewParamsResponseFormatUnion{
OfJSONSchema: &shared.ResponseFormatJSONSchemaParam{JSONSchema: shared.ResponseFormatJSONSchemaJSONSchemaParam{
Name: "ui", Description: openai.String("Dynamically generated UI"), Schema: schema, Strict: openai.Bool(true),
}},
},
})
if err != nil {
panic(err)
}
fmt.Println(completion.Choices[0].Message.Content)
}1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86import com.openai.client.OpenAIClient;
import com.openai.client.okhttp.OpenAIOkHttpClient;
import com.openai.core.JsonValue;
import com.openai.models.chat.completions.ChatCompletion;
import com.openai.models.chat.completions.ChatCompletionCreateParams;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
Map<String, Object> attributeProperties = new LinkedHashMap<>();
attributeProperties.put("name", Map.of("type", "string"));
attributeProperties.put("value", Map.of("type", "string"));
// Structured Outputs preserves the order of the schema's properties.
Map<String, Object> properties = new LinkedHashMap<>();
properties.put(
"type",
Map.of(
"type",
"string",
"enum",
List.of("div", "button", "header", "section", "field", "form")));
properties.put("label", Map.of("type", "string"));
properties.put("children", Map.of("type", "array", "items", Map.of("$ref", "#")));
properties.put(
"attributes",
Map.of(
"type",
"array",
"items",
Map.of(
"type",
"object",
"properties",
attributeProperties,
"required",
List.of("name", "value"),
"additionalProperties",
false)));
Map<String, Object> schema =
Map.of(
"type",
"object",
"properties",
properties,
"required",
List.of("type", "label", "children", "attributes"),
"additionalProperties",
false);
ChatCompletionCreateParams params =
ChatCompletionCreateParams.builder()
.model("gpt-6-astra")
.maxCompletionTokens(4096)
.addSystemMessage("Convert the user request into a UI definition.")
.addUserMessage("Make a user profile form.")
.putAdditionalBodyProperty(
"response_format",
JsonValue.from(
Map.of(
"type",
"json_schema",
"json_schema",
Map.of(
"name",
"ui",
"description",
"A dynamically generated UI",
"strict",
true,
"schema",
schema))))
.build();
var completion = client.chat().completions().create(params);
if (completion.choices().size() != 1) {
throw new IllegalStateException("UI generation did not complete.");
}
var choice = completion.choices().get(0);
if (!choice.finishReason().equals(ChatCompletion.Choice.FinishReason.STOP)
|| choice.message().refusal().isPresent()
|| choice.message().content().filter(text -> !text.isBlank()).isEmpty()) {
throw new IllegalStateException("UI generation did not complete.");
}
System.out.println(choice.message().content().orElseThrow());1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67using System.Text.Json;
using OpenAI.Chat;
string key = Environment.GetEnvironmentVariable("OPENAI_API_KEY")!;
string model = "gpt-6-astra";
ChatClient client = new(model, 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" },
"attributes": {
"type": "array",
"items": {
"type": "object",
"properties": { "name": { "type": "string" }, "value": { "type": "string" } },
"required": ["name", "value"],
"additionalProperties": false
}
},
"children": { "type": "array", "items": { "$ref": "#/$defs/component" } }
},
"required": ["type", "label", "children", "attributes"],
"additionalProperties": false
}
}
}
"""
);
ChatCompletionOptions options = new()
{
MaxOutputTokenCount = 4096,
ResponseFormat = ChatResponseFormat.CreateJsonSchemaFormat(
"ui",
schema,
jsonSchemaIsStrict: true
),
};
ChatCompletion completion = await client.CompleteChatAsync(
[
new SystemChatMessage("You are a UI generator. Convert the user request into a component tree."),
new UserChatMessage(
"Make a small user profile form with exactly three direct children: " +
"a Name field, an Email field, and a Save button. Give each child no children. " +
"Use short labels and at most two short attributes per component."
),
],
options
);
if (completion.FinishReason != ChatFinishReason.Stop || !string.IsNullOrEmpty(completion.Refusal) ||
completion.Content.Count != 1 || string.IsNullOrWhiteSpace(completion.Content[0].Text))
throw new InvalidOperationException("UI generation did not complete.");
using JsonDocument parsed = JsonDocument.Parse(completion.Content[0].Text);
Console.WriteLine(parsed.RootElement);1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56require "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
}
completion = client.chat.completions.create(
model: "gpt-6-astra",
messages: [
{
role: :system,
content: "Convert the user request into a UI definition."
},
{
role: :user,
content: "Make a user profile form."
}
],
response_format: {
type: :json_schema,
json_schema: {
name: "ui",
description: "A dynamically generated UI",
strict: true,
schema: ui_schema
}
}
)
puts(completion.choices.fetch(0).message.content)1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64curl https://api.openai.com/v1/chat/completions \
-H "Authorization: Bearer $OPENAI_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "gpt-6-astra",
"messages": [
{
"role": "system",
"content": "You are a UI generator AI. Convert the user input into a UI."
},
{
"role": "user",
"content": "Make a User Profile Form"
}
],
"response_format": {
"type": "json_schema",
"json_schema": {
"name": "ui",
"description": "Dynamically generated UI",
"schema": {
"type": "object",
"properties": {
"type": {
"type": "string",
"description": "The type of the UI component",
"enum": ["div", "button", "header", "section", "field", "form"]
},
"label": {
"type": "string",
"description": "The label of the UI component, used for buttons or form fields"
},
"children": {
"type": "array",
"description": "Nested UI components",
"items": {"$ref": "#"}
},
"attributes": {
"type": "array",
"description": "Arbitrary attributes for the UI component, suitable for any element",
"items": {
"type": "object",
"properties": {
"name": {
"type": "string",
"description": "The name of the attribute, for example onClick or className"
},
"value": {
"type": "string",
"description": "The value of the attribute"
}
},
"required": ["name", "value"],
"additionalProperties": false
}
}
},
"required": ["type", "label", "children", "attributes"],
"additionalProperties": false
},
"strict": true
}
}
}'1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38import 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;1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49from enum import Enum
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_parsed1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46package 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())
}1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85import 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.LinkedHashMap;
import java.util.List;
import java.util.Map;
Map<String, Object> attributeProperties = new LinkedHashMap<>();
attributeProperties.put("name", Map.of("type", "string"));
attributeProperties.put("value", Map.of("type", "string"));
// Structured Outputs preserves the order of the schema's properties.
Map<String, Object> properties = new LinkedHashMap<>();
properties.put(
"type",
Map.of(
"type",
"string",
"enum",
List.of("div", "button", "header", "section", "field", "form")));
properties.put("label", Map.of("type", "string"));
properties.put("children", Map.of("type", "array", "items", Map.of("$ref", "#")));
properties.put(
"attributes",
Map.of(
"type",
"array",
"items",
Map.of(
"type",
"object",
"properties",
attributeProperties,
"required",
List.of("name", "value"),
"additionalProperties",
false)));
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(properties))
.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()));1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71using 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" },
"attributes": {
"type": "array",
"items": {
"type": "object",
"properties": { "name": { "type": "string" }, "value": { "type": "string" } },
"required": ["name", "value"],
"additionalProperties": false
}
},
"children": { "type": "array", "items": { "$ref": "#/$defs/component" } }
},
"required": ["type", "label", "children", "attributes"],
"additionalProperties": false
}
}
}
"""
);
CreateResponseOptions options = new()
{
Model = "gpt-6-astra",
MaxOutputTokenCount = 4096,
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 small user profile form with exactly three direct children: " +
"a Name field, an Email field, and a Save button. Give each child no children. " +
"Use short labels and at most two short attributes per component."
));
ResponseResult response = await client.CreateResponseAsync(options);
string text = response.GetOutputText();
bool refused = response.OutputItems.OfType<MessageResponseItem>()
.SelectMany(message => message.Content)
.Any(part => part.Kind == ResponseContentPartKind.Refusal);
if (response.Status != ResponseStatus.Completed || refused || string.IsNullOrWhiteSpace(text))
{
throw new InvalidOperationException("UI generation did not complete.");
}
using JsonDocument parsed = JsonDocument.Parse(text);
Console.WriteLine(parsed.RootElement);1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56require "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)1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64curl 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"
}
]
}モデレーション
入力を複数のカテゴリに基づいて分類するのは、モデレーションでよく使われる手法です。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26import OpenAI from "openai";
import { z } from "zod";
import { zodResponseFormat } from "openai/helpers/zod";
const openai = new OpenAI();
const ContentCompliance = z.object({
is_violating: z.boolean(),
category: z.enum(["violence", "sexual", "self_harm"]).nullable(),
explanation_if_violating: z.string().nullable(),
});
const completion = await openai.chat.completions.parse({
model: "gpt-6-astra",
messages: [
{
role: "system",
content:
"Determine if the user input violates specific guidelines and explain if they do.",
},
{ role: "user", content: "How do I prepare for a job interview?" },
],
response_format: zodResponseFormat(ContentCompliance, "content_compliance"),
});
const compliance = completion.choices[0].message.parsed;1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32from enum import Enum
from pydantic import BaseModel
from openai import OpenAI
client = OpenAI()
class Category(str, Enum):
violence = "violence"
sexual = "sexual"
self_harm = "self_harm"
class ContentCompliance(BaseModel):
is_violating: bool
category: Category | None
explanation_if_violating: str | None
completion = client.chat.completions.parse(
model="gpt-6-astra",
messages=[
{
"role": "system",
"content": "Determine if the user input violates specific guidelines and explain if they do.",
},
{"role": "user", "content": "How do I prepare for a job interview?"},
],
response_format=ContentCompliance,
)
compliance = completion.choices[0].message.parsed1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43package main
import (
"context"
"fmt"
"github.com/openai/openai-go/v3"
"github.com/openai/openai-go/v3/shared"
)
func main() {
client := openai.NewClient()
schema := contentComplianceSchema()
completion, err := client.Chat.Completions.New(context.Background(), openai.ChatCompletionNewParams{
Model: "gpt-6-astra",
Messages: []openai.ChatCompletionMessageParamUnion{
openai.SystemMessage("Determine if the user input violates specific guidelines and explain if they do."),
openai.UserMessage("How do I prepare for a job interview?"),
},
ResponseFormat: openai.ChatCompletionNewParamsResponseFormatUnion{
OfJSONSchema: &shared.ResponseFormatJSONSchemaParam{JSONSchema: shared.ResponseFormatJSONSchemaJSONSchemaParam{
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(completion.Choices[0].Message.Content)
}
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,
}
}1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61import com.openai.client.OpenAIClient;
import com.openai.client.okhttp.OpenAIOkHttpClient;
import com.openai.core.JsonValue;
import com.openai.models.chat.completions.ChatCompletionCreateParams;
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);
ChatCompletionCreateParams params =
ChatCompletionCreateParams.builder()
.model("gpt-6-astra")
.addSystemMessage(
"Determine whether the user input violates the guidelines and explain any violation.")
.addUserMessage("How do I prepare for a job interview?")
.putAdditionalBodyProperty(
"response_format",
JsonValue.from(
Map.of(
"type",
"json_schema",
"json_schema",
Map.of(
"name",
"content_compliance",
"description",
"Determines whether content violates moderation rules",
"strict",
true,
"schema",
schema))))
.build();
client.chat().completions().create(params).choices().stream()
.flatMap(choice -> choice.message().content().stream())
.forEach(System.out::println);1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39using System.Text.Json;
using OpenAI.Chat;
string key = Environment.GetEnvironmentVariable("OPENAI_API_KEY")!;
string model = "gpt-6-astra";
ChatClient client = new(model, 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
}
"""
);
ChatCompletionOptions options = new()
{
ResponseFormat = ChatResponseFormat.CreateJsonSchemaFormat(
"content_compliance",
schema,
jsonSchemaIsStrict: true
),
};
ChatCompletion completion = await client.CompleteChatAsync(
[new SystemChatMessage("Determine whether the user input violates content guidelines."), new UserChatMessage("How do I prepare for a job interview?")],
options
);
using JsonDocument parsed = JsonDocument.Parse(completion.Content[0].Text);
Console.WriteLine(parsed.RootElement);1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48require "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
}
completion = client.chat.completions.create(
model: "gpt-6-astra",
messages: [
{
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?"
}
],
response_format: {
type: :json_schema,
json_schema: {
name: "content_compliance",
description: "Determines whether content violates moderation rules",
strict: true,
schema: compliance_schema
}
}
)
puts(completion.choices.fetch(0).message.content)1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44curl https://api.openai.com/v1/chat/completions \
-H "Authorization: Bearer $OPENAI_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "gpt-6-astra",
"messages": [
{
"role": "system",
"content": "Determine if the user input violates specific guidelines and explain if they do."
},
{
"role": "user",
"content": "How do I prepare for a job interview?"
}
],
"response_format": {
"type": "json_schema",
"json_schema": {
"name": "content_compliance",
"description": "Determines if content is violating specific moderation rules",
"schema": {
"type": "object",
"properties": {
"is_violating": {
"type": "boolean",
"description": "Indicates if the content is violating guidelines"
},
"category": {
"type": ["string", "null"],
"description": "Type of violation, if the content is violating guidelines. Null otherwise.",
"enum": ["violence", "sexual", "self_harm"]
},
"explanation_if_violating": {
"type": ["string", "null"],
"description": "Explanation of why the content is violating"
}
},
"required": ["is_violating", "category", "explanation_if_violating"],
"additionalProperties": false
},
"strict": true
}
}
}'1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31import 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;1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33from enum import Enum
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: Category | None
explanation_if_violating: str | None
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_parsed1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43package 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,
}
}1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73import 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()));1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42using 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);1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48require "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)1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44curl 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
}構造化出力の設定方法:response_format
新しい SDK ヘルパーを使うと、構造化出力を利用してモデルの出力を目的の形式にパースできます。JSON スキーマを直接指定することもできます。
注: ファインチューニング済みのモデルでは、スキーマを初めて使用するリクエストには、API がそのスキーマを処理する時間が加わります。以降、同じスキーマを使うリクエストでは、この追加の待ち時間は発生しません。他のモデルにはこの制約はありません。
まず、モデルの出力が従うべき JSON スキーマを表すオブジェクトまたはデータ構造を定義します。このガイドの冒頭にある例を参考にしてください。
構造化出力は JSON スキーマの機能の多くに対応していますが、パフォーマンス上または技術上の理由から、一部の機能は利用できません。詳しくは、サポートされているスキーマを参照してください。
たとえば、次のようにオブジェクトを定義できます。
1
2
3
4
5
6
7
8
9
10
11
12import { z } from "zod";
import { zodResponseFormat } from "openai/helpers/zod";
const Step = z.object({
explanation: z.string(),
output: z.string(),
});
const MathResponse = z.object({
steps: z.array(Step),
final_answer: z.string(),
});1
2
3
4
5
6
7
8
9
10
11from pydantic import BaseModel
class Step(BaseModel):
explanation: str
output: str
class MathResponse(BaseModel):
steps: list[Step]
final_answer: strデータ構造を設計する際のポイント
モデルの出力品質を最大限に高めるには、次の方法をおすすめします。
- キーには、意味がひと目でわかる名前を付ける
- データ構造の重要なキーには、わかりやすいタイトルと説明を付ける
- 評価テストを作成して実行し、用途に最も適したデータ構造を見極める
parse メソッドを使うと、JSON レスポンスを自動的に解析し、定義したオブジェクトに変換できます。
内部では、SDK がデータ構造に対応する JSON スキーマを API に渡し、返されたレスポンスを解析してオブジェクトに変換します。
1
2
3
4
5
6
7
8
9
10
11
12const completion = await openai.chat.completions.parse({
model: "gpt-6-astra",
messages: [
{
role: "system",
content:
"You are a helpful math tutor. Guide the user through the solution step by step.",
},
{ role: "user", content: "how can I solve 8x + 7 = -23" },
],
response_format: zodResponseFormat(MathResponse, "math_response"),
});1
2
3
4
5
6
7
8
9
10
11completion = client.chat.completions.parse(
model="gpt-6-astra",
messages=[
{
"role": "system",
"content": "You are a helpful math tutor. Guide the user through the solution step by step.",
},
{"role": "user", "content": "how can I solve 8x + 7 = -23"},
],
response_format=MathResponse,
)モデルが、指定した JSON スキーマに準拠する有効なレスポンスを生成できない場合があります。
たとえば、モデルが安全上の理由から回答を拒否した場合や、トークン数が上限に達してレスポンスが途中で途切れた場合です。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70try {
const completion = await openai.chat.completions.create({
model: "gpt-6-astra",
messages: [
{
role: "system",
content:
"You are a helpful math tutor. Guide the user through the solution step by step.",
},
{
role: "user",
content: "how can I solve 8x + 7 = -23",
},
],
store: true,
response_format: {
type: "json_schema",
json_schema: {
name: "math_response",
schema: {
type: "object",
properties: {
steps: {
type: "array",
items: {
type: "object",
properties: {
explanation: {
type: "string",
},
output: {
type: "string",
},
},
required: ["explanation", "output"],
additionalProperties: false,
},
},
final_answer: {
type: "string",
},
},
required: ["steps", "final_answer"],
additionalProperties: false,
},
strict: true,
},
},
max_completion_tokens: 1024,
});
if (completion.choices[0].finish_reason === "length") {
// Handle the case where the model did not return a complete response
throw new Error("Incomplete response");
}
const math_response = completion.choices[0].message;
if (math_response.refusal) {
// handle refusal
console.log(math_response.refusal);
} else if (math_response.content) {
console.log(math_response.content);
} else {
throw new Error("No response content");
}
} catch (e) {
// Handle edge cases
console.error(e);
}1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54try:
response = client.chat.completions.create(
model="gpt-6-astra",
messages=[
{
"role": "system",
"content": "You are a helpful math tutor. Guide the user through the solution step by step.",
},
{"role": "user", "content": "how can I solve 8x + 7 = -23"},
],
response_format={
"type": "json_schema",
"json_schema": {
"name": "math_response",
"strict": True,
"schema": {
"type": "object",
"properties": {
"steps": {
"type": "array",
"items": {
"type": "object",
"properties": {
"explanation": {"type": "string"},
"output": {"type": "string"},
},
"required": ["explanation", "output"],
"additionalProperties": False,
},
},
"final_answer": {"type": "string"},
},
"required": ["steps", "final_answer"],
"additionalProperties": False,
},
},
},
max_completion_tokens=1024,
)
if response.choices[0].finish_reason == "length":
raise Exception("Incomplete response")
math_response = response.choices[0].message
if math_response.refusal:
print(math_response.refusal)
elif math_response.content:
print(math_response.content)
else:
raise Exception("No response content")
except Exception as e:
# handle errors like finish_reason, refusal, content_filter, etc.
print(e)1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56package main
import (
"context"
"errors"
"fmt"
"github.com/openai/openai-go/v3"
"github.com/openai/openai-go/v3/shared"
)
func main() {
client := openai.NewClient()
completion, err := client.Chat.Completions.New(context.Background(), openai.ChatCompletionNewParams{
Model: "gpt-6-astra",
Messages: []openai.ChatCompletionMessageParamUnion{
openai.SystemMessage("You are a helpful math tutor. Guide the user through the solution step by step."),
openai.UserMessage("how can I solve 8x + 7 = -23"),
},
Store: openai.Bool(true),
MaxCompletionTokens: openai.Int(1024),
ResponseFormat: openai.ChatCompletionNewParamsResponseFormatUnion{
OfJSONSchema: &shared.ResponseFormatJSONSchemaParam{JSONSchema: shared.ResponseFormatJSONSchemaJSONSchemaParam{
Name: "math_response", Schema: mathSchema(), Strict: openai.Bool(true),
}},
},
})
if err != nil {
panic(err)
}
choice := completion.Choices[0]
if choice.FinishReason == "length" {
panic(errors.New("incomplete response"))
}
if choice.Message.Refusal != "" {
fmt.Println(choice.Message.Refusal)
return
}
if choice.Message.Content == "" {
panic(errors.New("no response content"))
}
fmt.Println(choice.Message.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,
}
}1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63import com.openai.client.OpenAIClient;
import com.openai.client.okhttp.OpenAIOkHttpClient;
import com.openai.core.JsonValue;
import com.openai.models.chat.completions.ChatCompletion;
import com.openai.models.chat.completions.ChatCompletionCreateParams;
import java.util.List;
import java.util.Map;
Map<String, Object> stepSchema =
Map.of(
"type",
"object",
"properties",
Map.of(
"explanation", Map.of("type", "string"),
"output", Map.of("type", "string")),
"required",
List.of("explanation", "output"),
"additionalProperties",
false);
Map<String, Object> mathSchema =
Map.of(
"type",
"object",
"properties",
Map.of(
"steps", Map.of("type", "array", "items", stepSchema),
"final_answer", Map.of("type", "string")),
"required",
List.of("steps", "final_answer"),
"additionalProperties",
false);
ChatCompletionCreateParams params =
ChatCompletionCreateParams.builder()
.model("gpt-6-astra")
.addSystemMessage(
"You are a helpful math tutor. Guide the user through the solution step by step.")
.addUserMessage("How can I solve 8x + 7 = -23?")
.maxCompletionTokens(1024)
.store(true)
.putAdditionalBodyProperty(
"response_format",
JsonValue.from(
Map.of(
"type",
"json_schema",
"json_schema",
Map.of("name", "math_response", "strict", true, "schema", mathSchema))))
.build();
var choice = client.chat().completions().create(params).choices().get(0);
if (choice.finishReason().equals(ChatCompletion.Choice.FinishReason.LENGTH)) {
System.out.println("Incomplete response");
} else if (choice.message().refusal().isPresent()) {
System.out.println(choice.message().refusal().orElseThrow());
} else {
System.out.println(
choice
.message()
.content()
.orElseThrow(() -> new IllegalStateException("No response content")));
}1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64using OpenAI.Chat;
string key = Environment.GetEnvironmentVariable("OPENAI_API_KEY")!;
string model = "gpt-6-astra";
ChatClient client = new(model, 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
}
"""
);
ChatCompletionOptions options = new()
{
MaxOutputTokenCount = 300,
ResponseFormat = ChatResponseFormat.CreateJsonSchemaFormat(
"math_response",
schema,
jsonSchemaIsStrict: true
),
};
ChatCompletion completion = await client.CompleteChatAsync(
[new SystemChatMessage("You are a helpful math tutor. Guide the user through the solution step by step."), new UserChatMessage("How can I solve 8x + 7 = -23?")],
options
);
if (completion.FinishReason == ChatFinishReason.Length)
{
throw new InvalidOperationException("The structured response was incomplete.");
}
if (completion.FinishReason == ChatFinishReason.ContentFilter)
{
throw new InvalidOperationException("The structured response was interrupted by the content filter.");
}
if (!string.IsNullOrEmpty(completion.Refusal))
{
Console.WriteLine(completion.Refusal);
}
else if (completion.Content.Count > 0)
{
Console.WriteLine(completion.Content[0].Text);
}
else
{
throw new InvalidOperationException("The completion did not contain a response.");
}1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58require "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
}
completion = client.chat.completions.create(
model: "gpt-6-astra",
messages: [
{
role: :system,
content: "You are a helpful math tutor. Guide the user through the solution step by step."
},
{
role: :user,
content: "How can I solve 8x + 7 = -23?"
}
],
max_completion_tokens: 1_024,
store: true,
response_format: {
type: :json_schema,
json_schema: {
name: "math_response",
strict: true,
schema: math_schema
}
}
)
choice = completion.choices.fetch(0)
if choice.finish_reason == OpenAI::Chat::ChatCompletion::Choice::FinishReason::LENGTH
raise "Incomplete response"
elsif choice.message.refusal
puts(choice.message.refusal)
else
content = choice.message.content or raise "No response content"
puts(content)
endまず、モデルの出力が従うべき JSON スキーマを設計します。このガイドの冒頭にある例を参考にしてください。
構造化出力は JSON スキーマの多くの機能に対応していますが、性能上または技術上の理由で利用できない機能もあります。詳しくは、対応しているスキーマを参照してください。
JSON スキーマ設計のポイント
モデルの出力品質を最大限に高めるには、次の点を意識して設計することをおすすめします。
- キーには、意味が直感的に伝わる名前を付ける
- スキーマ内の重要なキーには、わかりやすいタイトルと説明を付ける
- 評価を設計・実施し、用途に最も適した構造を見極める
構造化出力を使うには、次のように指定します。
response_format: { "type": "json_schema", "json_schema": … , "strict": true } text: { format: { type: "json_schema", "strict": true, "schema": … } } 以下は使用例です。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41const response = await openai.chat.completions.create({
model: "gpt-6-astra",
messages: [
{
role: "system",
content:
"You are a helpful math tutor. Guide the user through the solution step by step.",
},
{ role: "user", content: "how can I solve 8x + 7 = -23" },
],
store: true,
response_format: {
type: "json_schema",
json_schema: {
name: "math_response",
schema: {
type: "object",
properties: {
steps: {
type: "array",
items: {
type: "object",
properties: {
explanation: { type: "string" },
output: { type: "string" },
},
required: ["explanation", "output"],
additionalProperties: false,
},
},
final_answer: { type: "string" },
},
required: ["steps", "final_answer"],
additionalProperties: false,
},
strict: true,
},
},
});
console.log(response.choices[0].message.content);1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39response = client.chat.completions.create(
model="gpt-6-astra",
messages=[
{
"role": "system",
"content": "You are a helpful math tutor. Guide the user through the solution step by step.",
},
{"role": "user", "content": "how can I solve 8x + 7 = -23"},
],
response_format={
"type": "json_schema",
"json_schema": {
"name": "math_response",
"schema": {
"type": "object",
"properties": {
"steps": {
"type": "array",
"items": {
"type": "object",
"properties": {
"explanation": {"type": "string"},
"output": {"type": "string"},
},
"required": ["explanation", "output"],
"additionalProperties": False,
},
},
"final_answer": {"type": "string"},
},
"required": ["steps", "final_answer"],
"additionalProperties": False,
},
"strict": True,
},
},
)
print(response.choices[0].message.content)1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43package main
import (
"context"
"fmt"
"github.com/openai/openai-go/v3"
"github.com/openai/openai-go/v3/shared"
)
func main() {
client := openai.NewClient()
schema := mathSchema()
completion, err := client.Chat.Completions.New(context.Background(), openai.ChatCompletionNewParams{
Model: "gpt-6-astra",
Messages: []openai.ChatCompletionMessageParamUnion{
openai.SystemMessage("You are a helpful math tutor. Guide the user through the solution step by step."),
openai.UserMessage("how can I solve 8x + 7 = -23"),
},
Store: openai.Bool(true),
ResponseFormat: openai.ChatCompletionNewParamsResponseFormatUnion{
OfJSONSchema: &shared.ResponseFormatJSONSchemaParam{JSONSchema: shared.ResponseFormatJSONSchemaJSONSchemaParam{
Name: "math_response", Schema: schema, Strict: openai.Bool(true),
}},
},
})
if err != nil {
panic(err)
}
fmt.Println(completion.Choices[0].Message.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,
}
}1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52import com.openai.client.OpenAIClient;
import com.openai.client.okhttp.OpenAIOkHttpClient;
import com.openai.core.JsonValue;
import com.openai.models.chat.completions.ChatCompletionCreateParams;
import java.util.List;
import java.util.Map;
Map<String, Object> stepSchema =
Map.of(
"type",
"object",
"properties",
Map.of(
"explanation", Map.of("type", "string"),
"output", Map.of("type", "string")),
"required",
List.of("explanation", "output"),
"additionalProperties",
false);
Map<String, Object> mathSchema =
Map.of(
"type",
"object",
"properties",
Map.of(
"steps", Map.of("type", "array", "items", stepSchema),
"final_answer", Map.of("type", "string")),
"required",
List.of("steps", "final_answer"),
"additionalProperties",
false);
ChatCompletionCreateParams params =
ChatCompletionCreateParams.builder()
.model("gpt-6-astra")
.addSystemMessage(
"You are a helpful math tutor. Guide the user through the solution step by step.")
.addUserMessage("How can I solve 8x + 7 = -23?")
.store(true)
.putAdditionalBodyProperty(
"response_format",
JsonValue.from(
Map.of(
"type",
"json_schema",
"json_schema",
Map.of("name", "math_response", "strict", true, "schema", mathSchema))))
.build();
client.chat().completions().create(params).choices().stream()
.flatMap(choice -> choice.message().content().stream())
.forEach(System.out::println);1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46using System.Text.Json;
using OpenAI.Chat;
string key = Environment.GetEnvironmentVariable("OPENAI_API_KEY")!;
string model = "gpt-6-astra";
ChatClient client = new(model, 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
}
"""
);
ChatCompletionOptions options = new()
{
ResponseFormat = ChatResponseFormat.CreateJsonSchemaFormat(
"math_response",
schema,
jsonSchemaIsStrict: true
),
};
ChatCompletion completion = await client.CompleteChatAsync(
[new SystemChatMessage("You are a helpful math tutor. Guide the user through the solution step by step."), new UserChatMessage("How can I solve 8x + 7 = -23?")],
options
);
using JsonDocument parsed = JsonDocument.Parse(completion.Content[0].Text);
Console.WriteLine(parsed.RootElement);1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48require "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
}
completion = client.chat.completions.create(
model: "gpt-6-astra",
messages: [
{
role: :system,
content: "You are a helpful math tutor. Guide the user through the solution step by step."
},
{
role: :user,
content: "How can I solve 8x + 7 = -23?"
}
],
store: true,
response_format: {
type: :json_schema,
json_schema: {
name: "math_response",
strict: true,
schema: math_schema
}
}
)
puts(completion.choices.fetch(0).message.content)1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43curl https://api.openai.com/v1/chat/completions \
-H "Authorization: Bearer $OPENAI_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "gpt-6-astra",
"messages": [
{
"role": "system",
"content": "You are a helpful math tutor. Guide the user through the solution step by step."
},
{
"role": "user",
"content": "how can I solve 8x + 7 = -23"
}
],
"response_format": {
"type": "json_schema",
"json_schema": {
"name": "math_response",
"schema": {
"type": "object",
"properties": {
"steps": {
"type": "array",
"items": {
"type": "object",
"properties": {
"explanation": { "type": "string" },
"output": { "type": "string" }
},
"required": ["explanation", "output"],
"additionalProperties": false
}
},
"final_answer": { "type": "string" }
},
"required": ["steps", "final_answer"],
"additionalProperties": false
},
"strict": true
}
}
}'1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40const 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);1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39response = 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)1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45package 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,
}
}1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73import 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()));1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49using 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);1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47require "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)1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43curl 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
}
}
}'注意: 各スキーマを初めて使うリクエストでは、API がスキーマを処理する分だけ応答に時間がかかります。以降、同じスキーマを使うリクエストでは、この追加の待ち時間は発生しません。
モデルが、指定した JSON スキーマに準拠した有効なレスポンスを生成できないことがあります。
たとえば、モデルが安全上の理由で回答を拒否した場合や、トークン数が上限に達してレスポンスが途中で途切れた場合に起こります。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70try {
const completion = await openai.chat.completions.create({
model: "gpt-6-astra",
messages: [
{
role: "system",
content:
"You are a helpful math tutor. Guide the user through the solution step by step.",
},
{
role: "user",
content: "how can I solve 8x + 7 = -23",
},
],
store: true,
response_format: {
type: "json_schema",
json_schema: {
name: "math_response",
schema: {
type: "object",
properties: {
steps: {
type: "array",
items: {
type: "object",
properties: {
explanation: {
type: "string",
},
output: {
type: "string",
},
},
required: ["explanation", "output"],
additionalProperties: false,
},
},
final_answer: {
type: "string",
},
},
required: ["steps", "final_answer"],
additionalProperties: false,
},
strict: true,
},
},
max_completion_tokens: 1024,
});
if (completion.choices[0].finish_reason === "length") {
// Handle the case where the model did not return a complete response
throw new Error("Incomplete response");
}
const math_response = completion.choices[0].message;
if (math_response.refusal) {
// handle refusal
console.log(math_response.refusal);
} else if (math_response.content) {
console.log(math_response.content);
} else {
throw new Error("No response content");
}
} catch (e) {
// Handle edge cases
console.error(e);
}1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54try:
response = client.chat.completions.create(
model="gpt-6-astra",
messages=[
{
"role": "system",
"content": "You are a helpful math tutor. Guide the user through the solution step by step.",
},
{"role": "user", "content": "how can I solve 8x + 7 = -23"},
],
response_format={
"type": "json_schema",
"json_schema": {
"name": "math_response",
"strict": True,
"schema": {
"type": "object",
"properties": {
"steps": {
"type": "array",
"items": {
"type": "object",
"properties": {
"explanation": {"type": "string"},
"output": {"type": "string"},
},
"required": ["explanation", "output"],
"additionalProperties": False,
},
},
"final_answer": {"type": "string"},
},
"required": ["steps", "final_answer"],
"additionalProperties": False,
},
},
},
max_completion_tokens=1024,
)
if response.choices[0].finish_reason == "length":
raise Exception("Incomplete response")
math_response = response.choices[0].message
if math_response.refusal:
print(math_response.refusal)
elif math_response.content:
print(math_response.content)
else:
raise Exception("No response content")
except Exception as e:
# handle errors like finish_reason, refusal, content_filter, etc.
print(e)1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56package main
import (
"context"
"errors"
"fmt"
"github.com/openai/openai-go/v3"
"github.com/openai/openai-go/v3/shared"
)
func main() {
client := openai.NewClient()
completion, err := client.Chat.Completions.New(context.Background(), openai.ChatCompletionNewParams{
Model: "gpt-6-astra",
Messages: []openai.ChatCompletionMessageParamUnion{
openai.SystemMessage("You are a helpful math tutor. Guide the user through the solution step by step."),
openai.UserMessage("how can I solve 8x + 7 = -23"),
},
Store: openai.Bool(true),
MaxCompletionTokens: openai.Int(1024),
ResponseFormat: openai.ChatCompletionNewParamsResponseFormatUnion{
OfJSONSchema: &shared.ResponseFormatJSONSchemaParam{JSONSchema: shared.ResponseFormatJSONSchemaJSONSchemaParam{
Name: "math_response", Schema: mathSchema(), Strict: openai.Bool(true),
}},
},
})
if err != nil {
panic(err)
}
choice := completion.Choices[0]
if choice.FinishReason == "length" {
panic(errors.New("incomplete response"))
}
if choice.Message.Refusal != "" {
fmt.Println(choice.Message.Refusal)
return
}
if choice.Message.Content == "" {
panic(errors.New("no response content"))
}
fmt.Println(choice.Message.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,
}
}1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63import com.openai.client.OpenAIClient;
import com.openai.client.okhttp.OpenAIOkHttpClient;
import com.openai.core.JsonValue;
import com.openai.models.chat.completions.ChatCompletion;
import com.openai.models.chat.completions.ChatCompletionCreateParams;
import java.util.List;
import java.util.Map;
Map<String, Object> stepSchema =
Map.of(
"type",
"object",
"properties",
Map.of(
"explanation", Map.of("type", "string"),
"output", Map.of("type", "string")),
"required",
List.of("explanation", "output"),
"additionalProperties",
false);
Map<String, Object> mathSchema =
Map.of(
"type",
"object",
"properties",
Map.of(
"steps", Map.of("type", "array", "items", stepSchema),
"final_answer", Map.of("type", "string")),
"required",
List.of("steps", "final_answer"),
"additionalProperties",
false);
ChatCompletionCreateParams params =
ChatCompletionCreateParams.builder()
.model("gpt-6-astra")
.addSystemMessage(
"You are a helpful math tutor. Guide the user through the solution step by step.")
.addUserMessage("How can I solve 8x + 7 = -23?")
.maxCompletionTokens(1024)
.store(true)
.putAdditionalBodyProperty(
"response_format",
JsonValue.from(
Map.of(
"type",
"json_schema",
"json_schema",
Map.of("name", "math_response", "strict", true, "schema", mathSchema))))
.build();
var choice = client.chat().completions().create(params).choices().get(0);
if (choice.finishReason().equals(ChatCompletion.Choice.FinishReason.LENGTH)) {
System.out.println("Incomplete response");
} else if (choice.message().refusal().isPresent()) {
System.out.println(choice.message().refusal().orElseThrow());
} else {
System.out.println(
choice
.message()
.content()
.orElseThrow(() -> new IllegalStateException("No response content")));
}1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64using OpenAI.Chat;
string key = Environment.GetEnvironmentVariable("OPENAI_API_KEY")!;
string model = "gpt-6-astra";
ChatClient client = new(model, 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
}
"""
);
ChatCompletionOptions options = new()
{
MaxOutputTokenCount = 300,
ResponseFormat = ChatResponseFormat.CreateJsonSchemaFormat(
"math_response",
schema,
jsonSchemaIsStrict: true
),
};
ChatCompletion completion = await client.CompleteChatAsync(
[new SystemChatMessage("You are a helpful math tutor. Guide the user through the solution step by step."), new UserChatMessage("How can I solve 8x + 7 = -23?")],
options
);
if (completion.FinishReason == ChatFinishReason.Length)
{
throw new InvalidOperationException("The structured response was incomplete.");
}
if (completion.FinishReason == ChatFinishReason.ContentFilter)
{
throw new InvalidOperationException("The structured response was interrupted by the content filter.");
}
if (!string.IsNullOrEmpty(completion.Refusal))
{
Console.WriteLine(completion.Refusal);
}
else if (completion.Content.Count > 0)
{
Console.WriteLine(completion.Content[0].Text);
}
else
{
throw new InvalidOperationException("The completion did not contain a response.");
}1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58require "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
}
completion = client.chat.completions.create(
model: "gpt-6-astra",
messages: [
{
role: :system,
content: "You are a helpful math tutor. Guide the user through the solution step by step."
},
{
role: :user,
content: "How can I solve 8x + 7 = -23?"
}
],
max_completion_tokens: 1_024,
store: true,
response_format: {
type: :json_schema,
json_schema: {
name: "math_response",
strict: true,
schema: math_schema
}
}
)
choice = completion.choices.fetch(0)
if choice.finish_reason == OpenAI::Chat::ChatCompletion::Choice::FinishReason::LENGTH
raise "Incomplete response"
elsif choice.message.refusal
puts(choice.message.refusal)
else
content = choice.message.content or raise "No response content"
puts(content)
end1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77try {
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: 1024,
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);
}1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61try:
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=1024,
)
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)1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66package 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,
}
}1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93import 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());
}1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68using 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
);1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65require "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レスポンスにスキーマに準拠した JSON が含まれていることを確認したら、その JSON をパースして、使用している言語のネイティブなデータ構造に変換します。型付き言語では、対応する型やクラスでデータを表現することもできます。
以下に例を示します。
1
2
3
4
5// The request that produces `response` appears earlier in this guide.
const content = response.choices[0].message.content;
if (!content) throw new Error("The response did not contain JSON output.");
const solution = JSON.parse(content);1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18from pydantic import BaseModel, ValidationError
class Step(BaseModel):
explanation: str
output: str
class Solution(BaseModel):
steps: list[Step]
final_answer: str
try:
solution = Solution.model_validate_json(response.choices[0].message.content)
print(solution)
except ValidationError as error:
print(error.json())1
2
3
4
5
6
7
8
9
10
11var solution struct {
Steps []struct {
Explanation string `json:"explanation"`
Output string `json:"output"`
} `json:"steps"`
FinalAnswer string `json:"final_answer"`
}
if err := json.Unmarshal([]byte(completion.Choices[0].Message.Content), &solution); err != nil {
return err
}
fmt.Println(solution)1System.out.println(new ObjectMapper().readTree(content));1
2
3
4
5using System.Text.Json;
using OpenAI.Chat;
using JsonDocument solution = JsonDocument.Parse(completion.Content[0].Text);
Console.WriteLine(solution.RootElement);1
2
3
4
5content = completion.choices.fetch(0).message.content
raise "Response did not contain JSON output." if content.nil?
solution = JSON.parse(content)
puts(solution)構造化出力の設定方法:text.format
まず、モデルの出力が従うべき JSON スキーマを設計します。このガイドの冒頭にある例を参考にしてください。
構造化出力は JSON スキーマの多くの機能に対応していますが、性能上または技術上の理由で利用できない機能もあります。詳しくは、対応しているスキーマを参照してください。
JSON スキーマ設計のポイント
モデルの出力品質を最大限に高めるには、次の点を意識して設計することをおすすめします。
- キーには、意味が直感的に伝わる名前を付ける
- スキーマ内の重要なキーには、わかりやすいタイトルと説明を付ける
- 評価を設計・実施し、用途に最も適した構造を見極める
構造化出力を使うには、次のように指定します。
response_format: { "type": "json_schema", "json_schema": … , "strict": true } text: { format: { type: "json_schema", "strict": true, "schema": … } } 以下は使用例です。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41const response = await openai.chat.completions.create({
model: "gpt-6-astra",
messages: [
{
role: "system",
content:
"You are a helpful math tutor. Guide the user through the solution step by step.",
},
{ role: "user", content: "how can I solve 8x + 7 = -23" },
],
store: true,
response_format: {
type: "json_schema",
json_schema: {
name: "math_response",
schema: {
type: "object",
properties: {
steps: {
type: "array",
items: {
type: "object",
properties: {
explanation: { type: "string" },
output: { type: "string" },
},
required: ["explanation", "output"],
additionalProperties: false,
},
},
final_answer: { type: "string" },
},
required: ["steps", "final_answer"],
additionalProperties: false,
},
strict: true,
},
},
});
console.log(response.choices[0].message.content);1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39response = client.chat.completions.create(
model="gpt-6-astra",
messages=[
{
"role": "system",
"content": "You are a helpful math tutor. Guide the user through the solution step by step.",
},
{"role": "user", "content": "how can I solve 8x + 7 = -23"},
],
response_format={
"type": "json_schema",
"json_schema": {
"name": "math_response",
"schema": {
"type": "object",
"properties": {
"steps": {
"type": "array",
"items": {
"type": "object",
"properties": {
"explanation": {"type": "string"},
"output": {"type": "string"},
},
"required": ["explanation", "output"],
"additionalProperties": False,
},
},
"final_answer": {"type": "string"},
},
"required": ["steps", "final_answer"],
"additionalProperties": False,
},
"strict": True,
},
},
)
print(response.choices[0].message.content)1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43package main
import (
"context"
"fmt"
"github.com/openai/openai-go/v3"
"github.com/openai/openai-go/v3/shared"
)
func main() {
client := openai.NewClient()
schema := mathSchema()
completion, err := client.Chat.Completions.New(context.Background(), openai.ChatCompletionNewParams{
Model: "gpt-6-astra",
Messages: []openai.ChatCompletionMessageParamUnion{
openai.SystemMessage("You are a helpful math tutor. Guide the user through the solution step by step."),
openai.UserMessage("how can I solve 8x + 7 = -23"),
},
Store: openai.Bool(true),
ResponseFormat: openai.ChatCompletionNewParamsResponseFormatUnion{
OfJSONSchema: &shared.ResponseFormatJSONSchemaParam{JSONSchema: shared.ResponseFormatJSONSchemaJSONSchemaParam{
Name: "math_response", Schema: schema, Strict: openai.Bool(true),
}},
},
})
if err != nil {
panic(err)
}
fmt.Println(completion.Choices[0].Message.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,
}
}1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52import com.openai.client.OpenAIClient;
import com.openai.client.okhttp.OpenAIOkHttpClient;
import com.openai.core.JsonValue;
import com.openai.models.chat.completions.ChatCompletionCreateParams;
import java.util.List;
import java.util.Map;
Map<String, Object> stepSchema =
Map.of(
"type",
"object",
"properties",
Map.of(
"explanation", Map.of("type", "string"),
"output", Map.of("type", "string")),
"required",
List.of("explanation", "output"),
"additionalProperties",
false);
Map<String, Object> mathSchema =
Map.of(
"type",
"object",
"properties",
Map.of(
"steps", Map.of("type", "array", "items", stepSchema),
"final_answer", Map.of("type", "string")),
"required",
List.of("steps", "final_answer"),
"additionalProperties",
false);
ChatCompletionCreateParams params =
ChatCompletionCreateParams.builder()
.model("gpt-6-astra")
.addSystemMessage(
"You are a helpful math tutor. Guide the user through the solution step by step.")
.addUserMessage("How can I solve 8x + 7 = -23?")
.store(true)
.putAdditionalBodyProperty(
"response_format",
JsonValue.from(
Map.of(
"type",
"json_schema",
"json_schema",
Map.of("name", "math_response", "strict", true, "schema", mathSchema))))
.build();
client.chat().completions().create(params).choices().stream()
.flatMap(choice -> choice.message().content().stream())
.forEach(System.out::println);1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46using System.Text.Json;
using OpenAI.Chat;
string key = Environment.GetEnvironmentVariable("OPENAI_API_KEY")!;
string model = "gpt-6-astra";
ChatClient client = new(model, 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
}
"""
);
ChatCompletionOptions options = new()
{
ResponseFormat = ChatResponseFormat.CreateJsonSchemaFormat(
"math_response",
schema,
jsonSchemaIsStrict: true
),
};
ChatCompletion completion = await client.CompleteChatAsync(
[new SystemChatMessage("You are a helpful math tutor. Guide the user through the solution step by step."), new UserChatMessage("How can I solve 8x + 7 = -23?")],
options
);
using JsonDocument parsed = JsonDocument.Parse(completion.Content[0].Text);
Console.WriteLine(parsed.RootElement);1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48require "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
}
completion = client.chat.completions.create(
model: "gpt-6-astra",
messages: [
{
role: :system,
content: "You are a helpful math tutor. Guide the user through the solution step by step."
},
{
role: :user,
content: "How can I solve 8x + 7 = -23?"
}
],
store: true,
response_format: {
type: :json_schema,
json_schema: {
name: "math_response",
strict: true,
schema: math_schema
}
}
)
puts(completion.choices.fetch(0).message.content)1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43curl https://api.openai.com/v1/chat/completions \
-H "Authorization: Bearer $OPENAI_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "gpt-6-astra",
"messages": [
{
"role": "system",
"content": "You are a helpful math tutor. Guide the user through the solution step by step."
},
{
"role": "user",
"content": "how can I solve 8x + 7 = -23"
}
],
"response_format": {
"type": "json_schema",
"json_schema": {
"name": "math_response",
"schema": {
"type": "object",
"properties": {
"steps": {
"type": "array",
"items": {
"type": "object",
"properties": {
"explanation": { "type": "string" },
"output": { "type": "string" }
},
"required": ["explanation", "output"],
"additionalProperties": false
}
},
"final_answer": { "type": "string" }
},
"required": ["steps", "final_answer"],
"additionalProperties": false
},
"strict": true
}
}
}'1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40const 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);1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39response = 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)1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45package 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,
}
}1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73import 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()));1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49using 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);1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47require "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)1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43curl 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
}
}
}'注意: 各スキーマを初めて使うリクエストでは、API がスキーマを処理する分だけ応答に時間がかかります。以降、同じスキーマを使うリクエストでは、この追加の待ち時間は発生しません。
モデルが、指定した JSON スキーマに準拠した有効なレスポンスを生成できないことがあります。
たとえば、モデルが安全上の理由で回答を拒否した場合や、トークン数が上限に達してレスポンスが途中で途切れた場合に起こります。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70try {
const completion = await openai.chat.completions.create({
model: "gpt-6-astra",
messages: [
{
role: "system",
content:
"You are a helpful math tutor. Guide the user through the solution step by step.",
},
{
role: "user",
content: "how can I solve 8x + 7 = -23",
},
],
store: true,
response_format: {
type: "json_schema",
json_schema: {
name: "math_response",
schema: {
type: "object",
properties: {
steps: {
type: "array",
items: {
type: "object",
properties: {
explanation: {
type: "string",
},
output: {
type: "string",
},
},
required: ["explanation", "output"],
additionalProperties: false,
},
},
final_answer: {
type: "string",
},
},
required: ["steps", "final_answer"],
additionalProperties: false,
},
strict: true,
},
},
max_completion_tokens: 1024,
});
if (completion.choices[0].finish_reason === "length") {
// Handle the case where the model did not return a complete response
throw new Error("Incomplete response");
}
const math_response = completion.choices[0].message;
if (math_response.refusal) {
// handle refusal
console.log(math_response.refusal);
} else if (math_response.content) {
console.log(math_response.content);
} else {
throw new Error("No response content");
}
} catch (e) {
// Handle edge cases
console.error(e);
}1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54try:
response = client.chat.completions.create(
model="gpt-6-astra",
messages=[
{
"role": "system",
"content": "You are a helpful math tutor. Guide the user through the solution step by step.",
},
{"role": "user", "content": "how can I solve 8x + 7 = -23"},
],
response_format={
"type": "json_schema",
"json_schema": {
"name": "math_response",
"strict": True,
"schema": {
"type": "object",
"properties": {
"steps": {
"type": "array",
"items": {
"type": "object",
"properties": {
"explanation": {"type": "string"},
"output": {"type": "string"},
},
"required": ["explanation", "output"],
"additionalProperties": False,
},
},
"final_answer": {"type": "string"},
},
"required": ["steps", "final_answer"],
"additionalProperties": False,
},
},
},
max_completion_tokens=1024,
)
if response.choices[0].finish_reason == "length":
raise Exception("Incomplete response")
math_response = response.choices[0].message
if math_response.refusal:
print(math_response.refusal)
elif math_response.content:
print(math_response.content)
else:
raise Exception("No response content")
except Exception as e:
# handle errors like finish_reason, refusal, content_filter, etc.
print(e)1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56package main
import (
"context"
"errors"
"fmt"
"github.com/openai/openai-go/v3"
"github.com/openai/openai-go/v3/shared"
)
func main() {
client := openai.NewClient()
completion, err := client.Chat.Completions.New(context.Background(), openai.ChatCompletionNewParams{
Model: "gpt-6-astra",
Messages: []openai.ChatCompletionMessageParamUnion{
openai.SystemMessage("You are a helpful math tutor. Guide the user through the solution step by step."),
openai.UserMessage("how can I solve 8x + 7 = -23"),
},
Store: openai.Bool(true),
MaxCompletionTokens: openai.Int(1024),
ResponseFormat: openai.ChatCompletionNewParamsResponseFormatUnion{
OfJSONSchema: &shared.ResponseFormatJSONSchemaParam{JSONSchema: shared.ResponseFormatJSONSchemaJSONSchemaParam{
Name: "math_response", Schema: mathSchema(), Strict: openai.Bool(true),
}},
},
})
if err != nil {
panic(err)
}
choice := completion.Choices[0]
if choice.FinishReason == "length" {
panic(errors.New("incomplete response"))
}
if choice.Message.Refusal != "" {
fmt.Println(choice.Message.Refusal)
return
}
if choice.Message.Content == "" {
panic(errors.New("no response content"))
}
fmt.Println(choice.Message.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,
}
}1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63import com.openai.client.OpenAIClient;
import com.openai.client.okhttp.OpenAIOkHttpClient;
import com.openai.core.JsonValue;
import com.openai.models.chat.completions.ChatCompletion;
import com.openai.models.chat.completions.ChatCompletionCreateParams;
import java.util.List;
import java.util.Map;
Map<String, Object> stepSchema =
Map.of(
"type",
"object",
"properties",
Map.of(
"explanation", Map.of("type", "string"),
"output", Map.of("type", "string")),
"required",
List.of("explanation", "output"),
"additionalProperties",
false);
Map<String, Object> mathSchema =
Map.of(
"type",
"object",
"properties",
Map.of(
"steps", Map.of("type", "array", "items", stepSchema),
"final_answer", Map.of("type", "string")),
"required",
List.of("steps", "final_answer"),
"additionalProperties",
false);
ChatCompletionCreateParams params =
ChatCompletionCreateParams.builder()
.model("gpt-6-astra")
.addSystemMessage(
"You are a helpful math tutor. Guide the user through the solution step by step.")
.addUserMessage("How can I solve 8x + 7 = -23?")
.maxCompletionTokens(1024)
.store(true)
.putAdditionalBodyProperty(
"response_format",
JsonValue.from(
Map.of(
"type",
"json_schema",
"json_schema",
Map.of("name", "math_response", "strict", true, "schema", mathSchema))))
.build();
var choice = client.chat().completions().create(params).choices().get(0);
if (choice.finishReason().equals(ChatCompletion.Choice.FinishReason.LENGTH)) {
System.out.println("Incomplete response");
} else if (choice.message().refusal().isPresent()) {
System.out.println(choice.message().refusal().orElseThrow());
} else {
System.out.println(
choice
.message()
.content()
.orElseThrow(() -> new IllegalStateException("No response content")));
}1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64using OpenAI.Chat;
string key = Environment.GetEnvironmentVariable("OPENAI_API_KEY")!;
string model = "gpt-6-astra";
ChatClient client = new(model, 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
}
"""
);
ChatCompletionOptions options = new()
{
MaxOutputTokenCount = 300,
ResponseFormat = ChatResponseFormat.CreateJsonSchemaFormat(
"math_response",
schema,
jsonSchemaIsStrict: true
),
};
ChatCompletion completion = await client.CompleteChatAsync(
[new SystemChatMessage("You are a helpful math tutor. Guide the user through the solution step by step."), new UserChatMessage("How can I solve 8x + 7 = -23?")],
options
);
if (completion.FinishReason == ChatFinishReason.Length)
{
throw new InvalidOperationException("The structured response was incomplete.");
}
if (completion.FinishReason == ChatFinishReason.ContentFilter)
{
throw new InvalidOperationException("The structured response was interrupted by the content filter.");
}
if (!string.IsNullOrEmpty(completion.Refusal))
{
Console.WriteLine(completion.Refusal);
}
else if (completion.Content.Count > 0)
{
Console.WriteLine(completion.Content[0].Text);
}
else
{
throw new InvalidOperationException("The completion did not contain a response.");
}1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58require "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
}
completion = client.chat.completions.create(
model: "gpt-6-astra",
messages: [
{
role: :system,
content: "You are a helpful math tutor. Guide the user through the solution step by step."
},
{
role: :user,
content: "How can I solve 8x + 7 = -23?"
}
],
max_completion_tokens: 1_024,
store: true,
response_format: {
type: :json_schema,
json_schema: {
name: "math_response",
strict: true,
schema: math_schema
}
}
)
choice = completion.choices.fetch(0)
if choice.finish_reason == OpenAI::Chat::ChatCompletion::Choice::FinishReason::LENGTH
raise "Incomplete response"
elsif choice.message.refusal
puts(choice.message.refusal)
else
content = choice.message.content or raise "No response content"
puts(content)
end1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77try {
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: 1024,
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);
}1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61try:
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=1024,
)
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)1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66package 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,
}
}1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93import 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());
}1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68using 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
);1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65require "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レスポンスにスキーマに準拠した JSON が含まれていることを確認したら、その JSON をパースして、使用している言語のネイティブなデータ構造に変換します。型付き言語では、対応する型やクラスでデータを表現することもできます。
以下に例を示します。
1
2
3
4
5// The request that produces `response` appears earlier in this guide.
const content = response.choices[0].message.content;
if (!content) throw new Error("The response did not contain JSON output.");
const solution = JSON.parse(content);1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18from pydantic import BaseModel, ValidationError
class Step(BaseModel):
explanation: str
output: str
class Solution(BaseModel):
steps: list[Step]
final_answer: str
try:
solution = Solution.model_validate_json(response.choices[0].message.content)
print(solution)
except ValidationError as error:
print(error.json())1
2
3
4
5
6
7
8
9
10
11var solution struct {
Steps []struct {
Explanation string `json:"explanation"`
Output string `json:"output"`
} `json:"steps"`
FinalAnswer string `json:"final_answer"`
}
if err := json.Unmarshal([]byte(completion.Choices[0].Message.Content), &solution); err != nil {
return err
}
fmt.Println(solution)1System.out.println(new ObjectMapper().readTree(content));1
2
3
4
5using System.Text.Json;
using OpenAI.Chat;
using JsonDocument solution = JsonDocument.Parse(completion.Content[0].Text);
Console.WriteLine(solution.RootElement);1
2
3
4
5content = completion.choices.fetch(0).message.content
raise "Response did not contain JSON output." if content.nil?
solution = JSON.parse(content)
puts(solution)会話の途中での応答形式の変更
次の応答から新しいスキーマを使うには、configuration_update 項目を input に追加し、その後に次のユーザーメッセージを追加します。各リクエストのトップレベルの text.format には元の値を指定してください。これにより、それまでのプロンプトの先頭部分が引き続きプロンプトキャッシュの対象になります。
応答形式の更新は、GPT-6 以降の対応モデルを標準のシングルエージェントモードで使用する場合に利用できます。
前のターンで、出荷する荷物には赤い木箱が 17 個、青い木箱が 26 個あるとプレーンテキストで説明したとします。previous_response_id で会話を続け、次の配列を input として渡します。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28import OpenAI from "openai";
import { zodTextFormat } from "openai/helpers/zod";
import { z } from "zod";
const client = new OpenAI();
const model = "gpt-6-astra";
const CrateCount = z.object({ total_crates: z.number().int() });
const first = await client.responses.create({
model,
input:
"Summarize this shipment in one sentence: 17 red crates and 26 blue crates.",
store: true,
});
const format = zodTextFormat(CrateCount, "crate_count");
const second = await client.responses.parse({
model,
previous_response_id: first.id,
input: [
{ type: "configuration_update", text: { format } },
{ role: "user", content: "How many crates are in the shipment?" },
],
});
if (second.status === "completed" && second.output_parsed) {
console.log(second.output_parsed.total_crates);
}1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40from openai import OpenAI
from pydantic import BaseModel, ConfigDict
class CrateCount(BaseModel):
model_config = ConfigDict(extra="forbid")
total_crates: int
client = OpenAI()
model = "gpt-6-astra"
first = client.responses.create(
model=model,
input="Summarize this shipment in one sentence: 17 red crates and 26 blue crates.",
store=True,
)
second = client.responses.parse(
model=model,
previous_response_id=first.id,
input=[
{
"type": "configuration_update",
"text": {
"format": {
"type": "json_schema",
"name": "crate_count",
"schema": CrateCount.model_json_schema(),
"strict": True,
}
},
},
{"role": "user", "content": "How many crates are in the shipment?"},
],
parse_as=CrateCount,
)
if second.status == "completed" and second.output_parsed is not None:
print(second.output_parsed.total_crates)1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64package main
import (
"context"
"fmt"
"github.com/openai/openai-go/v3"
"github.com/openai/openai-go/v3/responses"
)
func main() {
client := openai.NewClient()
ctx := context.Background()
const model = "gpt-6-astra"
first, err := client.Responses.New(ctx, responses.ResponseNewParams{
Model: model,
Input: responses.ResponseNewParamsInputUnion{
OfString: openai.String("Summarize this shipment in one sentence: 17 red crates and 26 blue crates."),
},
Store: openai.Bool(true),
})
if err != nil {
panic(err)
}
format := responses.ResponseFormatTextJSONSchemaConfigParam{
Name: "crate_count",
Schema: map[string]any{
"type": "object",
"properties": map[string]any{"total_crates": map[string]any{"type": "integer"}},
"required": []string{"total_crates"},
"additionalProperties": false,
},
Strict: openai.Bool(true),
}
second, err := client.Responses.New(ctx, responses.ResponseNewParams{
Model: model,
PreviousResponseID: openai.String(first.ID),
Input: responses.ResponseNewParamsInputUnion{OfInputItemList: responses.ResponseInputParam{
{OfConfigurationUpdate: &responses.ResponseConfigurationUpdateItemParam{
Text: responses.ResponseConfigurationUpdateItemParamText{
Format: responses.ResponseConfigurationUpdateItemParamTextFormatUnion{OfJSONSchema: &format},
},
}},
responses.ResponseInputItemParamOfMessage("How many crates are in the shipment?", responses.EasyInputMessageRoleUser),
}},
})
if err != nil {
panic(err)
}
if second.Status != responses.ResponseStatusCompleted {
return
}
for _, item := range second.Output {
if item.Type != "message" || (item.Phase != "" && item.Phase != responses.ResponseOutputMessagePhaseFinalAnswer) {
continue
}
for _, part := range item.Content {
if part.Type == "output_text" {
fmt.Println(part.Text)
}
}
}
}1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73import com.openai.core.JsonValue;
import com.openai.models.responses.EasyInputMessage;
import com.openai.models.responses.ResponseConfigurationUpdateItemParam;
import com.openai.models.responses.ResponseCreateParams;
import com.openai.models.responses.ResponseFormatTextJsonSchemaConfig;
import com.openai.models.responses.ResponseInputItem;
import com.openai.models.responses.ResponseOutputMessage;
import com.openai.models.responses.ResponseStatus;
import java.util.List;
import java.util.Map;
String model = "gpt-6-astra";
var first =
client
.responses()
.create(
ResponseCreateParams.builder()
.model(model)
.input(
"Summarize this shipment in one sentence: 17 red crates and 26 blue crates.")
.store(true)
.build());
var schema =
Map.of(
"type",
"object",
"properties",
Map.of("total_crates", Map.of("type", "integer")),
"required",
List.of("total_crates"),
"additionalProperties",
false);
var format =
ResponseFormatTextJsonSchemaConfig.builder()
.name("crate_count")
.schema(JsonValue.from(schema).convert(ResponseFormatTextJsonSchemaConfig.Schema.class))
.strict(true)
.build();
var update =
ResponseConfigurationUpdateItemParam.builder()
.text(ResponseConfigurationUpdateItemParam.Text.builder().format(format).build())
.build();
var question =
EasyInputMessage.builder()
.role(EasyInputMessage.Role.USER)
.content("How many crates are in the shipment?")
.build();
var second =
client
.responses()
.create(
ResponseCreateParams.builder()
.model(model)
.previousResponseId(first.id())
.inputOfResponse(
List.of(
ResponseInputItem.ofConfigurationUpdate(update),
ResponseInputItem.ofEasyInputMessage(question)))
.build());
if (!ResponseStatus.COMPLETED.equals(second.status().orElse(null))) {
return;
}
second.output().stream()
.flatMap(item -> item.message().stream())
.filter(
message ->
message.phase().map(ResponseOutputMessage.Phase.FINAL_ANSWER::equals).orElse(true))
.flatMap(message -> message.content().stream())
.flatMap(content -> content.outputText().stream())
.forEach(text -> System.out.println(text.text()));1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52# gem install openai sorbet-runtime
require "openai"
require "openai/helpers/sorbet"
class CrateCount < T::Struct
const :total_crates, Integer
end
client = OpenAI::Client.new
model = "gpt-6-astra"
first = client.responses.create(
model: model,
input: "Summarize this shipment in one sentence: 17 red crates and 26 blue crates.",
store: true
)
second = client.responses.create(
model: model,
previous_response_id: first.id,
input: [
{
type: :configuration_update,
text: {
format: {
type: :json_schema,
name: "crate_count",
schema: OpenAI::StructuredOutput.from_sorbet(CrateCount),
strict: true
}
}
},
{
role: :user,
content: "How many crates are in the shipment?"
}
]
)
if second.status == OpenAI::Responses::ResponseStatus::COMPLETED
second.output.grep(OpenAI::Responses::ResponseOutputMessage).each do |message|
next unless message.phase.nil? || message.phase == :final_answer
message.content.grep(OpenAI::Responses::ResponseOutputText).each do |part|
count = part.parsed
case count
when CrateCount
puts count.total_crates
end
end
end
end期待される回答は {"total_crates":43} です。応答オブジェクトの text.format には、リクエストのトップレベルで指定した元の形式が引き続き表示されます。リクエストが拒否されておらず、応答が完全であることを確認してから、直近の形式更新で指定したスキーマを使って回答をパースしてください。
形式を更新するたびに、応答形式全体が置き換わります。更新後の形式は後続のターンでも有効で、reasoning.effort だけを更新した場合も引き継がれます。プレーンテキストに戻すには、{"type":"configuration_update","text":{"format":{"type":"text"}}} を追加します。更新時に指定できる形式は json_schema と text だけです。
会話履歴を手動で再送する場合は、各更新項目を元の位置に残してください。コンパクションを明示的に実行した後は、変更した設定をすべて再指定してください。詳しくは、設定更新の互換性を参照してください。
構造化出力でのリクエスト拒否
ユーザー入力に対して構造化出力を使うと、OpenAI のモデルが安全上の理由でリクエストを拒否することがあります。拒否時の応答は response_format で指定したスキーマに従うとは限らないため、API の応答には、モデルがリクエストを拒否したことを示す新しいフィールド refusal が含まれます。
出力オブジェクトに refusal プロパティが含まれている場合は、拒否メッセージを UI に表示したり、応答を受け取るコードに条件分岐を追加して拒否時の処理を実行したりできます。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31const Step = z.object({
explanation: z.string(),
output: z.string(),
});
const MathReasoning = z.object({
steps: z.array(Step),
final_answer: z.string(),
});
const completion = await openai.chat.completions.parse({
model: "gpt-6-astra",
messages: [
{
role: "system",
content:
"You are a helpful math tutor. Guide the user through the solution step by step.",
},
{ role: "user", content: "how can I solve 8x + 7 = -23" },
],
response_format: zodResponseFormat(MathReasoning, "math_reasoning"),
});
const math_reasoning = completion.choices[0].message;
// If the model refuses to respond, you will get a refusal message
if (math_reasoning.refusal) {
console.log(math_reasoning.refusal);
} else {
console.log(math_reasoning.parsed);
}1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30class Step(BaseModel):
explanation: str
output: str
class MathReasoning(BaseModel):
steps: list[Step]
final_answer: str
completion = client.chat.completions.parse(
model="gpt-6-astra",
messages=[
{
"role": "system",
"content": "You are a helpful math tutor. Guide the user through the solution step by step.",
},
{"role": "user", "content": "how can I solve 8x + 7 = -23"},
],
response_format=MathReasoning,
)
math_reasoning = completion.choices[0].message
# If the model refuses to respond, you will get a refusal message
if math_reasoning.refusal:
print(math_reasoning.refusal)
else:
print(math_reasoning.parsed)1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47package main
import (
"context"
"fmt"
"github.com/openai/openai-go/v3"
"github.com/openai/openai-go/v3/shared"
)
func main() {
client := openai.NewClient()
completion, err := client.Chat.Completions.New(context.Background(), openai.ChatCompletionNewParams{
Model: "gpt-6-astra",
Messages: []openai.ChatCompletionMessageParamUnion{
openai.SystemMessage("You are a helpful math tutor. Guide the user through the solution step by step."),
openai.UserMessage("how can I solve 8x + 7 = -23"),
},
ResponseFormat: openai.ChatCompletionNewParamsResponseFormatUnion{
OfJSONSchema: &shared.ResponseFormatJSONSchemaParam{JSONSchema: shared.ResponseFormatJSONSchemaJSONSchemaParam{
Name: "math_reasoning", Schema: mathSchema(), Strict: openai.Bool(true),
}},
},
})
if err != nil {
panic(err)
}
message := completion.Choices[0].Message
if message.Refusal != "" {
fmt.Println(message.Refusal)
return
}
fmt.Println(message.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,
}
}1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53import com.openai.client.OpenAIClient;
import com.openai.client.okhttp.OpenAIOkHttpClient;
import com.openai.core.JsonValue;
import com.openai.models.chat.completions.ChatCompletionCreateParams;
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);
ChatCompletionCreateParams params =
ChatCompletionCreateParams.builder()
.model("gpt-6-astra")
.addSystemMessage(
"You are a helpful math tutor. Guide the user through the solution step by step.")
.addUserMessage("How can I solve 8x + 7 = -23?")
.putAdditionalBodyProperty(
"response_format",
JsonValue.from(
Map.of(
"type",
"json_schema",
"json_schema",
Map.of("name", "math_reasoning", "strict", true, "schema", schema))))
.build();
var message = client.chat().completions().create(params).choices().get(0).message();
System.out.println(message.refusal().or(() -> message.content()).orElseThrow());1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51using OpenAI.Chat;
string key = Environment.GetEnvironmentVariable("OPENAI_API_KEY")!;
string model = "gpt-6-astra";
ChatClient client = new(model, 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
}
"""
);
ChatCompletionOptions options = new()
{
ResponseFormat = ChatResponseFormat.CreateJsonSchemaFormat(
"math_response",
schema,
jsonSchemaIsStrict: true
),
};
ChatCompletion completion = await client.CompleteChatAsync(
[new SystemChatMessage("You are a helpful math tutor. Guide the user through the solution step by step."), new UserChatMessage("How can I solve 8x + 7 = -23?")],
options
);
if (!string.IsNullOrEmpty(completion.Refusal))
{
Console.WriteLine(completion.Refusal);
}
else
{
Console.WriteLine(completion.Content[0].Text);
}1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48require "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
}
completion = client.chat.completions.create(
model: "gpt-6-astra",
messages: [
{
role: :system,
content: "You are a helpful math tutor. Guide the user through the solution step by step."
},
{
role: :user,
content: "How can I solve 8x + 7 = -23?"
}
],
response_format: {
type: :json_schema,
json_schema: {
name: "math_reasoning",
strict: true,
schema: math_schema
}
}
)
message = completion.choices.fetch(0).message
puts(message.refusal || message.content)1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44const 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);
}
}1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36class 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)1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57package 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,
}
}1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79import 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()));
}
}
}1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55using 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
);
}
}1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58require "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 は次のような応答を返します。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28{
"id": "chatcmpl-9nYAG9LPNonX8DAyrkwYfemr3C8HC",
"object": "chat.completion",
"created": 1721596428,
"model": "gpt-4o-2024-08-06",
"choices": [
{
"index": 0,
"message": {
"role": "assistant",
"refusal": "I'm sorry, I cannot assist with that request."
},
"logprobs": null,
"finish_reason": "stop"
}
],
"usage": {
"prompt_tokens": 81,
"completion_tokens": 11,
"total_tokens": 92,
"completion_tokens_details": {
"reasoning_tokens": 0,
"accepted_prediction_tokens": 0,
"rejected_prediction_tokens": 0
}
},
"system_fingerprint": "fp_3407719c7f"
}1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32{
"id": "resp_1234567890",
"object": "response",
"created_at": 1721596428,
"status": "completed",
"completed_at": 1721596429,
"error": null,
"incomplete_details": null,
"input": [],
"instructions": null,
"max_output_tokens": null,
"model": "gpt-4o-2024-08-06",
"output": [{
"id": "msg_1234567890",
"type": "message",
"role": "assistant",
"content": [
{
"type": "refusal",
"refusal": "I'm sorry, I cannot assist with that request."
}
]
}],
"usage": {
"input_tokens": 81,
"output_tokens": 11,
"total_tokens": 92,
"output_tokens_details": {
"reasoning_tokens": 0,
}
},
}ヒントとベストプラクティス
ユーザー入力の扱い
アプリケーションがユーザー入力を受け取る場合は、その入力から有効な応答を生成できないときの対処方法をプロンプトで指示してください。
モデルは常に指定されたスキーマに従おうとするため、入力がスキーマとまったく無関係な場合は、入力に根拠のない情報を生成することがあります。
たとえば、入力がタスクに適していないと判断した場合は、パラメータを空にして返すか、特定の文を返すようにプロンプトで指示できます。
出力内容に誤りがある場合の対処
構造化出力でも、内容に誤りが含まれることがあります。誤りが見つかった場合は、指示を調整する、システム指示に例を加える、タスクをより単純なサブタスクに分けるといった方法を試してください。入力の調整方法について詳しくは、プロンプトエンジニアリングガイドを参照してください。
JSON スキーマと型の不一致の防止
JSON スキーマとプログラミング言語側の型の定義が食い違わないように、SDK に組み込みのスキーマヘルパーがある場合は、その利用を強くおすすめします。
JSON スキーマを直接指定する場合は、スキーマまたは対応するデータオブジェクトのどちらかが編集されたことを検出して知らせる CI ルールを追加できます。また、型定義から JSON スキーマを自動生成する CI ステップや、逆にスキーマから型定義を自動生成する CI ステップを追加する方法もあります。
ストリーミング
ストリーミングを使うと、モデルの応答や関数呼び出しの引数を生成中に逐次処理し、構造化データとして解析できます。
応答全体の生成が完了するのを待たずに処理を始められます。 JSON のフィールドを一つずつ表示したい場合や、関数呼び出しの引数を受け取り次第処理したい場合に特に便利です。
構造化出力のストリーミングには、SDK の利用をおすすめします。
SDK の stream ヘルパーを使わずに関数呼び出しの引数をストリーミングで受け取る例は、Function Calling ガイドを参照してください。
次の例では、stream ヘルパーを使ってモデルの応答をストリーミングで受け取ります。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40import OpenAI from "openai";
import { zodResponseFormat } from "openai/helpers/zod";
import { z } from "zod";
const openai = new OpenAI();
const EntitiesSchema = z.object({
attributes: z.array(z.string()),
colors: z.array(z.string()),
animals: z.array(z.string()),
});
const stream = openai.chat.completions
.stream({
model: "gpt-6-astra",
messages: [
{ role: "system", content: "Extract entities from the input text" },
{
role: "user",
content:
"The quick brown fox jumps over the lazy dog with piercing blue eyes",
},
],
response_format: zodResponseFormat(EntitiesSchema, "entities"),
})
.on("refusal.done", () => console.log("request refused"))
.on("content.delta", ({ snapshot, parsed }) => {
console.log("content:", snapshot);
console.log("parsed:", parsed);
console.log();
})
.on("content.done", (props) => {
console.log(props);
});
await stream.done();
const finalCompletion = await stream.finalChatCompletion();
console.log(finalCompletion);1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34from pydantic import BaseModel
from openai import OpenAI
class EntitiesModel(BaseModel):
attributes: list[str]
colors: list[str]
animals: list[str]
client = OpenAI()
with client.beta.chat.completions.stream(
model="gpt-6-astra",
messages=[
{"role": "system", "content": "Extract entities from the input text"},
{
"role": "user",
"content": "The quick brown fox jumps over the lazy dog with piercing blue eyes",
},
],
response_format=EntitiesModel,
) as stream:
for event in stream:
if event.type == "content.delta":
if event.parsed is not None: # Print the parsed data as JSON
print("content.delta parsed:", event.parsed)
elif event.type == "content.done":
print("content.done")
elif event.type == "error":
print("Error in stream:", event.error)
final_completion = stream.get_final_completion()
print("Final completion:", final_completion)stream ヘルパーは、関数呼び出しの引数の解析にも使えます。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38import { zodFunction } from "openai/helpers/zod";
import OpenAI from "openai/index";
import { z } from "zod";
const GetWeatherArgs = z.object({
city: z.string(),
country: z.string(),
});
const client = new OpenAI();
const stream = client.chat.completions
.stream({
model: "gpt-5.6-terra",
reasoning_effort: "none",
parallel_tool_calls: true,
messages: [
{
role: "user",
content: "What's the weather like in SF and London?",
},
],
tools: [zodFunction({ name: "get_weather", parameters: GetWeatherArgs })],
})
.on("tool_calls.function.arguments.delta", (props) =>
console.log("tool_calls.function.arguments.delta", props)
)
.on("tool_calls.function.arguments.done", (props) =>
console.log("tool_calls.function.arguments.done", props)
)
.on("refusal.delta", ({ delta }) => {
process.stdout.write(delta);
})
.on("refusal.done", () => console.log("request refused"));
const completion = await stream.finalChatCompletion();
console.log("final completion:", completion);1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34from pydantic import BaseModel
import openai
from openai import OpenAI
class GetWeather(BaseModel):
city: str
country: str
client = OpenAI()
with client.beta.chat.completions.stream(
model="gpt-5.6-terra",
reasoning_effort="none",
messages=[
{
"role": "user",
"content": "What's the weather like in SF and London?",
},
],
tools=[
openai.pydantic_function_tool(GetWeather, name="get_weather"),
],
parallel_tool_calls=True,
) as stream:
for event in stream:
if (
event.type == "tool_calls.function.arguments.delta"
or event.type == "tool_calls.function.arguments.done"
):
print(event)
print(stream.get_final_completion())1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37import { 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);1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35from 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)1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86import 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());
});
});
}1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56require "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対応スキーマ
構造化出力は、JSON Schema の仕様の一部に対応しています。
対応する型
構造化出力では、次の型を使用できます。
- 文字列
- 数値
- 真偽値
- 整数
- オブジェクト
- 配列
- 列挙型
- anyOf
対応するプロパティ
プロパティの型に加えて、次の制約を指定できます。
string で使用できるプロパティ
pattern— 文字列が一致する必要のある正規表現format— 文字列に適用する定義済みの形式。現在は次の形式に対応しています。date-timetimedatedurationemailhostnameipv4ipv6uuid
number で使用できるプロパティ
multipleOf— 数値は指定値の倍数である必要があります。maximum— 数値は指定値以下である必要があります。exclusiveMaximum— 数値は指定値未満である必要があります。minimum— 数値は指定値以上である必要があります。exclusiveMinimum— 数値は指定値を超える必要があります。
array で使用できるプロパティ
minItems— 配列の要素数は指定値以上である必要があります。maxItems— 配列の要素数は指定値以下である必要があります。
型ごとの制約の使用例を以下に示します。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27{
"name": "user_data",
"strict": true,
"schema": {
"type": "object",
"properties": {
"name": {
"type": "string",
"description": "The name of the user"
},
"username": {
"type": "string",
"description": "The username of the user. Must start with @",
"pattern": "^@[a-zA-Z0-9_]+$"
},
"email": {
"type": "string",
"description": "The email of the user",
"format": "email"
}
},
"additionalProperties": false,
"required": [
"name", "username", "email"
]
}
}1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28{
"name": "weather_data",
"strict": true,
"schema": {
"type": "object",
"properties": {
"location": {
"type": "string",
"description": "The location to get the weather for"
},
"unit": {
"type": ["string", "null"],
"description": "The unit to return the temperature in",
"enum": ["F", "C"]
},
"value": {
"type": "number",
"description": "The actual temperature value in the location",
"minimum": -130,
"maximum": 130
}
},
"additionalProperties": false,
"required": [
"location", "unit", "value"
]
}
}これらの制約は、ファインチューニングしたモデルではまだ使用できません。
スキーマのルートはオブジェクト型に限定(anyOf は使用不可)
スキーマのルートはオブジェクトでなければならず、ルートで anyOf は使用できません。たとえば Zod で判別可能なユニオン型を使うと、最上位に anyOf が生成されます。そのため、次のようなコードは動作しません。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17import { 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 として指定する必要があります。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21{
"name": "get_weather",
"description": "Fetches the weather in the given location",
"strict": true,
"parameters": {
"type": "object",
"properties": {
"location": {
"type": "string",
"description": "The location to get the weather for"
},
"unit": {
"type": "string",
"description": "The unit to return the temperature in",
"enum": ["F", "C"]
}
},
"additionalProperties": false,
"required": ["location", "unit"]
}
}すべてのフィールドが必須で、モデルは各パラメータの値を返します。null を含むユニオン型を使えば、省略可能なパラメータと同様に扱えます。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23{
"name": "get_weather",
"description": "Fetches the weather in the given location",
"strict": true,
"parameters": {
"type": "object",
"properties": {
"location": {
"type": "string",
"description": "The location to get the weather for"
},
"unit": {
"type": ["string", "null"],
"description": "The unit to return the temperature in",
"enum": ["F", "C"]
}
},
"additionalProperties": false,
"required": [
"location", "unit"
]
}
}オブジェクトのネストの深さとサイズの上限
1 つのスキーマに含められるオブジェクトのプロパティは合計 5,000 個までで、ネストの深さは最大 10 階層です。
文字列の合計長の上限
1 つのスキーマ内のプロパティ名、定義名、enum の値、const の値をすべて合わせた文字列の長さは、120,000 文字までです。
enum のサイズの上限
1 つのスキーマ内のすべての enum プロパティに指定できる値は、合計 1,000 個までです。
文字列を値とする 1 つの enum プロパティに 250 個を超える値を指定する場合、それらの文字列の合計長は 15,000 文字までです。
すべてのオブジェクトで additionalProperties: false の指定が必須
additionalProperties は、JSON Schema に定義されていないキーと値の組をオブジェクトに追加できるかどうかを制御します。
構造化出力で生成できるのは、スキーマで指定したキーと値だけです。そのため、構造化出力を使用するには、additionalProperties: false を指定する必要があります。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23{
"name": "get_weather",
"description": "Fetches the weather in the given location",
"strict": true,
"schema": {
"type": "object",
"properties": {
"location": {
"type": "string",
"description": "The location to get the weather for"
},
"unit": {
"type": "string",
"description": "The unit to return the temperature in",
"enum": ["F", "C"]
}
},
"additionalProperties": false,
"required": [
"location", "unit"
]
}
}キーの順序
構造化出力では、スキーマに記述した順序でキーが出力されます。
現時点で未対応の型別キーワード
- スキーマの合成:
allOf、not、dependentRequired、dependentSchemas、if、then、else
ファインチューニングしたモデルでは、以下のキーワードも使用できません。
- 文字列:
minLength、maxLength、pattern、format - 数値:
minimum、maximum、multipleOf - オブジェクト:
patternProperties - 配列:
minItems、maxItems
strict: true を指定して構造化出力を有効にし、対応範囲外の JSON Schema で API を呼び出すと、エラーが返されます。
anyOf 内の各スキーマに適用される JSON Schema の要件
anyOf 内の各スキーマは、構造化出力が対応する JSON Schema の範囲で有効である必要があります。以下は、使用できる anyOf スキーマの例です。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56{
"type": "object",
"properties": {
"item": {
"anyOf": [
{
"type": "object",
"description": "The user object to insert into the database",
"properties": {
"name": {
"type": "string",
"description": "The name of the user"
},
"age": {
"type": "number",
"description": "The age of the user"
}
},
"additionalProperties": false,
"required": [
"name",
"age"
]
},
{
"type": "object",
"description": "The address object to insert into the database",
"properties": {
"number": {
"type": "string",
"description": "The number of the address. Eg. for 123 main st, this would be 123"
},
"street": {
"type": "string",
"description": "The street name. Eg. for 123 main st, this would be main st"
},
"city": {
"type": "string",
"description": "The city of the address"
}
},
"additionalProperties": false,
"required": [
"number",
"street",
"city"
]
}
]
}
},
"additionalProperties": false,
"required": [
"item"
]
}定義の使用
サブスキーマを定義すると、スキーマ内の各所から参照できます。以下に簡単な例を示します。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37{
"type": "object",
"properties": {
"steps": {
"type": "array",
"items": {
"$ref": "#/$defs/step"
}
},
"final_answer": {
"type": "string"
}
},
"$defs": {
"step": {
"type": "object",
"properties": {
"explanation": {
"type": "string"
},
"output": {
"type": "string"
}
},
"required": [
"explanation",
"output"
],
"additionalProperties": false
}
},
"required": [
"steps",
"final_answer"
],
"additionalProperties": false
}再帰スキーマの使用
以下は、# でルートを参照する再帰スキーマの例です。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47{
"name": "ui",
"description": "Dynamically generated UI",
"strict": true,
"schema": {
"type": "object",
"properties": {
"type": {
"type": "string",
"description": "The type of the UI component",
"enum": ["div", "button", "header", "section", "field", "form"]
},
"label": {
"type": "string",
"description": "The label of the UI component, used for buttons or form fields"
},
"children": {
"type": "array",
"description": "Nested UI components",
"items": {
"$ref": "#"
}
},
"attributes": {
"type": "array",
"description": "Arbitrary attributes for the UI component, suitable for any element",
"items": {
"type": "object",
"properties": {
"name": {
"type": "string",
"description": "The name of the attribute, for example onClick or className"
},
"value": {
"type": "string",
"description": "The value of the attribute"
}
},
"additionalProperties": false,
"required": ["name", "value"]
}
}
},
"required": ["type", "label", "children", "attributes"],
"additionalProperties": false
}
}以下は、再帰参照を明示したスキーマの例です。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37{
"type": "object",
"properties": {
"linked_list": {
"$ref": "#/$defs/linked_list_node"
}
},
"$defs": {
"linked_list_node": {
"type": "object",
"properties": {
"value": {
"type": "number"
},
"next": {
"anyOf": [
{
"$ref": "#/$defs/linked_list_node"
},
{
"type": "null"
}
]
}
},
"additionalProperties": false,
"required": [
"next",
"value"
]
}
},
"additionalProperties": false,
"required": [
"linked_list"
]
}JSON モード
JSON モードは、構造化出力の前身にあたる、より基本的な機能です。JSON モードはモデルが有効な JSON を出力することを保証します。構造化出力では、モデルの出力が指定したスキーマに準拠することも保証されます。用途に応じて構造化出力が利用できる場合は、その使用をおすすめします。
JSON モードを有効にすると、一部の例外を除き、モデルの出力が有効な JSON であることが保証されます。例外はアプリケーション側で検出し、適切に処理してください。
Chat Completions API で JSON モードを有効にするには、response_format を { "type": "json_object" } に設定します。Function Calling を使う場合、JSON モードは常に有効です。
Responses API で JSON モードを有効にするには、text.format を { "type": "json_object" } に設定します。Function Calling を使う場合、JSON モードは常に有効です。
次の点に注意してください。
- JSON モードを使う場合は、システムメッセージなど、会話内のいずれかのメッセージで、必ず JSON を生成するようモデルに指示してください。明示的な指示がないと、モデルが空白文字を出力し続け、トークンの上限に達するまでリクエストが終了しない場合があります。指示の入れ忘れを防ぐため、コンテキスト内に文字列「JSON」が含まれていない場合、API はエラーを返します。
- JSON モードが保証するのは、出力が有効な JSON であり、エラーなくパースできることだけです。特定のスキーマへの準拠は保証されません。出力を目的のスキーマに準拠させるには、構造化出力を使ってください。利用できない場合は、検証ライブラリで出力がスキーマに準拠しているかを確認し、必要に応じてリクエストを再試行してください。
- モデルが完全な JSON オブジェクトを出力できない場合があるため、アプリケーションでこうした例外を検出し、処理する必要があります(以下を参照)。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52const we_did_not_specify_stop_tokens = true;
try {
const response = await openai.chat.completions.create({
model: "gpt-6-astra",
messages: [
{
role: "system",
content: "You are a helpful assistant designed to output JSON.",
},
{
role: "user",
content:
"Who won the world series in 2020? Please respond in the format {winner: ...}",
},
],
store: true,
response_format: { type: "json_object" },
});
// Check if the conversation was too long for the context window, resulting in incomplete JSON
if (response.choices[0].finish_reason === "length") {
// your code should handle this error case
}
// Check if the OpenAI safety system refused the request and generated a refusal instead
if (response.choices[0].message.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(response.choices[0].message.refusal);
}
// Check if the model's output included restricted content, so the generation of JSON was halted and may be partial
if (response.choices[0].finish_reason === "content_filter") {
// your code should handle this error case
}
if (response.choices[0].finish_reason === "stop") {
// 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.choices[0].message.content));
} else {
// Check if the response.choices[0].message.content 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);
}1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42we_did_not_specify_stop_tokens = True
try:
response = client.chat.completions.create(
model="gpt-6-astra",
messages=[
{
"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"}.',
},
],
response_format={"type": "json_object"},
)
# Check if the conversation was too long for the context window, resulting in incomplete JSON
if response.choices[0].finish_reason == "length":
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 response.choices[0].message.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(response.choices[0].message.refusal)
# Check if the model's output included restricted content, so the generation of JSON was halted and may be partial
if response.choices[0].finish_reason == "content_filter":
raise RuntimeError("The response was interrupted by the content filter.")
if response.choices[0].finish_reason == "stop":
# 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.choices[0].message.content)
except Exception as e:
# Your code should handle errors here, for example a network error calling the API
print(e)1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44package main
import (
"context"
"encoding/json"
"fmt"
"github.com/openai/openai-go/v3"
"github.com/openai/openai-go/v3/shared"
)
func main() {
client := openai.NewClient()
completion, err := client.Chat.Completions.New(context.Background(), openai.ChatCompletionNewParams{
Model: "gpt-6-astra",
Messages: []openai.ChatCompletionMessageParamUnion{
openai.SystemMessage("You are a helpful assistant designed to output JSON."),
openai.UserMessage("Who won the world series in 2020? Please respond in the format {winner: ...}"),
},
ResponseFormat: openai.ChatCompletionNewParamsResponseFormatUnion{
OfJSONObject: &shared.ResponseFormatJSONObjectParam{},
},
})
if err != nil {
panic(err)
}
choice := completion.Choices[0]
if choice.FinishReason == "length" || choice.FinishReason == "content_filter" {
fmt.Println("The JSON response is incomplete.")
return
}
if choice.Message.Refusal != "" {
fmt.Println(choice.Message.Refusal)
return
}
if choice.FinishReason == "stop" {
var value map[string]any
if err := json.Unmarshal([]byte(choice.Message.Content), &value); err != nil {
panic(err)
}
fmt.Println(value)
}
}1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31import com.fasterxml.jackson.databind.ObjectMapper;
import com.openai.client.OpenAIClient;
import com.openai.client.okhttp.OpenAIOkHttpClient;
import com.openai.core.JsonValue;
import com.openai.models.chat.completions.ChatCompletion;
import com.openai.models.chat.completions.ChatCompletionCreateParams;
import java.io.IOException;
import java.util.Map;
ChatCompletionCreateParams params =
ChatCompletionCreateParams.builder()
.model("gpt-6-astra")
.addSystemMessage("You are a helpful assistant designed to output JSON.")
.addUserMessage("Who won the World Series in 2020? Respond as {winner: ...}.")
.putAdditionalBodyProperty(
"response_format", JsonValue.from(Map.of("type", "json_object")))
.build();
var choice = client.chat().completions().create(params).choices().get(0);
if (choice.finishReason().equals(ChatCompletion.Choice.FinishReason.LENGTH)
|| choice.finishReason().equals(ChatCompletion.Choice.FinishReason.CONTENT_FILTER)) {
System.out.println("The JSON response is incomplete.");
} else if (choice.message().refusal().isPresent()) {
System.out.println(choice.message().refusal().orElseThrow());
} else if (choice.finishReason().equals(ChatCompletion.Choice.FinishReason.STOP)) {
String content = choice.message().content().orElseThrow();
System.out.println(
new ObjectMapper()
.writerWithDefaultPrettyPrinter()
.writeValueAsString(new ObjectMapper().readTree(content)));
}1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35using OpenAI.Chat;
string key = Environment.GetEnvironmentVariable("OPENAI_API_KEY")!;
string model = "gpt-6-astra";
ChatClient client = new(model, key);
ChatCompletionOptions options = new()
{
ResponseFormat = ChatResponseFormat.CreateJsonObjectFormat(),
};
ChatCompletion completion = await client.CompleteChatAsync(
[new SystemChatMessage("You are a helpful assistant designed to output JSON."), new UserChatMessage("Who won the World Series in 2020? Respond with the winner in JSON.")],
options
);
if (completion.FinishReason == ChatFinishReason.Length)
{
Console.WriteLine("The response was truncated before the JSON completed.");
}
else if (completion.FinishReason == ChatFinishReason.ContentFilter)
{
Console.WriteLine("The response was interrupted by the content filter.");
}
else if (!string.IsNullOrEmpty(completion.Refusal))
{
Console.WriteLine(completion.Refusal);
}
else if (completion.FinishReason == ChatFinishReason.Stop && completion.Content.Count > 0)
{
Console.WriteLine(completion.Content[0].Text);
}
else
{
throw new InvalidOperationException("The completion did not contain a JSON response.");
}1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32require "json"
require "openai"
client = OpenAI::Client.new
completion = client.chat.completions.create(
model: "gpt-6-astra",
messages: [
{
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: ...}."
}
],
response_format: { type: :json_object }
)
choice = completion.choices.fetch(0)
finish_reason = choice.finish_reason
if [
OpenAI::Chat::ChatCompletion::Choice::FinishReason::LENGTH,
OpenAI::Chat::ChatCompletion::Choice::FinishReason::CONTENT_FILTER
].include?(finish_reason)
warn("The JSON response is incomplete.")
elsif choice.message.refusal
puts(choice.message.refusal)
elsif finish_reason == OpenAI::Chat::ChatCompletion::Choice::FinishReason::STOP
content = choice.message.content or raise "No response content"
puts(JSON.pretty_generate(JSON.parse(content)))
end1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60const 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);
}1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51we_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)1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57package 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)
}
}1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61import 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());
}1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46using 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}");
}1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33require "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参考資料
構造化出力について詳しくは、次の資料を参照してください。
- 構造化出力の入門クックブック
- 構造化出力を使ったマルチエージェントシステムの構築方法