English ← MyDocs

Tool search tool


Tool search tool 使 Claude 能够通过动态发现和按需加载来处理数百或数千个工具。Claude 不是将所有工具定义预先加载到上下文窗口中,而是搜索你的工具目录(包括工具名称、描述、参数名称和参数描述),并只加载需要的工具。

这种方法解决了随着工具库扩展而快速复合的两个问题:

  • 上下文膨胀: 工具定义会快速消耗你的上下文预算。典型的多服务器设置(GitHub、Slack、Sentry、Grafana、Splunk)在 Claude 做任何实际工作之前就可以在定义中消耗约 55k 个 token。Tool search 通常将此减少 85% 以上,只加载 Claude 在给定请求中实际需要的 3-5 个工具。
  • 工具选择准确性: 一旦你超过 30-50 个可用工具,Claude 正确选择正确工具的能力会显著下降。通过按需呈现一组集中的相关工具,tool search 即使在数千个工具中也能保持高选择准确性。
Tip

有关 tool search 解决的扩展挑战的背景,请参见高级工具使用。Tool search 的按需加载也是有效的上下文工程中描述的更广泛即时检索原则的一个实例。

虽然这是作为服务器端工具提供的,但你也可以实现自己的客户端 tool search 功能。详情参见自定义 tool search 实现

Note

通过反馈表分享对此功能的反馈。

Note

此功能符合零数据留存 (ZDR) 条件。当你的组织有 ZDR 安排时,通过此功能发送的数据在 API 响应返回后不会被存储。

Warning

在 Amazon Bedrock 上,服务器端 tool search 仅通过 InvokeModel API 可用,不支持 Converse API。

Note

AWS 上的 Claude Platform 上,服务器端 tool search 与 Claude API 的工作方式相同。AWS 上的 Claude Platform 直接使用 Anthropic Messages API,因此没有 InvokeModel 或 Converse 的区别。

Tool search 的工作原理

有两种 tool search 变体:

  • Regextool_search_tool_regex_20251119):Claude 构造正则表达式模式来搜索工具
  • BM25tool_search_tool_bm25_20251119):Claude 使用自然语言查询来搜索工具

当你启用 tool search tool 时:

  1. 你在工具列表中包含一个 tool search tool(例如 tool_search_tool_regex_20251119tool_search_tool_bm25_20251119)。
  2. 你为不应立即加载的工具提供 defer_loading: true 的工具定义。
  3. Claude 最初只看到 tool search tool 和任何非延迟的工具。
  4. 当 Claude 需要额外工具时,它使用 tool search tool 进行搜索。
  5. API 返回 3-5 个最相关的 tool_reference 块。
  6. 这些引用自动展开为完整的工具定义。
  7. Claude 从发现的工具中选择并调用它们。

这使你的上下文窗口保持高效,同时保持高工具选择准确性。

快速开始

这是一个使用延迟工具的简单示例:

curl https://api.anthropic.com/v1/messages \
    --header "x-api-key: $ANTHROPIC_API_KEY" \
    --header "anthropic-version: 2023-06-01" \
    --header "content-type: application/json" \
    --data '{
        "model": "claude-opus-4-7",
        "max_tokens": 2048,
        "messages": [
            {
                "role": "user",
                "content": "What is the weather in San Francisco?"
            }
        ],
        "tools": [
            {
                "type": "tool_search_tool_regex_20251119",
                "name": "tool_search_tool_regex"
            },
            {
                "name": "get_weather",
                "description": "Get the weather at a specific location",
                "input_schema": {
                    "type": "object",
                    "properties": {
                        "location": {"type": "string"},
                        "unit": {
                            "type": "string",
                            "enum": ["celsius", "fahrenheit"]
                        }
                    },
                    "required": ["location"]
                },
                "defer_loading": true
            },
            {
                "name": "search_files",
                "description": "Search through files in the workspace",
                "input_schema": {
                    "type": "object",
                    "properties": {
                        "query": {"type": "string"},
                        "file_types": {
                            "type": "array",
                            "items": {"type": "string"}
                        }
                    },
                    "required": ["query"]
                },
                "defer_loading": true
            }
        ]
    }'
