Claude Media
Claude Codeワークフローのプロンプトキャッシュの効き方

Claude Codeワークフローのプロンプトキャッシュの効き方

ワークフローのファンアウトで同時に起動した複数エージェントは、条件が揃えば互いのプロンプトキャッシュを読めます。既定TTLが5分な理由と、1時間へ延ばす設定、同時起動を待ち合わせる仕組みを扱います。

ワークフローがファンアウトで同時に何体ものエージェントを起動すると、モデル・エフォート・エージェント種別・ツール・出力スキーマ・作業ディレクトリが揃うエージェント同士は、同じプレフィックスを組み立てます。後から始まるエージェントは、先に応答を始めた同型のエージェントのキャッシュを読めます。ただしこのキャッシュは会話本体のTTLバケットの外にあり、既定では5分しか持ちません。仕組みと、1時間へ延ばす設定、複数エージェントの同時起動をずらして待ち合わせる仕組み(prefix stagger)を扱います。

なぜファンアウト内のエージェントはキャッシュを共有できるのか

APIのプロンプトキャッシュは、リクエストの先頭(プレフィックス)が直近に処理した内容と一致するかどうかで判定します。マッチは完全一致で、プレフィックスのどこかが変わるとそこから後ろが丸ごと再計算されます。ワークフローの各エージェントが投げるリクエストも同じ仕組みに従うため、システムプロンプトとツール定義が同一なら、後発のエージェントは先発のエージェントが温めたキャッシュをそのまま読めます。

一致の条件は6つ揃うことです。モデル・エフォートレベル・エージェント種別・ツール構成・出力スキーマ・作業ディレクトリが同じエージェント同士だけが、ツール定義とシステムプロンプトからなるプレフィックスを組み立てます。1つでも違えば別のプレフィックスとして扱われ、キャッシュは共有されません。作業ディレクトリが効く理由は、システムプロンプト自体に作業ディレクトリ・プラットフォーム・シェル・OSバージョン・自動メモリーのパスが埋め込まれているためです。同じリポジトリでもworktreeが違えば作業ディレクトリも違うので、別々のプレフィックスになります。

ファンアウトのキャッシュは会話本体と違うTTLバケットに入る

Claude Codeはリクエストを2つのバケットに振り分けます。メイン会話(対話ターン、-p実行、Agent SDKのターン)と、それ以外(サブエージェント・ワークフロー・teammates・fork・compaction・セッションタイトルなど)です。ワークフローのエージェントが投げるリクエストは後者に入ります。

リクエストの種類Claudeサブスクリプション(プラン内利用)利用クレジット・APIキー・クラウドプロバイダー
メイン会話Claudeサブスクリプション(プラン内利用)1時間利用クレジット・APIキー・クラウドプロバイダー5分
それ以外(ワークフロー含む)Claudeサブスクリプション(プラン内利用)5分(サーバー側制御のヘルパーリクエストのみ1時間)利用クレジット・APIキー・クラウドプロバイダー5分

つまりClaudeサブスクリプションでプラン内利用に収まっていても、ワークフローのエージェントが使うキャッシュは既定で5分しか保ちません。ファンアウトが5分を超えて分散して起動される、あるいは1つのエージェントの応答に5分以上かかるようなら、後発のエージェントが読もうとしたときにはすでにキャッシュが切れている可能性があります。

1時間キャッシュへ延ばす設定

この5分を1時間へ延ばすには、subagentPromptCacheTtl設定かCLAUDE_CODE_SUBAGENT_PROMPT_CACHE_TTL環境変数を使います。どちらも5m1hのどちらかしか受け付けず、Claude Code v2.1.242以降が必要です。

{
  "subagentPromptCacheTtl": "1h"
}

メイン会話側は別の設定promptCacheTtl(またはCLAUDE_CODE_PROMPT_CACHE_TTL環境変数)で制御するため、ワークフローを含む全リクエストのTTLを揃えたいなら両方を設定します。ただし1時間キャッシュはキャッシュ書き込みが高い単価で課金されます。短時間で完結するファンアウトや、頻繁に新しい種類のエージェントを起動する運用では、1時間へ延ばしても書き込みコストが嵩むだけで恩恵が出ないことがあります。恩恵が出るのは、ファンアウトが5分を超えて分散する、あるいは同じ形のエージェントを間隔を空けて繰り返し起動するようなワークフローです。

複数の制御が同時に当てはまる場合の優先順位は次の通りです。

  1. FORCE_PROMPT_CACHING_5M=1(両バケットとも強制的に5分)
  2. バケットごとの環境変数(CLAUDE_CODE_SUBAGENT_PROMPT_CACHE_TTL)
  3. バケットごとの設定(subagentPromptCacheTtl)
  4. サブエージェントのexperimentalフロントマターのcacheTtl値(サブエージェントのリクエストに限り適用、Claude Code v2.1.248以降。Claudeサブスクリプションが利用クレジットを使っている間は1h指定を無視)
  5. ENABLE_PROMPT_CACHING_1H=1(両バケットとも1時間を要求)
  6. リクエストのバケットごとの既定値(前表)

同時起動をずらして先頭のキャッシュを待つ仕組み

ファンアウトが複数の一致するエージェントを一斉に起動すると、Claude Codeは最初のエージェント以外を、最初のエージェントの応答が始まるまで保留し、その後まとめて解放します。この待ち合わせ(prefix stagger)によって、保留されていたエージェントの最初のリクエストは共有プレフィックスを未キャッシュのまま処理するのでなく、最初のエージェントが温めたキャッシュを読めます。

