Home 論文解説: Don't Break the Cache — LLMエージェントフレームワークのプロンプトキャッシュ効率を体系評価
投稿
キャンセル

📄 論文解説: Don't Break the Cache — LLMエージェントフレームワークのプロンプトキャッシュ効率を体系評価

本記事は Don’t Break the Cache: An Evaluation of Prompt Caching for Long-Horizon Agentic Tasks の解説記事です。

論文概要(Abstract)

LLMのエージェント応用が拡大するなか、マルチターン推論で発生する高コスト・高レイテンシの課題に対し、プロンプトキャッシュ(KVキャッシュの再利用)が有効な最適化手法として注目されている。著者らは、エージェントタスクにおけるプロンプトキャッシュの体系的評価が存在しないことを指摘し、Prompt Caching Metrics(PCMs)という評価指標群を新たに定義した。さらに、LangChain・LlamaIndex・CrewAI・AutoGen・OpenAI Agents SDK・AWS Bedrock Agentsの6フレームワークを4タスクで横断評価し、キャッシュ安定性の差異とその根本原因を明らかにしている。

この記事は Zenn記事: LangGraph×Claude Sonnet 4.6のプロンプトキャッシュ最適化でAgentic RAGコスト90%削減 の深掘りです。

情報源

背景と動機(Background & Motivation)

LLMのエージェント応用(マルチステップのワークフロー実行、ツール呼び出し、マルチエージェント協調)では、1つのタスク完了に数十回のLLM呼び出しが発生する。各呼び出しで長いシステムプロンプト・ツール定義・会話履歴を毎回再処理するのは計算コストとレイテンシの両面で非効率である。

プロンプトキャッシュは、前回のリクエストと共通するプレフィックス部分のKVキャッシュを再利用することで、この問題を軽減する。Anthropic・OpenAI・GCP/Gemini・AWS Bedrockの各プロバイダがキャッシュ機能を提供しているが、エージェントフレームワークがこのキャッシュをどれだけ効率的に活用できているかの体系的評価は、本論文以前には存在しなかった。

著者らは、フレームワークの内部実装がプロンプトのプレフィックス安定性を意図せず破壊しているケースが多いことに着目し、その定量評価と原因特定を行った。

主要な貢献(Key Contributions)

  • Prompt Caching Metrics(PCMs)の定義: Cache Hit Rate(CHR)、Input Tokens Processed(ITP)、Cache Miss Cost(CMC)の3指標を新規に提案。モデル内部にアクセスすることなく、APIのusageフィールドから計測可能
  • 6フレームワーク × 4タスクの体系的ベンチマーク: LangChain、LlamaIndex、CrewAI、AutoGen、OpenAI Agents SDK、AWS Bedrock Agentsを横断的に評価した初の研究
  • キャッシュ破壊の根本原因を5つ特定: 動的タイムスタンプ挿入、ツール定義の非決定的順序付け、会話履歴管理の差異、メッセージシリアライズ差異、フレームワーク固有メタデータの注入
  • 最大99.2%のキャッシュヒット率と93.3%のコスト削減を実証: 正しくキャッシュが機能する場合の上限を定量的に示した
  • CMCによる過剰コストの定量化: 理想コストに対する実コストの倍率として表現し、CrewAIでは100〜1000倍の過剰コストが生じることを報告

技術的詳細(Technical Details)

Prompt Caching Metricsの数学的定義

著者らが定義した3つの指標を数式で整理する。

Input Tokens Processed(ITP): キャッシュミスしたトークン数、すなわちモデルが新規に計算する必要があるトークン数を表す。

\[\text{ITP}_i = n_i^{\text{input}} - n_i^{\text{cached}}\]

ここで、

  • $n_i^{\text{input}}$: $i$番目のAPI呼び出しにおける総入力トークン数
  • $n_i^{\text{cached}}$: そのうちキャッシュから読み取られたトークン数

Cache Hit Rate(CHR): 入力トークンのうちキャッシュヒットした割合を表す。

\[\text{CHR}_i = 1 - \frac{\text{ITP}_i}{n_i^{\text{input}}} = \frac{n_i^{\text{cached}}}{n_i^{\text{input}}}\]

