Galirage Inc.
🤖

KVキャッシュとは?【Prompt CachingとCAGの裏側】

に公開

はじめまして、ますみです!

株式会社Galirage(ガリレージ)というAIスタートアップで、代表をしております^^

その他にも、「AIとコミュニケーションする技術(インプレス出版)」という書籍を執筆させていただいたり、生成AIアカデミーというYouTubeチャンネルを運営したり、上智大学で非常勤講師をしたりしています!

自己紹介.png
「KVキャッシュ」を知らずにPrompt CachingやCAGを語るのは難しいです。

生成AIエンジニアとして現場で活躍するためには、LLMの内部構造への理解が欠かせません。

本記事では、 KVキャッシュ(Key-Value Cache) の仕組みを、GPTモデルの内部構造から丁寧に解説します。

「難しそう」と感じる方もご安心ください。順を追って説明しますので、ぜひ最後までご覧ください。

KVキャッシュとは?(概要)

KVキャッシュは、ChatGPTなどのモデル(Attention機構を持ったモデル)において、過去の履歴を保持しておく技術です。

具体的には、会話履歴とそれに紐づくKey / Valueのベクトルをメモリ上に保持します。
これにより、続きの文章を生成するときに、少ない計算量で処理できるようになります。

事例として、KVキャッシュを採用することで、通常40秒かかっていた処理が9秒に短縮される(約4.5倍高速化)ケースがあるほどです。

KVキャッシュとは?(詳細)

GPTモデル内の仕組み

KVキャッシュを理解するために、GPTモデル(デコーダーモデル)の内部構造を見てみましょう。

  1. トークナイズ:文章からトークンの配列に変換されます。(例:「吾輩は猫である」→ [吾輩, は, 猫, で, ある])
  2. エンベディング:各トークンがベクトルに変換されます。ベクトルになることで、機械学習モデル内での数理演算が可能になります。
  3. 行列変換:各ベクトルからKey・Value・Queryの3つの行列に変換します。Queryは最後のトークンのみの計算で十分です。
  4. アテンション計算:Query、Key、Valueを使用してアテンションを計算します。特徴量抽出をしている処理であり、複数のAttention機構に対して並列で実行されます(Multi-head Attention)。
  5. フィードフォワードや残差演算など:ここまでの処理結果をもとに次単語の確率を計算し、文字を生成します。

上記の全体の流れにおいて、 アテンション計算においてKVキャッシュを活用 しています。

アテンション計算までの流れ

アテンション計算の流れを整理すると、次のようになります。

KVキャッシュのあり/なしで計算がどう変わるかを比較した図が下記です。

KVキャッシュ あり vs なし の計算フロー比較
KVキャッシュ あり vs なし の計算フロー比較 — キャッシュなしでは毎回全トークンを再計算するが、キャッシュありでは過去のKey/Valueを再利用して重複計算を省略できる

上記の例では、「吾輩は猫で」という文章をあらかじめキャッシュしておきます。
計算を行う際に、このキャッシュを活用することで、計算量を削減しています。

キャッシュをしない場合、「吾輩」「は」「猫」「で」の4つの塊に対して、トークナイズ・エンベディング・行列変換(KeyとValueの算出)をする必要があります。

キャッシュをすることで、これらの計算を省略できます。

なぜ「KVQ」キャッシュではなく「KV」キャッシュなのか?

「なぜKVQキャッシュではなく、KVキャッシュなのか?」と感じた方もいるのではないでしょうか。

GPTなどのデコーダーモデルでは、 次単語予測時に必要なのは最後のトークンのQueryベクトルのみ だからです。

Transformerのモデルでは、「Position-wise Feed-Forward Networks」という手法を使用しています。

この手法を用いることで、次単語の確率を算出する際のベクトル計算において、最後のトークン以外のQueryはなくても計算が可能になっています。

別の言い方をすると、 最後のトークンのQueryと、全コンテキストのKeyとValueがあれば、次単語を予測できます。

そのため、KeyとValueのみをキャッシングしておけば良いというわけです。

計算量削減の効果

実際に、KVキャッシュによってどれくらい計算量が減るのかを確認してみましょう。

4トークン(Token1, Token2, Token3, Token4)のコンテキストを入力した場合を考えます。

KVキャッシュを使用しない場合は、下記のような計算が必要になります。

トークン1: Q1, K1, V1を計算
トークン2: Q1,K1,V1 + Q2,K2,V2を再計算 ← 重複
トークン3: Q1,K1,V1 + Q2,K2,V2 + Q3,K3,V3を再計算 ← さらに重複

KVキャッシュを使用する場合は、重複計算を省略できます。

トークン1: Q1, K1, V1を計算 → K1,V1をキャッシュ
トークン2: キャッシュのK1,V1 + 新規Q2,K2,V2
トークン3: キャッシュのK1,V1,K2,V2 + 新規Q3,K3,V3

これにより、理論上は最大で L 倍のスループット向上が実現できます。


主な特徴・メリット

  1. 計算量削減:同一Key/Valueを再計算しないため、理論上は最大で L 倍のスループット向上が期待できます。
  2. レイテンシ短縮:ファーストトークンのみKVを構築し、2トークン目以降はキャッシュを参照するため、体感応答速度が向上します。
  3. メモリ効率のカスタマイズ:ストリーミング生成では「sliding-window cache」を採用し、GPU VRAMを一定量に抑制可能です。
  4. CAGとの親和性:ドメイン知識を「KV化」して先読みロードすることで、RAGのretrieval latencyと誤検索を排除できます。
  5. Prompt Cachingと合わせたコスト削減:システムプロンプトを固定し、JSON順序・タイムスタンプを変えない設計パターンにより、最大90%のコスト削減も可能です。