この待ち合わせの上限はCLAUDE_CODE_WORKFLOW_PREFIX_STAGGER_MS環境変数で、既定値は5000(5秒)です。Claude Code v2.1.229以降が対象で、0に設定すると待ち合わせを無効化できます。DISABLE_PROMPT_CACHINGが設定されているときは、エージェントは待ち合わせをしません(キャッシュ自体を使わないため待つ意味がないからです)。

ワークフローの他の制約とキャッシュの関係

ワークフロー実行には同時実行数の上限(既定16、CPUが少ない環境ではさらに少なくなる)があります。この待ち合わせは、この上限の中で起動されたエージェント同士の間で働く仕組みで、上限そのものを変えるものではありません。

制約内容
同時実行エージェント数内容既定16(CPU制限のある環境ではさらに少ない)
ファンアウト時のキャッシュ共有待ち内容最大CLAUDE_CODE_WORKFLOW_PREFIX_STAGGER_MS(既定5秒)
parallel()pipeline()1回あたりの項目数内容最大4,096件
1実行あたりの総エージェント数内容最大1,000体

コストへの影響も無視できません。ワークフローは多数のエージェントを立ち上げるため、同じタスクを会話の中でこなすより明確に多くのトークンを使うことがあります。キャッシュが効かない(TTL切れ・プレフィックス不一致)状態でファンアウトを回すと、各エージェントがツール定義とシステムプロンプトを毎回フルで処理するため、この差はさらに広がります。大きなタスクにかける前に小さな範囲で試し、/workflowsビューでエージェントごとのトークン使用量を確認するのが実務での確認手順です。

中断・再開はプロンプトキャッシュと別の仕組み

ワークフローを中断して再開したときに「完了済みのエージェントはキャッシュされた結果を返す」という挙動がありますが、これは本稿で扱っているプロンプトキャッシュとは別物です。再開時の「キャッシュされた結果」は、ランタイムがエージェントごとの実行結果を保存しておき、スクリプトが変わっていなければ同じ結果を再利用する仕組みを指します。プロンプトキャッシュはAPIリクエストのプレフィックスをサーバー側で再利用する仕組みで、どちらも「キャッシュ」と呼ばれますが対象も保存場所も別です。中断・再開の詳しい挙動は/workflowsで実行を管理するにまとめています。

サブエージェント一般とワークフロー内エージェントの違い

サブエージェントは親の会話とは別の会話を独自のシステムプロンプトとツールセットで始めるため、最初のリクエストは親のキャッシュを読めません。ワークフロー内のファンアウトで起きているのはこれとは違う状況で、同じワークフロー実行内の複数エージェント同士が条件次第で互いのキャッシュを読み合う点が特徴です。一方、forkは親のシステムプロンプト・ツール・会話履歴をそのまま引き継ぐため、最初のリクエストから親のキャッシュを読みます。compactionの要約呼び出しも同じプレフィックス共有の考え方を使っています。

APIレベルのプロンプトキャッシュの基本的な仕組み(プレフィックスマッチ・キャッシュブレークポイント・課金体系)はAnthropic APIのPrompt Cachingを理解するで扱っています。本稿はその上に立つ、Claude Codeのワークフロー機能に固有の挙動に絞っています。

よくある質問

ファンアウトで起動したエージェントが違うモデルを使っていてもキャッシュは共有されますか

されません。モデルはキャッシュキーの一部で、モデルが違えば別のキャッシュとして扱われます。エフォートレベルが違う場合も同様に別キャッシュです。

1時間キャッシュに設定を変えるとメイン会話にも影響しますか

subagentPromptCacheTtlはメイン会話のバケットに影響しません。メイン会話のTTLは別の設定promptCacheTtlで制御します。ワークフローを含む全リクエストのTTLを揃えたいなら両方を設定する必要があります。

待ち合わせ(prefix stagger)を無効化すると何が変わりますか

CLAUDE_CODE_WORKFLOW_PREFIX_STAGGER_MS=0に設定すると、ファンアウトの各エージェントは互いを待たずに即座にリクエストを送ります。一致するプレフィックスを持つエージェント同士でも、最初のエージェントの応答が返る前に後続が動き出した場合はキャッシュを未書き込みの状態で処理することになり、無効化前より未キャッシュ処理が増える可能性があります。

キャッシュのヒット状況を確認する方法はありますか

最も手早いのはstatuslineスクリプトで、APIレスポンスに含まれるcache_creation_input_tokenscache_read_input_tokensの2フィールドをライブ表示させる方法です。加えて/workflowsビューは各エージェントのトークン使用量を表示するので、そこから間接的にキャッシュの効き具合を推測できます。

まとめ

ワークフローのファンアウトでは、モデル・エフォート・エージェント種別・ツール・出力スキーマ・作業ディレクトリが揃うエージェント同士がプロンプトキャッシュを共有できます。ただしこのキャッシュはメイン会話用のTTLバケットの外にあり、Claudeサブスクリプションのプラン内利用でも既定は5分です。長めに分散するファンアウトや同じ形のエージェントを繰り返し起動する運用ではsubagentPromptCacheTtl1hに上げる価値があり、同時起動時の未キャッシュ処理はCLAUDE_CODE_WORKFLOW_PREFIX_STAGGER_MS(既定5秒)の待ち合わせが吸収します。中断・再開時の「キャッシュされた結果」は実行結果の再利用であり、本稿のプロンプトキャッシュとは別の仕組みだと区別しておくと、コスト調整で設定を間違えずに済みます。

この記事を共有:XはてブLinkedIn