Claude Media
Tool Search Toolのregex版とBM25版はクエリの書き方が全く違う

Tool Search Toolのregex版とBM25版はクエリの書き方が全く違う

Tool Search Toolのregex版はPython正規表現(200字上限)、BM25版は自然文(500字上限)でクエリを書きます。defer_loadingの仕様も含めて実装差を扱います。

このTipsでできること

Advanced Tool Useの3機能の1つに、Anthropic APIのTool Search Toolがあります。変種はtool_search_tool_regex_20251119とtool_search_tool_bm25_20251119の2つです。Claudeが書くクエリの形式がまったく違い、regex版はPythonの正規表現、BM25版は自然文です。

どちらをtools配列に入れるか、defer_loadingで何が変わるのか、400エラーになる書き方、MCPサーバー単位での遅延読み込みまで、実装で迷う順に取り上げます。

regex版とBM25版 — クエリの書式が違う2つの変種

Tool Search Toolは、数百から数千のツールをカタログとして持たせ、Claudeが必要なツールだけをその場で発見して読み込む仕組みです。ツール名・説明・引数名・引数の説明が検索対象で、これはどちらの変種でも同じです。マッチングはどちらも大文字小文字を区別しません。

変種typeの値クエリの書式上限
regex版typeの値tool_search_tool_regex_20251119クエリの書式Pythonのre.search()パターン上限200字
BM25版typeの値tool_search_tool_bm25_20251119クエリの書式自然文上限500字
{ "type": "tool_search_tool_regex_20251119", "name": "tool_search_tool_regex" }
{ "type": "tool_search_tool_bm25_20251119", "name": "tool_search_tool_bm25" }

tools配列にはどちらか一方、または両方を入れられます。対応モデルは両変種で共通で、Claude Haiku 4.5・Sonnet 4.5以降のモデルと、Opus 4.5以降のモデルが並びます。Opus 4.1以前は非対応です。

くらべる

どちらの変種を選ぶか

パターンで絞る

regex版

ツール名にgithub_やslack_のようなプレフィックスが揃っているときに向きます。github_.*のように、グループ全体を1回の検索で引けます。a|bで言い換えを並べるのは、パターンを書く側(Claude)の仕事です。

自然文で探す

BM25版

Claudeが自然文でクエリを書くため、パターンの書き方を実装側が気にする必要がありません。上限は500字で、regex版の2.5倍です。

両方を同じtools配列に並べることもできます。

regex版 — Claudeが書くのは自然言語のクエリではない

regex版で誤解しやすいのは、Claudeが渡すpatternが検索語ではなく、Pythonの正規表現そのものだという点です。単純な単語のほか、次のようなパターンをClaudeが自分で組み立てます。

  • "weather": ツール名・説明に"weather"を含むものにマッチ
  • "get_.*_data": get_user_dataやget_weather_dataのようなツールにマッチ
  • "database.*query|query.*database": 語順のどちらにもマッチ

パターン長の上限は200字です。実際には".*weather.*"のような広めのパターンを書くため、完全一致を前提にした名前の付け方より、キーワードが名前や説明に含まれているかどうかが効きます。

ローカルで当たり方を試す

デバッグ手順としては、re.search(r"your_pattern", "tool_name", re.IGNORECASE)をPythonで実行する方法が挙げられています。次の7つのツール名に対するPython 3のreでの結果です。

import re
 
names = ["get_user_data", "get_weather_data", "getWeatherData",
         "github_create_issue", "slack_post_message",
         "query_database", "database_schema"]
 
def hits(pattern):
    return [n for n in names if re.search(pattern, n, re.IGNORECASE)]
パターンマッチしたツール名
weatherマッチしたツール名get_weather_data、getWeatherData
get_.*_dataマッチしたツール名get_user_data、get_weather_data
database.*query|query.*databaseマッチしたツール名query_database
^github_マッチしたツール名github_create_issue
GITHUBマッチしたツール名github_create_issue
get.weatherマッチしたツール名get_weather_data

weatherはキャメルケースのgetWeatherDataにも当たります。一方、get_.*_dataはアンダースコア区切りが前提なのでgetWeatherDataには当たりません。命名規則がまちまちなツール群では、パターンの書き方で取りこぼしが出ます。database_schemaは名前にqueryを含まないので、database.*queryの組み合わせには当たりません。

