Skip to content
Published on

LLMキャッシングの原理 — プロンプトキャッシングとPrefix Cacheはなぜお金を節約できるのか

シェア
Authors

はじめに — 「前半が同じなら安くなる」の謎

LLM APIのプロンプトキャッシングを初めて見ると不思議です。同じ質問を二度すると安くなるのではなく、プロンプトの前半が同じなら安くなります。後半が完全に違っても構いません。しかも、あるプロバイダーはキャッシュに「書く」費用を割増しで取り、「読む」費用は10分の1に割り引きます。この奇妙な価格表はマーケティングではなく、トランスフォーマー内部の物理学をそのまま反映したものです。

この記事はその物理学を底から登っていきます。トランスフォーマーがテキストを生成するとき内部で何が起きているのか、KVキャッシュとは何でなぜプレフィックス(前半)にだけ効くのか、vLLMやSGLangといったサービングエンジンがそれをどう実装しているのか、そしてAnthropic・OpenAIのプロンプトキャッシングを実践でどう設計すべきかまで。

ステップ1 — 推論は二つの局面に分かれる:PrefillとDecode

トランスフォーマー推論には、性格の全く異なる二つの局面があります。

  • Prefill(プリフィル) — 入力プロンプト全体を一度に処理する局面です。プロンプトの全トークンを並列に計算できるので、GPUの演算能力を使い切ります(compute-bound)。最初のトークンが出るまでの遅延(TTFT)はほぼここで決まります。
  • Decode(デコード) — 回答をトークン一つずつ生成する局面です。トークンごとにモデル全体を一度通過する必要があり、このときは演算よりメモリ帯域がボトルネックです(memory-bound)。

プロンプトキャッシングが節約してくれるのは、まさにprefill局面の演算です。10万トークンのシステムプロンプトがキャッシュにあれば、その10万トークンを再びprefillする必要はありません。だからキャッシュヒットはコストだけでなくTTFTを劇的に縮めます。

ステップ2 — アテンションとK/V:トークンごとに作られる名刺

なぜprefillを飛ばせるのでしょうか。アテンションの内部を見る必要があります。

トランスフォーマーの各層で、各トークンは三つのベクトルに変換されます — Query(質問)、Key(キー)、Value(値)。直観的に言えば、各トークンは自分を紹介する**名刺(K)中身(V)を作っておき、新しいトークンは自分の質問(Q)**で以前のトークンたちの名刺を眺めて関連度を計算し、関連度に応じて中身を混ぜていきます。

核心的な性質が一つあります。GPT系モデルのアテンションは**因果的(causal)**です — 各トークンは自分より前のトークンしか見られません。これが意味すること:

トークンiのKとVは、トークン1からiまでだけの関数だ。後ろに何が来ようと絶対に変わらない。

この性質があらゆるキャッシングの根です。「ここまでのテキスト」が同じなら、各トークンのK/Vベクトルはビット単位で同一に計算されます。なら、一度計算したものをなぜまた計算するのか? 保存しておけばいい。

ステップ3 — KVキャッシュ:保存しておけばいい

KVキャッシュがまさにその保管庫です。decode局面で新しいトークンを生成するとき、モデルは以前の全トークンのK/Vを必要とします。キャッシュがなければトークン生成のたびにこれまでの全シーケンスを再計算する羽目になり、生成コストは長さの二乗で爆発します。KVキャッシュがあれば、新トークンのQ/K/Vだけ計算し、以前のものはキャッシュから読みます。

タダではありません。KVキャッシュはメモリを食います。トークン一つが占めるサイズはおよそ:

トークンあたりKVキャッシュ = 2(KとV)× 層数 × KVヘッド数 × ヘッド次元 × バイト数

例:7Bクラスのモデル(32層、隠れ次元4096、fp16)
   = 2 × 32 × 4096 × 2バイト ≈ トークンあたり約512KB
   → 4,000トークンの会話一つ ≈ 約2GB
   → 同時ユーザー数十人でGPUメモリはあっという間に枯渇

このメモリ圧力が最新アーキテクチャの多くを説明します — GQA(複数のQヘッドがK/Vヘッドを共有)やMQAはKVヘッド数を減らしてキャッシュを数分の一にする設計であり、KVキャッシュ量子化(FP8/INT4)も同じ圧力から生まれました。長文コンテキスト時代の本当のコストは、重みではなくKVキャッシュであることが多いのです。

ステップ4 — Prefix Cache:リクエスト間でも再利用する

ここまでのKVキャッシュは一つのリクエスト内の話でした。Prefix Cache(プレフィックスキャッシュ)はこれをリクエスト間に拡張します。

二つのリクエストが同じ前半部分(例:同じシステムプロンプト+同じ文書)を共有するなら、その部分のK/Vは完全に同一です — 先ほどの因果性のおかげで。だから最初のリクエストで計算したK/Vブロックを捨てずに保管し、次のリクエストでプレフィックスが一致すればprefillなしにそのまま続きから使えばいい。

