在庫確認、顧客情報の取得、見積履歴の検索。社内エージェントが3つのツールを順番に呼ぶせいで、回答まで毎回待たされる。実はClaudeは1回の応答で複数のツールを同時に呼べます。ところが結果の返し方を間違えると、この能力は静かに失われます。
並列ツール呼び出しとは何で、何が決まっているのか
並列ツール呼び出しは、1回の応答に複数のtool_useブロックが入る挙動です。Claude 4以降のモデルでは既定で有効で、実行順序の決定は呼び出し側に委ねられています。
Claudeが複数のツールを必要と判断すると、stop_reason が tool_use の1つの応答に、複数の tool_use ブロックが並びます。公式ドキュメントによれば、APIは実行順序を規定しません。asyncio.gather で同時に走らせても、出現順に順次実行しても構いません。
守るべき規則は結果の返し方だけです。
- 各
tool_useに対してtool_resultを1つずつ返す - 全ての
tool_resultを、次の1通のuserメッセージにまとめる tool_use_idで呼び出しと結果を対応づけるtool_resultはメッセージ内でテキストより前に置く
stop_reason 全体の分岐はstop_reason別の分岐設計で整理しています。ここでは、tool_use の中身が複数あるケースに絞ります。
なぜ結果の返し方で並列呼び出しが減るのか
結果をtool_useごとに別のuserメッセージで返すと、Claudeは並列呼び出しを避けるようになります。公式が「最も多い原因」とするのが、このフォーマットミスです。
公式のトラブルシューティングは、並列呼び出しが起きない最も一般的な原因として、履歴の誤った整形を挙げています。履歴の書き方が「お手本」になり、Claudeが並列に呼ばなくなるためです。
``json``
// 誤り: 結果ごとにuserメッセージを分ける
[
{"role": "assistant", "content": [tool_use_1, tool_use_2]},
{"role": "user", "content": [tool_result_1]},
{"role": "user", "content": [tool_result_2]}
]
// 正しい: 1通にまとめる
[
{"role": "assistant", "content": [tool_use_1, tool_use_2]},
{"role": "user", "content": [tool_result_1, tool_result_2]}
]
Python SDKで自前のループを書く場合は、tool_use ブロックを全て抽出してから結果のリストを作り、1回の append で追加します。ループ内で1件ずつ append する実装が、典型的な落とし穴です。SDKのTool Runnerを使えば、この整形は自動で行われます。自前実装が必要なのは、バッチの分割や順序、エラー処理を細かく制御したい場合に限られます。
並列実行してよい処理と、直列にすべき処理は何か
読み取り専用で互いに独立した処理は並列実行に向きます。書き込み、共有状態、順序依存がある処理は直列実行が安全です。
公式ドキュメントも、独立した読み取り操作は並列が安全で、副作用や順序要件のあるツールは直列に向くと述べています。中小企業の業務に当てはめると、次の整理になります。
| 処理 | 実行方針 |
|---|---|
| 在庫・顧客・価格の参照 | 並列で実行 |
| メール送信、請求書の発行 | 1件ずつ直列で実行 |
| 同じレコードを更新する複数処理 | 直列で実行し、失敗時は中断 |
直列に回して途中で失敗した場合、実行しなかった呼び出しにも tool_result が必要です。is_error: true と「前の処理が失敗したため未実行」といった短い説明を返します。結果の欠落は400エラーの原因になります。
書き込み系ツールが重複実行されても事故にならないようにする設計は、エージェントの冪等性設計が参考になります。ツール定義そのものの書き方はFunction Callingと構造化出力のツール設計を参照してください。
並列を増やす・止めるにはどう設定するのか
並列を止めるには tool_choice の中に disable_parallel_tool_use: true を入れます。トップレベルの引数ではありません。増やしたいときはシステムプロンプトで明示します。
止める場合の指定は次のとおりです。tool_choice オブジェクトの内側に書く点が重要です。
``python``
response = client.messages.create(
model=MODEL,
max_tokens=1024,
tools=tools,
messages=messages,
tool_choice={"type": "auto", "disable_parallel_tool_use": True},
)
type が auto なら「呼ぶツールは最大1つ」、any または tool なら「ちょうど1つ」になります。ただし公式ドキュメントによれば、Claude Opus 5.5、Sonnet 5.5、Fable 5.1、Mythos 5.1 は any と tool の tool_choice に対応していません。モデルを切り替えるときは、強制指定を使っていないか確認してください。
並列を増やしたい場合は、システムプロンプトに「独立した操作を複数行うときは、全ての関連ツールを順次ではなく同時に呼び出す」と明記します。公式は タグで囲んだ、より強い指示文も紹介しています。ユーザー側の発話で「同時に確認して」と書く方法も有効です。
Claude Fable 5.1 は、次の読み取りが暗黙的にしか示されない長いエージェントループで、旧モデルより並列呼び出しが減る場合があると公式に記載があります。通常のFunction Callingは影響を受けません。
効果の測定は、ツール呼び出しを含む応答ごとの平均ツール数で行います。公式の測定コードでは、この値が1.0を超えていれば並列呼び出しが機能していると判断します。
参考
- Parallel tool use(Claude Platform Docs)
- Handle tool calls(Claude Platform Docs)
- Define tools(Claude Platform Docs)
まとめ
並列ツール呼び出しの成否は、tool_resultを1通のuserメッセージにまとめる整形と、副作用のある処理を直列にする判断で決まります。
最初に確認する点は3つです。結果を1通にまとめているか、書き込み系を直列に回しているか、平均ツール数を計測しているか。この3点で、応答の待ち時間とコストの両方が変わります。
自社のエージェントのループ設計や、ツール実行の安全な分離にお悩みなら、導入から定着まで伴走するKuu株式会社のAIオペレーション支援にご相談ください。