ant messages create <<'YAML'
model: claude-opus-4-7
max_tokens: 2048
messages:
  - role: user
    content: What is the weather in San Francisco?
tools:
  - type: tool_search_tool_regex_20251119
    name: tool_search_tool_regex
  - name: get_weather
    description: Get the weather at a specific location
    input_schema:
      type: object
      properties:
        location:
          type: string
        unit:
          type: string
          enum: [celsius, fahrenheit]
      required: [location]
    defer_loading: true
  - name: search_files
    description: Search through files in the workspace
    input_schema:
      type: object
      properties:
        query:
          type: string
        file_types:
          type: array
          items:
            type: string
      required: [query]
    defer_loading: true
YAML
import anthropic

client = anthropic.Anthropic()

response = client.messages.create(
    model="claude-opus-4-7",
    max_tokens=2048,
    messages=[{"role": "user", "content": "What is the weather in San Francisco?"}],
    tools=[
        {"type": "tool_search_tool_regex_20251119", "name": "tool_search_tool_regex"},
        {
            "name": "get_weather",
            "description": "Get the weather at a specific location",
            "input_schema": {
                "type": "object",
                "properties": {
                    "location": {"type": "string"},
                    "unit": {"type": "string", "enum": ["celsius", "fahrenheit"]},
                },
                "required": ["location"],
            },
            "defer_loading": True,
        },
        {
            "name": "search_files",
            "description": "Search through files in the workspace",
            "input_schema": {
                "type": "object",
                "properties": {
                    "query": {"type": "string"},
                    "file_types": {"type": "array", "items": {"type": "string"}},
                },
                "required": ["query"],
            },
            "defer_loading": True,
        },
    ],
)

print(response)
import Anthropic from "@anthropic-ai/sdk";

const client = new Anthropic();

const response = await client.messages.create({
  model: "claude-opus-4-7",
  max_tokens: 2048,
  messages: [
    {
      role: "user",
      content: "What is the weather in San Francisco?"
    }
  ],
  tools: [
    {
      type: "tool_search_tool_regex_20251119",
      name: "tool_search_tool_regex"
    },
    {
      name: "get_weather",
      description: "Get the weather at a specific location",
      input_schema: {
        type: "object" as const,
        properties: {
          location: { type: "string" },
          unit: {
            type: "string",
            enum: ["celsius", "fahrenheit"]
          }
        },
        required: ["location"]
      },
      defer_loading: true
    },
    {
      name: "search_files",
      description: "Search through files in the workspace",
      input_schema: {
        type: "object" as const,
        properties: {
          query: { type: "string" },
          file_types: {
            type: "array",
            items: { type: "string" }
          }
        },
        required: ["query"]
      },
      defer_loading: true
    }
  ]
});

console.log(response);
using System;
using System.Text.Json;
using Anthropic;
using Anthropic.Models.Messages;

AnthropicClient client = new();

var parameters = new MessageCreateParams
{
    Model = Model.ClaudeOpus4_7,
    MaxTokens = 2048,
    Messages = [
        new() {
            Role = Role.User,
            Content = "What is the weather in San Francisco?"
        }
    ],
    Tools = [
        new ToolUnion(new ToolSearchToolRegex20251119
        {
            Type = ToolSearchToolRegex20251119Type.ToolSearchToolRegex20251119
        }),
        new ToolUnion(new Tool()
        {
            Name = "get_weather",
            Description = "Get the weather at a specific location",
            InputSchema = new InputSchema()
            {
                Properties = new Dictionary<string, JsonElement>
                {
                    ["location"] = JsonSerializer.SerializeToElement(new { type = "string" }),
                    ["unit"] = JsonSerializer.SerializeToElement(new { type = "string", @enum = new[] { "celsius", "fahrenheit" } }),
                },
                Required = ["location"],
            },
            DeferLoading = true,
        }),
        new ToolUnion(new Tool()
        {
            Name = "search_files",
            Description = "Search through files in the workspace",
            InputSchema = new InputSchema()
            {
                Properties = new Dictionary<string, JsonElement>
                {
                    ["query"] = JsonSerializer.SerializeToElement(new { type = "string" }),
                    ["file_types"] = JsonSerializer.SerializeToElement(new { type = "array", items = new { type = "string" } }),
                },
                Required = ["query"],
            },
            DeferLoading = true,
        }),
    ]
};