なぜ「前半」だけなのか? 因果性の裏面です。トークンiのK/Vは1..iの関数なので、途中の一トークンでも変われば、その地点以降のすべてのトークンのK/Vが変わります。プロンプトの途中にタイムスタンプを一つ挟むと、その後ろの10万トークンのキャッシュが全部無効になる理由です。キャッシュは「同じ内容を含む」ではなく「バイト単位で同一のプレフィックス」にだけ反応します。

実際のサービングエンジンの実装:

  • vLLM — Automatic Prefix Caching(APC):vLLMのPagedAttentionはKVキャッシュをOSのページングのように固定サイズブロックで管理します。APCは各ブロックを「そのブロックまでのトークン列」のハッシュで識別し、同じハッシュのブロックが既にあれば再利用します。ブロック単位なので部分一致も自然に処理されます。
  • SGLang — RadixAttention:共有プレフィックスを**radix tree(基数木)**で管理します。数百のリクエストが同じシステムプロンプトから枝分かれする形(木!)をデータ構造がそのまま反映し、マルチターン会話・並列分岐のようなワークロードで特に効率的です。古い枝はLRUで刈り取られます。

ステップ5 — プロバイダーのプロンプトキャッシング:価格表の読み方

APIプロバイダーの「プロンプトキャッシング」は、このprefix cacheを商品化したものです。これで価格表が物理学として読めます。

Anthropic(Claude) — 明示的キャッシング。リクエストにcache_controlブレークポイント(最大4個)を付けます。

  • キャッシュ書き込み:基本入力価格の1.25倍(5分TTL)または2倍(1時間TTL) — K/Vを計算して保持するコストです。
  • キャッシュ読み取り:基本入力価格の約0.1倍 — prefill演算を飛ばすので10分の1です。
  • 損益分岐:5分TTLは2回目のリクエストから得(1.25 + 0.1 < 2)、1時間TTLは3回以上の再利用で得(2 + 0.2 < 3)。
  • 最小キャッシュ長:モデルによりプレフィックスが1024〜4096トークン以上必要です。短いプレフィックスはマーカーを付けても静かにキャッシュされません。
  • レンダー順序は tools → system → messages — ツール一覧が最前列に置かれるので、ツールを追加・削除・並べ替えると全キャッシュが無効化されます。

OpenAI — 自動キャッシング。1024トークン以上のプロンプトでプレフィックスが一致すれば表示なしで適用され、キャッシュされた入力トークンは公開基準で50%割引です。明示マーカーがなく楽ですが、どこまでキャッシュされたかの制御権もありません。

どちらの方式でも検証方法は同じです — レスポンスのusageフィールドを見てください。Anthropicならcache_read_input_tokensがゼロでないことが、キャッシュが実際に読まれている証拠です。繰り返しリクエストでずっとゼロなら、どこかに沈黙のキャッシュ破壊者がいます。

ステップ6 — 実践設計ルール

原理が分かればルールは自然に出てきます。

  • 安定したものを前に、変わるものを後ろに。 固定システムプロンプト・文書・ツール定義が前、ユーザーの質問・タイムスタンプ・リクエストIDが後ろです。プロンプトを組み立てるコードの「順序」がキャッシング性能を決めます。
  • 沈黙のキャッシュ破壊者を摘発せよ。 システムプロンプトに埋め込まれたdatetime.now()、リクエストごとに新しく発行されるUUID、ソートしていないJSONシリアライズ(キー順が毎回違う)、ユーザーごとに異なるツール一覧 — すべてプレフィックスのバイトを変え、キャッシュを壊します。
  • 会話は累積プレフィックスだ。 マルチターン会話では以前のターン全体がプレフィックスになるので、ターンが積み重なるほどキャッシュの利得が大きくなります。最後に追加したターンの末尾にブレークポイントを置くのが標準パターンです。
  • モデルを変えるとキャッシュも消える。 K/Vは特定モデルの重みで計算された値なので、キャッシュはモデル別です。途中でモデルを乗り換えると最初から書き直しです。
  • セルフホスティングなら有効化を忘れずに。 vLLMのAPCやSGLangを使うだけで、チャット系ワークロードのprefillコストが大きく減ります。特に「同じ文書に複数の質問」パターンで効果は劇的です。

おわりに — 価格表は物理学だ

まとめるとこう圧縮されます。アテンションは因果的なので前方トークンのK/Vは不変であり、KVキャッシュはそれを一つのリクエスト内で、prefix cacheはリクエスト間で再利用し、プロンプトキャッシングの価格表(書き込み割増、読み取り割引、プレフィックス限定、最小長)はその再利用のコスト構造をそのまま価格に写したものです。「なぜ前半だけ?」という問いの答えはマーケティング政策ではなく、トークンiのK/Vは1..iだけの関数という一行の数学でした。

サービングコスト全般の絵は AIモデル開発ライフサイクル のサービング節と、GPUを分割して使う MIGガイド に続きます。

参考資料