不正なパターンは、検索の実行時にinvalid_tool_inputのエラーになります。たとえば閉じ括弧の無い(abcは、Pythonではmissing ), unterminated subpattern at position 0で失敗します。ドキュメントの例はmissing ) at position 1で、Pythonの文面とは異なります。そのため文面ではなくerror_codeで判定するほうが安全です。

BM25版 — Claudeが書くのは自然文

BM25版では、Claudeは正規表現ではなく自然文のクエリを書きます。上限は500字です。BM25は情報検索で使われるランキングアルゴリズムの名前ですが、実装側がクエリの書式を意識する必要はありません。

どちらの変種でも、検索の的中率を左右するのはツール定義の側です。ドキュメントが挙げている工夫は次のとおりです。

  • サービスやリソース名のプレフィックス(github_、slack_)を揃え、1回の検索でグループごとに当たるようにする
  • 利用者がタスクを説明するときの言葉を、説明文のキーワードに入れる
  • システムプロンプトに「Slack・GitHub・Jiraのツールを検索できます」のようにカテゴリを書いておく
  • Claudeがどのツールを発見しているかを観察して、説明文を直す

defer_loadingは「送るかどうか」ではなく「文脈に載せるかどうか」

検索対象にしたいツールにはdefer_loading: trueを付けます。このフラグが制御するのはClaudeの文脈に最初から載るかどうかで、APIに送るデータは変わりません。deferしたツールも、完全な定義を毎リクエストのtools配列に含めます。APIがサーバー側で検索を実行し、tool_referenceを展開するために、定義を手元に持つ必要があるからです。

手順

検索から呼び出しまでの流れ

  1. 1

    リクエストを送る

    最初の文脈に載るのは、Tool Search Toolとdeferしていないツールだけです。

  2. 2

    Claudeが検索する

    server_tool_useブロックとして検索が呼ばれます。検索はAnthropicのサーバー内で実行され、limitを省くと既定で5件が返ります。

  3. 3

    APIが定義を展開する

    見つかったツールはtool_referenceとして返り、APIが完全な定義に展開してからClaudeに渡します。

  4. 4

    Claudeがツールを呼ぶ

    発見したツールへのtool_useだけが、アプリ側で実行してtool_resultを返す対象です。

defer_loadingの付け方には、ほかにもいくつか決まりがあります。

  • Tool Search Tool自体には付けません。少なくとも1つのツール(通常はTool Search Tool自身)をdeferしない状態にします
  • よく使う3〜5個のツールは付けずに残し、検索を挟まず直接呼べるようにします
  • computer useとbrowser useのツールセット(computer_toolset_20260801とbrowser_toolset_20260801)では、configsの中の各メンバーに付けます。エントリ直下に付けたリクエストは拒否されます

プロンプトキャッシュとの関係

deferしたツールはシステムプロンプトの先頭部分(prefix)に入りません。発見されると、会話の途中にtool_referenceが追記され、そこで完全な定義に展開されます。prefixは変わらないので、プロンプトキャッシュは保たれます。

ただし、defer_loading: trueのツールにcache_controlは付けられません。付けると400エラーです。

MCPサーバーのツールはmcp_toolsetで遅延読み込みにする

ツールがMCPコネクタ経由で入ってくる場合は、1本ずつdefer_loadingを書く必要はありません。mcp_toolsetエントリのdefault_configにサーバー全体の既定を置き、例外だけconfigsにツール単位で書きます。

{
  "type": "mcp_toolset",
  "mcp_server_name": "google-calendar-mcp",
  "default_config": { "defer_loading": true },
  "configs": {
    "search_events": { "enabled": false }
  }
}

この例ではsearch_eventsが無効になり、残りのツールはすべてdeferされます。優先順位はconfigsのツール設定、default_config、システム既定の順です。defer_loadingの既定値はfalseなので、書かなければ最初から文脈に載ります。

400エラーになる書き方と、見つからないときの切り分け

エラー

400エラーになる3つの書き方

  • 全ツールをdeferした

    At least one tool must have defer_loading=false. All tools cannot be deferred.が返ります。Tool Search Tool自体にdefer_loadingを付けたのが典型で、定義から外せば直ります。

  • 定義の無いツールを参照した

    Tool reference 'unknown_tool' not found in available toolsの形で返ります。発見されうるすべてのツールの完全な定義を、toolsに入れておきます。

  • deferしたツールにcache_controlを付けた

    defer_loading: trueとcache_controlは同居できません。ブレークポイントはdeferしていないツールに移します。

