ツール検索を使うと、モデルは必要に応じてツールを動的に検索し、コンテキストに読み込めます。すべてのツール定義を最初からモデルのコンテキストに読み込む必要がなくなり、 全体のトークン使用量とコストの削減につながる可能性があります。ツール検索は、コストとレイテンシを最適化するために、 モデルのキャッシュを維持する設計になっています。モデルが新しいツールを見つけると、そのツールはコンテキストウィンドウの末尾に追加されます。
Responses API では、gpt-5.4 以降のモデルのみが tool_search をサポートしています。
以下の構成と例では Responses API を使用します。セッション単位の関数読み込みと MCP の自動検出については、Agents API を参照してください。
Responses API でツール検索を有効にするには、次の 2 つの設定が必要です。
tools 配列に、ツールとして tool_search を追加します。
- 関数を使う場合は、読み込みを遅延させたい関数に
defer_loading: true を指定します。MCP サーバーを使う場合は、MCP サーバーのツール定義に defer_loading: true を設定します。
ツール検索は、遅延読み込みを設定した関数、名前空間、MCP サーバーで使えますが、可能であれば名前空間または MCP サーバーの利用を推奨します。OpenAI のモデルは主にこれらを検索するように学習されており、通常はトークンの削減効果もより大きくなります。
名前空間を使う場合、defer_loading は名前空間オブジェクト自体ではなく、その中の関数に適用されます。
リクエストの開始時にも、検索対象の名前と説明はモデルに提示されます。名前空間や MCP サーバーの場合、最初に提示されるのは名前空間やサーバーの名前と説明だけです。その中に含まれる個々の関数の詳細は、ツール検索ツールが読み込むまで提示されません。個別の関数に遅延読み込みを設定した場合も、関数の名前と説明はモデルに提示されるため、実際にツール検索で読み込みが遅延されるのは主にパラメータースキーマです。
トークンを最大限に削減するには、遅延読み込みを設定した関数を名前空間や MCP サーバーにまとめ、中に何が含まれるかをモデルが十分に把握できる、明確な概要説明を付けることを推奨します。これにより、モデルは効率よく検索し、必要な関数だけを読み込めます。トークン効率とモデルのパフォーマンスを高めるため、各名前空間の関数は 10 個未満に抑えることを目安にしてください。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28{
"tools": [
{
"type": "namespace",
"name": "crm",
"description": "CRM tools for customer lookup and order management.",
"tools": [
{
"type": "function",
"name": "list_open_orders",
"description": "List open orders for a customer ID.",
"defer_loading": true,
"parameters": {
"type": "object",
"properties": {
"customer_id": { "type": "string" }
},
"required": ["customer_id"],
"additionalProperties": false
}
}
]
},
{
"type": "tool_search"
}
]
}
名前空間には、遅延読み込みを設定したツールと設定していないツールを混在させることができます。defer_loading: true を指定していないツールはすぐに呼び出せます。同じ名前空間内でも、遅延読み込みを設定したツールはツール検索を通じて読み込まれます。
次の 2 種類のツール検索から選択します。
- ホスト型ツール検索: OpenAI が、リクエストで宣言された遅延読み込み対象のツールを検索し、読み込んだツール群を同じレスポンスで返します。
- クライアント実行型ツール検索: モデルが
tool_search_call を出力し、アプリケーションが検索を実行して、対応する tool_search_output を返します。
リクエストの作成時点で候補となるツールがわかっている場合は、ホスト型ツール検索から始めてください。ツールの検索がプロジェクトやテナントの状態、またはアプリケーションが制御する別のシステムに依存する場合は、クライアント実行型ツール検索を使ってください。
モデルに検索させたい関数、名前空間、MCP サーバーの全体がすでにわかっている場合は、ホスト型ツール検索が最も簡単な方法です。これらをあらかじめ宣言し、{"type": "tool_search"} を追加すれば、何を読み込むかは 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
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47import OpenAI from "openai";
const client = new OpenAI();
const crmNamespace = {
type: "namespace",
name: "crm",
description: "CRM tools for customer lookup and order management.",
tools: [
{
type: "function",
name: "get_customer_profile",
description: "Fetch a customer profile by customer ID.",
parameters: {
type: "object",
properties: {
customer_id: { type: "string" },
},
required: ["customer_id"],
additionalProperties: false,
},
},
{
type: "function",
name: "list_open_orders",
description: "List open orders for a customer ID.",
defer_loading: true,
parameters: {
type: "object",
properties: {
customer_id: { type: "string" },
},
required: ["customer_id"],
additionalProperties: false,
},
},
],
};
const response = await client.responses.create({
model: "gpt-6-astra",
input: "List open orders for customer CUST-12345.",
tools: [crmNamespace, { type: "tool_search" }],
parallel_tool_calls: false,
});
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
50from openai import OpenAI
client = OpenAI()
crm_namespace = {
"type": "namespace",
"name": "crm",
"description": "CRM tools for customer lookup and order management.",
"tools": [
{
"type": "function",
"name": "get_customer_profile",
"description": "Fetch a customer profile by customer ID.",
"parameters": {
"type": "object",
"properties": {
"customer_id": {"type": "string"},
},
"required": ["customer_id"],
"additionalProperties": False,
},
},
{
"type": "function",
"name": "list_open_orders",
"description": "List open orders for a customer ID.",
"defer_loading": True,
"parameters": {
"type": "object",
"properties": {
"customer_id": {"type": "string"},
},
"required": ["customer_id"],
"additionalProperties": False,
},
},
],
}
response = client.responses.create(
model="gpt-6-astra",
input="List open orders for customer CUST-12345.",
tools=[
crm_namespace,
{"type": "tool_search"},
],
parallel_tool_calls=False,
)
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
41package main
import (
"context"
"fmt"
"github.com/openai/openai-go/v3"
"github.com/openai/openai-go/v3/responses"
)
func main() {
client := openai.NewClient()
parameters := map[string]any{
"type": "object",
"properties": map[string]any{"customer_id": map[string]any{"type": "string"}},
"required": []string{"customer_id"},
"additionalProperties": false,
}
namespace := responses.ToolParamOfNamespace(
"CRM tools for customer lookup and order management.",
"crm",
[]responses.NamespaceToolToolUnionParam{
{OfFunction: &responses.NamespaceToolToolFunctionParam{
Name: "get_customer_profile", Description: openai.String("Fetch a customer profile by customer ID."), Parameters: parameters,
}},
{OfFunction: &responses.NamespaceToolToolFunctionParam{
Name: "list_open_orders", Description: openai.String("List open orders for a customer ID."), DeferLoading: openai.Bool(true), Parameters: parameters,
}},
},
)
response, err := client.Responses.New(context.Background(), responses.ResponseNewParams{
Model: "gpt-6-astra",
Input: responses.ResponseNewParamsInputUnion{OfString: openai.String("List open orders for customer CUST-12345.")},
Tools: []responses.ToolUnionParam{namespace, {OfToolSearch: &responses.ToolSearchToolParam{}}},
ParallelToolCalls: openai.Bool(false),
})
if err != nil {
panic(err)
}
fmt.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
58import 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("List open orders for customer CUST-12345.")
.parallelToolCalls(false)
.addTool(
NamespaceTool.builder()
.name("crm")
.description("CRM tools for customer lookup and order management.")
.addTool(
NamespaceTool.Tool.Function.builder()
.name("get_customer_profile")
.description("Fetch a customer profile by customer ID.")
.strict(true)
.parameters(
JsonValue.from(
Map.of(
"type",
"object",
"properties",
Map.of("customer_id", Map.of("type", "string")),
"required",
List.of("customer_id"),
"additionalProperties",
false)))
.build())
.addTool(
NamespaceTool.Tool.Function.builder()
.name("list_open_orders")
.description("List open orders for a customer ID.")
.deferLoading(true)
.strict(true)
.parameters(
JsonValue.from(
Map.of(
"type",
"object",
"properties",
Map.of("customer_id", Map.of("type", "string")),
"required",
List.of("customer_id"),
"additionalProperties",
false)))
.build())
.build())
.addTool(ToolSearchTool.builder().execution(ToolSearchTool.Execution.SERVER).build())
.build();
client.responses().create(params).output().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
39require "openai"
client = OpenAI::Client.new
parameters = {
type: :object,
properties: { customer_id: { type: :string } },
required: ["customer_id"],
additionalProperties: false
}
response = client.responses.create(
model: "gpt-6-astra",
input: "List open orders for customer CUST-12345.",
parallel_tool_calls: false,
tools: [
{
type: :namespace,
name: "crm",
description: "CRM tools for customer lookup and order management.",
tools: [
{
type: :function,
name: "get_customer_profile",
description: "Fetch a customer profile by customer ID.",
parameters: parameters
},
{
type: :function,
name: "list_open_orders",
description: "List open orders for a customer ID.",
defer_loading: true,
parameters: parameters
}
]
},
{ type: :tool_search }
]
)
puts(response.output)
遅延読み込み対象のツールが必要だとモデルが判断すると、レスポンスには、実際の関数呼び出しの前に次の 2 つの出力項目が追加されます。
tool_search_call:ホスト側での検索ステップを記録する項目
tool_search_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[
{
"type": "tool_search_call",
"execution": "server",
"call_id": null,
"status": "completed",
"arguments": {
"paths": ["crm"]
}
},
{
"type": "tool_search_output",
"execution": "server",
"call_id": null,
"status": "completed",
"tools": [
{
"type": "namespace",
"name": "crm",
"description": "CRM tools for customer lookup and order management.",
"tools": [
{
"type": "function",
"name": "list_open_orders",
"description": "List open orders for a customer ID.",
"defer_loading": true,
"parameters": {
"type": "object",
"properties": {
"customer_id": { "type": "string" }
},
"required": ["customer_id"],
"additionalProperties": false
}
}
]
}
]
},
{
"type": "function_call",
"name": "list_open_orders",
"namespace": "crm",
"call_id": "call_abc123",
"arguments": "{\"customer_id\":\"CUST-12345\"}"
}
]
ホスト型モードでは、execution は server に、call_id は null に設定されます。
より複雑なタスクでは、モデルは同じ tool_search_call で複数の名前空間や MCP サーバーを読み込むこともできます。たとえば、1 つのタスクを完了するために異なる名前空間の関数が必要な場合、モデルは後続の関数呼び出しを行う前に、それらをまとめて検索して読み込むことがあります。
クライアント実行型ツール検索では、ツールを探す仕組みをアプリケーション側で完全に制御できます。利用可能なツールが、最初の tools リストでは宣言しにくい情報に依存する場合に便利です。
tool_search ツールに execution: "client" と、アプリケーションが受け取る検索引数のスキーマを設定します。
1
2
3
4
5
6
7
8
9
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
70import OpenAI from "openai";
import { toResponseInputItems } from "openai/lib/responses/ResponseInputItems";
const client = new OpenAI();
const firstResponse = await client.responses.create({
model: "gpt-6-astra",
input: "Find the shipping ETA tool first, then use it for order_42.",
tools: [
{
type: "tool_search",
execution: "client",
description:
"Find the project-specific tools needed to continue the task.",
parameters: {
type: "object",
properties: {
goal: { type: "string" },
},
required: ["goal"],
additionalProperties: false,
},
},
],
parallel_tool_calls: false,
});
const searchCall = firstResponse.output.find(
(item) => item.type === "tool_search_call"
);
if (!searchCall) {
throw new Error("The response did not include a tool search call.");
}
const loadedTools = [
{
type: "function",
name: "get_shipping_eta",
description: "Look up shipping ETA details for an order.",
defer_loading: true,
parameters: {
type: "object",
properties: {
order_id: { type: "string" },
},
required: ["order_id"],
additionalProperties: false,
},
strict: true,
},
];
const searchOutput = {
type: "tool_search_output",
execution: "client",
call_id: searchCall.call_id,
status: "completed",
tools: loadedTools,
};
const secondResponse = await client.responses.create({
model: "gpt-6-astra",
input: [
...toResponseInputItems(firstResponse.output),
searchOutput,
],
});
console.log(secondResponse.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
61from openai import OpenAI
client = OpenAI()
first_response = client.responses.create(
model="gpt-6-astra",
input="Find the shipping ETA tool first, then use it for order_42.",
tools=[
{
"type": "tool_search",
"execution": "client",
"description": "Find the project-specific tools needed to continue the task.",
"parameters": {
"type": "object",
"properties": {
"goal": {"type": "string"},
},
"required": ["goal"],
"additionalProperties": False,
},
}
],
parallel_tool_calls=False,
)
search_call = next(
item for item in first_response.output if item.type == "tool_search_call"
)
loaded_tools = [
{
"type": "function",
"name": "get_shipping_eta",
"description": "Look up shipping ETA details for an order.",
"defer_loading": True,
"parameters": {
"type": "object",
"properties": {
"order_id": {"type": "string"},
},
"required": ["order_id"],
"additionalProperties": False,
},
}
]
second_response = client.responses.create(
model="gpt-6-astra",
input=[
*first_response.output,
{
"type": "tool_search_output",
"execution": "client",
"call_id": search_call.call_id,
"status": "completed",
"tools": loaded_tools,
},
],
)
print(second_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
61
62
63
64
65package main
import (
"context"
"fmt"
"github.com/openai/openai-go/v3"
"github.com/openai/openai-go/v3/responses"
)
func main() {
client := openai.NewClient()
searchTool := responses.ToolUnionParam{OfToolSearch: &responses.ToolSearchToolParam{
Execution: responses.ToolSearchToolExecutionClient,
Description: openai.String("Find the project-specific tools needed to continue the task."),
Parameters: map[string]any{
"type": "object",
"properties": map[string]any{"goal": map[string]any{"type": "string"}},
"required": []string{"goal"},
"additionalProperties": false,
},
}}
first, err := client.Responses.New(context.Background(), responses.ResponseNewParams{
Model: "gpt-6-astra",
Input: responses.ResponseNewParamsInputUnion{OfString: openai.String("Find the shipping ETA tool first, then use it for order_42.")},
Tools: []responses.ToolUnionParam{searchTool},
ParallelToolCalls: openai.Bool(false),
})
if err != nil {
panic(err)
}
callID := ""
for _, item := range first.Output {
if item.Type == "tool_search_call" {
callID = item.CallID
break
}
}
if callID == "" {
panic("the response did not include a tool search call")
}
loadedTool := responses.ToolParamOfFunction("get_shipping_eta", map[string]any{
"type": "object",
"properties": map[string]any{"order_id": map[string]any{"type": "string"}},
"required": []string{"order_id"},
"additionalProperties": false,
}, true)
loadedTool.OfFunction.Description = openai.String("Look up shipping ETA details for an order.")
loadedTool.OfFunction.DeferLoading = openai.Bool(true)
searchOutput := responses.ResponseInputItemParamOfToolSearchOutput([]responses.ToolUnionParam{loadedTool})
searchOutput.OfToolSearchOutput.CallID = openai.String(callID)
searchOutput.OfToolSearchOutput.Execution = responses.ResponseToolSearchOutputItemParamExecutionClient
searchOutput.OfToolSearchOutput.Status = responses.ResponseToolSearchOutputItemParamStatusCompleted
second, err := client.Responses.New(context.Background(), responses.ResponseNewParams{
Model: "gpt-6-astra",
PreviousResponseID: openai.String(first.ID),
Input: responses.ResponseNewParamsInputUnion{OfInputItemList: responses.ResponseInputParam{searchOutput}},
})
if err != nil {
panic(err)
}
fmt.Println(second.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
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81import com.openai.client.OpenAIClient;
import com.openai.client.okhttp.OpenAIOkHttpClient;
import com.openai.core.JsonValue;
import com.openai.models.responses.FunctionTool;
import com.openai.models.responses.ResponseCreateParams;
import com.openai.models.responses.ResponseInputItem;
import com.openai.models.responses.ResponseToolSearchOutputItemParam;
import com.openai.models.responses.ToolSearchTool;
import java.util.List;
import java.util.Map;
ResponseCreateParams searchRequest =
ResponseCreateParams.builder()
.model("gpt-6-astra")
.input("Find the shipping ETA tool, then use it for order_42.")
.parallelToolCalls(false)
.addTool(
ToolSearchTool.builder()
.execution(ToolSearchTool.Execution.CLIENT)
.description("Find the project tools needed to continue the task.")
.parameters(
JsonValue.from(
Map.of(
"type",
"object",
"properties",
Map.of("goal", Map.of("type", "string")),
"required",
List.of("goal"),
"additionalProperties",
false)))
.build())
.build();
var search = client.responses().create(searchRequest);
var searchCall =
search.output().stream()
.flatMap(item -> item.toolSearchCall().stream())
.findFirst()
.orElseThrow(() -> new IllegalStateException("No tool search call returned"));
FunctionTool shippingTool =
FunctionTool.builder()
.name("get_shipping_eta")
.description("Look up shipping details for an order.")
.deferLoading(true)
.strict(true)
.parameters(
FunctionTool.Parameters.builder()
.putAdditionalProperty("type", JsonValue.from("object"))
.putAdditionalProperty(
"properties", JsonValue.from(Map.of("order_id", Map.of("type", "string"))))
.putAdditionalProperty("required", JsonValue.from(List.of("order_id")))
.putAdditionalProperty("additionalProperties", JsonValue.from(false))
.build())
.build();
var searchOutput =
ResponseToolSearchOutputItemParam.builder()
.callId(searchCall.callId().orElseThrow())
.execution(ResponseToolSearchOutputItemParam.Execution.CLIENT)
.status(ResponseToolSearchOutputItemParam.Status.COMPLETED)
.addTool(shippingTool)
.build();
var response =
client
.responses()
.create(
ResponseCreateParams.builder()
.model("gpt-6-astra")
.previousResponseId(search.id())
.inputOfResponse(List.of(ResponseInputItem.ofToolSearchOutput(searchOutput)))
.build());
var loadedCalls =
response.output().stream().flatMap(item -> item.functionCall().stream()).toList();
if (loadedCalls.isEmpty()) {
throw new IllegalStateException("No loaded function call returned");
}
loadedCalls.forEach(call -> System.out.println(call.name() + "(" + call.arguments() + ")"));
1
2
3
4
5
6
7
8
9
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
64require "openai"
client = OpenAI::Client.new
search = client.responses.create(
model: "gpt-6-astra",
input: "Find the shipping ETA tool, then use it for order_42.",
parallel_tool_calls: false,
tools: [
{
type: :tool_search,
execution: :client,
description: "Find the project tools needed to continue the task.",
parameters: {
type: :object,
properties: { goal: { type: :string } },
required: ["goal"],
additionalProperties: false
}
}
]
)
call = search.output.find do |item|
item.is_a?(OpenAI::Models::Responses::ResponseToolSearchCall)
end
unless call.is_a?(OpenAI::Models::Responses::ResponseToolSearchCall)
raise "No tool search call returned"
end
response = client.responses.create(
model: "gpt-6-astra",
previous_response_id: search.id,
input: [
{
type: :tool_search_output,
call_id: call.call_id,
execution: :client,
status: :completed,
tools: [
{
type: :function,
name: "get_shipping_eta",
description: "Look up shipping details for an order.",
defer_loading: true,
strict: true,
parameters: {
type: :object,
properties: { order_id: { type: :string } },
required: ["order_id"],
additionalProperties: false
}
}
]
}
]
)
function_calls = response.output.grep(
OpenAI::Models::Responses::ResponseFunctionToolCall
)
raise "No loaded function call returned" if function_calls.empty?
function_calls.each do |function_call|
puts("#{function_call.name}(#{function_call.arguments})")
end
最初のターンでは、モデルは tool_search_call を出力したところで処理を停止します。
1
2
3
4
5
6
7
8
9
10
11[
{
"type": "tool_search_call",
"execution": "client",
"call_id": "call_abc123",
"status": "completed",
"arguments": {
"goal": "Find the shipping ETA tool for order_42."
}
}
]
続いてアプリケーションが検索を実行し、読み込みたいツールを含む tool_search_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[
{
"type": "tool_search_output",
"execution": "client",
"call_id": "call_abc123",
"status": "completed",
"tools": [
{
"type": "function",
"name": "get_shipping_eta",
"description": "Look up shipping ETA details for an order.",
"defer_loading": true,
"parameters": {
"type": "object",
"properties": {
"order_id": { "type": "string" }
},
"required": ["order_id"],
"additionalProperties": false
}
}
]
}
]
次のターンでは、読み込んだツールを通常の関数と同じように呼び出せます。
1
2
3
4
5
6
7
8
9[
{
"type": "function_call",
"name": "get_shipping_eta",
"namespace": "get_shipping_eta",
"call_id": "call_xyz456",
"arguments": "{\"order_id\":\"order_42\"}"
}
]
クライアントモードでは、execution は client に設定され、call_id が定義されます。tool_search_output には、tool_search_call の call_id と同じ値をそのまま含めて返してください。
名前空間の説明は、用途が明確に伝わるように記述してください。モデルはこの説明をもとに、その名前空間の一部の関数をいつ読み込むかを判断します。説明が長くなりすぎないようにし、詳しい情報は、必要なときだけ読み込まれる遅延読み込み対象の関数の説明に記述してください。
tool_search_output.tools には、モデルが動的に読み込んだツールのリストが含まれます。モデルは以降のターンでこれらのツールをすべて呼び出せるため、クライアントモードではターンごとに同じツールを読み込み直す必要はありません。この配列に含まれていないツールは、モデルから利用できません。読み込んだツールを無効にするには、読み込み済みツールの集合を定義している tool_search_output 項目からそのツールを削除します。ただし、読み込み済みツールの集合を変更すると、その位置以降のモデルのキャッシュが無効になる点に注意してください。
ほとんどの連携では、リクエストの tools パラメーターでツールを宣言します。クライアント実行型ツール検索では、元のリクエストに含まれていなかったツールをアプリケーションが返す、より高度なパターンにも対応しています。これは高度なワークフローとして扱い、返されるスキーマを慎重に検証したうえで、信頼できるツール定義だけをモデルに公開してください。
すべてのツールは、モデルのコンテキストウィンドウの末尾に読み込まれます。これはホスト型ツール検索でもクライアント実行型ツール検索でも同じです。これにより、リクエスト間でモデルのキャッシュを維持でき、全体のコスト削減と高速化につながります。
高度なワークフローでは、additional_tools 入力項目を使って、会話の特定の位置でツールを利用可能にできます。アプリケーションが通常のツール検索フロー以外でツールを読み込む場合や、以前のレスポンス中に追加されたツールの順序を維持する必要がある場合に便利です。
role を developer に設定し、追加するツールをそのアイテムの tools 配列に含めます。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19{
"type": "additional_tools",
"role": "developer",
"tools": [
{
"type": "function",
"name": "get_customer",
"description": "Look up a customer by ID.",
"parameters": {
"type": "object",
"properties": {
"customer_id": { "type": "string" }
},
"required": ["customer_id"],
"additionalProperties": false
}
}
]
}
additional_tools アイテムに含まれるツールは、そのアイテムが入力に現れた後でのみ利用可能になります。会話アイテムを手動で次のリクエストに引き継ぐ場合は、モデルが会話の同じ時点で同じツールを参照できるように、そのアイテムの位置を維持してください。
Agents API は、デフォルトでは関数定義を最初に読み込みます。特定の関数を遅延読み込みの対象にするには、agent.tools に { "type": "tool_search" } を追加し、エージェントが必要に応じて検索できるようにする各関数に defer_loading: true を設定します。tool_search を追加するだけでは、すべての関数が遅延読み込みの対象になるわけではありません。
セッションのリクエストには、引き続き名前、説明、引数のスキーマを含む完全な関数定義を指定します。ツール検索によって変わるのは、その定義がモデルに渡されるタイミングです。関数が見つかった後は、通常どおりアプリケーションが関数呼び出しを処理し、結果を返します。結果の処理については、関数を参照してください。
この例を実行する前に、OPENAI_API_KEY を設定してください。
1
2
3
4
5
6
7
8
9
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
44import OpenAI from "openai";
const client = new OpenAI();
const result = await client.beta.agents.sessions.create({
agent: {
model: "gpt-6-astra",
tools: [
{
type: "tool_search",
},
{
type: "function",
name: "lookup_account",
description: "Find an account by its account number.",
parameters: {
type: "object",
properties: {
account_id: {
type: "string",
},
},
required: ["account_id"],
additionalProperties: false,
},
defer_loading: true,
},
],
},
environment: {
type: "none",
},
input: [
{
role: "user",
content: [
{
type: "input_text",
text: "Look up account 42.",
},
],
},
],
});
console.log(result.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
29
30
31
32from openai import OpenAI
client = OpenAI()
result = client.beta.agents.sessions.create(
agent={
"model": "gpt-6-astra",
"tools": [
{"type": "tool_search"},
{
"type": "function",
"name": "lookup_account",
"description": "Find an account by its account number.",
"parameters": {
"type": "object",
"properties": {"account_id": {"type": "string"}},
"required": ["account_id"],
"additionalProperties": False,
},
"defer_loading": True,
},
],
},
environment={"type": "none"},
input=[
{
"role": "user",
"content": [{"type": "input_text", "text": "Look up account 42."}],
}
],
)
print(result.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
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45import (
"context"
"fmt"
"github.com/openai/openai-go/v3"
)
ctx := context.Background()
client := openai.NewClient()
result, err := client.Beta.Agents.Sessions.New(ctx,
openai.BetaAgentSessionNewParams{
Agent: openai.BetaAgentSessionNewParamsAgent{
Model: openai.String("gpt-6-astra"),
Tools: []openai.AgentToolParamUnion{
{OfParamToolSearch: &openai.AgentToolParamToolSearch{}},
{
OfParamFunction: &openai.AgentToolParamFunction{
Name: "lookup_account",
Description: "Find an account by its account number.",
Parameters: map[string]any{
"type": "object",
"properties": map[string]any{"account_id": map[string]any{"type": "string"}},
"required": []any{"account_id"},
"additionalProperties": false,
},
DeferLoading: openai.Bool(true),
},
},
},
},
Environment: openai.EnvironmentParamUnion{OfParamNone: &openai.EnvironmentParamNone{}},
Input: openai.BetaAgentSessionNewParamsInputUnion{
OfArrayOfInputMessages: []openai.AgentSessionInputMessageParam{
{
Content: []openai.InputContentParamUnion{
{OfParamInputText: &openai.InputContentParamInputText{Text: "Look up account 42."}},
},
},
},
},
})
if err != nil {
panic(err)
}
fmt.Println(result.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
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43import com.openai.client.OpenAIClient;
import com.openai.client.okhttp.OpenAIOkHttpClient;
import com.openai.core.JsonValue;
import com.openai.models.beta.agents.AgentToolParam;
import com.openai.models.beta.agents.sessions.SessionCreateParams;
import java.util.List;
import java.util.Map;
OpenAIClient client = OpenAIOkHttpClient.fromEnv();
var result =
client
.beta()
.agents()
.sessions()
.create(
SessionCreateParams.builder()
.agent(
SessionCreateParams.Agent.builder()
.model("gpt-6-astra")
.addToolToolSearch()
.addTool(
AgentToolParam.Function.builder()
.name("lookup_account")
.description("Find an account by its account number.")
.parameters(
AgentToolParam.Function.Parameters.builder()
.putAdditionalProperty("type", JsonValue.from("object"))
.putAdditionalProperty(
"properties",
JsonValue.from(
Map.of("account_id", Map.of("type", "string"))))
.putAdditionalProperty(
"required", JsonValue.from(List.of("account_id")))
.putAdditionalProperty(
"additionalProperties", JsonValue.from(false))
.build())
.deferLoading(true)
.build())
.build())
.environmentNone()
.input("Look up account 42.")
.build());
System.out.println(result.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
29
30
31
32
33
34
35
36require "openai"
client = OpenAI::Client.new
result = client.beta.agents.sessions.create(
agent: {
model: "gpt-6-astra",
tools: [
{ type: "tool_search" },
{
type: "function",
name: "lookup_account",
description: "Find an account by its account number.",
parameters: {
type: "object",
properties: { account_id: { type: "string" } },
required: ["account_id"],
additionalProperties: false
},
defer_loading: true
}
]
},
environment: { type: "none" },
input: [
{
role: "user",
content: [
{
type: "input_text",
text: "Look up account 42."
}
]
}
]
)
puts result.id
| 方式 | 構成 | 適した用途 | トレードオフ |
|---|
| 即時読み込み | defer_loading を省略するか、false に設定します。 | 関数が少数の場合や、ほとんどのタスクで必要になる関数 | 使わない定義もコンテキストを占有します。定義を変更すると、キャッシュされたプレフィックスが無効になる場合があります。 |
| 遅延読み込み | defer_loading: true を設定し、tool_search を追加します。 | 多数の関数があり、各タスクで必要になるのはそのうち数個だけの場合 | ツールを検索するステップが増え、適切なツールを見つけられることが前提になります。 |
Agents API のセッションでは、即時読み込みと遅延読み込みの関数を混在させることができますが、通常は推奨されません。遅延読み込みの対象となる関数には、明確な名前と説明を付けてください。デフォルトの方式を選ぶ前に、代表的なリクエストでタスクの完了状況、入力トークン使用量、レイテンシを比較してください。
Agents API では、モデルとプロバイダーがツール検索をサポートしている場合、MCP ツールの自動検出が使用されます。ランタイムは MCP ツールを遅延読み込みの対象とし、検索可能な遅延読み込み対象のツールがある場合にツール検索を追加します。これは、リモート MCP、エグゼキューター MCP、プラグインが提供する MCP ツールに適用されます。
MCP ツールのためだけに { "type": "tool_search" } を追加したり、MCP サーバーに関数レベルの defer_loading フラグを設定したりする必要はありません。MCP 接続を使用してサーバーを構成してください。このガイドの前半で説明した Responses API の構成は、Agents API の MCP サーバーには適用されません。