Mid-conversation Tool Changes——ツール入替設計
長時間の運用チケット対応エージェントが、調査フェーズでは検索・ログ参照ツールを、対応フェーズでは書き込み・通知ツールを使う——セッション途中でツールの構成を切り替えたい場面は多い。しかしtools配列はプロンプトキャッシュのハッシュ対象で最も先頭に位置するため、1つ書き換えるだけでそれ以降の会話全体のキャッシュが失効していた。
なぜツール入替はキャッシュを壊すのか
プロンプトキャッシュは
tools・system・messagesの順でハッシュ化するため、toolsの変更は会話全体のキャッシュを失効させる。
プロンプトキャッシュはリクエストのプレフィックスをtools配列→systemフィールド→messagesの順でハッシュ化し、直近のリクエストと完全一致した範囲までキャッシュを読む。toolsはこのプレフィックスの最も早い位置にあるため、フェーズが切り替わってツールを1つ足し引きしただけで、それより後ろにある大量の会話履歴もまとめてキャッシュミスになる。数十ターン続くエージェントハーネスのセッションでは、この再計算コストが無視できない規模になる。
同じ問題はsystemフィールドにも存在し、AnthropicはMid-conversation system messagesでこれを解決した。systemを書き換える代わりに、会話の末尾へrole: "system"のメッセージを追加して以降のターンにだけ指示を効かせる仕組みだ。Mid-conversation Tool Changesは同じ考え方をtools配列に適用したベータ機能で、Claude Opus 5・Claude Mythos 5・Claude Opus 4.8で利用でき、Claude Sonnet 5では使えない。
Mid-conversation Tool Changesはどう動くのか
tools配列は変更せず、tool_addition/tool_removalブロックでツールの提供・撤回を会話の途中に差し込む。
実装はmid-conversation-tool-changes-2026-07-01ベータヘッダーを付けたリクエストで、role: "system"メッセージのcontent配列にtool_additionまたはtool_removalブロックを置く。各ブロックのtoolフィールドは、ツールを新たに定義するのではなく{"type": "tool_reference", "name": "..."}でtools配列に宣言済みのツールを名指しで参照する。MCP connector経由のツールはmcp_tool_reference(server_nameとname)で個別に、mcp_toolset_reference(server_name)でサーバー単位でまとめて参照できる。toolsに宣言されていない名前を参照すると400エラーになる。
この設計の要点は、tools配列そのものは会話を通じて一切変更しないことにある。ツールの提供・撤回はすべて会話履歴に追加されるメッセージとして表現されるため、キャッシュのハッシュ対象であるtoolsのプレフィックスは常に同一のまま保たれる。ツール入替の事実は「何をAPIに送るツール定義として持つか」ではなく「その時点でどのツールをClaudeに提示するか」という会話内の状態として扱われる。
defer_loadingとどう組み合わせるか
defer_loading: trueのツールは初期状態で撤回済み扱いになり、tool_additionが最初の提示として機能する。
tools配列内の各ツールは、Tool loading controlのdefer_loading: trueを付けない限り会話開始時点からClaudeに提示される。defer_loading: trueを付けたツールは会話開始時点では撤回された状態にあり、tool_additionブロックが最初にそのツールを提示するトリガーになる。逆にtool_removalで一度撤回したツールも、後続のtool_additionで再提示できる。
これはTool Search Toolのdefer_loadingと同じプロパティを使うが、目的は異なる。Tool Search Toolは大量のツールカタログからClaudeが検索して必要なものを見つける仕組みであり、tool_referenceの展開はモデル自身の検索呼び出しがトリガーになる。Mid-conversation Tool Changesは、アプリケーション側が会話のフェーズ遷移を検知してtool_addition/tool_removalを能動的に発行する仕組みで、どのツールをいつ提示するかの判断はアプリケーション側にある。両者はdefer_loadingという同じ土台の上で、検索駆動か明示的な状態遷移かという別の制御モデルを提供する。
設計・運用のポイントは何か
ブロックは
role: "system"メッセージのcontent配列に置き、直前のuserターンかtool_result直後にのみ配置できる。
tool_addition/tool_removalブロックは、Mid-conversation system messagesと同じ配置制約を継承する。role: "system"メッセージは、userターン(tool_resultブロックを含むものも可)の直後、またはサーバーツール結果で終わるassistantターンの直後にのみ置け、messages配列の末尾になるか直後にassistantターンが続く必要がある。tool_useブロックとそれに対応するtool_resultの間に挟むと400エラーになる。エージェントループでは、ツール実行結果を返すuserメッセージの直後にこのブロックを挿入する設計が基本形になる。
実装時は3点を押さえる。第一に、フェーズごとのツール構成をあらかじめ設計し、フェーズ開始点でtool_removal(前フェーズ専用ツールの撤回)とtool_addition(次フェーズ専用ツールの提示)をまとめて1つのシステムメッセージに含める。第二に、一度送信したtool_addition/tool_removalメッセージは編集・削除しない。過去のメッセージへの変更は他のメッセージ編集と同様にキャッシュを失効させるため、状態を変えたい場合は新しいメッセージを追記する。第三に、LLMゲートウェイ経由で複数チームのエージェントトラフィックを中継している場合、ベータヘッダーの伝搬とモデル対応(Sonnet 5では使えない)をゲートウェイ側のルーティング設定に反映しておく必要がある。長時間セッションかつ大規模なツールインベントリを持つエンタープライズのエージェント基盤では、このキャッシュ保持の効果が特に大きい。
Mid-conversation Tool Changesを含むツール定義設計全体の考え方はFunction callingのツール定義、キャッシュ設計の基礎はプロンプトキャッシュ設計も参照してほしい。複数チームのLLM/エージェント基盤設計はKuuの RDE サービスでも技術支援している。
参考
- Mid-conversation system messages and tool changes — Claude Platform Docs
- Tool reference — Claude Platform Docs
- Prompt caching — Claude Platform Docs
まとめ
Mid-conversation Tool Changesは、tools配列を書き換えずにtool_addition/tool_removalブロックでツールの提示・撤回を会話履歴側の状態として表現することで、フェーズが切り替わる長時間セッションでもプロンプトキャッシュを保ち続ける設計を可能にする。defer_loadingとの組み合わせ、配置制約、ゲートウェイでのベータヘッダー伝搬という3点を押さえて設計すれば、大規模なツールインベントリを持つエンタープライズのエージェント基盤でキャッシュ効率を落とさずにツール構成を動的に切り替えられる。