CHR = 1はすべてのトークンがキャッシュから提供されたことを意味し、CHR = 0はキャッシュが全く機能していないことを意味する。

Optimal ITP(ITP*): プレフィックスキャッシュが理論的に最適に機能した場合の最小ITP。

\[\text{ITP}^*_i = |P_i| - \text{lcp}(P_i, P_{i-1})\]

ここで、

  • $P_i$: $i$番目のAPI呼び出しのプロンプトトークン列
  • $\text{lcp}(P_i, P_{i-1})$: 2つのプロンプト間の最長共通プレフィックスのトークン数
  • $P_0 = \emptyset$(初回呼び出しにはキャッシュなし)

Cache Miss Cost(CMC): 実際のITPと理論最適ITPの比率で、キャッシュの非効率性を定量化する。

\[\text{CMC} = \frac{\sum_{i=1}^{N} \text{ITP}_i}{\sum_{i=1}^{N} \text{ITP}^*_i}\]

CMC = 1が理想(すべてのキャッシュミスが不可避なもののみ)。CMC = 1000は、最適なキャッシュ運用と比較して1000倍のコストが発生していることを意味する。

プロバイダ間のキャッシュ価格構造

著者らが評価に用いたプロバイダのキャッシュ価格体系を整理する(論文Table 1より)。

