AIFCC
記事一覧へ
claude-setupagent-opsharness-design

LLMのprompt caching完全解説

Avi Chawla@_avichawla
64797
LLMにおけるprompt cachingの完全解説 AIエージェントがステップを踏むたびに、会話履歴全体をLLMに送り返している。システム指示、ツール定義、3ターン前に処理済みのプロジェクトコンテキストもすべて含めて。毎回、再読み込み・再処理・再課金される。 長時間稼働するエージェントワークフローにおいて、この冗長な計算がAIインフラ全体で最も高コストな項目になることが多い。 20,000トークンのシステムプロンプトが50ターンにわたって実行されると、100万トークン分の冗長計算が定価で課金され、新たな価値はゼロ。そのコストはすべてのユーザー、すべてのセッションにわたって積み重なる。 解決策はprompt cachingだ。ただし使いこなすには、内部で何が起きているかを理解する必要がある。 ## 静的コンテキストと動的コンテキスト プロンプトを最適化する前に、何が変化し何が変化しないかを理解する必要がある。 すべてのエージェントリクエストには、根本的に異なる2つの部分がある: - ターンをまたいで同一のままの**静的プレフィックス**:システム指示、ツール定義、プロジェクトコンテキスト、行動ガイドライン - ターンごとに成長する**動的サフィックス**:ユーザーメッセージ、アシスタント応答、ツール出力、ターミナルの観察結果 この分割がprompt cachingを可能にする。インフラは静的プレフィックスの数学的状態を保存するため、同じプレフィックスを共有する後続リクエストは計算を丸ごとスキップして、メモリから読み込める。 これを内面化すると、この記事のすべての設計判断が自明になる。 ## KVキャッシュはどう機能するのか? キャッシングが非常に効果的な理由を理解するには、トランスフォーマーがプロンプトを処理する際に実際に何をしているかを知る必要がある。 すべてのLLM推論リクエストには2つのフェーズがある: **プレフィルフェーズ**:入力プロンプト全体を処理する。コンテキスト内のすべてのトークンに対して密な行列乗算を実行し、モデルの内部表現を構築する。これは計算負荷が高く高コストだ。 **デコードフェーズ**:トークンを1つずつ生成する。新しいトークンがシーケンスに追加されるたびに、モデルが次を予測する。このフェーズは重い計算よりも過去の状態を読み込むことが多いため、メモリバウンドだ。 プレフィルフェーズでは、トランスフォーマーが各トークンに対してQuery、Key、Valueの3つのベクトルを計算する。アテンション機構はこれらを使って各トークンが他のすべてのトークンとどう関連するかを決定する。特定のトークンのKeyとValueベクトルは、そのトークン以前のトークンのみに依存し、一度計算されると変わることはない。 キャッシングなしでは、これらのKeyとValueのテンソルはリクエストごとに破棄され、次のリクエストが最初から再計算する。20,000トークンのプレフィックスなら、再度行う必要のなかった20,000トークン分のアテンション計算だ。 KVキャッシュはこれらのテンソルをトークンシーケンスの暗号ハッシュでインデックス付けして推論サーバーに永続化することで解決する。同じプレフィックスを持つ新しいリクエストが来ると、ハッシュが一致し、テンソルがメモリから読み込まれ、それらのトークンのプレフィルフェーズの計算は完全にスキップされる。 これにより計算複雑度が生成トークンあたりO(n²)からO(n)に低下する。20,000トークンのプレフィックスが50ターンにわたって繰り返されると、これは莫大な削減だ。 ## コスト構造 この価格構造が設計判断を決定的に重要なものにする。 キャッシュ読み込みは基本入力価格の0.1倍、つまりキャッシュされたトークンに90%の割引。キャッシュ書き込みは1.25倍、KVテンソルの保存に25%のプレミアム。1時間の拡張キャッシングは2.0倍。 この計算はキャッシュヒット率が高く保たれる場合のみ成立する。それがどんな見た目かの最高の実稼働例がClaude Codeだ。 ## 30分のコーディングセッション with Claude Code Claude Codeはひとつの目的だけに設計されている:キャッシュをホットに保つ。 実際の30分コーディングセッションが課金の観点からどう見えるか: **0分**:Claude CodeはシステムプロンプトとツールとCLAUDE.mdファイルを読み込む。このペイロードは20,000トークンを超え、すべてのトークンが新規なので、セッション全体で最もコストがかかる瞬間だ。ただしこのコストは一度だけ払う。 **1〜5分**:指示を出すと、Claude CodeはExploreサブエージェントをコードベースのナビゲート、ファイルオープン、grepコマンドの実行に派遣する。これらはすべて動的サフィックスに追加される。しかし20,000トークンの静的プレフィックスは今や$3.00/MTokではなく$0.30/MTokでキャッシュから読み込まれている。 **6〜15分**:Planサブエージェントは生の結果ではなく要約されたブリーフを受け取る。生の出力を渡すと動的サフィックスが不必要に膨らむからだ。実装計画を作成し、承認して、Claude Codeが変更を開始する。毎ターン静的プレフィックスをキャッシュから読み込み、ヒット率は90%を超え、各アクセスがTTLをリセットしてキャッシュをホットに保つ。 **16〜25分**:変更を要求すると、さらなるツール呼び出し、ターミナル出力、動的サフィックスにコンテキストが蓄積する。セッションはすでに数十万トークンを処理したが、毎ターン20,000トークンの基盤をキャッシュから読み込んでいる。 **28分**:ターミナルで/costを実行する。キャッシュなしなら、Sonnet 4.5レートで200万トークンは$6.00。92%の効率でキャッシュが動作したことで、184万トークンがキャッシュ読み込みとなり、合計コストは$1.15。1タスクで81%の削減だ。 これがホットキャッシュの見た目だ。静的基盤は一度払えば、その後は無料で読める。動的テールだけが課金される。 ## ハッシュベースキャッシングの脆弱性 prompt cachingで最も直感に反することがある: 「1 + 2 = 3」は機能するが「2 + 1」はキャッシュミスだ。 インフラは最初からトークンシーケンス全体をハッシュする。そのシーケンスの何かが変わると、2つの要素の順序だけが変わっても、ハッシュが変わりプレフィックス全体が定価で再計算される。 これは些細な実装詳細ではない。Claude Codeのすべての設計判断が対処するように設計された中心的制約だ。 実稼働でキャッシュを破壊した実例: - システムプロンプトに注入されたタイムスタンプがリクエストごとにユニークなハッシュを生成した - リクエスト間でツールスキーマのキーを異なる方法でソートするJSONシリアライザーがプレフィックスを無効化した - セッション途中でパラメータが更新されたAgentToolが20,000トークンのキャッシュ全体を消去した ここから3つのルールが導かれる: 1. **セッション中にツールを変更しない**:ツール定義はキャッシュされたプレフィックスの一部なので、ツールの追加・削除は下流のすべてを無効化する 2. **セッション中にモデルを切り替えない**:キャッシュはモデル固有なので、会話の途中で安価なモデルに切り替えるとキャッシュ全体の再構築が必要になる 3. **状態更新のためにプレフィックスを変更しない**:システムプロンプトを編集する代わりに、Claude Codeはプレフィックスを手つかずのままにするために次のユーザーメッセージにリマインダータグを追加する ## 自分のエージェントへの応用 同じルールは、Claude Codeを使う場合でも自分でゼロからエージェントを構築する場合でも適用される。 プロンプトをこの順序で構成する: 1. トップにシステム指示と行動ルール。セッション中に変更しない 2. すべてのツール定義を最初にロード。追加・削除しない 3. 次に取得したコンテキストと参照ドキュメント。セッション期間中安定させる 4. 一番下に会話履歴とツール出力。これが動的サフィックスだ AnthropicのAPIでauto-cachingを有効にすると、会話が成長するにつれてキャッシュのブレークポイントが自動的に進む。なければトークン境界を手動で追跡する必要があり、間違った境界はキャッシュを完全に見逃すことを意味する。 コンテキスト制限に近づいたときのコンテキスト圧縮には、キャッシュセーフのフォーキングを使う。同じシステムプロンプト、ツール、会話履歴を保ち、圧縮指示を新しいメッセージとして追加する。キャッシュされたプレフィックスが再利用され、課金される新しいトークンは圧縮指示のみだ。 キャッシングが機能しているか確認するには、すべてのAPIレスポンスで次の3つのフィールドを監視する: - `cache_creation_input_tokens`:キャッシュに書き込まれたトークン - `cache_read_input_tokens`:キャッシュから提供されたトークン - `input_tokens`:キャッシュなしで処理されたトークン キャッシュ効率は `cache_read_input_tokens / (cache_read_input_tokens + cache_creation_input_tokens)` だ。稼働率と同じように追跡する。 ## まとめ prompt cachingはオンにする機能ではない。設計の規律だ。 コアのアイデアはシンプル:静的コンテンツが上部に、動的コンテンツが下部で成長するようにプロンプトを構成する。インフラがプレフィックスをハッシュし、KVテンソルを保存し、後続の読み込みごとに90%の割引を与える。 しかし規律は詳細にある。システムプロンプトにタイムスタンプを注入しない、ツール定義をシャッフルしない、セッション中にモデルを切り替えない、キャッシュのブレークポイントより上流の何も変更しない。 Claude Codeはこれが大規模にどう見えるかを示している。92%のキャッシュヒット率と81%のコスト削減。エージェントを構築していてprompt cachingを中心に設計していないなら、利益のほとんどをテーブルに置いてきていることになる。
原文を表示 / Show original
A case study on how Claude achieves 92% cache hit-rate Every time an AI agent takes a step, it sends the entire conversation history back to the LLM. That includes the system instructions, the tool definitions, and the project context it already processed three turns ago. All of it gets re-read, re-processed, and re-billed on every single turn. For long-running agentic workflows, this redundant computation is often the most expensive line item in your entire AI infrastructure. A system prompt with 20,000 tokens running over 50 turns means 1 million tokens of redundant computation billed at full price, producing zero new value. And that cost compounds across every user and every session. The fix is prompt caching. But to use it well, you need to understand what’s actually happening under the hood. Static vs. Dynamic context Before you can optimize a prompt, you need to understand what changes and what doesn’t. Every agent request has two fundamentally different parts: The static prefix that stays identical across turns: system instructions, tool definitions, project context, and behavioral guidelines. The dynamic suffix that grows with every turn: user messages, assistant responses, tool outputs, and terminal observations. This split is what makes prompt caching possible. The infrastructure stores the mathematical state of the static prefix so that subsequent requests sharing that exact prefix can skip the computation entirely and read from memory. Once you internalize this, every architectural decision in this article becomes obvious. How does the KV Cache work? To understand why caching is so effective, you need to know what the transformer actually does when it processes your prompt. Every LLM inference request has two phases: The prefill phase handles the entire input prompt. It runs dense matrix multiplications across all tokens in context to build the model’s internal representation. This is compute-bound and expensive. The decode phase generates tokens one at a time. Each new token gets added to the sequence, and the model predicts the next one. This phase is memory-bound because it mostly reads the historical state rather than doing heavy computation. During the prefill phase, the transformer computes three vectors for each token: a Query, a Key, and a Value. The attention mechanism uses these to determine how each token relates to every other token. The Key and Value vectors for any given token depend only on the tokens before it, and once computed, they never change. GIF Without caching, these Key and Value tensors get thrown away after every request, and the next request recomputes them from scratch. For a 20,000-token prefix, that’s 20,000 tokens worth of attention computation that didn’t need to happen again. The KV cache fixes this by persisting those tensors on the inference servers, indexed by a cryptographic hash of the token sequence. When a new request comes in with the same prefix, the hash matches, the tensors are loaded from memory, and the prefill computation for those tokens is skipped entirely. This drops computational complexity from O(n²) per generated token to O(n). And for a 20,000-token prefix repeated across 50 turns, that's an enormous reduction. The Economics The pricing structure is what makes this architectural decision so consequential. Cache reads cost 0.1x the base input price, which is a 90% discount on every cached token. Cache writes cost 1.25x, a 25% premium to store the KV tensors. Extended one-hour caching costs 2.0x. Here’s what this looks like across Anthropic’s Claude models: This math only works if the cache hit rate stays high. The best production example of what that looks like is Claude Code. A 30-minute coding session with Claude Code Claude Code is built entirely around one objective: keep the cache hot. Here’s what a real 30-minute coding session looks like from a billing perspective. Minute 0: Claude Code loads its system prompt, tool definitions, and the project’s CLAUDE.md file. This payload exceeds 20,000 tokens, and since every token is new, this is the most expensive moment of the entire session. But you only pay this cost once. Minutes 1 to 5: You start giving instructions, and Claude Code dispatches its Explore Subagent to navigate the codebase, open files, and run grep commands. All of this gets appended to the dynamic suffix. But the 20,000-token static prefix is now reading from cache at $0.30/MTok instead of $3.00/MTok. Minutes 6 to 15: The Plan Subagent receives a summarized brief rather than the raw results, because passing raw output would bloat the dynamic suffix unnecessarily. It produces an implementation plan, you approve it, and Claude Code starts making changes. Every turn reads the static prefix from cache, the hit rate climbs past 90%, and each access resets the TTL to keep the cache warm. Minutes 16 to 25: You request changes, which means more tool calls, more terminal output, and more context accumulating in the dynamic suffix. By now the session has processed hundreds of thousands of tokens, but every single turn has read the 20,000-token foundation from cache. Minute 28: You run /cost in the terminal. Without caching, 2 million tokens at the Sonnet 4.5 rate would cost $6.00. With the cache running at 92% efficiency, 1.84 million tokens were cache reads, bringing the total cost to $1.15. That’s an 81% reduction on a single task. This is how a hot cache looks. You have to pay for the static foundation once, and then you can read it for free. The dynamic tail is the only thing that is ever charged. The fragility of hash-based caching Here’s the most counterintuitive thing about prompt caching: “1 + 2 = 3” works but “2 + 1” is a cache miss. The infrastructure hashes the full token sequence from the beginning. If anything in that sequence changes, even just the order of two elements, the hash changes and the entire prefix gets recomputed at full price. This isn’t a minor implementation detail. It’s the central constraint that every engineering decision in Claude Code is designed around. Here are real examples of what has broken caches in production: A timestamp injected into the system prompt created a unique hash on every request. A JSON serializer that sorted tool schema keys differently between requests invalidated the prefix. An AgentTool whose parameters were updated mid-session wiped the entire 20,000-token cache. Three rules follow from this: Don’t modify tools during a session. The tool definitions are part of the cached prefix, so adding or removing a tool invalidates everything downstream. Never switch models mid-session. Caches are model-specific, which means switching to a cheaper model mid-conversation requires rebuilding the entire cache from scratch. Never mutate the prefix to update state. Instead of editing the system prompt, Claude Code appends a reminder tag to the next user message so that the prefix stays untouched. Applying this to your own Agents The same rules apply whether you’re using Claude Code or building your own agent from scratch. Structure your prompts in this order: System instructions and behavioral rules at the top. Don’t change them mid-session. Load all tool definitions upfront. Don’t add or remove them. Retrieved context and reference documents next. Keep them stable for the session duration. Conversation history and tool outputs at the bottom. This is your dynamic suffix. With auto-caching enabled on the Anthropic API, the cache breakpoint advances automatically as the conversation grows. Without it, you’d need to manually track token boundaries, and a wrong boundary means missing the cache entirely. For context compaction when you’re approaching the context limit, use cache-safe forking. Keep the same system prompt, tools, and conversation history, then append the compaction instruction as a new message. The cached prefix gets reused, and the only new tokens billed are the compaction instruction itself. To verify your caching is working, monitor these three fields in every API response: cache_creation_input_tokens are the tokens written to cache. cache_read_input_tokens are the tokens served from cache. input_tokens are the tokens processed without caching. Your cache efficiency is cache_read_input_tokens / (cache_read_input_tokens + cache_creation_input_tokens). Track it the same way you track uptime. Key takeaways Prompt caching isn’t a feature you toggle on. It’s an architectural discipline you design around. The core idea is simple: structure your prompts so the static content sits at the top and the dynamic content grows at the bottom. The infrastructure hashes the prefix, stores the KV tensors, and gives you a 90% discount on every subsequent read. But the discipline is in the details. Don’t inject timestamps into system prompts, don’t shuffle tool definitions, don’t switch models mid-session, and don’t mutate anything upstream of the cache breakpoint. Claude Code demonstrates what this looks like at scale, with a 92% cache hit rate and an 81% cost reduction. If you’re building agents and not designing around prompt caching, you’re leaving most of your margin on the table.​ That's a wrap! If you enjoyed this tutorial: Find me → @_avichawla Every day, I share tutorials and insights on DS, ML, LLMs, and RAGs.

AIFCC — AI Fluent CxO Club

読み書きそろばん、AI。経営者が AI を自分で動かせるようになるコミュニティ。

LLMのprompt caching完全解説 | AIFCC