この回のゴール
- 複数のツールを並べたとき、Claude が どう選ぶか を理解する
- tool_choice パラメータの 3 つの値(
auto/any/ 特定ツール指定)を使い分ける - 並列ツール使用(parallel tool use)の挙動を理解する
- 次章の AI エージェントへの橋渡しとして、「1 ターンで 複数回 ツールを呼ぶ」ループの必要性を感じる
1. 前回の復習
前回は電卓 1 つだけ。実運用では 複数のツール を並べて、Claude に場面に応じて選ばせます:
tools = [
{"name": "calculator", "description": "数式を計算する", ...},
{"name": "get_current_time", "description": "現在時刻を返す", ...},
{"name": "search_dictionary", "description": "辞書を検索する", ...},
{"name": "get_weather", "description": "天気を取得する", ...},
]
2. Claude はどうやってツールを選ぶか
Claude は各ツールの description と input_schema.properties.*.description を 読んで、ユーザーの質問に 最も合うもの を選びます。
例:
| 質問 | Claude の思考 | 呼ばれるツール |
|---|---|---|
| 「123×456 は?」 | 計算が必要 | calculator |
| 「今何時?」 | 時刻が必要 | get_current_time |
| 「"apple" の意味は?」 | 辞書が必要 | search_dictionary |
| 「東京の天気は?」 | 天気が必要 | get_weather |
| 「こんにちは」 | ツール不要 | なし(直接応答) |
カギは description の質。曖昧だと Claude が迷ったり、間違ったツールを呼んだりします。
3. tool_choice — 選択の制御
response = client.messages.create(
...,
tools=tools,
tool_choice={"type": "auto"}, # 👈 ここ
)
tool_choice |
意味 |
|---|---|
{"type": "auto"} |
(デフォルト) Claude が自由に判断。ツールが不要なら使わない |
{"type": "any"} |
必ずどれかのツール を使う。使わない応答は禁止 |
{"type": "tool", "name": "calculator"} |
特定のツール を強制 |
{"type": "none"} |
ツールを 絶対使わない |
いつどれを使う?
auto— 自然な会話、ユーザーに柔軟に応答したいとき(基本これ)any— エージェントで「次の 1 アクションを決める」強制的な場面- 特定ツール名 — フォーマットの強制、評価タスク
none— 会話モードに戻したいとき
4. 並列ツール使用 (Parallel Tool Use)
Claude は 1 レスポンスで複数のツールを同時に呼ぶ ことがあります:
User: 東京と大阪の天気、あと 1+2+3 を計算して
Claude: [tool_use: get_weather(city="東京")]
[tool_use: get_weather(city="大阪")]
[tool_use: calculator(expression="1+2+3")]
実装側は 全部を並行して実行 し、全部の結果を 1 つの user メッセージ にまとめて返します:
messages = [
...,
{"role": "assistant", "content": response.content}, # 3 つの tool_use
{"role": "user", "content": [
{"type": "tool_result", "tool_use_id": "toolu_A", "content": "..."},
{"type": "tool_result", "tool_use_id": "toolu_B", "content": "..."},
{"type": "tool_result", "tool_use_id": "toolu_C", "content": "..."},
]},
]
効率化ポイント:
- API 呼び出しが 2 回で済む(3 連続ではなく)
- ツール実行は Python 側で asyncio.gather や ThreadPoolExecutor で並列可能
5. 無効化したいなら
response = client.messages.create(
...,
tool_choice={"type": "auto", "disable_parallel_tool_use": True},
)
1 回に 1 つしかツール呼ばない状態にできる。順次実行したい場合に使う。
6. エラーが出たら
ツール実行でエラーが出たら is_error: True を付けて伝える:
{
"type": "tool_result",
"tool_use_id": "toolu_ABC",
"content": "Error: ネットワーク接続に失敗しました",
"is_error": True,
}
Claude はこれを見て「別のツールを試す」「ユーザーに状況を伝える」などの賢い対応を取ります。
7. まだできないこと(→ 次章エージェント)
この回までの tool_use には 制約 があります:
# 今の実装: 1回だけツールを使って終わる
response1 = client.messages.create(tools=tools, messages=[...]) # tool_use
result = execute(response1)
response2 = client.messages.create(tools=tools, messages=[..., tool_result]) # 最終回答
でも実際は:
- 計算→天気取得→判断→別の計算 のような 連鎖 が必要なケース
- Claude が何度でもツールを呼ぶ必要がある
- いつ「終わり」になるかは Claude が決める
👉 次章「AI エージェント」では、この ループ を自動化します。これが「エージェント」という概念です。
まとめ
- 複数ツールを並べると Claude が
descriptionを頼りに 適切なものを選ぶ tool_choiceで選択を制御(auto / any / 特定 / none)- 並列ツール使用 で 1 レスポンスに複数
tool_useブロックが返る → 並列実行で効率化 - エラーは
is_error: Trueで伝えれば Claude が賢く対応
第 4 章のクロージング → 次章への接続
ツール呼び出しの仕組みはわかった。でも 1 ターン 1 往復では、連続的な思考(計算→天気→判断→別の計算)ができない。 👉 次章「AI エージェント」では、ツール呼び出しを多段でループさせる ReAct パターン に進みます。