var message = await client.Messages.Create(parameters);
Console.WriteLine(message);
package main

import (
	"context"
	"fmt"
	"log"

	"github.com/anthropics/anthropic-sdk-go"
)

func main() {
	client := anthropic.NewClient()

	response, err := client.Messages.New(context.TODO(), anthropic.MessageNewParams{
		Model:     anthropic.ModelClaudeOpus4_7,
		MaxTokens: 2048,
		Messages: []anthropic.MessageParam{
			anthropic.NewUserMessage(anthropic.NewTextBlock("What is the weather in San Francisco?")),
		},
		Tools: []anthropic.ToolUnionParam{
			{OfToolSearchToolRegex20251119: &anthropic.ToolSearchToolRegex20251119Param{
				Type: anthropic.ToolSearchToolRegex20251119TypeToolSearchToolRegex20251119,
			}},
			{OfTool: &anthropic.ToolParam{
				Name:        "get_weather",
				Description: anthropic.String("Get the weather at a specific location"),
				InputSchema: anthropic.ToolInputSchemaParam{
					Properties: map[string]any{
						"location": map[string]any{"type": "string"},
						"unit": map[string]any{
							"type": "string",
							"enum": []string{"celsius", "fahrenheit"},
						},
					},
					Required: []string{"location"},
				},
				DeferLoading: anthropic.Bool(true),
			}},
			{OfTool: &anthropic.ToolParam{
				Name:        "search_files",
				Description: anthropic.String("Search through files in the workspace"),
				InputSchema: anthropic.ToolInputSchemaParam{
					Properties: map[string]any{
						"query":      map[string]any{"type": "string"},
						"file_types": map[string]any{"type": "array", "items": map[string]any{"type": "string"}},
					},
					Required: []string{"query"},
				},
				DeferLoading: anthropic.Bool(true),
			}},
		},
	})
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println(response)
}
import com.anthropic.client.AnthropicClient;
import com.anthropic.client.okhttp.AnthropicOkHttpClient;
import com.anthropic.core.JsonValue;
import com.anthropic.models.messages.Message;
import com.anthropic.models.messages.MessageCreateParams;
import com.anthropic.models.messages.Model;
import com.anthropic.models.messages.Tool;
import com.anthropic.models.messages.Tool.InputSchema;
import com.anthropic.models.messages.ToolSearchToolRegex20251119;

void main() {
    AnthropicClient client = AnthropicOkHttpClient.fromEnv();

    InputSchema weatherSchema = InputSchema.builder()
        .properties(JsonValue.from(Map.of(
            "location", Map.of("type", "string"),
            "unit", Map.of(
                "type", "string",
                "enum", List.of("celsius", "fahrenheit")
            )
        )))
        .putAdditionalProperty("required", JsonValue.from(List.of("location")))
        .build();

    InputSchema searchSchema = InputSchema.builder()
        .properties(JsonValue.from(Map.of(
            "query", Map.of("type", "string"),
            "file_types", Map.of(
                "type", "array",
                "items", Map.of("type", "string")
            )
        )))
        .putAdditionalProperty("required", JsonValue.from(List.of("query")))
        .build();

    MessageCreateParams params = MessageCreateParams.builder()
        .model(Model.CLAUDE_OPUS_4_7)
        .maxTokens(2048L)
        .addUserMessage("What is the weather in San Francisco?")
        .addTool(ToolSearchToolRegex20251119.builder()
            .type(ToolSearchToolRegex20251119.Type.TOOL_SEARCH_TOOL_REGEX_20251119)
            .build())
        .addTool(Tool.builder()
            .name("get_weather")
            .description("Get the weather at a specific location")
            .inputSchema(weatherSchema)
            .deferLoading(true)
            .build())
        .addTool(Tool.builder()
            .name("search_files")
            .description("Search through files in the workspace")
            .inputSchema(searchSchema)
            .deferLoading(true)
            .build())
        .build();

    Message response = client.messages().create(params);
    IO.println(response);
}
<?php