実装例

サンプルコード(PyTorch + Transformers v4.45)
from transformers import AutoModelForCausalLM, AutoTokenizer
import torch, time

model_id = "TinyLlama/TinyLlama-1.1B-intermediate-step-200k"
model = AutoModelForCausalLM.from_pretrained(model_id, torch_dtype=torch.float16, device_map="auto")
tok   = AutoTokenizer.from_pretrained(model_id)

prompt = "Explain the difference between RAG and CAG."
inputs = tok(prompt, return_tensors="pt").to(model.device)

# KVキャッシュなし
start = time.perf_counter()
_ = model.generate(**inputs, max_new_tokens=128, use_cache=False)
print(f"No KV: {time.perf_counter()-start:.2f}s")

# KVキャッシュあり
start = time.perf_counter()
_ = model.generate(**inputs, max_new_tokens=128, use_cache=True)
print(f"KV cache: {time.perf_counter()-start:.2f}s")

実際には max_batch_sizesliding_window などのハイパーパラメーターでVRAMを最適化することも大切です。


具体的なユースケース

1. Prompt Caching

同一のシステムプロンプトやコンテキストが繰り返し使用される場合、KVキャッシュを活用してコストを大幅削減できます。

設計のベストプラクティス

  • システムプロンプトを固定する
  • JSONフィールド順序も固定する
  • タイムスタンプ等の揮発情報は末尾に付与する

2. CAG(Cache-Augmented Generation)

従来のRAG(Retrieval-Augmented Generation)では、実行時にベクトル検索が必要でした。

一方 CAG(Cache-Augmented Generation)では、事前にナレッジをKVキャッシュとして保存します。
検索レスで高速生成を実現できるのが特徴です。

ユースケース KVキャッシュ活用例 期待効果
AIコーディングエージェント チャット履歴をKVに保持 推論レイテンシを200ms→40msへ削減
長文要約(128K context) セクション単位でKVを段階的に破棄 VRAMを40GB→14GBへ削減
CAG-based FAQボット よくある質問5,000件分を事前キャッシュ RAG検索レイヤーを削除し15%コスト減

RAG vs CAGのパラダイムシフト

従来、各ステップでQuery・Key・Value行列を再計算すると計算量が O(L^2) に跳ね上がります。
「過去トークンのKey/Valueをメモリに保持し再利用する」ことで、この重複計算を削減できます。

  • RAG:実行時にベクトルDBからドキュメントを取得し、コンテキストに追加する方式
  • CAG:事前に長大コンテキストをKVキャッシュごとプリロードし、推論時は検索レスで生成する方式

2つのアーキテクチャの違いを図で比較すると、下記のようになります。

RAG vs CAG アーキテクチャ比較
RAG vs CAG アーキテクチャ比較 — RAGは実行時にベクトルDB検索が必要でレイテンシが大きいが、CAGはKVキャッシュを事前ロードすることで検索レスの高速生成を実現する

長コンテキストLLM(128K+ token)の登場により、「検索のレイテンシ」と「キャッシュのメモリ」という新たな設計トレードオフが生まれています。


ベンチマーク

トークン数 KVキャッシュあり KVキャッシュなし メモリ(GB)
32K 15.3 tok/s 3.4 tok/s 9.1
64K 14.1 tok/s 1.7 tok/s 18.2
128K 13.8 tok/s 0.9 tok/s 34.5

実測では 4.1〜15.3倍 のスループット向上を確認しています。
メモリ増加はトークン長に線形で、1 token ≈ 2.5MB です。

RAG vs CAGの比較

項目 RAG CAG
レイテンシ ネットワークI/O依存 キャッシュ照会のみ
ソース鮮度 高い(リアルタイム) 低い(事前ロード)
メモリ 少ない 大きい(KVサイズ ∝ L)
実装複雑度 高い(retriever/reader) 低い(単一モデル)

考察・Tips

  • Decoder-onlyモデルとの相性が良い:GPT系(Decoder Model)は次トークン予測のみを担うため、Queryは最新トークンのみ生成し、Key/Valueをキャッシュすればよいです。
  • Encoder-Decoder(BART/T5)での応用:エンコーダー側はBERTと同じ双方向注意を持ちKVが不要です。一方デコーダーはGPTと同様にキャッシュ可能です。
  • KVシャーディング:1層ごとに異なるGPUへ張り付けることで、128K+コンテキストを単機で処理できます。

まとめ

KVキャッシュは「過去トークンのKey/Valueをメモリに置いておくだけ」というシンプルなアイデアです。
しかし、それだけで最大10倍超のスループット改善をもたらします。

  • KVキャッシュ:アテンション計算の重複を省き、推論速度を大幅に向上させる基盤技術
  • Prompt Caching:KVキャッシュを活用してAPI呼び出しコストを最大90%削減する設計パターン
  • CAG:KVキャッシュをナレッジとして事前ロードし、RAGの検索レイヤーを不要にするアーキテクチャ

実戦投入時は メモリ使用量の上限コンテキスト鮮度 のバランスを評価した上で、

  1. ベンチマーク
  2. A/Bテスト
  3. 本番

のステップでチューニングすることをおすすめします。

KVキャッシュへの理解が深まれば、Prompt CachingやCAGの設計判断もより自信を持ってできるようになるはずです。ぜひ試してみてください!

最後に

最後まで読んでくださり、ありがとうございました!
この記事を通して、少しでもあなたの学びに役立てば幸いです✨

参考文献

https://arxiv.org/pdf/1706.03762

https://www.dailydoseofds.com/p/kv-caching-in-llms-explained-visually/

Galirage Inc.
Galirage Inc.

Discussion