400にはならないものの、よくあるのが「期待したツールが見つからない」です。ドキュメントの切り分け手順は、まずツール名・説明・引数名・引数の説明にキーワードがあるかを見ます。regex版ならローカルでパターンを試し、大文字小文字は無関係だと割り切ります。対処は説明文へのキーワード追加です。

一致するツールが1件も無い検索は、エラーではありません。tool_referencesが空配列のtool_search_tool_search_resultとして返ります。

検索そのものが失敗したとき — 4種類のerror_code

検索の実行が失敗した場合、HTTPステータスは200のままです。tool_search_tool_resultの中にtool_search_tool_result_errorとしてエラーが返ります。

error_code意味
invalid_tool_input意味検索の入力が不正(不正な正規表現、200字超のパターン等)
unavailable意味検索処理がタイムアウトした、またはサービスが一時的に利用できない
too_many_requests意味検索操作のレート制限を超過した
execution_time_exceeded意味検索の実行時間が上限を超えた

「見つからない」と「検索に失敗した」は、応答の形が別です。リトライや説明文の見直しの出番を分けるには、この2つを区別して受け取ります。

会話の続きで発見済みのツールを使い回す

APIは会話履歴の中のtool_referenceを毎回展開します。一度発見したツールは、後続のターンでも再検索なしに呼べます。

継続リクエストでは、アシスタントのserver_tool_useとtool_search_tool_resultをそのまま履歴に残します。tools配列には、Tool Search Toolと全deferred定義を毎回含めます。srvtoolu_...のIDを持つ検索呼び出しにtool_resultを返すと、APIに拒否されます。

ストリーミングでは、server_tool_useとして検索呼び出しが流れ、実行中はストリームが止まります。結果はtool_search_tool_resultとして届きます。Messages Batches APIにも組み込めます。

自前の検索ロジックを実装する

埋め込みベクトルによる意味検索のような独自の検索を使いたいときは、通常のカスタムツールとして検索ツールを作ります。その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_tool_resultはサーバー内部の応答形式なので、自前実装では標準のtool_resultとtool_referenceの組み合わせを使います。

数値の上限と、使うかどうかの目安

defer_loading: trueを付けられるツールは、1リクエストあたり最大10,000個です。検索結果は既定で5件ですが、Claudeがlimitに1から10,000までの整数を指定できます。

使うかどうかの目安は、次のいずれかに当てはまるかどうかです。

  • ツールが10個以上ある
  • ツール定義の合計が10,000トークンを超える
  • 構成の拡大とともに、ツール選択の精度が落ちている
  • 複数のMCPサーバーを束ねていて、200個を超えるツールがある

ドキュメントによると、GitHub・Slack・Sentry・Grafana・Splunkを束ねた構成は、定義だけで約55,000トークンになります。Tool Searchでは、これを85%以上減らせるのが通常とされています。逆に、ツールが10個未満の構成、毎回すべてのツールを使う構成、定義の合計が100トークン未満の構成では、通常のツール呼び出しのほうが向きます。

検索は別課金の対象ではありません。レスポンスのusage.server_tool_useに検索用のフィールドは無く、検索で文脈に載った定義は通常のツール定義と同じく入力トークンに数えられます。Amazon Bedrockでは、サーバー側のTool SearchはInvokeModel APIでだけ使え、Converse APIでは使えません。

ツール設計そのもの(命名・粒度・説明文の書き方)はエージェント向けツール設計の原則で扱っています。

Agent SDKのTool Searchとは別の層にある

Agent SDK Tool Searchは、ENABLE_TOOL_SEARCHという環境変数でオン・オフや閾値を制御する、SDK側の機能です。本記事のregex版・BM25版の定義は、Messages APIを直接呼ぶ実装で書く低レベルの仕様です。Agent SDKのドキュメントは、この2つのtypeを書き分ける設定を載せていません。

Messages APIを直接呼ぶ実装では、ここまでの定義を自分で組み立てます。公式ホスト以外を指すプロキシ構成では、SDK側が既定でオフになる点にも注意が必要です。

Tool Searchが見つけたツールの定義には、input_examplesも一緒に展開されます。ただし設定している場合に限ります。

まとめ

github_やslack_のように命名規則が揃っているツール群なら、regex版でグループ単位に絞れます。命名がまちまちで、説明文のキーワードに頼る構成なら、書式を気にしなくて済むBM25版が合います。

この記事を共有:XはてブLinkedIn