プロバイダキャッシュ方式ヒット時価格(通常入力比)最小プレフィックス長
Anthropic明示的(cache_control25%(0.25x)1024トークン
OpenAI自動(プレフィックス≥1024)50%(0.5x)1024トークン
GCP/Gemini明示的(キャッシュオブジェクト)別課金体系設定依存
AWS Bedrock自動(エージェント用)10%(0.1x)管理側自動

Anthropicのキャッシュヒット時価格(25%)は最も低いが、キャッシュ書込コスト(125%)が通常入力より高いため、再利用されない場合は逆にコスト増となる。この構造がキャッシュ設計で考慮すべきトレードオフである。

評価タスクの設計

著者らは4つのタスクカテゴリを設計し、エージェントのプロンプト構造が異なるパターンでキャッシュに与える影響を評価している。

  1. Summarization: 「戦争と平和」の1000チャンクを逐次要約。プロンプトが各ターンで累積的に成長するパターン
  2. QA: Anthropicの利用規約文書に対する5問の質問応答。長い共有コンテキスト + 短い質問のパターン
  3. Coding: テストフィードバックに基づくコード反復改善。プロンプトに前回のコードとフィードバックが追加されるパターン
  4. Multi-Agent: Planner・Coder・Reviewerの3エージェント協調。各エージェントが異なるシステムプロンプトを持ち、共有の会話履歴が成長するパターン

キャッシュ破壊の根本原因分析

著者らが特定した5つのキャッシュ破壊パターンは以下の通りである。

1. 動的タイムスタンプ挿入(最重要、CrewAI該当)

1
2
3
4
5
# CrewAIの内部実装(著者らによる分析結果より)
# システムプロンプトに毎ターン現在時刻が挿入される
system_prompt = f"Current time: {datetime.now()}. You are an agent..."
# 毎秒変化するため、プレフィックスが毎ターン完全に異なる
# → CHR ≈ 0 (キャッシュ全滅)

2. ツール定義の非決定的順序付け(AutoGen該当)

ツール定義がPythonのdictsetから構築される際、実行ごとに順序が変わる可能性がある。ツール定義はAnthropicのキャッシュ階層で最上位(toolssystemmessages)に位置するため、ツールの順序変更は全キャッシュを無効化する。

3. 会話履歴管理の差異(Multi-Agentで顕著)

マルチエージェント設定で全会話履歴を毎ターン含める場合、思考連鎖(Chain-of-Thought)の内容やフォーマットが微妙に変化することでプレフィックスが破壊される。

4. メッセージシリアライズの差異

JSONのフィールド順序やホワイトスペースの扱いがフレームワークによって異なり、見た目には同一のプロンプトでもバイト列レベルで不一致が発生する。

5. フレームワーク固有メタデータの注入

リクエストID、セッション識別子などの動的値がプロンプトに注入されるケースがある。

実験結果(Results)

フレームワーク別キャッシュ効率

以下は著者らが報告したフレームワーク別の評価結果の要約である(論文Section 5より)。

フレームワークCHR(キャッシュヒット率)CMC(キャッシュミスコスト)評価
LangChain~0.80~1.1(ほぼ理想)最良クラス
LlamaIndex~0.72~1.2(ほぼ理想)最良クラス
CrewAI0.02–0.20100–1000x要改善
AutoGen0.10–0.4010–500x要設定修正
OpenAI Agents SDK0.60–0.752–10x中程度
AWS Bedrock AgentsN/A(自動管理)AWS管理AWS専用

著者らの報告によると、最良ケースではOpenAI Agents SDKのQAタスクでCHR = 0.992(入力トークンの99.2%がキャッシュヒット)を達成している。一方、最悪ケースではCrewAIのCMCが1000倍に達し、最適なキャッシュ運用と比較して1000倍のコストが発生している。

コストへの影響

著者らはAnthropicモデル(claude-3-5-sonnet-20241022)での具体的なコスト計算を示している。

\[\text{Cost}_{\text{cached}} = n^{\text{cached}} \times p_{\text{hit}} + \text{ITP} \times p_{\text{miss}}\]

ここで、

  • $p_{\text{hit}} = 0.25 \times p_{\text{base}}$(Anthropicのキャッシュヒット時価格)
  • $p_{\text{miss}} = p_{\text{base}}$(通常の入力トークン価格)

キャッシュが正常に機能する場合(CHR > 0.80):

  • コスト削減: 最大93.3%(著者らの報告による)
  • レイテンシ削減: 長いプロンプトでTTFT(Time-to-First-Token)が50〜80%改善

キャッシュが破壊されている場合(CHR < 0.20):

  • 理論最適コストの10〜1000倍が発生
  • レイテンシ改善の恩恵なし

タスク別の傾向

著者らの分析によると、タスクの特性によってキャッシュの効果が大きく異なる。

  • QA: 長い共有ドキュメントが安定したプレフィックスとなるため、最もキャッシュが効果的
  • Summarization: プロンプトが累積的に成長するが、プレフィックスは安定しやすい
  • Coding: テストフィードバックの変動が中程度のキャッシュ不安定性を引き起こす
  • Multi-Agent: 各エージェントのシステムプロンプトが異なるため、エージェント切り替え時にキャッシュが破壊されやすい

実装のポイント(Implementation)

著者らの分析結果に基づき、プロンプトキャッシュ効率を維持するための実装上の注意点を整理する。

プレフィックス安定性を確保する設計パターン

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
from typing import Any

def build_stable_prompt(
    system_prompt: str,
    tools: list[dict[str, Any]],
    messages: list[dict[str, str]],
) -> dict[str, Any]:
    """キャッシュ安定性を確保するプロンプト構築

    - ツール定義を名前順でソート(非決定的順序を排除)
    - 動的コンテンツ(タイムスタンプ等)をプレフィックスに含めない
    - 静的コンテンツを先頭に配置
    """
    # ツール定義を名前順でソート(決定的な順序を保証)
    sorted_tools = sorted(tools, key=lambda t: t["name"])

    # 動的コンテンツはメッセージ末尾に配置
    # システムプロンプトには静的コンテンツのみ
    return {
        "tools": sorted_tools,
        "system": system_prompt,  # 静的のみ
        "messages": messages,
    }

PCMsの計測実装

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
import json
from dataclasses import dataclass


@dataclass
class CacheMetrics:
    """Prompt Caching Metrics(論文Section 3の定義に準拠)"""
    cache_read_tokens: int
    cache_write_tokens: int
    uncached_tokens: int

    @property
    def total_input(self) -> int:
        return self.cache_read_tokens + self.cache_write_tokens + self.uncached_tokens

    @property
    def itp(self) -> int:
        """Input Tokens Processed(キャッシュミストークン数)"""
        return self.total_input - self.cache_read_tokens

    @property
    def chr(self) -> float:
        """Cache Hit Rate"""
        if self.total_input == 0:
            return 0.0
        return self.cache_read_tokens / self.total_input


def compute_cmc(metrics_sequence: list[CacheMetrics], prompts: list[str]) -> float:
    """Cache Miss Cost(論文Definition 4)

    Args:
        metrics_sequence: 各API呼び出しのキャッシュメトリクス
        prompts: 各API呼び出しのプロンプト文字列

    Returns:
        CMC値(1.0が理想、大きいほど非効率)
    """
    total_itp = sum(m.itp for m in metrics_sequence)
    total_optimal_itp = 0
    prev_prompt = ""
    for prompt in prompts:
        lcp_len = len(_longest_common_prefix(prev_prompt, prompt))
        optimal_itp = len(prompt) - lcp_len
        total_optimal_itp += optimal_itp
        prev_prompt = prompt

    if total_optimal_itp == 0:
        return 1.0
    return total_itp / total_optimal_itp


def _longest_common_prefix(a: str, b: str) -> str:
    """2つの文字列の最長共通プレフィックスを返す"""
    i = 0
    while i < min(len(a), len(b)) and a[i] == b[i]:
        i += 1
    return a[:i]

監視の実装

著者らが定義したPCMsをプロダクション環境で継続監視する設計が推奨される。CHRが80%を下回った場合はアラートを発火し、プロンプト構造の変更がキャッシュ効率に悪影響を与えていないか調査するワークフローが有効である。

実運用への応用(Practical Applications)

フレームワーク選定への示唆

著者らの評価結果は、LLMエージェントフレームワーク選定において以下の判断材料を提供する。

  • LangChain / LlamaIndex: デフォルトでキャッシュ安定性が高い。Zenn記事で紹介されているLangGraph(LangChainの上位フレームワーク)は、この恩恵を受けやすい
  • CrewAI: 動的タイムスタンプの除去(または1セッション内での固定化)を適用しない限り、コストが100〜1000倍に膨らむリスクがある
  • AutoGen: ツール定義のシリアライズをsorted()で決定的にするだけでCMCが大幅に改善される
  • OpenAI Agents SDK: QA系タスクでは良好だが、マルチエージェント設定では会話履歴管理に注意が必要

Zenn記事の4層キャッシュブレークポイント設計との関連

Zenn記事で解説されている「ツール定義 → システムプロンプト → RAGコンテキスト → 会話履歴」の4層設計は、本論文のキャッシュ破壊分析と整合する。著者らの知見によれば、変更頻度の低いコンテンツを先頭に配置し、各層の境界にブレークポイントを設定することで、部分的な変更が上位層のキャッシュを破壊しない構造が実現できる。

関連研究(Related Work)

  • PagedAttention / vLLM (Kwon et al., SOSP 2023): KVキャッシュのメモリ管理をOSのページング手法で効率化。本論文が評価するクライアントサイドのキャッシュ効率とは補完的な関係にある
  • SGLang / RadixAttention (Zheng et al., 2024): サーバーサイドでのプロンプトプレフィックス共有を基数木(Radix Tree)で管理。本論文が焦点を当てるフレームワーク側のプレフィックス安定性が、サーバーサイド最適化の前提条件となる
  • Prompt Cache (Gim et al., 2023): プロンプトのモジュール単位でのアテンション状態再利用。本論文はこの概念をエージェントフレームワーク評価に拡張している

まとめと今後の展望

本論文の主要な成果は以下の3点である。

  1. PCMsによる定量評価の標準化: CHR・ITP・CMCという指標により、フレームワークのキャッシュ効率を客観的に比較可能にした
  2. キャッシュ破壊パターンの体系的特定: 動的タイムスタンプ、非決定的ツール順序などの具体的な原因を明らかにし、開発者が即座に対応可能な知見を提供した
  3. フレームワーク選定への実証的根拠: LangChain/LlamaIndexが最もキャッシュ効率が高く、CrewAIが最も低いという定量的な比較結果は、技術選定の意思決定に直結する

今後の研究として、著者らはキャッシュ破壊パターンの自動検出・修復ツールの開発、およびより多様なエージェントベンチマークでの検証を挙げている。

参考文献

この投稿は CC BY 4.0 でライセンスされています。

論文解説: Vibe Coding — AIとの対話によるプログラミングの実証分析

Anthropic解説: Citations API — RAGシステムに自動出典付与を実現するsearch_result content blocks