Claude Codeワークフローのプロンプトキャッシュの効き方
ワークフローのファンアウトで同時に起動した複数エージェントは、条件が揃えば互いのプロンプトキャッシュを読めます。既定TTLが5分な理由と、1時間へ延ばす設定、同時起動を待ち合わせる仕組みを扱います。
ワークフローがファンアウトで同時に何体ものエージェントを起動すると、次の6つが揃うエージェント同士は同じプレフィックスを組み立てます。6つはモデル・エフォート・エージェント種別・ツール・出力スキーマ・作業ディレクトリです。後から始まるエージェントは、先に応答を始めた同型のエージェントのキャッシュを読めます。
ただしこのキャッシュは会話本体のTTLバケットの外にあり、既定では5分しか持ちません。本稿は、どの条件でキャッシュが共有されるか、5分を1時間へ延ばす設定、同時起動をずらして待ち合わせる仕組み(prefix stagger)を扱います。
プロンプト中のultracodeという単語だけで、意図せずワークフローが起動することもあります。無効化の手順はworkflowKeywordTriggerEnabledでultracode起動を止めるにあります。
どのリクエストが誰のキャッシュを読めるのか
APIのプロンプトキャッシュは、リクエストの先頭(プレフィックス)が直近に処理した内容と一致するかどうかで判定します。マッチは完全一致で、プレフィックスのどこかが変わるとそこから後ろが丸ごと再計算されます。ワークフローの各エージェントが投げるリクエストも同じ仕組みに従います。
Claude Codeが組み立てるプレフィックスは、同じ設定のエージェントなら同一になります。だから最初のエージェントが書いたキャッシュを、後発のエージェントが読めます。
最初のリクエストが読めるキャッシュ、読めないキャッシュ
読める
- ワークフローで、条件が揃った同型のエージェント同士
- forkした会話(親のシステムプロンプト・ツール・履歴をそのまま引き継ぐ)
- 再開したサブエージェント(元の実行が温めたキャッシュ)
- 同じディレクトリで並行して動かした別セッション
読めない
- 通常のサブエージェントの最初のリクエスト(親とシステムプロンプトもツールも違う)
- 別のディレクトリで動くセッション
- モデルや作業ディレクトリが違うワークフローのエージェント
エフォートの扱いは、公式ページによって書き方が違います。ワークフローのページは、エフォートレベルを一致の条件の1つに挙げています。
プロンプトキャッシュのページには、メイン会話についての例外があります。Opus 5.5・Sonnet 5.5・Fable 5.1をAPIキーかClaudeサブスクリプションで使っていれば、エフォートを変えてもキャッシュは保たれます。Amazon Bedrock、Google CloudのAgent Platform、Claude apps gatewayでは当てはまりません。CLAUDE_CODE_DISABLE_EXPERIMENTAL_BETASを設定したときと、HIPAA構成の組織も対象外です。Fable 5.1はv2.1.260より前は、この仕組みが無効化されていました。
作業ディレクトリが効く理由は2つあります。システムプロンプトには自動メモリーのパスが入り、会話の冒頭には作業ディレクトリ・プラットフォーム・シェル・OSバージョンの告知が付くためです。同じリポジトリでもworktreeが違えば作業ディレクトリが違うので、別のプレフィックスになります。
キャッシュの有効範囲は「1台のマシンの1つのディレクトリ」が基本です。順番に動かすセッションは、起動時のgitステータスのスナップショット(ブランチと直近のコミット)が一致したときだけ、プレフィックスを共有します。
ファンアウトのキャッシュは会話本体と違うTTLバケットに入る
Claude Codeはリクエストを2つのバケットに振り分けます。メイン会話は対話ターン、-p実行、Agent SDKのターンです。それ以外はサブエージェント・ワークフロー・teammates・fork・compaction・セッションタイトルなどで、ワークフローのエージェントはこちらに入ります。
| リクエストの種類 | Claudeサブスクリプション(プラン内利用) | 利用クレジット・APIキー・クラウドプロバイダー |
|---|---|---|
| メイン会話 | Claudeサブスクリプション(プラン内利用)1時間 | 利用クレジット・APIキー・クラウドプロバイダー5分 |
| それ以外(ワークフロー含む) | Claudeサブスクリプション(プラン内利用)5分(サーバー側制御のヘルパーリクエストのみ1時間) | 利用クレジット・APIキー・クラウドプロバイダー5分 |
5分を過ぎてから動き出すエージェントは、先発が書いたキャッシュを読めない場合があります。
なお、プラン内の使用量を使い切って利用クレジットに切り替わると、メイン会話の既定も5分に下がります。1時間を保ちたいときは、TTLを自分で指定します。
5分を1時間へ延ばす設定
ワークフロー側のTTLを変えるには、subagentPromptCacheTtl設定かCLAUDE_CODE_SUBAGENT_PROMPT_CACHE_TTL環境変数を使います。どちらも5mか1hのどちらかしか受け付けず、Claude Code v2.1.242以降が必要です。
{
"subagentPromptCacheTtl": "1h"
}この設定が対象にするのは、サブエージェントやワークフローのほか、compactionやセッションタイトルなどメイン会話の外のリクエスト全部です。メイン会話側は別の設定promptCacheTtl(またはCLAUDE_CODE_PROMPT_CACHE_TTL環境変数)で決まります。APIキーやクラウドプロバイダーで使っている場合、メイン会話の1時間キャッシュも、promptCacheTtlを1hにして初めて有効になります。
1時間キャッシュは、キャッシュの書き込みが高い単価で課金されます。同じプレフィックスを再利用しない運用では、書き込みの上乗せ分だけが残ります。逆に、ファンアウトが長く続いたり、同じ形のエージェントを間隔を空けて繰り返し起動したりするワークフローでは、1時間が効きます。
複数の制御が同時に当てはまる場合の優先順位は次のとおりです。上にあるものが勝ちます。
FORCE_PROMPT_CACHING_5M=1(両バケットとも強制的に5分)- バケットごとの環境変数(
CLAUDE_CODE_SUBAGENT_PROMPT_CACHE_TTL) - バケットごとの設定(
subagentPromptCacheTtl) - サブエージェントの
experimentalフロントマターのcacheTtl値(サブエージェントのリクエストに限り適用、Claude Code v2.1.248以降。Claudeサブスクリプションが利用クレジットを使っている間は1h指定を無視) ENABLE_PROMPT_CACHING_1H=1(両バケットとも1時間を要求)- リクエストのバケットごとの既定値(前表)
FORCE_PROMPT_CACHING_5M=1は、キャッシュの挙動をデバッグするときや、2つのTTLを比べるとき、管理設定で配られた長いTTLを上書きしたいときの逃げ道です。
同時起動をずらして先頭のキャッシュを待つ仕組み
ファンアウトが複数の一致するエージェントを一斉に起動すると、そのままでは全員が共有プレフィックスを未キャッシュで処理してしまいます。Claude Codeはこれを避けるために、起動を次の順にずらします。
prefix staggerの流れ
- 1
一致するエージェントを一斉に起動する
ファンアウトが、プレフィックスの揃ったエージェントを同時に始めます。
- 2
最初の1体だけが進み、残りは保留される
最初のエージェントのリクエストだけが先に出ます。
- 3
最初のエージェントの応答が始まる
保留は、この最初のエージェントの応答が始まるまで続きます。
- 4
保留中のエージェントをまとめて解放する
応答が始まったあとに解放されたエージェントの最初のリクエストは、未キャッシュで処理せず、書かれたキャッシュを読みます。
この保留の上限がCLAUDE_CODE_WORKFLOW_PREFIX_STAGGER_MS環境変数で、既定値は5000(5秒)です。Claude Code v2.1.229以降が対象で、0にすると保留しなくなります。
DISABLE_PROMPT_CACHINGを設定しているときは、エージェントは保留されません。キャッシュを使わない以上、待つ意味がないためです。全体ではなくモデルファミリー単位でキャッシュを切りたいときは、DISABLE_PROMPT_CACHING_OPUS/SONNETでモデル別にキャッシュを無効化が使えます。
同時実行の上限とファンアウトの設計
待ち合わせは、同時実行の上限の内側で起動されたエージェント同士で働きます。上限そのものを変える仕組みではありません。
ワークフローの実行上限
同時実行エージェント
既定16
CPUが少ない環境ではさらに少ない。1〜256で調整
parallel() / pipeline() 1回の項目数
4,096件
超えるとエラーで拒否される
1実行の総エージェント数
1,000体
暴走したループを止めるための上限
同時実行数はCLAUDE_CODE_WORKFLOW_MAX_CONCURRENT_AGENTSで変えられます(Claude Code v2.1.269以降)。値を上げると、走っているエージェントの会話記録がClaude Codeのメモリー上に残るため、メモリーの使用量も増えます。詳しい設定は別記事にあります。
上限を超えたagent()の呼び出しは、空きができるまで待たされます。待っている間に先発のキャッシュがTTLを過ぎるかどうかは、先発の書き込み時刻と待ち時間の関係で決まります。
ワークフローは多数のエージェントを立ち上げるため、同じタスクを会話の中でこなすより明確に多くのトークンを使うことがあります。プレフィックスが一致しない、あるいはTTLが切れた状態では、各エージェントがツール定義とシステムプロンプトを自前で処理することになり、差はさらに開きます。
大きなタスクに投入する前に、1つのディレクトリや狭い問いのような小さな範囲で試します。/workflowsビューは、エージェントごとのトークン使用量を実行中に表示します。エージェントが25体を超える、または見込みのトークン合計が150万を超えると、タスクパネルの進行行にLarge workflowの警告が出ます。
この警告は助言にとどまり、実行を止めたり制限したりはしません。ワークフローのサイズガイドラインを自分で選ぶと、そのエージェント数が25体のしきい値に置き換わります。ultracodeをオンにしたセッションには警告が出ません。ultracodeをオンにした時点で、大きな実行を受け入れたことになるためです。
効いているかどうかをどこで見るか
キャッシュの状況を直接見る手段は、メイン会話とそれ以外で分かれます。
メイン会話については、/usageのSessionブロックにPrompt cache (main)という行が付きます(Claude Code v2.1.251以降)。キャッシュから読まれた入力トークンの割合、ミスの回数、いまキャッシュが温まっているかが出ます。ミスの原因が特定できるときは、likely cause: tool definitions changedのような原因も添えられます(v2.1.260以降)。行名の(main)が示すとおり、これはメイン会話の集計で、サブエージェントは含みません。
もう一つの手段が、statuslineスクリプトです。APIが返すcache_creation_input_tokens(書き込み)とcache_read_input_tokens(読み込み)の2つの値をリアルタイムで表示できます。読み込みが書き込みを大きく上回っていればキャッシュが効いています。書き込みが毎ターン多いなら、プレフィックスのどこかが変わり続けています。Claude Code v2.1.251以降は、statuslineスクリプトがprompt_cacheオブジェクトを読むと、/usageと同じ数値を得られます。
書き込みのTTLを確かめる方法もあります。claude -p "hello" --output-format jsonを実行し、結果のusage.cache_creationを読みます。1時間の書き込みはephemeral_1h_input_tokens、5分の書き込みはephemeral_5m_input_tokensに出ます。これが確かめられるのはメイン会話の書き込みです。
中断・再開はプロンプトキャッシュと別の仕組み
ワークフローを中断して再開したときに「完了済みのエージェントはキャッシュされた結果を返す」という挙動がありますが、これはプロンプトキャッシュとは別物です。再開時の「キャッシュされた結果」は、ランタイムがエージェントごとの実行結果を保存しておく仕組みを指します。再開時は、前回とプロンプトが同じ間は保存した結果を返し、プロンプトが違う最初のエージェント以降は再実行されます。
プロンプトキャッシュはAPIリクエストのプレフィックスをサーバー側で再利用する仕組みで、どちらも「キャッシュ」と呼ばれますが対象も保存場所も別です。中断・再開の詳しい挙動は/workflowsで実行を管理するにあります。
サブエージェントの呼び出しは親のプレフィックスを崩さない
サブエージェントの呼び出しと結果は、親の側から見ると会話に追記されるだけです。親のプレフィックスは崩れません。compactionの要約呼び出しも、同じプレフィックス共有の考え方を使っています。
APIレベルのプロンプトキャッシュの基本的な仕組み(プレフィックスマッチ・キャッシュブレークポイント・課金体系)はAnthropic APIのPrompt Cachingを理解するで扱っています。本稿は、その上に立つClaude Codeのワークフロー機能に固有の挙動に絞っています。
まとめ
ワークフローのキャッシュが効くかは、プレフィックスが揃っているかと、先発が書いてから5分以内に後発が動くかで決まります。後者に不安があるときの分かれ目が、subagentPromptCacheTtlを1hにするかどうかです。