必ず最初に Responses API を使ってください。OpenAI の主力 API であり、モデルの最新の動作、組み込みツール、状態を保持するワークフロー、エージェント機能を利用するのに最適です。
実際のワークロードで GPT-6 モデルファミリー を評価してください。最高の性能が必要なら gpt-6-astra 、複雑なコーディングや専門業務を Astra より低コストで処理するなら gpt-6.1-sol 、定型作業を繰り返し効率よく処理するなら gpt-6-luna を使います。すべてのリクエストを最高性能のモデルに送るのではなく、代表的なタスクで良い結果を出せるモデルを選びます。
GPT-6 に移行する際は、対応している範囲で、現在のモデルに任せている作業と実際に適用されている推論強度を維持します。ツールを使った推論には Responses API を使ってください。GPT-6 Astra と GPT-6.1 Sol のツール呼び出しには Responses が必要です。GPT-6 Sol と GPT-6 Luna が Chat Completions で Function Calling に対応するのは reasoning_effort: "none" の場合だけです。推論強度が none 以外の場合は、temperature、top_p、top_logprobs を削除します。また、logprobs は Chat Completions のリクエストから、message.output_text.logprobs は Responses の include 配列から削除します。モデルや処理ティアを選ぶ前に、データレジデンシーの適用対象 を確認してください。その他の互換性の確認事項はモデル移行ガイド を参照してください。プロンプトを変更したり新しい機能を追加したりする前に、代表的なタスクで評価を実施します。タスクの成功率、レイテンシ、入力、出力、推論、キャッシュ書き込みの各トークン数、成功したタスクあたりのコストを比較してください。
reasoning.effort で、モデルが回答前にどの程度推論するかを設定します。
GPT-6 Astra、GPT-6.1 Sol、GPT-6 Sol、GPT-6 Luna は low、medium、high、xhigh、max に対応しています。GPT-6 Sol と GPT-6 Luna は none にも対応していますが、GPT-6 Astra と GPT-6.1 Sol は対応していません。推論強度を下げると応答が速くなり、推論トークンの使用量が減ります。強度を上げると、計画、デバッグ、情報の統合、複数の段階にわたるトレードオフの検討に時間をかけられます。
抽出、振り分け、分類、定型的な書き換えが中心なら low を使います。問題の診断、選択肢の比較、計画の作成、コードを読み解く作業には medium または high を使います。xhigh または max は、レイテンシとコストの増加に見合う品質向上が代表的なタスクの評価で確認できた場合にのみ使ってください。minimal から移行する場合や、none を使っていたモデルから GPT-6 Astra または GPT-6.1 Sol に移行する場合は、まず low で結果を比較します。それ以外の場合は現在の実効推論強度を維持し、変更する際は品質、レイテンシ、コストの目標を満たすか検証します。
品質を最優先する特に難しいワークロードでは、reasoning.mode: "pro" と標準モードも同じ推論強度で比較してください。推論モードと推論強度は独立した設定です。Pro モードでは、モデルがより多くの処理を行ってから最終回答を 1 つ返すため、信頼性の向上が期待できますが、レイテンシとトークン使用量は増えます。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 import OpenAI from "openai";
const openai = new OpenAI();
const prompt = [
"Our CI job started failing after a dependency bump.",
"",
"Error:",
"TypeError: Timeout.__init__() got an unexpected keyword argument 'connect'",
"",
"Identify the likeliest root cause and the smallest safe fix.",
].join("\n");
const response = await openai.responses.create({
model: "gpt-6-astra",
reasoning: { effort: "xhigh", mode: "pro" },
input: prompt,
});
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 from openai import OpenAI
client = OpenAI()
prompt = """
Our CI job started failing after a dependency bump.
Error:
TypeError: Timeout.__init__() got an unexpected keyword argument 'connect'
Identify the likeliest root cause and the smallest safe fix.
"""
response = client.responses.create(
model = "gpt-6-astra" ,
reasoning = { "effort" : "xhigh" , "mode" : "pro" },
input = prompt,
)
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 package main
import (
"context"
"fmt"
"strings"
"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()
prompt := strings.Join([]string{
"Our CI job started failing after a dependency bump.",
"",
"Error:",
"TypeError: Timeout.__init__() got an unexpected keyword argument 'connect'",
"",
"Identify the likeliest root cause and the smallest safe fix.",
}, "\n")
reasoning := shared.ReasoningParam{Effort: shared.ReasoningEffortXhigh}
reasoning.SetExtraFields(map[string]any{"mode": "pro"})
response, err := client.Responses.New(context.Background(), responses.ResponseNewParams{
Model: "gpt-6-astra",
Reasoning: reasoning,
Input: responses.ResponseNewParamsInputUnion{OfString: openai.String(prompt)},
})
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 import com.openai.client.OpenAIClient;
import com.openai.client.okhttp.OpenAIOkHttpClient;
import com.openai.core.JsonValue;
import com.openai.models.Reasoning;
import com.openai.models.ReasoningEffort;
import com.openai.models.responses.ResponseCreateParams;
ResponseCreateParams params =
ResponseCreateParams.builder()
.model("gpt-6-astra")
.input(
"Our CI job started failing after a dependency bump. Error: TypeError: Timeout.__init__() got an unexpected keyword argument 'connect'. Identify the likeliest root cause and the smallest safe fix.")
.reasoning(
Reasoning.builder()
.effort(ReasoningEffort.XHIGH)
.putAdditionalProperty("mode", JsonValue.from("pro"))
.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 require "openai"
client = OpenAI::Client.new
prompt = <<~PROMPT
Our CI job started failing after a dependency bump.
Error:
TypeError: Timeout.__init__() got an unexpected keyword argument 'connect'
Identify the likeliest root cause and the smallest safe fix.
PROMPT
response = client.responses.create(
model: "gpt-6-astra",
reasoning: {
effort: :xhigh,
mode: :pro
},
input: prompt
)
puts(response.output_text)
GPT-6 モデルを標準のシングルエージェントモードで使う場合は、次のユーザーメッセージの前に configuration_update 入力項目を追加すると、応答の合間に推論強度を変更できます。元のプロンプトの先頭部分を引き続きキャッシュできるように、リクエストレベルの reasoning.effort は変更しません。更新は次の応答から適用され、別の更新で上書きするまで有効です。設定更新は自動コンパクションや自動切り詰めと併用できません。また、/responses/compact は設定更新を含む履歴を受け付けません。履歴にコンパクションを適用するには、compaction_trigger 項目を含め、その後に新たな設定更新を追加します。
text.verbosity の設定
text.verbosity は、回答の簡潔さと網羅性のバランスを調整する主な設定です。製品で短い回答をすばやく返す必要がある場合は詳細度を下げ、詳しい説明、明確な構成、十分な背景情報が必要な場合は詳細度を上げます。詳細度を下げると生成する出力トークンが減るため、結果をより早く返せます。
コーディングでは、medium と high を使うと、長めで構成の明確な出力が得られる傾向があります。low では回答が簡潔になり、必要最小限の内容に絞られます。
移行時には、「簡潔に」のような大まかな指示が引き続き役立つかを確認してください。既定の詳細度は text.verbosity で調整し、必要な内容、構成、長さはプロンプトで指定することをおすすめします。
プロンプトも品質、トークン使用量、コスト、レイテンシに影響します。詳細度を設定する際には、最新モデルのプロンプト作成のベストプラクティス を参照し、コーディングエージェントのテストと検証に関する指針も確認してください。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 import OpenAI from "openai";
const openai = new OpenAI();
const incident = [
"Summarize this incident for the next on-call engineer.",
"- checkout latency spiked from 220 ms to 4.8 s",
"- only us-east-1 was affected",
"- rollback is complete",
"- likely trigger: cache stampede after deploy",
].join("\n");
const response = await openai.responses.create({
model: "gpt-6-astra",
text: { verbosity: "low" },
input: incident,
});
console.log(response.output_text); 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 from openai import OpenAI
client = OpenAI()
response = client.responses.create(
model = "gpt-6-astra" ,
text = { "verbosity" : "low" },
input = """
Summarize this incident for the next on-call engineer.
- checkout latency spiked from 220 ms to 4.8 s
- only us-east-1 was affected
- rollback is complete
- likely trigger: cache stampede after deploy
""" ,
)
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 package main
import (
"context"
"fmt"
"strings"
"github.com/openai/openai-go/v3"
"github.com/openai/openai-go/v3/responses"
)
func main() {
client := openai.NewClient()
incident := strings.Join([]string{
"Summarize this incident for the next on-call engineer.",
"- checkout latency spiked from 220 ms to 4.8 s",
"- only us-east-1 was affected",
"- rollback is complete",
"- likely trigger: cache stampede after deploy",
}, "\n")
response, err := client.Responses.New(context.Background(), responses.ResponseNewParams{
Model: "gpt-6-astra",
Text: responses.ResponseTextConfigParam{Verbosity: "low"},
Input: responses.ResponseNewParamsInputUnion{OfString: openai.String(incident)},
})
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 import com.openai.client.OpenAIClient;
import com.openai.client.okhttp.OpenAIOkHttpClient;
import com.openai.models.responses.ResponseCreateParams;
import com.openai.models.responses.ResponseTextConfig;
ResponseCreateParams params =
ResponseCreateParams.builder()
.model("gpt-6-astra")
.input(
"Summarize this incident for the next on-call engineer: checkout latency spiked from 220 ms to 4.8 s, only us-east-1 was affected, rollback is complete, and the likely trigger was a cache stampede.")
.text(ResponseTextConfig.builder().verbosity(ResponseTextConfig.Verbosity.LOW).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 require "openai"
client = OpenAI::Client.new
incident = <<~INCIDENT
Summarize this incident for the next on-call engineer.
- checkout latency spiked from 220 ms to 4.8 s
- only us-east-1 was affected
- rollback is complete
- likely trigger: cache stampede after deploy
INCIDENT
response = client.responses.create(
model: "gpt-6-astra",
text: { verbosity: :low },
input: incident
)
puts(response.output_text)
phase は、会話履歴のアシスタントメッセージに付けるラベルです。以前のアシスタントメッセージが作業途中の説明か最終回答かをモデルに伝えます。進捗報告、ツール呼び出し前の説明など、途中のメッセージには phase: "commentary" を使います。完成した回答には phase: "final_answer" を使います。
たとえば、アシスタントが次のようなメッセージを返すことがあります。
1
2
3
4
5 {
"role" : "assistant" ,
"phase" : "commentary" ,
"content" : "I'm checking the logs and comparing them to the last successful deploy."
}
これは作業途中の進捗報告です。その後、アシスタントが次のように回答することがあります。
1
2
3
4
5 {
"role" : "assistant" ,
"phase" : "final_answer" ,
"content" : "The deploy failed because the migration referenced a column that does not exist in production."
}
この区別は、作業が長引く場合やツールを多用する場合など、アシスタントが完了前にユーザーに進捗を知らせるワークフローで役立ちます。gpt-5.3-codex 以降のモデルへの後続リクエストで履歴を送り返す際は、モデルが進捗報告と最終結果を区別できるよう、アシスタントメッセージの phase を保持して再送してください 。これにより、エージェントが途中で停止することが減り、最終回答に到達するまで作業を続けやすくなります。
すべてのリクエストにツールカタログ全体を読み込む代わりに、ツール検索 を使います。{"type": "tool_search"} を追加し、読み込みコストの高いツール定義に defer_loading: true を指定します。これにより、モデルは実行時に必要なツールだけを読み込めます。リクエスト開始時にモデルに見えるのは検索ツールの名前と説明だけです。読み込みを遅延させたツールが必要だと判断すると、モデルはツール検索を実行します。その時点で初めて該当するツール定義がコンテキストに読み込まれ、モデルがツールを呼び出せるようになります。これによりトークンを節約し、キャッシュの性能を維持できます。
ツール検索には 2 つのモードがあります。
ホスト型ツール検索 は、より簡単に使える方式です。リクエストで利用できるツールの候補があらかじめわかっている場合に使います。
クライアント実行型ツール検索 は、ユーザーのテナント、プロジェクト、権限、内部レジストリなどに基づき、アプリ側で利用可能なツールを決める必要がある場合に使います。
アプリ側でツールの検索を制御する必要がある場合を除き、まずホスト型ツール検索を使ってください 。
ユーザーの目的別にツールをまとめます。可能なら名前空間または MCP サーバーを使ってください。長い関数一覧から選ぶよりも、違いが明確な少数のグループから選ぶ方がモデルには容易です。トークン効率とモデル性能を最適化するため、各名前空間の関数はおおむね 10 個未満に抑えることをおすすめします。
名前空間の説明は短くし、他の名前空間との違いがわかるようにします。詳しい指示は、読み込みを遅延させるツール定義に記載します。すべてのツールを 1 つの巨大な名前空間にまとめるのは避けてください。
1
2
3
4
5
6
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 import OpenAI from "openai";
const openai = new OpenAI();
const billingNamespace = {
type: "namespace",
name: "billing",
description: "Billing tools for invoices, payments, taxes, and credits.",
tools: [
{
type: "function",
name: "lookup_invoice",
description:
"Look up invoice state, taxes, credits, and payment attempts.",
parameters: {
type: "object",
properties: {
invoice_id: { type: "string" },
},
required: ["invoice_id"],
additionalProperties: false,
},
strict: true,
defer_loading: true,
},
],
};
const crmNamespace = {
type: "namespace",
name: "crm",
description:
"CRM tools for account ownership, plans, health, and payment history.",
tools: [
{
type: "function",
name: "get_account",
description: "Fetch account owner, plan, health, and payment history.",
parameters: {
type: "object",
properties: {
account_id: { type: "string" },
},
required: ["account_id"],
additionalProperties: false,
},
strict: true,
defer_loading: true,
},
],
};
const response = await openai.responses.create({
model: "gpt-6-astra",
input:
"Find the right billing tool and explain why invoice INV-1043 still " +
"shows overdue after a payment yesterday.",
tools: [billingNamespace, crmNamespace, { type: "tool_search" }],
});
console.log(response.output); 1
2
3
4
5
6
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 from openai import OpenAI
client = OpenAI()
billing_namespace = {
"type" : "namespace" ,
"name" : "billing" ,
"description" : "Billing tools for invoices, payments, taxes, and credits." ,
"tools" : [
{
"type" : "function" ,
"name" : "lookup_invoice" ,
"description" : "Look up invoice state, taxes, credits, and payment attempts." ,
"parameters" : {
"type" : "object" ,
"properties" : {
"invoice_id" : { "type" : "string" },
},
"required" : [ "invoice_id" ],
"additionalProperties" : False ,
},
"strict" : True ,
"defer_loading" : True ,
}
],
}
crm_namespace = {
"type" : "namespace" ,
"name" : "crm" ,
"description" : "CRM tools for account ownership, plans, health, and payment history." ,
"tools" : [
{
"type" : "function" ,
"name" : "get_account" ,
"description" : "Fetch account owner, plan, health, and payment history." ,
"parameters" : {
"type" : "object" ,
"properties" : {
"account_id" : { "type" : "string" },
},
"required" : [ "account_id" ],
"additionalProperties" : False ,
},
"strict" : True ,
"defer_loading" : True ,
}
],
}
response = client.responses.create(
model = "gpt-6-astra" ,
input = (
"Find the right billing tool and explain why invoice INV-1043 still "
"shows overdue after a payment yesterday."
),
tools = [billing_namespace, crm_namespace, { "type" : "tool_search" }],
)
print (response.output) 1
2
3
4
5
6
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 package main
import (
"context"
"fmt"
"github.com/openai/openai-go/v3"
"github.com/openai/openai-go/v3/responses"
)
func main() {
client := openai.NewClient()
billing := namespaceTool(
"billing",
"Billing tools for invoices, payments, taxes, and credits.",
"lookup_invoice",
"Look up invoice state, taxes, credits, and payment attempts.",
"invoice_id",
)
crm := namespaceTool(
"crm",
"CRM tools for account ownership, plans, health, and payment history.",
"get_account",
"Fetch account owner, plan, health, and payment history.",
"account_id",
)
toolSearch := responses.ToolUnionParam{OfToolSearch: &responses.ToolSearchToolParam{}}
response, err := client.Responses.New(context.Background(), responses.ResponseNewParams{
Model: "gpt-6-astra",
Input: responses.ResponseNewParamsInputUnion{OfString: openai.String(
"Find the right billing tool and explain why invoice INV-1043 still shows overdue after a payment yesterday.",
)},
Tools: []responses.ToolUnionParam{billing, crm, toolSearch},
})
if err != nil {
panic(err)
}
fmt.Println(response.Output)
}
func namespaceTool(namespace, namespaceDescription, name, description, argument string) responses.ToolUnionParam {
parameters := map[string]any{
"type": "object",
"properties": map[string]any{
argument: map[string]any{"type": "string"},
},
"required": []string{argument},
"additionalProperties": false,
}
function := responses.NamespaceToolToolFunctionParam{
Name: name, Description: openai.String(description), Parameters: parameters, Strict: openai.Bool(true), DeferLoading: openai.Bool(true),
}
return responses.ToolParamOfNamespace(
namespaceDescription,
namespace,
[]responses.NamespaceToolToolUnionParam{{OfFunction: &function}},
)
} 1
2
3
4
5
6
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 import com.openai.client.OpenAIClient;
import com.openai.client.okhttp.OpenAIOkHttpClient;
import com.openai.core.JsonValue;
import com.openai.models.responses.NamespaceTool;
import com.openai.models.responses.ResponseCreateParams;
import com.openai.models.responses.ToolSearchTool;
import java.util.List;
import java.util.Map;
ResponseCreateParams params =
ResponseCreateParams.builder()
.model("gpt-6-astra")
.input(
"Find the right billing tool and explain why invoice INV-1043 still shows overdue after a payment yesterday.")
.addTool(
namespace(
"billing",
"Billing tools for invoices, payments, taxes, and credits.",
"lookup_invoice",
"Look up invoice state, taxes, credits, and payment attempts.",
"invoice_id"))
.addTool(
namespace(
"crm",
"CRM tools for account ownership, plans, health, and payment history.",
"get_account",
"Fetch account owner, plan, health, and payment history.",
"account_id"))
.addTool(ToolSearchTool.builder().execution(ToolSearchTool.Execution.SERVER).build())
.build();
client.responses().create(params).output().forEach(System.out::println);
private static NamespaceTool namespace(
String name,
String description,
String function,
String functionDescription,
String argument) {
return NamespaceTool.builder()
.name(name)
.description(description)
.addTool(
NamespaceTool.Tool.Function.builder()
.name(function)
.description(functionDescription)
.deferLoading(true)
.strict(true)
.parameters(
JsonValue.from(
Map.of(
"type",
"object",
"properties",
Map.of(argument, Map.of("type", "string")),
"required",
List.of(argument),
"additionalProperties",
false)))
.build())
.build();
} 1
2
3
4
5
6
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 require "openai"
def namespace_tool(name, description, function_name, function_description, argument)
{
type: :namespace,
name: name,
description: description,
tools: [
{
type: :function,
name: function_name,
description: function_description,
defer_loading: true,
strict: true,
parameters: {
type: "object",
properties: { argument => { type: "string" } },
required: [argument],
additionalProperties: false
}
}
]
}
end
client = OpenAI::Client.new
billing = namespace_tool(
"billing",
"Billing tools for invoices, payments, taxes, and credits.",
"lookup_invoice",
"Look up invoice state, taxes, credits, and payment attempts.",
"invoice_id"
)
crm = namespace_tool(
"crm",
"CRM tools for account ownership, plans, health, and payment history.",
"get_account",
"Fetch account owner, plan, health, and payment history.",
"account_id"
)
response = client.responses.create(
model: "gpt-6-astra",
input: "Find the right billing tool and explain why invoice INV-1043 still shows overdue after a payment yesterday.",
tools: [billing, crm, { type: :tool_search }]
)
puts(response.output)
プログラムによるツール呼び出し では、対応モデルが JavaScript を記述し、ホスト型ランタイム内で対象ツールを呼び出して中間結果を絞り込めます。処理の範囲が明確で、ツールが返す大量の結果をコードで処理できる場合に使います。フィルタリング、結合、順位付け、重複排除、集約、検証などを行ってから、必要な結果だけを構造化してモデルに返せます。
programmatic_tool_calling ツールを追加し、対象となる各ツールでこの機能を有効にします。プログラムからのみ呼び出すツールには allowed_callers: ["programmatic"] を、モデルが直接呼び出すこともできるツールには allowed_callers: ["direct", "programmatic"] を使います。個々の結果によってモデルの次の判断が変わり得る場合、アクションに承認が必要な場合、最終回答に引用やツール固有の成果物を保持する必要がある場合は、直接呼び出してください。モデルが結果を事前に確認しなくても正しいプログラムを書けるよう、ツールが返すフィールドとエラー時の動作を文書化します。
ツール実行ループでは、program 項目と program_output 項目に加え、プログラムが発行する function_call 項目と、それに対応する function_call_output 項目を処理する必要があります。サービスが正しいプログラムを再開できるよう、各 call_id を保持し、関数呼び出しの caller を対応する出力にコピーします。
program_output とアシスタントの最終メッセージの両方をテストしてください。プログラムの結果が正しくても、最終回答に必要な内容が欠けることがあります。同じワークフローでツールを直接呼び出した場合と比較し、タスクの成功率、必要な根拠が含まれているか、総トークン数、レイテンシ、コストを評価します。
マルチエージェント では、GPT-6 モデルを含む対応モデルが、互いに独立した作業をサブエージェントに委任し、その結果を統合できます。調査、分析、実装を、それぞれ別のコンテキストで並列実行できる具体的で範囲の明確なタスクに分割できる場合に使います。
リクエストで multi_agent.enabled を true に設定します。HTTP では、ベータ版の Responses SDK で client.beta.responses を使い、responses_multi_agent=v1 を betas に渡します。HTTP を直接使う場合や WebSocket 接続の場合は、OpenAI-Beta: responses_multi_agent=v1 を送信します。マルチエージェントのベータ期間中は、項目のスキーマが変更されることがあります。
短いタスク、各ステップが直前のステップに依存する一連の処理、同じリソースを書き換える作業には、単一のエージェントが適しています。サブエージェントを使うとトークン使用量が増えることがあるため、まず max_concurrent_subagents を既定値の 3 にして、ワークフロー全体の品質、レイテンシ、コストを測定します。ツールを多用する場合や長時間実行する場合は、WebSocket モードを使うとマルチエージェントの処理を継続する際のオーバーヘッドを抑えられます。
マルチエージェントを有効にする前に、現在の制限を確認してください。/responses/compact、reasoning.summary、max_tool_calls には対応していません。サーバーがルートのコンテキストとすべてのサブエージェントのコンテキストに自動でコンパクションを適用します。
GPT-6 モデルでは、アプリケーションが関数やカスタムツールを実行している間もモデルが作業を続けられる場合、その関数やツールに async: true を設定します。時間のかかるツールは早めに呼び出し、モデルには並行して独立した作業を進めさせます。呼び出しの実行と追跡は引き続きアプリケーションが担当し、後続の Responses リクエストで元の call_id とともに結果を返します。組み込みツールやプログラムによるツール呼び出しには非同期実行を適用できません。マルチエージェントモードでは、非同期ツールと並列ツール呼び出しを併用しないでください。一連の手順は非同期ツール呼び出し を参照してください。
組み込みツール は API が標準で提供する機能です。すべてのツールを自作する必要はなく、Responses API でそのまま使えるツールへのアクセスをモデルに付与できます。モデルは各ツールをいつ使うかを判断できます。
OpenAI は組み込みツールを順次追加しています。ワークフローに合うものがあれば、まず組み込みツールを使ってください。標準の機能ではタスクに対応できない場合に、カスタムツールを作成します。現在利用できる組み込みツールと関連機能には、次のものがあります。
ウェブ検索 :ウェブで最新情報を検索
ファイル検索 :アップロードしたファイルやベクトルストアを検索
コードインタープリター :Python を実行して分析、計算、グラフ作成、ファイル処理を実施
シェル :ホスト型コンテナまたは独自のランタイムでシェルコマンドを実行
コンピューターの使用 :スクリーンショットを確認し、クリック、文字入力、スクロールで UI を操作
画像生成 :画像を生成または編集
MCP/コネクタ :モデルを外部サービスやツールに接続
スキル :再利用可能な指示のセットやワークフローファイルを添付
パッチの適用 :構造化された形式でコードを編集
ツールを使う際のモデルの性能も、組み込みツールを優先する理由です。組み込みツールは事後学習で扱うデータの分布に含まれます。つまり、モデルはこれらのツールの形式、動作、出力を使って訓練・評価されています。そのため、OpenAI のモデルは新規のツールを使う場合に比べて適切なツールを選びやすく、実行も円滑で、失敗が少なくなります。
コンパクション は、多数のターンにわたってモデルがどの情報を引き継ぐかを制御する、コンテキスト設計のためのツールです。長時間動作するエージェントでは、「コンテキストの上限に達するか」だけが問題ではありません。古いメッセージ、ツールのログ、再試行の記録、すでに意味を失った詳細が、モデルに必要な状態情報を圧迫します。
コンパクションを使うと、後続のターンに必要な状態を保持しながら、コンテキストを計画的に縮小できます。デバッグの一段階を終えたときや根本原因を絞り込んだときなど、作業の節目でそれまでのコンテキストウィンドウにコンパクションを適用し、その出力から作業を続けられます。次のターンでは、途中の推論、失敗したコマンド、検討済みの古い仮説をすべて引き継がず、重要な状態を中心に処理を進められるため、モデルがタスクに集中できます。
コンパクションには 2 つの使い方があります。
サーバーに任せる場合 :previous_response_id を使っている場合は、context_management を有効にし、compact_threshold を指定します。会話が大きくなると、サーバーが自動でコンパクションを適用します。引き続き最新のユーザーメッセージだけを送信してください。
自分で管理する場合 :入力配列全体を自分で管理している場合は、client.responses.compact() を呼び出します。小さくなったコンテキストウィンドウが返るので、その出力を次の responses.create() 呼び出しにそのまま使います。
コンパクション後の出力は編集しないでください。 これは人間向けの要約ではなく、モデルが作業を続けるための内部状態です。そのまま引き継ぎ、続けて次のユーザーメッセージを追加します。
1
2
3
4
5
6
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 import OpenAI from "openai";
import { toResponseInputItems } from "openai/lib/responses/ResponseInputItems";
const openai = new OpenAI();
// Full window collected from a long debugging session:
// user messages, assistant outputs, tool calls, and tool outputs.
const longWindow = sessionItems;
const compacted = await openai.responses.compact({
model: "gpt-6-astra",
input: longWindow,
});
const nextResponse = await openai.responses.create({
model: "gpt-6-astra",
store: false,
input: [
// Preserve replayable compacted items.
...toResponseInputItems(compacted.output),
{
type: "message",
role: "user",
content:
"We found the bad cache invalidation path. Write the fix plan " +
"and the verification checklist.",
},
],
});
console.log(nextResponse.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 from openai import OpenAI
client = OpenAI()
# Full window collected from a long debugging session:
# user messages, assistant outputs, tool calls, and tool outputs.
long_window = session_items
compacted = client.responses.compact(
model = "gpt-6-astra" ,
input = long_window,
)
next_response = client.responses.create(
model = "gpt-6-astra" ,
store = False ,
input = [
* compacted.output, # Use compact output as-is.
{
"type" : "message" ,
"role" : "user" ,
"content" : (
"We found the bad cache invalidation path. Write the fix plan "
"and the verification checklist."
),
},
],
)
print (next_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 package main
import (
"context"
"encoding/json"
"fmt"
"github.com/openai/openai-go/v3"
"github.com/openai/openai-go/v3/responses"
)
func main() {
client := openai.NewClient()
longWindow := []responses.ResponseInputItemUnionParam{
responses.ResponseInputItemParamOfMessage("Find the cache invalidation bug in this debugging session.", responses.EasyInputMessageRoleUser),
}
compacted, err := client.Responses.Compact(context.Background(), responses.ResponseCompactParams{
Model: "gpt-6-astra",
Input: responses.ResponseCompactParamsInputUnion{OfResponseInputItemArray: longWindow},
})
if err != nil {
panic(err)
}
input := append(outputAsInput(compacted.Output),
responses.ResponseInputItemParamOfMessage(
"We found the bad cache invalidation path. Write the fix plan and the verification checklist.",
responses.EasyInputMessageRoleUser,
),
)
nextResponse, err := client.Responses.New(context.Background(), responses.ResponseNewParams{
Model: "gpt-6-astra",
Store: openai.Bool(false),
Input: responses.ResponseNewParamsInputUnion{OfInputItemList: input},
})
if err != nil {
panic(err)
}
fmt.Println(nextResponse.OutputText())
}
func outputAsInput(output []responses.ResponseOutputItemUnion) []responses.ResponseInputItemUnionParam {
input := make([]responses.ResponseInputItemUnionParam, 0, len(output))
for _, item := range output {
var converted responses.ResponseInputItemUnion
if err := json.Unmarshal([]byte(item.RawJSON()), &converted); err != nil {
panic(err)
}
input = append(input, converted.ToParam())
}
return 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
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 import com.openai.client.OpenAIClient;
import com.openai.client.okhttp.OpenAIOkHttpClient;
import com.openai.models.responses.EasyInputMessage;
import com.openai.models.responses.ResponseCompactParams;
import com.openai.models.responses.ResponseCompactionItemParam;
import com.openai.models.responses.ResponseCreateParams;
import com.openai.models.responses.ResponseInputItem;
import java.util.ArrayList;
var compacted =
client
.responses()
.compact(
ResponseCompactParams.builder()
.model("gpt-6-astra")
.input("Find the cache invalidation bug in this debugging session.")
.build());
var input = new ArrayList<ResponseInputItem>();
for (var item : compacted.output()) {
item.message().map(ResponseInputItem::ofResponseOutputMessage).ifPresent(input::add);
item.reasoning().map(ResponseInputItem::ofReasoning).ifPresent(input::add);
item.compaction()
.map(
value ->
ResponseInputItem.ofCompaction(
ResponseCompactionItemParam.builder()
.id(value.id())
.encryptedContent(value.encryptedContent())
.build()))
.ifPresent(input::add);
}
input.add(
ResponseInputItem.ofEasyInputMessage(
EasyInputMessage.builder()
.role(EasyInputMessage.Role.USER)
.content(
"We found the bad cache invalidation path. Write the fix plan and the verification checklist.")
.build()));
client
.responses()
.create(
ResponseCreateParams.builder()
.model("gpt-6-astra")
.inputOfResponse(input)
.store(false)
.build())
.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 require "openai"
client = OpenAI::Client.new
long_window = [
{
role: :user,
content: "Find the cache invalidation bug in this debugging session."
}
]
compacted = client.responses.compact(
model: "gpt-6-astra",
input: long_window
)
input = compacted.output.dup
input << {
role: :user,
content: "We found the bad cache invalidation path. Write the fix plan and the verification checklist."
}
response = client.responses.create(
model: "gpt-6-astra",
store: false,
input: input
)
puts(response.output_text)
プロンプトキャッシュ は、複数のリクエストで共通の長いプレフィックスを再利用するときに、レイテンシとコストを自動で削減します。変化しない指示、例、参考資料を先頭に置き、その後にユーザーごとに変わる内容を配置します。ツール定義とその順序を一定に保ち、それまでのコンテキストを書き換えずに、新しい会話ターンを末尾に追加します。
GPT-5.6 で明示的なプロンプトキャッシュが導入されました。既定は引き続き暗黙的なキャッシュですが、GPT-5.6 モデルとそれ以降のモデルファミリーでは、キャッシュのブレークポイントを明示し、リクエスト全体のキャッシュポリシーを設定することもできます。固定のプレフィックスの後に可変部分が続く場合は、再利用できる部分の末尾に prompt_cache_breakpoint を明示的に追加します。暗黙のブレークポイントを使わず、指定したブレークポイントだけを使うリクエストに限り、prompt_cache_options.mode を explicit に設定してください。それより前のモデルでは、引き続き自動プロンプトキャッシュのみを使用します。
GPT-5.5 以前から移行する場合は、prompt_cache_retention を prompt_cache_options.ttl: "30m" に置き換えます。キャッシュ設定を変更する前に、モデルによるプロンプトキャッシュの違い を確認してください。
GPT-5.6 モデルとそれ以降のモデルファミリーでは、キャッシュ書き込みの単価は、キャッシュされていない入力トークンの単価の 1.25 倍です。cached_tokens と cache_write_tokens を記録し、書き込み量とその後のキャッシュ読み取り量を比較して、差し引きのコストを測定し、ブレークポイントの位置を調整します。
GPT-5.6 より前のモデルでは、再利用できるプレフィックスを共有するリクエストに同じ prompt_cache_key を使います。関連するリクエストが同じキャッシュに振り分けられやすくなり、キャッシュヒット率を最適化できます。リクエストが集中するグループについては、キーを増やしてトラフィックを分散するための指針 に従ってください。
GPT-5.6 以降では prompt_cache_key は任意で、指定しなくても最適なキャッシュヒット率を達成できます。このキーを使うと、顧客、ユーザー、ワークスペースごとにキャッシュ利用量を個別に集計できます。各グループのキャッシュ済みトークンの使用量と請求額も説明しやすくなります。顧客ごとに異なるキーを割り当て、その顧客の関連リクエストでは同じキーを使います。キーを分けることで、ある顧客が別の顧客のキャッシュヒットの有無を探る行為も防ぎやすくなります。キーによるキャッシュ利用量の個別集計 を参照してください。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 import OpenAI from "openai";
const openai = new OpenAI();
const instructions = [
"You are the support agent for Acme.",
"Follow the Acme support policy and escalation rubric.",
"Use the same tone, safety rules, and tool plan for each ticket.",
].join("\n");
const response = await openai.responses.create({
model: "gpt-6-astra",
prompt_cache_key: "tenant-acme-support-agent",
instructions,
input: "Summarize the current escalation for the on-call lead.",
});
console.log(response.output_text); 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 from openai import OpenAI
client = OpenAI()
instructions = """
You are the support agent for Acme.
Follow the Acme support policy and escalation rubric.
Use the same tone, safety rules, and tool plan for each ticket.
"""
response = client.responses.create(
model = "gpt-6-astra" ,
prompt_cache_key = "tenant-acme-support-agent" ,
instructions = instructions,
input = "Summarize the current escalation for the on-call lead." ,
)
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 package main
import (
"context"
"fmt"
"strings"
"github.com/openai/openai-go/v3"
"github.com/openai/openai-go/v3/responses"
)
func main() {
client := openai.NewClient()
instructions := strings.Join([]string{
"You are the support agent for Acme.",
"Follow the Acme support policy and escalation rubric.",
"Use the same tone, safety rules, and tool plan for each ticket.",
}, "\n")
response, err := client.Responses.New(context.Background(), responses.ResponseNewParams{
Model: "gpt-6-astra",
PromptCacheKey: openai.String("tenant-acme-support-agent"),
Instructions: openai.String(instructions),
Input: responses.ResponseNewParamsInputUnion{OfString: openai.String("Summarize the current escalation for the on-call lead.")},
})
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 import com.openai.client.OpenAIClient;
import com.openai.client.okhttp.OpenAIOkHttpClient;
import com.openai.models.responses.ResponseCreateParams;
ResponseCreateParams params =
ResponseCreateParams.builder()
.model("gpt-6-astra")
.instructions(
"You are the support agent for Acme.\n"
+ "Follow the Acme support policy and escalation rubric.\n"
+ "Use the same tone, safety rules, and tool plan for each ticket.")
.input("Summarize the current escalation for the on-call lead.")
.promptCacheKey("tenant-acme-support-agent")
.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 using OpenAI.Responses;
#pragma warning disable OPENAI001
string key = Environment.GetEnvironmentVariable("OPENAI_API_KEY")!;
ResponsesClient client = new(key);
CreateResponseOptions options = new()
{
Model = "gpt-6-astra",
PromptCacheKey = "tenant-acme-support-agent",
Instructions = "Follow the Acme support policy and escalation rubric.",
};
options.InputItems.Add(
ResponseItem.CreateUserMessageItem("Summarize the current escalation for the on-call lead.")
);
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 require "openai"
client = OpenAI::Client.new
instructions = <<~INSTRUCTIONS
You are the support agent for Acme.
Follow the Acme support policy and escalation rubric.
Use the same tone, safety rules, and tool plan for each ticket.
INSTRUCTIONS
response = client.responses.create(
model: "gpt-6-astra",
prompt_cache_key: "tenant-acme-support-agent",
instructions: instructions,
input: "Summarize the current escalation for the on-call lead."
)
puts(response.output_text)
reasoning.encrypted_content の利用
GPT-6 モデルを含む対応モデルでは、複数の呼び出しにわたって推論を保持 できます。タスクの目標、前提、優先順位が変わらない場合は reasoning.context: "all_turns" を使います。以前の推論がもはや役立たず、モデルが古いアプローチに引きずられるおそれがある場合は current_turn を使います。reasoning.context を省略するか auto に設定した場合は、応答の reasoning.context フィールドで実際に適用されたモードを確認してください。
保持された推論の利用 には、以前の推論項目が必要です。保存済みの応答には previous_response_id を使います。ゼロデータ保持(ZDR) の要件により応答データを保存できない場合は、暗号化された推論内容を使うことで、ステートレスに引き継げます。
応答の出力に含まれる推論項目には、既定で暗号化された推論内容が含まれます。各推論項目の encrypted_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 import OpenAI from "openai";
import { toResponseInputItems } from "openai/lib/responses/ResponseInputItems";
const openai = new OpenAI();
const history = [
{
role: "user",
content: "Investigate why invoice INV-1043 has mismatched tax totals.",
},
];
const first = await openai.responses.create({
model: "gpt-6-astra",
store: false,
reasoning: { effort: "medium", context: "current_turn" },
input: history,
});
history.push(...toResponseInputItems(first.output));
history.push({
role: "user",
content: "Now write the customer-facing explanation in plain English.",
});
const second = await openai.responses.create({
model: "gpt-6-astra",
store: false,
reasoning: { effort: "medium", context: "all_turns" },
input: history,
});
console.log(second.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 from openai import OpenAI
client = OpenAI()
history = [
{
"role" : "user" ,
"content" : "Investigate why invoice INV-1043 has mismatched tax totals." ,
}
]
first = client.responses.create(
model = "gpt-6-astra" ,
store = False ,
reasoning = { "effort" : "medium" , "context" : "current_turn" },
input = history,
)
history.extend(item.to_dict() for item in first.output)
history.append(
{
"role" : "user" ,
"content" : "Now write the customer-facing explanation in plain English." ,
}
)
second = client.responses.create(
model = "gpt-6-astra" ,
store = False ,
reasoning = { "effort" : "medium" , "context" : "all_turns" },
input = history,
)
print (second.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 package main
import (
"context"
"encoding/json"
"fmt"
"github.com/openai/openai-go/v3"
"github.com/openai/openai-go/v3/responses"
"github.com/openai/openai-go/v3/shared"
)
func main() {
client := openai.NewClient()
history := []responses.ResponseInputItemUnionParam{
responses.ResponseInputItemParamOfMessage("Investigate why invoice INV-1043 has mismatched tax totals.", responses.EasyInputMessageRoleUser),
}
first, err := client.Responses.New(context.Background(), responses.ResponseNewParams{
Model: "gpt-6-astra",
Store: openai.Bool(false),
Reasoning: shared.ReasoningParam{Effort: shared.ReasoningEffortMedium, Context: shared.ReasoningContextCurrentTurn},
Include: []responses.ResponseIncludable{responses.ResponseIncludableReasoningEncryptedContent},
Input: responses.ResponseNewParamsInputUnion{OfInputItemList: history},
})
if err != nil {
panic(err)
}
history = append(history, outputAsInput(first.Output)...)
history = append(history, responses.ResponseInputItemParamOfMessage(
"Now write the customer-facing explanation in plain English.",
responses.EasyInputMessageRoleUser,
))
second, err := client.Responses.New(context.Background(), responses.ResponseNewParams{
Model: "gpt-6-astra",
Store: openai.Bool(false),
Reasoning: shared.ReasoningParam{Effort: shared.ReasoningEffortMedium, Context: shared.ReasoningContextAllTurns},
Input: responses.ResponseNewParamsInputUnion{OfInputItemList: history},
})
if err != nil {
panic(err)
}
fmt.Println(second.OutputText())
}
func outputAsInput(output []responses.ResponseOutputItemUnion) []responses.ResponseInputItemUnionParam {
input := make([]responses.ResponseInputItemUnionParam, 0, len(output))
for _, item := range output {
var converted responses.ResponseInputItemUnion
if err := json.Unmarshal([]byte(item.RawJSON()), &converted); err != nil {
panic(err)
}
input = append(input, converted.ToParam())
}
return 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
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 import com.openai.client.OpenAIClient;
import com.openai.client.okhttp.OpenAIOkHttpClient;
import com.openai.core.JsonValue;
import com.openai.models.Reasoning;
import com.openai.models.responses.EasyInputMessage;
import com.openai.models.responses.ResponseCreateParams;
import com.openai.models.responses.ResponseIncludable;
import com.openai.models.responses.ResponseInputItem;
import java.util.ArrayList;
var history = new ArrayList<ResponseInputItem>();
history.add(
ResponseInputItem.ofEasyInputMessage(
EasyInputMessage.builder()
.role(EasyInputMessage.Role.USER)
.content("Investigate why invoice INV-1043 has mismatched tax totals.")
.build()));
var first =
client
.responses()
.create(
ResponseCreateParams.builder()
.model("gpt-6-astra")
.inputOfResponse(history)
.store(false)
.reasoning(
Reasoning.builder()
.effort(com.openai.models.ReasoningEffort.MEDIUM)
.putAdditionalProperty("context", JsonValue.from("current_turn"))
.build())
.addInclude(ResponseIncludable.of("reasoning.encrypted_content"))
.build());
first.output().stream()
.map(item -> JsonValue.from(item).convert(ResponseInputItem.class))
.forEach(history::add);
history.add(
ResponseInputItem.ofEasyInputMessage(
EasyInputMessage.builder()
.role(EasyInputMessage.Role.USER)
.content("Now write the customer-facing explanation in plain English.")
.build()));
client
.responses()
.create(
ResponseCreateParams.builder()
.model("gpt-6-astra")
.inputOfResponse(history)
.store(false)
.reasoning(
Reasoning.builder()
.effort(com.openai.models.ReasoningEffort.MEDIUM)
.putAdditionalProperty("context", JsonValue.from("all_turns"))
.build())
.build())
.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 require "openai"
client = OpenAI::Client.new
history = [
{
role: :user,
content: "Investigate why invoice INV-1043 has mismatched tax totals."
}
]
first = client.responses.create(
model: "gpt-6-astra",
store: false,
reasoning: {
effort: :medium,
context: :current_turn
},
include: ["reasoning.encrypted_content"],
input: history
)
history.concat(first.output)
history << {
role: :user,
content: "Now write the customer-facing explanation in plain English."
}
second = client.responses.create(
model: "gpt-6-astra",
store: false,
reasoning: {
effort: :medium,
context: :all_turns
},
input: history
)
puts(second.output_text)
画像の detail の既定値は auto で、画像サイズの扱いはモデルによって異なります。大きな画像では、入力トークンが増え、レイテンシが長くなる場合があります。モデル別の画像サイズの扱いを示した表 を確認し、デプロイ前に選択したモデルで画像のトークン使用量と上限を確かめてください。
タスクに合わせて detail を選びます。必要に応じて画像のサイズを変更し、細部が重要でない場合は low、標準的な高精細処理で画像を読み取る場合は high を使います。大きな画像や情報密度の高い画像を扱うタスク、正確な座標が必要なタスク、OCR、位置の特定、外観検査など、細部を保持すると品質が向上する場合は、対応モデルで original を使ってください。デプロイ前に、最も負荷の高いケースで画像のトークン数とレイテンシを測定します。
個々のエンドユーザーにサービスを提供するアプリケーションでは、ユーザーごとに一貫した、プライバシーを保護できる safety_identifier を各リクエストに含めます。これにより、OpenAI が不正利用を検出しやすくなり、開発チームも同じ識別子でポリシー違反を追跡できます。また、あるユーザーの不正利用によって組織全体のアクセスに影響が及ぶ可能性を抑えられます。
個人を特定できる情報をそのまま送信せず、ユーザー名またはメールアドレスをハッシュ化してください。ログインしていないユーザーには、一貫したセッション ID を使います。
GPT-6 Astra のエージェントワークフローでは、ミスアライメント監視 への対応をあらかじめ設計してください。リクエストが 403 と misalignment_policy_violation を返した場合は、その会話で新たなアクションを発行するのをやめ、ブロックされたワークフローを自動で再試行しないでください。ストリーミング中のエラーにも対応し、すでに実行された可能性があるアクションを確認します。チームでプロジェクトのアラートを受け取る必要がある場合は、safety.alert.created を購読してください。Webhook を使う場合も、リクエストのエラー処理は必要です。どの Responses リクエストが自動停止の対象になるかはガイドを確認してください。
復旧方法を決める前に、HTTP ステータスと error.code を確認します。429 と slow_down が返った場合は、リクエストの頻度が急激に上昇しています。Retry-After があればそれに従い、トラフィックを減らしてから徐々に増やしてください。503 と server_is_overloaded が返った場合は、リクエスト先のモデルが一時的に過負荷になっています。Retry-After があれば、指定された時間だけ待ってから再試行します。ヘッダーがない場合は、再試行の間隔にランダムなばらつきを加えながら指数関数的に延ばし、再試行回数に上限を設けます。請求、支出、クォータに関するエラーは、再試行の前に対処が必要です。すべての 429 を一時的なレート制限として扱わないでください。レート制限 とエラーコード を参照してください。
処理に時間がかかる可能性があるリクエストには background=True を使います。クライアント接続を維持する代わりに、API がジョブを開始して ID を返します。アプリはジョブが完了、失敗、またはキャンセルされるまで、その状態をポーリングできます。大規模な分析、長時間のツール実行、状態の確認や再試行が必要な作業に使ってください。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28 // Replace the illustrative IDs and URLs below with your own resource values.
import OpenAI from "openai";
const openai = new OpenAI();
const logBundleFileId = "file_123";
let job = await openai.responses.create({
model: "gpt-6-astra",
background: true,
store: false,
input: "Analyze this large log bundle and cluster the primary failure modes.",
tools: [
{
type: "code_interpreter",
container: {
type: "auto",
file_ids: [logBundleFileId],
},
},
],
});
while (["queued", "in_progress"].includes(job.status)) {
await new Promise((resolve) => setTimeout(resolve, 2000));
job = await openai.responses.retrieve(job.id);
}
console.log(job.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 # Replace the illustrative IDs and URLs below with your own resource values.
from openai import OpenAI
import time
client = OpenAI()
log_bundle_file_id = "file_123"
job = client.responses.create(
model = "gpt-6-astra" ,
background = True ,
store = False ,
input = "Analyze this large log bundle and cluster the primary failure modes." ,
tools = [
{
"type" : "code_interpreter" ,
"container" : {
"type" : "auto" ,
"file_ids" : [log_bundle_file_id],
},
}
],
)
while job.status in { "queued" , "in_progress" }:
time.sleep( 2 )
job = client.responses.retrieve(job.id)
print (job.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 package main
import (
"context"
"fmt"
"time"
"github.com/openai/openai-go/v3"
"github.com/openai/openai-go/v3/responses"
)
func main() {
client := openai.NewClient()
tool := responses.ToolParamOfCodeInterpreter(responses.ToolCodeInterpreterContainerCodeInterpreterContainerAutoParam{
FileIDs: []string{"file_abc123"},
})
job, err := client.Responses.New(context.Background(), responses.ResponseNewParams{
Model: "gpt-6-astra",
Background: openai.Bool(true),
Store: openai.Bool(false),
Input: responses.ResponseNewParamsInputUnion{OfString: openai.String("Analyze this large log bundle and cluster the primary failure modes.")},
Tools: []responses.ToolUnionParam{tool},
})
if err != nil {
panic(err)
}
for job.Status == responses.ResponseStatusQueued || job.Status == responses.ResponseStatusInProgress {
time.Sleep(2 * time.Second)
job, err = client.Responses.Get(context.Background(), job.ID, responses.ResponseGetParams{})
if err != nil {
panic(err)
}
}
fmt.Println(job.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 import com.openai.client.OpenAIClient;
import com.openai.client.okhttp.OpenAIOkHttpClient;
import com.openai.models.responses.ResponseCreateParams;
import com.openai.models.responses.ResponseStatus;
import com.openai.models.responses.Tool;
String fileId = "file_abc123";
ResponseCreateParams params =
ResponseCreateParams.builder()
.model("gpt-6-astra")
.input("Analyze this large log bundle and cluster the primary failure modes.")
.background(true)
.store(false)
.addCodeInterpreterTool(
Tool.CodeInterpreter.Container.CodeInterpreterToolAuto.builder()
.addFileId(fileId)
.build())
.build();
var response = client.responses().create(params);
while (response.status().filter(ResponseStatus.QUEUED::equals).isPresent()
|| response.status().filter(ResponseStatus.IN_PROGRESS::equals).isPresent()) {
Thread.sleep(1000);
response = client.responses().retrieve(response.id());
}
if (response.status().filter(ResponseStatus.COMPLETED::equals).isEmpty()) {
throw new IllegalStateException(
"Research ended with status: " + response.status().orElseThrow());
}
response.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 require "openai"
client = OpenAI::Client.new
job = client.responses.create(
model: "gpt-6-astra",
background: true,
store: false,
input: "Analyze this large log bundle and cluster the primary failure modes.",
tools: [
{
type: :code_interpreter,
container: {
type: :auto,
file_ids: ["file_abc123"]
}
}
]
)
while [:queued, :in_progress].include?(job.status)
sleep(2)
job = client.responses.retrieve(job.id)
end
puts(job.output_text)
stream=True と併用すると進捗イベントを受け取れますが、最初のイベントが届くまでに通常のリクエストより時間がかかる場合があります。
UI では、バックグラウンドモードの状態を「処理中です。現在の進捗はこちらで確認できます。完了するとここに結果が表示されます」のように伝えます。
WebSocket モード は、ツール呼び出しが多く、長時間実行されるワークフロー向けに設計されています。接続を開いたまま、新しい入力項目と previous_response_id だけを送って処理を続けます。ツール呼び出しが 20 回以上あるワークフローでは、処理全体が最大で約 40% 高速化した例があります。
動作の仕組み :最初のメッセージは通常の Responses リクエストと同様に、モデル、指示、ツール、ユーザー入力を含みます。サーバーはイベントをストリーミングで返します。モデルがツールの実行を要求すると、アプリがそのツールを実行します。その後、新しい HTTP リクエストを送る代わりに、同じソケットで次の response.create イベントを送信します。このイベントには、前の応答を指す previous_response_id と新しい項目を含めます。これによりレイテンシが短縮されます。通常の HTTP では、後続の処理は毎回新しいリクエストになります。WebSocket モードでは接続を維持し、その接続のメモリ上で直近の応答状態をすぐに利用できます。次のターンをその応答から続けるときに、サービス側の準備処理が少なくて済みます。
1 回のリクエストに 1 回回答して完了するワークフローでは、引き続き HTTP を使ってください 。長時間動作するエージェントのようなワークフローでは、WebSocket モードを試してください。
1 つの接続で複数の会話を並行して進める場合は、会話ごとに異なる stream_id を使い、混在して届くイベントを stream_id で振り分けます。1 接続で最大 16 件の応答を同時に処理できますが、同じストリームのリクエストは順番に実行されます。接続時間の上限は 60 分です。処理を継続するときの previous_response_id の意味は HTTP モードと同じで、各ストリームの最新の応答には接続ごとのキャッシュを使います。
注:WebSocket モードではデータをディスクに保存せず、メモリ内にのみ保持するため、ZDR と併用できます。
Python のサンプルでは pip install "openai[realtime]>=3.8.0" を使います。
JavaScript のサンプルでは npm install openai@^7.10.0 ws を使います。
Ruby のサンプルでは gem install openai async-websocket を使います。
Go では go get github.com/openai/openai-go/v3@v3.97.0 を実行してください。
Java では Maven の依存関係 com.openai:openai-java:4.101.0 を追加してください。
これらのバージョンの Go SDK と Java SDK は、Responses の WebSocket 接続に標準で対応しています。
1
2
3
4
5
6
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 import OpenAI from "openai";
import { ResponsesWS } from "openai/resources/responses/ws";
const testLogTool = {
type: "function",
name: "search_test_logs",
description: "Search test logs for a query.",
parameters: {
type: "object",
properties: { query: { type: "string" } },
required: ["query"],
additionalProperties: false,
},
strict: true,
};
const codeSearchTool = {
type: "function",
name: "search_code",
description: "Search the codebase for a query.",
parameters: {
type: "object",
properties: { query: { type: "string" } },
required: ["query"],
additionalProperties: false,
},
strict: true,
};
const openai = new OpenAI();
const ws = new ResponsesWS(openai);
try {
ws.send({
type: "response.create",
model: "gpt-6-astra",
store: false,
input: [
{
type: "message",
role: "user",
content: [
{
type: "input_text",
text:
"Find the flaky test in this run, call the tools you need, " +
"and keep going until you can explain the root cause.",
},
],
},
],
tools: [testLogTool, codeSearchTool],
});
let completed = false;
for await (const event of ws) {
if (event.type === "error") throw event.error;
if (event.type !== "message") continue;
const message = event.message;
if (message.type === "response.completed") {
console.log(JSON.stringify(message.response.output));
completed = true;
break;
}
if (
message.type === "response.failed" ||
message.type === "response.incomplete"
) {
throw new Error(JSON.stringify(message));
}
}
if (!completed) {
throw new Error("Connection closed before the response finished.");
}
} finally {
ws.close();
} 1
2
3
4
5
6
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 from openai import OpenAI
from openai.types.responses import FunctionToolParam
test_log_tool: FunctionToolParam = {
"type" : "function" ,
"name" : "search_test_logs" ,
"description" : "Search test logs." ,
"parameters" : {
"type" : "object" ,
"properties" : { "query" : { "type" : "string" }},
"required" : [ "query" ],
"additionalProperties" : False ,
},
"strict" : True ,
}
code_search_tool: FunctionToolParam = {
"type" : "function" ,
"name" : "search_code" ,
"description" : "Search source code." ,
"parameters" : {
"type" : "object" ,
"properties" : { "query" : { "type" : "string" }},
"required" : [ "query" ],
"additionalProperties" : False ,
},
"strict" : True ,
}
client = OpenAI()
with client.responses.connect() as connection:
# Use the same typed parameters as client.responses.create(...).
connection.response.create(
model = "gpt-6-astra" ,
store = False ,
input = [
{
"type" : "message" ,
"role" : "user" ,
"content" : [
{
"type" : "input_text" ,
"text" : (
"Find the flaky test in this run, call the tools "
"you need, and keep going until you can explain "
"the root cause."
),
}
],
}
],
tools = [test_log_tool, code_search_tool],
)
for event in connection:
if event.type == "response.completed" :
print (event.response.output)
break
if event.type in { "response.failed" , "response.incomplete" , "error" }:
raise RuntimeError (event.to_json())
else :
raise RuntimeError ( "Connection closed before the response finished." ) 1
2
3
4
5
6
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 tools := []responses.ToolUnionParam{}
for _, name := range []string{
"search_test_logs",
"search_code",
} {
tools = append(tools, responses.ToolUnionParam{
OfFunction: &responses.FunctionToolParam{
Name: name,
Description: openai.String("Search for a query."),
Parameters: map[string]any{
"type": "object",
"properties": map[string]any{
"query": map[string]any{
"type": "string",
},
},
"required": []string{
"query",
},
"additionalProperties": false,
},
Strict: openai.Bool(true),
},
})
}
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Minute)
defer cancel()
client := openai.NewClient()
conn, err := client.Responses.Connect(ctx, responses.ResponseConnectionOptions{})
if err != nil {
log.Fatal(err)
}
defer conn.Close()
if err := conn.Create(ctx, responses.ResponsesClientEventResponseCreateParam{
Model: "gpt-6-astra",
Store: openai.Bool(false),
Input: responses.ResponsesClientEventResponseCreateInputUnionParam{
OfString: openai.String("Find the flaky test in this run, call the tools you need, and keep going until you can explain the root cause."),
},
Tools: tools,
}); err != nil {
log.Fatal(err)
}
response, err := conn.FinalResponse(ctx)
if err != nil {
log.Fatal(err)
}
if response.Status != responses.ResponseStatusCompleted {
log.Fatalf("Response ended with status %s", response.Status)
}
output := make([]json.RawMessage, 0, len(response.Output))
for _, item := range response.Output {
output = append(output, json.RawMessage(item.RawJSON()))
}
if err := json.NewEncoder(os.Stdout).Encode(output); err != nil {
log.Fatal(err)
} 1
2
3
4
5
6
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 import com.openai.client.okhttp.OpenAIOkHttpClient;
import com.openai.core.JsonValue;
import com.openai.models.responses.*;
import java.util.*;
var tools = new ArrayList<Tool>();
for (var name : List.of("search_test_logs", "search_code"))
tools.add(
Tool.ofFunction(
FunctionTool.builder()
.name(name)
.description("Search for a query.")
.strict(true)
.parameters(
FunctionTool.Parameters.builder()
.putAdditionalProperty("type", JsonValue.from("object"))
.putAdditionalProperty(
"properties",
JsonValue.from(Map.of("query", Map.of("type", "string"))))
.putAdditionalProperty("required", JsonValue.from(List.of("query")))
.putAdditionalProperty("additionalProperties", JsonValue.from(false))
.build())
.build()));
try (var conn = client.responses().connect()) {
conn.send(
ResponsesClientEvent.ofResponseCreate(
ResponsesClientEvent.ResponseCreate.builder()
.model("gpt-6-astra")
.store(false)
.input(
"Find the flaky test in this run, call the tools you need, and keep going until you can explain the root cause.")
.tools(tools)
.build()));
var response = conn.finalResponse();
if (response.status().filter(ResponseStatus.COMPLETED::equals).isEmpty())
throw new IllegalStateException(
"Response ended with status " + response.status().orElse(null));
System.out.println(response.output());
} 1
2
3
4
5
6
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 require "async"
require "openai"
require "json"
def wait_for_response(connection)
while (event = connection.receive)
case event.type.to_s
when "response.completed" then return event.response
when "response.failed", "response.incomplete", "error"
raise "Response failed: #{event.to_json}"
end
end
raise "Connection closed before the response finished"
end
test_log_tool = {
type: "function",
name: "search_test_logs",
description: "Search test logs.",
parameters: {
type: "object",
properties: { query: { type: "string" } },
required: ["query"],
additionalProperties: false
},
strict: true
}
code_search_tool = {
type: "function",
name: "search_code",
description: "Search source code.",
parameters: {
type: "object",
properties: { query: { type: "string" } },
required: ["query"],
additionalProperties: false
},
strict: true
}
client = OpenAI::Client.new
Sync do |task|
task.with_timeout(120) do
client.responses.connect(request_options: { timeout: 10 }) do |connection|
connection.response.create(
stream_id: "main", model: "gpt-6-astra", store: false,
input: [
{
role: "user",
content: "Find the flaky test in this run, call the tools you need, and keep going until you can explain the root cause."
}
],
tools: [test_log_tool, code_search_tool]
)
puts(JSON.pretty_generate(wait_for_response(connection).output.map(&:to_h)))
end
end
end
GPT-6 モデルの作業中にユーザーが要件を追加する可能性がある場合は、Responses API に WebSocket で接続します。response.steer イベントを送信する際に、previous_response_id に処理中の応答の ID を指定し、新しいユーザー入力を含めます。その後もイベントを引き続き読み取ってください。response.steer.accepted は更新がキューに入ったことを示します。途中で指示を追加しても、アプリケーションに送信済みの出力は変わらず、実行を開始したツールの処理が取り消されることもありません。イベントの流れとツールの結果の扱いは、ターン途中での指示の追加 を参照してください。
Responses API は、より高度な判断と処理ができる OpenAI アプリケーションを構築するための基盤です。開発者は、単発のプロンプトから、ツールとコンテキストを活用しながら継続的に動作し、タスクの複雑さに応じて処理を変えられるワークフローへと移行できます。本番環境での性能向上に、このガイドを活用してください。