use Anthropic\Client;

$client = new Client(apiKey: getenv("ANTHROPIC_API_KEY"));

$message = $client->messages->create(
    maxTokens: 2048,
    messages: [
        ['role' => 'user', 'content' => 'What is the weather in San Francisco?'],
    ],
    model: 'claude-opus-4-7',
    tools: [
        [
            'type' => 'tool_search_tool_regex_20251119',
            'name' => 'tool_search_tool_regex',
        ],
        [
            'name' => 'get_weather',
            'description' => 'Get the weather at a specific location',
            'input_schema' => [
                'type' => 'object',
                'properties' => [
                    'location' => ['type' => 'string'],
                    'unit' => [
                        'type' => 'string',
                        'enum' => ['celsius', 'fahrenheit'],
                    ],
                ],
                'required' => ['location'],
            ],
            'defer_loading' => true,
        ],
        [
            'name' => 'search_files',
            'description' => 'Search through files in the workspace',
            'input_schema' => [
                'type' => 'object',
                'properties' => [
                    'query' => ['type' => 'string'],
                    'file_types' => [
                        'type' => 'array',
                        'items' => ['type' => 'string'],
                    ],
                ],
                'required' => ['query'],
            ],
            'defer_loading' => true,
        ],
    ],
);

echo $message;
require "anthropic"

client = Anthropic::Client.new

message = client.messages.create(
  model: "claude-opus-4-7",
  max_tokens: 2048,
  messages: [
    { role: "user", content: "What is the weather in San Francisco?" }
  ],
  tools: [
    {
      type: "tool_search_tool_regex_20251119",
      name: "tool_search_tool_regex"
    },
    {
      name: "get_weather",
      description: "Get the weather at a specific location",
      input_schema: {
        type: "object",
        properties: {
          location: { type: "string" },
          unit: {
            type: "string",
            enum: ["celsius", "fahrenheit"]
          }
        },
        required: ["location"]
      },
      defer_loading: true
    },
    {
      name: "search_files",
      description: "Search through files in the workspace",
      input_schema: {
        type: "object",
        properties: {
          query: { type: "string" },
          file_types: {
            type: "array",
            items: { type: "string" }
          }
        },
        required: ["query"]
      },
      defer_loading: true
    }
  ]
)

puts message

工具定义

Tool search tool 有两个变体:

{
  "type": "tool_search_tool_regex_20251119",
  "name": "tool_search_tool_regex"
}
{
  "type": "tool_search_tool_bm25_20251119",
  "name": "tool_search_tool_bm25"
}
Warning

Regex 变体查询格式:Python 正则表达式,不是自然语言

使用 tool_search_tool_regex_20251119 时,Claude 使用 Python 的 re.search() 语法构造正则表达式模式,而不是自然语言查询。常见模式:

  • "weather" - 匹配包含 "weather" 的工具名称/描述
  • "get_.*_data" - 匹配如 get_user_dataget_weather_data 的工具
  • "database.*query|query.*database" - 用于灵活性的 OR 模式
  • "(?i)slack" - 不区分大小写搜索

最大查询长度:200 个字符

Note

BM25 变体查询格式:自然语言

使用 tool_search_tool_bm25_20251119 时,Claude 使用自然语言查询来搜索工具。

延迟工具加载

通过添加 defer_loading: true 标记工具为按需加载:

{
  "name": "get_weather",
  "description": "Get current weather for a location",
  "input_schema": {
    "type": "object",
    "properties": {
      "location": { "type": "string" },
      "unit": { "type": "string", "enum": ["celsius", "fahrenheit"] }
    },
    "required": ["location"]
  },
  "defer_loading": true
}

关键点:

  • 没有 defer_loading 的工具立即加载到上下文中
  • defer_loading: true 的工具仅在 Claude 通过搜索发现时加载
  • Tool search tool 本身永远不应有 defer_loading: true
  • 保持你最常用的 3-5 个工具为非延迟以获得最佳性能

两种 tool search 变体(regexbm25)都搜索工具名称、描述、参数名称和参数描述。

