Claude APIのツールは誰が実行するか — 3分類とループの違い
Claude APIのツールは実行主体で3つに分かれます。自分のアプリが動かすユーザー定義とAnthropicスキーマ、Anthropicが動かすサーバーツール。ループを回す側とツール化の判断基準を表で比べます。
Claude APIのツールは、コードを動かす主体によって3つに分かれます。自分のアプリが動かす「ユーザー定義ツール」、スキーマだけをAnthropicが用意して実行は自分のアプリが担う「Anthropicスキーマツール」、実行までAnthropicが引き受ける「サーバーツール」です。どの箱に入るかで、アプリ側が書くループの量がまるで変わります。
モデルが自分で何かを実行することはありません。モデルが出すのは構造化されたリクエストだけで、それを自分のコードかAnthropicのサーバーが実行し、結果が会話に戻ります。
3分類は「どこでコードが動くか」で決まる
ツールを分ける主軸は、コードが動く場所です。箱ごとに、アプリが負う責任が決まります。
| 分類 | スキーマ | 実行 | レスポンスのブロック | ループを回す側 |
|---|---|---|---|---|
| ユーザー定義ツール | スキーマ自分で書く | 実行自分のアプリ | レスポンスのブロックtool_use | ループを回す側自分のアプリ |
| Anthropicスキーマツール | スキーマAnthropicが公開 | 実行自分のアプリ | レスポンスのブロックtool_use | ループを回す側自分のアプリ |
| サーバーツール | スキーマAnthropicが公開 | 実行Anthropicのサーバー | レスポンスのブロックserver_tool_use | ループを回す側Anthropic(基本は返却前に完了) |
ユーザー定義ツール — 実装はClaudeに渡らない
スキーマもコードも自分で用意する、最も一般的なタイプです。データベース検索、HTTP呼び出し、ファイル書き込みなど、アプリ固有の処理がここに入ります。
Claudeが呼ぶと、レスポンスにはツール名と引数のJSONを持つtool_useブロックが入ります。アプリは引数を取り出して処理を実行し、次のリクエストでtool_resultブロックとして出力を返します。Claudeが受け取るのは自分が渡したスキーマと返された結果だけで、実装の中身は見えません。
Anthropicスキーマツール — スキーマは借りて実行は自前
スクラッチパッド的な記憶の管理、シェルコマンド、ファイル編集、デスクトップやブラウザの操作といった定番の操作には、Anthropicがスキーマを公開しているものがあります。該当するのはmemory、bash、text_editor、computer、browserの5つです。
実行モデルはユーザー定義ツールと同じです。tool_useブロックが返り、自分のコードが実行し、tool_resultを返します。それでも自作せずに使う理由は、これらのスキーマがモデルに学習済みだからです。同じ署名を使う成功例で最適化されているため、同等の機能を自作スキーマで定義するより呼び出しが安定し、エラーからの立て直しも上手になります。
実装の具体例はComputer Useツールを自前実装する最小構成で扱っています。
サーバーツール — 有効化して最終回答を読む
web_search、web_fetch、code_execution、tool_searchの4つは、Anthropicが実行まで担います。リクエストでツールを有効にすれば、残りはサーバー側の仕事です。tool_resultブロックを自分で組み立てる必要はありません。
レスポンスには、何が実行されて何が返ったかを示すserver_tool_useブロックが含まれます。idはsrvtoolu_で始まり、クライアントツールの呼び出しと見分けられます。結果ブロック(Web検索ならweb_search_tool_result)は同じアシスタントターンの中で、tool_use_idで対応づけて続きます。多くの場合、アプリの仕事はツールを有効にして最終回答を読むことで足ります。
ループを回す側が違う — クライアントツールとサーバーツール
分類の違いが最も表に出るのが、エージェントループを誰が回すかです。
クライアントツールはstop_reasonで回す
モデルは自分のコードを動かせないので、ツール呼び出しは毎回往復になります。モデルが依頼し、アプリが実行し、結果を戻し、モデルが続きます。標準の形はstop_reasonを条件にしたwhileループです。
クライアントツールのループ
- 1
リクエストを送る
tools配列とユーザーメッセージを送ります。 - 2
tool_useで止まる
Claudeが
stop_reason: "tool_use"と1つ以上のtool_useブロックを返します。 - 3
ツールを実行する
各ツールを実行し、出力を
tool_resultブロックに整えます。 - 4
結果を添えて再送する
元のメッセージ、アシスタントの応答、
tool_resultを載せたユーザーメッセージを新しいリクエストで送ります。 - 5
stop_reasonを見て繰り返す
stop_reasonが"tool_use"の間は手順2に戻ります。
ループが終わるのはtool_use以外の停止理由のときです。end_turn、max_tokens、stop_sequence、refusalのいずれかで、最終回答が出たか、アプリが別途扱うべき理由で止まったことを意味します。
骨格を書くと次のような形になります(説明用の最小例です。run_toolは自分で実装する関数を指します)。
messages = [{"role": "user", "content": user_input}]
while True:
response = client.messages.create(
model=MODEL, max_tokens=1024, tools=tools, messages=messages
)
if response.stop_reason != "tool_use":
break # end_turn / max_tokens / stop_sequence / refusal
messages.append({"role": "assistant", "content": response.content})
results = [
{
"type": "tool_result",
"tool_use_id": block.id,
"content": run_tool(block.name, block.input),
}
for block in response.content
if block.type == "tool_use"
]
messages.append({"role": "user", "content": results})このwhileを自前で書かない選択肢として、SDKにはループを肩代わりする仕組みがあります。Tool RunnerでAnthropic APIのツール呼び出しループを自動化するにその使い方があります。
サーバーツールのループはAnthropic側の中で回る
サーバーツールは、Anthropicのインフラの中で自前のループを持ちます。1回のリクエストで、検索やコード実行が何度も走ってから応答が返ることがあります。モデルが検索し、結果を読み、もう一度検索するかを判断し、必要な情報がそろうまで繰り返します。アプリは途中に関与しません。
stop_reasonの読み方もここで変わります。クライアントツールだけの会話ならtool_useが出る間は自分が動く番、サーバーツールだけなら通常はend_turnで完結した回答が届きます。
サーバーツールのループが自分に戻ってくる2つの場面
サーバー側ループが完全に閉じず、制御がアプリに戻る場面が2つあります。
サーバー側ループが戻るパターン
反復上限に達した
サーバー側ループには反復の上限があります。モデルがまだ反復している途中で上限に達すると、stop_reasonがend_turnではなくpause_turnになります。作業は未完了なので、一時停止した応答を含めて会話を再送し、続きを実行させます。
クライアントツールと同時に呼んだ
同じ並列呼び出しのグループにサーバーツールとクライアントツールが混ざると、サーバーツールはまだ実行されません。stop_reasonはtool_useで、結果ブロックを持たないserver_tool_useが残ります。クライアントのtool_resultを返した次のリクエストで、APIがそのサーバーツールを実行します。
pause_turnは、反復上限に達して応答が途中で返るサインです。上限に達したかどうかは回数でなく、stop_reasonがpause_turnかどうかで判定します。バッチ処理では1ターンあたりの反復上限が通常より高くなりますが、それでも上限に達すれば同じくpause_turnで終わります。
2つの停止理由の見分け方、混在時にtool_resultだけで応答すると何が起きるかといった判定の実務は、tool_useとpause_turnの違いに詳しくあります。この記事の範囲は、そもそもなぜその2つが生まれるかの全体像までです。
「次に何をするか」を実行主体で引く
3分類を覚えるより、レスポンスを受け取った時点で「自分に何が求められているか」を引ければ実装は迷いません。
| 受け取ったもの | 自分のやること |
|---|---|
tool_use(ユーザー定義、Anthropicスキーマのどちらも) | 自分のやることツールを実行してtool_resultを返す |
server_tool_useと対応する結果ブロック | 自分のやること何もしない。完了済みで、最終回答を読む |
server_tool_useだけで結果ブロックが無い(stop_reasonはtool_use) | 自分のやること同居するクライアントツールを実行して結果を返す |
stop_reason: "pause_turn" | 自分のやること応答を含めて会話を再送して続行させる |
見分けの手がかりは、ブロックの種類とidの接頭辞に集約されます。toolu_はクライアント、srvtoolu_はサーバーです。
ツールを使う場面、使わない場面
実行主体の次に決めるのは、そもそもツールを使うかどうかです。ツールが向くのは、テキストだけではモデルにできないことがあるときです。
- 副作用のある操作: メール送信、ファイル書き込み、レコード更新。モデルは操作を説明できても、実行できるのはツールだけです。
- 最新または外部のデータ: 現在の価格、今日の天気、データベースの中身など、学習データの外にあるもの。
- 形が保証された構造化出力: 特定のフィールドを持つJSONが欲しいとき、ツールのスキーマが形を強制します。
- 既存システムとの接続: データベース、社内API、ファイルシステム。自然言語の依頼と実システムをつなぐ橋になります。
逆に、ツールが向かない場面もあります。
- 学習内容だけで答えられる質問(要約、翻訳、一般知識)
- 副作用のない一問一答。実行するものがなければ、ツールの出番もありません
- 往復の遅延が軽い処理より重くなるとき。ツール呼び出しは最低1往復を足すので、軽い作業では本体より重くなることがあります
正規表現を書き始めたらツール化の合図
判断の目安として、モデルの出力から決定を取り出すために正規表現を書いているなら、その決定は最初からツール呼び出しの形にできていた、という見方があります。自由な文章から構造化された意図を復元しているなら、その構造はスキーマに属している、という考え方です。
例として、問い合わせの分類をプロンプトで「カテゴリ名を1行目に書いてください」と頼み、受け取った文字列を正規表現で切り出しているとします。この場合は、categoryを列挙型で持つツールを1つ定義し、tool_useブロックのinputをそのまま読む形にできます(下は説明用の例です)。
{
"name": "classify_ticket",
"description": "問い合わせを分類して記録する",
"input_schema": {
"type": "object",
"properties": {
"category": { "type": "string", "enum": ["billing", "bug", "other"] },
"urgent": { "type": "boolean" }
},
"required": ["category", "urgent"]
}
}出力の形を整えたいだけで外部システムに触れない場合も、この使い方は成立します。ただしクライアントツールなので、tool_useで止まった後にtool_resultを返す往復は発生します。往復の遅延が気になるときは、先ほどの「向かない場面」の3つ目と見比べて決めることになります。
実行主体の選び方 — 3つの比較
新しい機能を足すときの選び方を表にまとめます。
| 選択肢 | 向く用途 | 自分の負担 |
|---|---|---|
| ユーザー定義クライアントツール | 向く用途独自の業務ロジック、社内API、独自データ | 自分の負担実行とループを自分で担う |
| Anthropicスキーマのクライアントツール | 向く用途bash、ファイル編集、デスクトップ・ブラウザ操作などの定番操作 | 自分の負担実行は自前。スキーマが学習済みなので呼び出しが安定する |
| サーバー実行ツール | 向く用途Web検索、コード実行サンドボックス、Web取得 | 自分の負担実行はAnthropic。結果は作るのでなく読む |
迷ったときの順序は、まず定番操作がAnthropicスキーマにあるかを確かめ、無ければユーザー定義で作り、外部の情報取得や計算ならサーバーツールで足りないかを見る、という流れが無理がありません。サーバーツールが使えるなら、ループを書く手間とtool_resultの組み立てを丸ごと省けます。
大量のツールを扱う段階になったら、読み込みや呼び出しの仕組みを変える選択肢があります。その入口はAnthropic Advanced Tool Useにまとまっています。ツール利用で増えるトークンの見積もりはClaudeのツール利用で増えるトークン数をモデル別に見るで確認できます。
実装前に確認すること
- サーバーツールの基本版(
web_search_20250305、web_fetch_20250910)はZero Data Retention(ZDR)の対象です。動的フィルタリングを持つ_20260209以降の版は、内部でコード実行を使うため既定ではZDR対象外です。allowed_callers: ["direct"]で動的フィルタリングを外すと、ZDRと併用できます - Web Fetchでは、ZDR対象の構成でも、取得先サイトの運営者が、URLに渡したパラメーターを保持する可能性があります
- バッチ処理でも
pause_turnで終わったときは、続きを追加のリクエストで送ります
ツールの種類を分けて考えると、アプリが負う責任は「実行」「ループ」「tool_resultの組み立て」の3つに整理できます。ユーザー定義とAnthropicスキーマは3つとも自分の仕事、サーバーツールはほぼ全部がAnthropic側です。この差を先に頭に置いておけば、stop_reasonを見たときに自分が動く番かどうかを迷わず決められます。
参照した一次ソース
この記事の記述は、次の一次ソースと照合しています。更新時に参照先が変わった場合は一覧も更新します。