KV cache と prompt cache の違いを解説
KV cache はリクエストごとに RAM や VRAM を消費し、枯渇するとモデルのロード失敗やリクエスト拒否につながります。prompt cache は課金割引で、容量不足ではなくキャッシュミスとして通常料金が発生します。
KV cache と prompt cache の違い: 短い答え
KV cache とプロバイダーの prompt cache は、同じ単語を1つ含むだけで、ほかはほとんど別物です。KV cache はリクエストごとの作業メモリです。1つのリクエストが存続する間、サーバーの RAM または VRAM に保持されます。コンテキスト長と、同時に実行するリクエスト数に応じて増加します。プロバイダーの prompt caching は、課金とレイテンシーに関する機能です。プロンプトの安定したプレフィックスがプロバイダーのサーバーに保存され、再送時には割引料金が適用されます。
一方は、ハードウェアとして購入するメモリです。もう一方は、他者が保持し、利用料を請求するメモリです。
定義よりも、実際の違いが重要です。KV cache は使い果たすことがあります。使い果たすと、モデルのロードに失敗するか、リクエストが拒否されます。prompt cache は使い果たすことがありません。キャッシュがヒットしないだけで、その場合は気付かないまま通常料金を全額支払います。
KV キャッシュが保持するものと、その存在理由
トークン番号 500 を生成する transformer は、その前にある 499 個のトークンすべてに attention を行う必要があります。各トークンについて、すべての層で key ベクトルと value ベクトルが必要です。新しいトークンを生成するたびにこれらをすべて再計算すると、生成に必要な処理量はシーケンス長の 2 乗に比例して増加します。そのため、runtime はこれらを保持します。この保存領域が KV キャッシュ(key/value cache)です。
これはリクエストごとの状態です。リクエスト固有の正確なトークン列から構築されるためです。異なる prompt を送信した 2 人のユーザーがこのキャッシュを共有することはできません。ただし、runtime が prefix caching を実行する場合は例外です。これは後述する別の機能です。
Serving は 2 つのフェーズで行われます。Prefill は prompt 全体を読み取り、キャッシュを埋めます。この処理は compute によって制限されます。Decode は一度に 1 個のトークンを生成してキャッシュに追加します。この処理はメモリ帯域幅によって制限されます。この分離により、自分の環境で tokens per second を測定すると、prompt の処理速度とトークン生成速度に異なる値が表示されます。
KV キャッシュはどの程度のメモリを使用しますか?
ベンダーの表を探す必要はありません。サイズは、どのモデルでも再計算できる算術で求められます。
bytes per token = 2 * layers * kv_heads * head_dim * bytes per element2 は key と value の数を表します。それ以外の数値はすべて、モデルの config.json に由来します。この値はモデルの Hugging Face ページで公開されています。
Llama 3.1 8B を例にします。その設定には、num_hidden_layers が 32、num_key_value_heads が 8 と記載されています。hidden_size の 4096 を 32 個の attention head に分配すると、1 つの head の次元は 128 になります。f16 では各要素が 2 bytes です。
2 * 32 * 8 * 128 * 2 = 131072 bytes = 128 KiB per tokenこれに要求するコンテキスト長を掛け、さらに同時に処理するリクエスト数を掛けます。
The data behind this chart
[
{
"label": "2k context",
"one_request_gib": 0.25,
"four_requests_gib": 1
},
{
"label": "8k context",
"one_request_gib": 1,
"four_requests_gib": 4
},
{
"label": "32k context",
"one_request_gib": 4,
"four_requests_gib": 16
},
{
"label": "128k context",
"one_request_gib": 16,
"four_requests_gib": 64
}
]コンテキスト長が 8k の場合、1 リクエストのキャッシュは 1 GiB です。32k では 4 GiB になり、4-bit の重み自体と同程度の範囲に達します。モデルの最大コンテキスト長である 128k では、1 リクエストで 16 GiB、4 つのリクエストがそれぞれ最大まで使用すると 64 GiB です。重みは変わっていません。変化したのはキャッシュだけです。
Grouped query attention (GQA) が、この数値に大きく影響します。Llama 3.1 8B には 32 個の query head に対応する 8 個の key/value head があるため、4 個の query head が 1 組の保存済み key/value を共有します。num_key_value_heads と num_attention_heads が同じモデルでは、パラメーター数が同じでもキャッシュ使用量は 4 倍になります。2 つの 8B モデルを提供するコストが同じだと判断する前に、そのフィールドを確認してください。
2k で実行できたモデルが 32k では読み込めない理由
ランタイムはモデルの読み込み時に、実際に送信するプロンプトではなく、設定したコンテキスト長に合わせたサイズで KV キャッシュを予約します。Ollama のデフォルトのコンテキストウィンドウは 4096 トークンです。これを 32k に引き上げると、1 トークンも到着していない段階で 4 GiB の追加メモリ割り当てを要求することになります。
OLLAMA_CONTEXT_LENGTH=32768 ollama serve対話プロンプトから、セッションごとに同じ設定を指定する方法は次のとおりです。
ollama run llama3.1:8b
/set parameter num_ctx 32768スタックによって失敗時の挙動は異なります。vLLM は起動時に計算結果を確認し、実行を拒否します。
ValueError: The model's max seq len (131072) is larger than the maximum number of tokens that can be stored in KV cache (78336). Try increasing `gpu_memory_utilization` or decreasing `max_model_len` when initializing the engine.CPU のみの VPS では、そのような確認はありません。割り当ては通常のシステム RAM に対して行われるためです。代わりにカーネルの OOM Killer がプロセスを終了し、カーネルリングバッファーに証拠を残します。
dmesg -T | grep -i "killed process"提供プロセスの名前を含む行があれば、そのサーバーが実際の容量を超えるメモリを要求したことを示します。対処方法は、より大きな swap ファイルではなく、コンテキストを小さくすることです。ディスクにページングされた KV キャッシュは、生成するすべてのトークンで読み取られるため、生成速度が実用にならないほど低下します。適切な値の選び方については、Ollama の num_ctx とコンテキスト長に関するガイドで説明しています。
並行処理が数値に与える影響
処理中の各リクエストは、それぞれ専用の KV キャッシュを保持します。これは、キャパシティ計画で見落とされやすい点です。コンテキスト長 32k のユーザーが 4 人いる場合、モデルの重みに加えて、全体で 16 GiB が必要です。
この点に対する厳密さは、ランタイムによって異なります。Ollama と llama.cpp は、モデルのロード時に指定されたコンテキスト分を確保するため、実際に使用されるかどうかに関係なくメモリが割り当てられます。vLLM はプールを固定サイズのブロックに分割し、各リクエストの成長に応じてブロックを割り当てます。そのため、500 トークンのリクエストが保持するのは 500 トークン分だけです。いずれの場合もプールの容量には上限があり、満杯になると新しいリクエストは実行されず、キューに入ります。このキューイングが応答時間に与える影響については、自己ホスト型 LLM が処理できる同時利用ユーザー数で詳しく説明します。
KV cache を小さくする 4 つの方法
- コンテキスト長を短くします。最も効果が大きく、通常は最も低コストです。多くのチャット処理では、32k に近づくことさえありません。
- KV cache 自体を量子化します。Ollama の
OLLAMA_KV_CACHE_TYPEはデフォルトでf16で、メモリ使用量が約半分になるq8_0と、約 4 分の 1 になるq4_0を使用できます。llama.cpp に相当する設定は-ctk q8_0と-ctv q8_0です。 - key/value head の数が少ないモデル、または layer 数が少ないモデルを選びます。40 GB の weight をダウンロードする前に
config.jsonを確認してください。 - 同時に処理するリクエスト数を減らし、残りをキューに入れます。
q4_0 では、Llama 3.1 8B の値が token あたり 128 KiB から約 32 KiB に下がります。そのため、コンテキスト 32k のコストは約 1 GiB で、4 GiB ではありません。この節約は無償ではありません。key と value は低い精度で保存されるため、維持する前に自分の prompt で出力を比較してください。
プロバイダーのプロンプトキャッシュで実際に得られるもの
プロバイダーのプロンプトキャッシュは、別の製品であり、課金単位も異なります。安定したプレフィックスを指定するとプロバイダーが保存し、後続の呼び出しで同じプレフィックスを完全に再利用した場合、入力料金全額ではなく割引料金で課金されます。
2026年8月時点で Anthropic が公開している倍率は次のとおりです。5分間のキャッシュ書き込みは、基本入力トークン料金の 1.25 倍です。1時間の書き込みは 2 倍で、キャッシュ読み取りは 0.1 倍です。20,000 トークンのシステムプロンプトをこの条件に当てはめると、仕組みが明確になります。
The data behind this chart
[
{
"label": "No caching, every call",
"billed_token_equivalents": "20,000"
},
{
"label": "First call, 5 minute cache write",
"billed_token_equivalents": "25,000"
},
{
"label": "First call, 1 hour cache write",
"billed_token_equivalents": "40,000"
},
{
"label": "Every later call, cache hit",
"billed_token_equivalents": "2,000"
}
]算術として考えてください。5分間の書き込みにかかる追加料金は、最初の呼び出しで 5,000 トークン相当です。キャッシュなしで送信した場合の 20,000 に対し、請求されるトークン相当量は 25,000 です。ウィンドウ内の後続の呼び出しでは、20,000 ではなく 2,000 が課金され、18,000 トークン相当を節約できます。したがって、5分間のキャッシュは 2 回目の呼び出しから有利になります。
1時間のキャッシュは、別の判断になります。書き込み時に 40,000 が課金され、追加料金は 20,000 トークン相当です。そのため、1時間以内に 2 回ヒットする必要があります。これはモデルではなく、トラフィックパターンに関する問題です。ウィンドウの選び方を含む完全な計算は、Claude のプロンプトキャッシュの損益分岐計算にあります。
キャッシュを実際に利用できるかどうかは、2 つの点で決まります。まず、プレフィックスがモデルの最小長未満の場合、キャッシュには記録されません。2026年8月時点のドキュメント上の最小値は Claude Opus 5 で 512 トークン、Claude Sonnet 5 で 1,024 トークンです。短いリクエストはエラーを返さず、通常どおり処理されます。次に、有効期間はエントリの書き込みまたは読み取りを行うリクエストの開始時点から測定され、読み取りのたびに追加料金なしで有効期間が更新されます。そのため、頻繁に呼び出されるエンドポイントでは、5分間のキャッシュを無期限に維持できます。10分間隔で 1 回だけ呼び出されるエンドポイントでは、毎回書き込みの追加料金を支払い、キャッシュによる節約を得られません。
推測で判断せず、レスポンスを確認してください。usage オブジェクトには cache_creation_input_tokens と cache_read_input_tokens が示されます。毎回の読み取り数が 0 なら、書き込み料金だけを支払い、キャッシュから何も得られていません。
2 つのキャッシュが接する場所
長いシステムプロンプトが両者の接点になります。しかも、双方で同時にコストが発生します。
ローカルでは、f16 の Llama 3.1 8B サーバー上で 20,000-token のシステムプロンプトが約 2.4 GiB の KV キャッシュを占有します。この領域は、そのプロンプトを含む同時実行リクエストごとに個別に必要です。リモートでは、同じプレフィックスに対して最初に 1 回キャッシュ書き込みが発生し、その後の各呼び出しでは入力料金の 0.1 倍がかかります。ローカルのコストはユーザー数に応じて増加します。リモートのコストはトラフィックに応じて増加し、アイドル時間中にリセットされます。
ローカルには、プロバイダーのプロンプトキャッシュに似ているため、常に混同される機能があります。prefix caching です。vLLM のドキュメントでは、automatic prefix caching を「既存のクエリの KV キャッシュをキャッシュし、新しいクエリが既存のクエリのいずれかと同じプレフィックスを共有している場合に、その KV キャッシュを直接再利用できる」機能と説明しています。llama.cpp server はデフォルトでスロットごとに prompt cache を保持し、--cache-reuse N により再利用を試みる最小チャンクを指定します。
prefix caching が削減するのは prefill の計算量です。20,000-token のシステムプロンプトはリクエストごとではなく 1 回だけ処理されるため、最初のトークンが返るまでの時間が大幅に短縮されます。vLLM では共有ブロックが複製されずに再利用されるため、メモリ使用量も改善します。ただし、現在有効なトークン用に保持する必要があるキャッシュの量が減ることはありません。リクエスト間で重みを常駐させる方法は関連しますが別の対策であり、リクエスト間で Ollama モデルをロードしたままにする で説明しています。
自分のサーバーで測定する項目
目標とするコンテキスト長でモデルをロードし、推定値を信頼するのではなく、実測値を確認します。
ollama ps
nvidia-smi --query-gpu=memory.used,memory.total --format=csv
free -gollama ps は、ロード済みモデル、そのサイズ、GPU または CPU のどちらで実行されているかを表示します。GPU に完全に収まると想定したモデルで CPU への分割が表示される場合、KV cache によってモデルの一部が GPU から押し出されています。そのため、生成速度は低下します。nvidia-smi は実際の VRAM 使用量を示し、free -g は CPU のみの VPS で同じ役割を果たします。コンテキスト長を段階的に増やして再ロードし、数値の変化を確認します。計算値と表示値は、ほぼ一致するはずです。一致しない場合、その差は通常、計算式の誤りではなく、runtime 自身が使用する計算用バッファーです。
これらの数値から、借りたくないハードウェアが必要だと判断した場合は、トークン単位で支払う場合との比較を GPU VPS と API トークンの比較 で説明しています。
FAQ
KV キャッシュはプロンプトキャッシュと同じものですか?
いいえ。KV キャッシュはサービングプロセス内のリクエスト単位のメモリで、現在のコンテキストに含まれるすべてのトークンの key ベクトルと value ベクトルを保持します。RAM または VRAM 上に存在し、リクエストが終了すると解放されます。プロバイダーのプロンプトキャッシュは課金機能です。プロバイダーのインフラストラクチャ上に安定したプロンプトプレフィックスを保存し、同じ内容を再送したときの料金を割り引きます。KV キャッシュが不足すると、モデルをロードできません。プロンプトキャッシュがない場合に増えるのは、請求額と最初のトークンが返るまでの時間だけです。
モデルは 2k コンテキストならロードできますが、32k では失敗するのはなぜですか?
ランタイムは、送信するプロンプトの長さではなく、設定したコンテキスト長に合わせて KV キャッシュ全体をロード時に確保するためです。Llama 3.1 8B を f16 で使用する場合、キャッシュは 1 トークンあたり 128 KiB です。そのため、2k のコンテキストには 0.25 GiB、32k には 4 GiB が必要です。どちらの場合も重みは収まります。失敗するのはメモリの予約です。vLLM では、保存できるトークンの最大数を示す ValueError として報告され、gpu_memory_utilization を増やすか max_model_len を減らすよう提案されます。CPU のみのマシンでは、代わりにカーネルの out-of-memory killer がプロセスを終了します。これは dmesg -T | grep -i "killed process" で確認できます。
モデルの KV キャッシュサイズはどのように計算しますか?
レイヤー数、key/value ヘッド数、ヘッドの次元数、1 要素あたりのバイト数を 2 倍し、その値を掛け合わせます。これで 1 トークンあたりのバイト数が求まります。次に、コンテキスト長と同時実行するリクエスト数を掛けます。レイヤー数とヘッド数はモデルの config.json から確認します。f16 または bf16 では、1 要素あたり 2 バイトを使用します。q8_0 キャッシュはその約半分、q4_0 は約 4 分の 1 です。
プロンプトキャッシュを使うと、自分のサーバーに必要なメモリは減りますか?
プロバイダーのプロンプトキャッシュは、保存先がプロバイダー側にあるため、自分のハードウェアには影響しません。ローカルで同等の機能を提供するのが prefix caching で、vLLM と llama.cpp server の両方が対応しています。共有プレフィックスについて計算済みの key ベクトルと value ベクトルを再利用するため、prefill の計算量を減らし、最初のトークンが返るまでの時間を短縮できます。vLLM では共有ブロックを複製せずに再利用するため、メモリ使用量も改善します。ただし、どちらの機能も現在処理中のトークンに必要なキャッシュ容量を減らすものではありません。そのため、必要な最小容量はコンテキスト長と同時実行数によって決まります。
1 回しか送信しないプロンプトをキャッシュする価値はありますか?
いいえ。キャッシュへの書き込みは通常の入力より高く、2026 年 8 月時点で 5 分間のオプションでは基本料金の 1.25 倍です。そのため、ウィンドウ内に再送しないプレフィックスをキャッシュすると、単純に損失になります。同じプレフィックスを繰り返し使用する場合は有効です。たとえば、長いシステムプロンプトや、複数の質問を行う文書などです。API response の cache_read_input_tokens を確認し、書き込み料金を支払うだけでなく、実際にキャッシュがヒットしていることを確認してください。