延迟的工作原理: 延迟工具不包含在系统提示前缀中。当模型通过 tool search 发现延迟工具时,API 在对话中内联追加一个 tool_reference 块,然后在传递给 Claude 之前将其展开为完整的工具定义。前缀未被修改,因此 prompt caching 得以保留。Strict mode 的语法(约束工具调用输出以匹配你的 schema 的规则)从完整工具集构建,因此 defer_loading 和 strict mode 可以组合使用而无需语法重编译。

响应格式

当 Claude 使用 tool search tool 时,响应包含新的块类型:

{
  "role": "assistant",
  "content": [
    {
      "type": "text",
      "text": "I'll search for tools to help with the weather information."
    },
    {
      "type": "server_tool_use",
      "id": "srvtoolu_01ABC123",
      "name": "tool_search_tool_regex",
      "input": {
        "query": "weather"
      }
    },
    {
      "type": "tool_search_tool_result",
      "tool_use_id": "srvtoolu_01ABC123",
      "content": {
        "type": "tool_search_tool_search_result",
        "tool_references": [{ "type": "tool_reference", "tool_name": "get_weather" }]
      }
    },
    {
      "type": "text",
      "text": "I found a weather tool. Let me get the weather for San Francisco."
    },
    {
      "type": "tool_use",
      "id": "toolu_01XYZ789",
      "name": "get_weather",
      "input": { "location": "San Francisco", "unit": "fahrenheit" }
    }
  ],
  "stop_reason": "tool_use"
}

理解响应

  • server_tool_use 表示 Claude 正在调用 tool search tool
  • tool_search_tool_result 包含搜索结果,嵌套有 tool_search_tool_search_result 对象
  • tool_references 指向发现工具的 tool_reference 对象数组
  • tool_use Claude 调用发现的工具

tool_reference 块在显示给 Claude 之前自动展开为完整的工具定义。你不需要自己处理此展开。只要你提供所有匹配的工具定义在 tools 参数中,它就会在 API 中自动发生。

MCP 集成

有关配置 mcp_toolsetdefer_loading,请参见 MCP connector

自定义 tool search 实现

你可以通过从自定义工具返回 tool_reference 块来实现自己的 tool search 逻辑(例如使用嵌入或语义搜索)。当 Claude 调用你的自定义搜索工具时,返回一个标准 tool_result,内容数组中包含 tool_reference 块:

{
  "type": "tool_result",
  "tool_use_id": "toolu_your_tool_id",
  "content": [{ "type": "tool_reference", "tool_name": "discovered_tool_name" }]
}

每个被引用的工具必须在顶层 tools 参数中有对应的工具定义,并设置 defer_loading: true。这种方法让你可以使用更复杂的搜索算法,同时保持与 tool search 系统的兼容性。

Note

响应格式部分展示的 tool_search_tool_result 格式是 Anthropic 内置 tool search 内部使用的服务端格式。对于自定义客户端实现,请始终使用前面示例中展示的标准 tool_result 格式和 tool_reference 内容块。

有关使用嵌入的完整示例,请参见使用嵌入的 tool search cookbook

错误处理

Note

Tool search tool 与工具使用示例不兼容。如果你需要提供工具使用示例,请使用不带 tool search 的标准工具调用。

HTTP 错误(400 状态)

这些错误阻止请求被处理:

所有工具被延迟:

{
  "type": "error",
  "error": {
    "type": "invalid_request_error",
    "message": "All tools have defer_loading set. At least one tool must be non-deferred."
  }
}

缺少工具定义:

{
  "type": "error",
  "error": {
    "type": "invalid_request_error",
    "message": "Tool reference 'unknown_tool' has no corresponding tool definition"
  }
}

工具结果错误(200 状态)

工具执行期间的错误返回 200 响应,错误信息在响应体中:

{
  "type": "tool_search_tool_result",
  "tool_use_id": "srvtoolu_01ABC123",
  "content": {
    "type": "tool_search_tool_result_error",
    "error_code": "invalid_pattern"
  }
}

错误码:

  • too_many_requests:tool search 操作超出速率限制
  • invalid_pattern:格式错误的正则表达式模式
  • pattern_too_long:模式超出 200 字符限制
  • unavailable:tool search 服务暂时不可用

