工具搜索(Tool search)允许模型根据需要动态搜索并加载工具到上下文窗口中。这使您可以避免在前期将所有工具定义加载到模型上下文中,并有助于减少总体 Token 使用量和成本。为了实现最佳的成本和延迟表现,工具搜索旨在保留模型的缓存。当模型发现新工具时,这些工具会被注入到上下文窗口的末尾。
gpt-5.4 及更高版本的模型支持 tool_search。要激活工具搜索,您必须执行两项操作:
- 在您的
tools数组中添加tool_search作为工具。 - 如果您正在使用 函数,请将想要延迟加载的函数标记为
defer_loading: true。如果您正在使用 MCP 服务器,请在 MCP 服务器的工具定义中设置defer_loading: true。
尽可能使用命名空间(Namespaces)
您可以将工具搜索与延迟加载的 函数、命名空间 或 MCP 服务器 配合使用,但我们建议尽可能使用命名空间或 MCP 服务器。我们的模型经过训练,主要针对这些载体进行搜索,且通常能在此处获得更显著的 Token 节省。
对于命名空间,defer_loading 适用于命名空间内的函数,而不适用于命名空间对象本身。
在请求开始时,模型仍然能看到可搜索内容的名称和描述。对于命名空间或 MCP 服务器,这意味着模型在开始时仅能看到命名空间或服务器的名称和描述,直到工具搜索工具将其加载,才会展示其中包含的具体函数详情。对于单个延迟加载的函数,模型仍然可以看到函数名称和描述,因此实际上工具搜索主要延迟的是参数模式(parameter schema)。
为了最大限度地节省 Token,我们建议将延迟加载的函数归类到具有清晰、高层级描述的命名空间或 MCP 服务器中。这些描述应为模型提供其中所含内容的明确概览,以便其能高效搜索并仅加载相关函数。作为最佳实践,建议将每个命名空间内的函数保持在 10 个以内,以获得更好的 Token 效率和模型性能。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
{
"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 的工具可立即调用,而同一命名空间中的延迟工具则通过工具搜索加载。
工具搜索类型
有两种使用工具搜索的方法:
- 托管式工具搜索 (Hosted tool search): OpenAI 会在您在请求中声明的延迟工具范围内进行搜索,并在同一响应中返回已加载的子集。
- 客户端执行工具搜索 (Client-executed tool search): 模型发出一个
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
47
48
49
50
from 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-5.5",
input="List open orders for customer CUST-12345.",
tools=[
crm_namespace,
{"type": "tool_search"},
],
parallel_tool_calls=False,
)
print(response.output)如果模型决定需要某个延迟工具,响应中会在最终函数调用前包含两个额外的输出项:
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 服务器。例如,如果它需要来自不同命名空间的函数来完成一项任务,它可能会选择在进行后续函数调用之前,将这些内容一并搜索并加载。
客户端执行工具搜索
客户端执行工具搜索使您的应用程序能够完全控制工具发现的工作方式。当可用的工具依赖于在初始 tools 列表中声明不便的信息时,这种方式非常有用。
将 tool_search 工具配置为 execution: "client",并为您应用程序预期的搜索参数提供架构(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
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
client = OpenAI()
first_response = client.responses.create(
model="gpt-5.5",
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-5.5",
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)在第一轮对话中,模型发出一个 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 参数中声明工具。客户端执行工具搜索还支持更高级的模式,即您的应用程序返回原始请求中不存在的工具。请将其视为高级工作流:仔细验证返回的架构,并仅暴露受信任的工具定义。
工具搜索与缓存
所有工具均在模型上下文窗口的末尾加载。这对于托管式工具搜索和客户端执行工具搜索均适用。这使得模型的缓存可以从一个请求保留到另一个请求,从而降低总体成本并提高速度。