常见错误

400 错误:所有工具被延迟

原因: 你在所有工具(包括搜索工具)上设置了 defer_loading: true

修复: 从 tool search tool 移除 defer_loading

{
  "type": "tool_search_tool_regex_20251119",
  "name": "tool_search_tool_regex"
}

400 错误:缺少工具定义

原因: tool_reference 指向不在你 tools 数组中的工具

修复: 确保每个可能被发现的工具都有完整定义:

{
  "name": "my_tool",
  "description": "Full description here",
  "input_schema": {
    "type": "object"
  },
  "defer_loading": true
}

Claude 找不到预期的工具

原因: 工具名称、描述、参数名称或参数描述与正则表达式模式不匹配

调试步骤:

  1. 检查工具名称、描述、参数名称和参数描述。Claude 搜索所有这些字段。
  2. 测试你的模式:import re; re.search(r"your_pattern", "tool_name")
  3. 记住搜索默认区分大小写(使用 (?i) 进行不区分大小写搜索)。
  4. Claude 使用宽泛模式如 ".*weather.*" 而非精确匹配。

提示: 在工具描述中添加常见关键词以提高可发现性

Prompt caching

有关 defer_loading 如何保留 prompt caching,请参见工具使用与 prompt caching

系统自动在整个对话历史中展开 tool_reference 块,因此 Claude 可以在后续轮次中复用发现的工具而无需重新搜索。

流式传输

启用流式传输后,你将作为流的一部分接收 tool search 事件:

event: content_block_start
data: {"type": "content_block_start", "index": 1, "content_block": {"type": "server_tool_use", "id": "srvtoolu_xyz789", "name": "tool_search_tool_regex"}}

// 搜索查询流式传输
event: content_block_delta
data: {"type": "content_block_delta", "index": 1, "delta": {"type": "input_json_delta", "partial_json": "{\"query\":\"weather\"}"}}

// 搜索执行期间暂停

// 搜索结果流式传输
event: content_block_start
data: {"type": "content_block_start", "index": 2, "content_block": {"type": "tool_search_tool_result", "tool_use_id": "srvtoolu_xyz789", "content": {"type": "tool_search_tool_search_result", "tool_references": [{"type": "tool_reference", "tool_name": "get_weather"}]}}}

// Claude 使用发现的工具继续

批量请求

你可以在 Messages Batches API 中包含 tool search tool。通过 Messages Batches API 的 tool search 操作与常规 Messages API 请求中的定价相同。

限制和最佳实践

限制

  • 最大工具数: 你的目录中最多 10,000 个工具
  • 搜索结果: 每次搜索返回 3-5 个最相关的工具
  • 模式长度: 正则表达式模式最大 200 个字符
  • 模型支持: Claude Mythos Preview、Sonnet 4.0+、Opus 4.0+、Haiku 4.5+

好的使用场景:

  • 你的系统中有 10+ 个可用工具
  • 工具定义消耗 >10k 个 token
  • 大型工具集遇到工具选择准确性问题
  • 构建具有多个服务器(200+ 个工具)的 MCP 驱动系统
  • 工具库随时间增长

传统工具调用可能更好的场景:

  • 总共少于 10 个工具
  • 所有工具在每个请求中频繁使用
  • 非常小的工具定义(总共 <100 个 token)

优化提示

  • 保持 3-5 个最常用的工具为非延迟
  • 编写清晰、描述性的工具名称和描述
  • 在工具名称中使用一致的命名空间:按服务或资源加前缀(例如 github_slack_),以便搜索查询自然地呈现正确的工具组
  • 在描述中使用与用户描述任务方式匹配的语义关键词
  • 添加描述可用工具类别的系统提示部分:"You can search for tools to interact with Slack, GitHub, and Jira"
  • 监控 Claude 发现的工具以优化描述

使用量

Tool search tool 使用量在响应使用量对象中跟踪:

{
  "usage": {
    "input_tokens": 1024,
    "output_tokens": 256,
    "server_tool_use": {
      "tool_search_requests": 2
    }
  }
}

下一步