# コンテキストウィンドウとプロンプトキャッシュ：前方一致とコストの式

> 要求ごとに文脈全体を送り直すエージェントの入力コストを、プロンプトキャッシュの公開仕様（前方一致・書き込みと読み取りの倍率・有効期間）から模型として定式化し、位置 j の変更が j 以降を無効にすること、k ターンの合計コストの閉じた式、損益分岐、有効期間とモデル切り替えのコストを証明する。
> https://rikai.mugen-giken.com/computer-science/claude-code-internals/context-window-and-prompt-caching

## 0. この記事の要点

AI のエージェントに長い作業を任せると、返事を 1 回もらうたびに、それまでのやり取りの全部が毎回送り直されます。10 回目の質問には、1 回目から 9 回目までの内容も添えられるわけです。このとき、先頭が前回とまったく同じ部分を、安い料金で読み直す仕組みがあります。この記事では、その料金の規則を小さな式にして、どんな使い方だと得になり、どんな変更をすると高くつくのかを、計算で確かめます。

- Claude API は状態を持ちません。エージェントは要求のたびに、ツール定義（モデルが使える道具の説明）・システムプロンプト・それまでのメッセージ列の全体を送り直します。[第 1 章](/computer-science/claude-code-internals/agent-loop)で見たとおり、入力の合計はターン数の 2 次で増えます。
- **プロンプトキャッシュ**は、要求の先頭からの部分（プレフィックス）が、最近処理した内容と完全に一致するとき、その部分を安い単価で読み直す仕組みです。料金は、基準の入力単価を 1 として、キャッシュへの書き込みが $w \gt 1$ 倍、読み取りが $r \lt 1$ 倍です。2026-10 時点の公式ドキュメントでは、5 分の有効期間の書き込みが 1.25 倍、1 時間が 2 倍、読み取りは標準で 0.1 倍です。
- 一致は**前方一致**です。要求の位置 $j$ の内容が変わると、$j$ 以降はキャッシュから読めません。$j$ より前は影響を受けません。要求がツール定義・システムプロンプト・メッセージ列の順に並ぶので、ツール定義の変更は全体を無効にし、末尾への追記は何も無効にしません。
- 固定部分 $s$ とターンごとの追記 $d$ の会話では、$k$ 回目の要求のコストはキャッシュなしで $s + kd$、キャッシュありで $r(s + (k-1)d) + wd$ です。合計はどちらも 2 次ですが、2 次の係数が $r$ 倍になります。
- 長さ $L$ のプレフィックスを 1 回書いて $n$ 回読むと得になるのは $n \gt (w-1)/(1-r)$ のときです。上の倍率では、5 分の有効期間なら 1 回、1 時間なら 2 回読めば元が取れます。
- キャッシュは料金と遅延を下げますが、**コンテキストウィンドウの消費は変えません**。キャッシュされたプレフィックスもウィンドウを占めます。ウィンドウの上限そのものへの対処は[次章](/computer-science/claude-code-internals/compaction-memory-subagents)で扱います。

<Aside type="tip" title="この記事で使う事前知識">

- **プレフィックス**: 列の先頭から数えて、ある長さまでを切り出した部分。→ 2 節の定義で改めて述べます。
- **KV キャッシュ**: 文章を 1 トークンずつ生成するとき、処理済みのトークンの内部の計算結果をとっておいて使い回す仕組み。→ [推論](/computer-science/llm-architecture/inference-and-sampling)
- **因果マスク**: 各位置の計算が、その位置以前のトークンだけに依存するようにする制限。→ [因果マスク](/computer-science/llm-architecture/self-attention#def-attention)
- **確率変数と期待値**: 試行の結果によって値が決まる量と、その平均。5 節の最後で使います。→ [確率変数](/mathematics/probability/random-variables#def-random-variable)、[期待値](/mathematics/probability/random-variables#def-expectation)
- **エージェントループ**: モデルの呼び出しとツールの実行を繰り返す仕組み。送る入力の合計がターン数の 2 次で増えることを前提にします。→ [エージェントループ](/computer-science/claude-code-internals/agent-loop)

</Aside>

倍率・有効期間・モデル名・ウィンドウの大きさは、2026-10-10 に確認した公式ドキュメントの値です。料金は変わるので、使う前に出典のページで確かめてください。命題では倍率を記号 $w$・$r$ のまま扱います。

## 1. 動機

第 1 章の <Ref to="computer-science/claude-code-internals/agent-loop#prop-context-growth" /> は、圧縮をしないループで、$k$ 回目のモデル呼び出しの入力トークン数が $k$ の 1 次、$K$ 回の合計が $K$ の 2 次で増えることを示しました。同じ履歴を毎回送り直すからです。100 ターンの作業の最後の要求は、最初の 99 ターンの内容をすべて含みます。そのほとんどは、1 つ前の要求と 1 トークンも違いません。

送り直しが避けられないのは、API が状態を持たないからです。モデルは要求と要求のあいだで何も覚えていません。そこで、「同じ先頭部分をもう一度処理する」ことの料金と時間を下げる仕組みが要ります。それがプロンプトキャッシュです。

なぜ「先頭部分」なのかは、モデルの構造から来ます。自己回帰の言語モデルでは、[因果マスク](/computer-science/llm-architecture/self-attention#def-attention)によって、位置 $i$ の内部の状態は位置 $i$ 以前のトークンだけで決まります（<Ref to="computer-science/llm-architecture/self-attention#thm-causal-mask" />）。したがって、2 つの入力の先頭の $j$ トークンが同じなら、その $j$ 位置分の計算結果は同じで、使い回せます（<Ref to="computer-science/llm-architecture/inference-and-sampling#thm-kv-cache-correct" />、<Ref to="computer-science/llm-architecture/inference-and-sampling#thm-kv-cache-cost" />）。途中の 1 トークンが違えば、それより後ろの状態はすべて変わります。「前方一致でなければ使い回せない」は、料金の規則である前に、計算の性質です。この記事は、API が公開している料金と一致の規則を出発点にし、サーバの内部でどう実装されているかには立ち入りません。

エージェントを作る側・使う側にとって、この規則は設計の制約になります。要求の中で、何を前に置き、何を後ろに置くか。会話の途中で何を変えると高くつくか。休憩のあとの最初の要求はなぜ遅いのか。どれも、前方一致という 1 つの性質から計算できます。

## 2. コンテキストウィンドウと要求の構成

<Definition id="def-context-window" title="コンテキストウィンドウ">
モデルごとに定まる正の整数 $W$ を**コンテキストウィンドウ**の大きさという。1 回の要求で、モデルに渡す入力のトークン数 $n$ と、モデルがその要求に対して生成する出力のトークン数 $o$ は、$n + o \le W$ を満たさなければならない。
</Definition>

公式ドキュメントは、コンテキストウィンドウを「応答を生成するときにモデルが参照できるすべての文章で、応答自身を含む」と説明し、学習データとは別の、モデルの作業記憶に当たるものと述べています。要求の中のすべて（システムプロンプト、`messages` のすべてのメッセージ、ツール定義）と、そのターンに生成する出力（拡張思考、つまり答える前にモデルが考えを書き出す機能の出力を含む）が数えられます。2026-10 時点の公式ドキュメントでは、ウィンドウの大きさは、列挙されている新しいモデル（Claude Opus 5.5、Claude Sonnet 5.5 など）で 100 万トークン、それ以外のモデルで 20 万トークンです。命題では $W$ のまま扱います。

<Definition id="def-request" title="要求とプレフィックス">
トークンの集合を $\mathcal{V}$ とする。**要求**は、モデルの名前 $\mu$ と、トークン列 $x = (x_1, \ldots, x_n) \in \mathcal{V}^n$ の組である。$x$ は、ツール定義の部分 $x^{\mathrm{tools}}$、システムプロンプトの部分 $x^{\mathrm{sys}}$、メッセージ列の部分 $x^{\mathrm{msg}}$ をこの順につないだ列
$$
x = x^{\mathrm{tools}} \cdot x^{\mathrm{sys}} \cdot x^{\mathrm{msg}}
$$
である。$0 \le j \le n$ について、先頭の $j$ トークン $x[1..j] = (x_1, \ldots, x_j)$ を $x$ の長さ $j$ の**プレフィックス**という。列 $p$ が $x$ のプレフィックスであることを $p \sqsubseteq x$ と書く。
</Definition>

「ツール定義・システムプロンプト・メッセージ列の順」は、API のドキュメントが、キャッシュのプレフィックスが作られる順序として明記しているものです。実物の要求は構造を持った JSON で、モデルに渡る前にトークン列に直されます。模型では、直したあとの列だけを見ます。

**状態を持たない API。** 第 1 章のループで、モデル $M$ は「メッセージ列を受け取って応答を返す写像」でした。実物でもそのとおりで、$k$ 回目の要求は、$k - 1$ 回目の要求の内容に、前回の応答とツール結果を足したものです。Claude Code のドキュメントは、メッセージを送るたびに新しい API 要求が作られ、モデルは要求のあいだで何も覚えていないので、文脈の全体（システムプロンプト、プロジェクトの文脈、過去のすべてのメッセージとツール結果、新しいメッセージ）を送り直す、と説明しています。新しい内容は末尾に足されるので、各要求の大部分は 1 つ前の要求と同じです。

出典（確認日 2026-10-10）: [Context windows](https://platform.claude.com/docs/en/build-with-claude/context-windows)、[Prompt caching](https://platform.claude.com/docs/en/build-with-claude/prompt-caching)、[How Claude Code uses prompt caching](https://code.claude.com/docs/en/prompt-caching)。

## 3. プロンプトキャッシュ：仕様と模型

### 3.1. 公開されている仕様

API のドキュメントが述べるプロンプトキャッシュの規則を、2026-10 時点の値とともに整理します。この小節は事実の引用で、命題ではありません。

**印とプレフィックス。** 要求の中のブロックに `cache_control` という印を付けると、その位置が**ブレークポイント**になります。キャッシュの対象は、要求の先頭（ツール定義・システムプロンプト・メッセージ列の順）から、印の付いたブロックまで（そのブロックを含む）の全体です。命中するには、そこまでの内容が完全に一致していなければなりません。明示的なブレークポイントは 1 つの要求に 4 つまで置けます。要求の最上位に印を 1 つ置き、最後のキャッシュ可能なブロックに自動でブレークポイントを置かせる方法（自動キャッシュ）もあります。

**さかのぼる範囲。** ブレークポイントの位置そのものが命中しなくても、API はそこから手前へさかのぼって、過去に書かれた項目を探します。調べる位置は、ブレークポイントごとに 20 か所まで（ブレークポイント自身を 1 つ目に数える）です。

**有効期間。** キャッシュの項目の有効期間（TTL）は、既定で 5 分です。追加の料金で 1 時間も選べます（`"cache_control": {"type": "ephemeral", "ttl": "1h"}`）。キャッシュされた内容が使われるたびに、有効期間は追加料金なしで更新されます。有効期間は、その項目を書いた、または読んだ要求の**開始**の時点から測られます。

**料金。** 基準の入力単価に対する倍率は次のとおりです。

| 操作 | 倍率（基準の入力単価 = 1） |
|---|---|
| 5 分の有効期間での書き込み | 1.25 |
| 1 時間の有効期間での書き込み | 2 |
| 読み取り（命中と更新） | 0.1（Claude Opus 5.5 と Claude Sonnet 5.5 では 0.05、Claude Fable 5.1 と Claude Mythos 5.1 では 0.025） |

**最小の長さ。** キャッシュできるプレフィックスには、モデルごとに最小のトークン数があります（2026-10 時点の表では、モデルによって 512・1,024・2,048・4,096 のいずれか）。それより短いプレフィックスは、印を付けてもキャッシュされず、エラーにもなりません。

**使用量の報告。** 応答の `usage` には 3 つの欄があります。`cache_read_input_tokens` はキャッシュから読んだトークン数、`cache_creation_input_tokens` はキャッシュに書いたトークン数、`input_tokens` はどちらでもない入力（最後のブレークポイントより後ろ）のトークン数です。入力の合計は 3 つの和です。

**分離。** キャッシュは組織のあいだで共有されません（提供の経路によっては、組織の中のワークスペースごとにも分かれます）。Claude Code のドキュメントは、モデルごとに別のキャッシュがあり、内容が同じでもモデルを切り替えると全体が再計算される、と述べています。

出典（確認日 2026-10-10）: [Prompt caching](https://platform.claude.com/docs/en/build-with-claude/prompt-caching)、[Pricing](https://platform.claude.com/docs/en/about-claude/pricing)（"Prompt caching" の節）、[How Claude Code uses prompt caching](https://code.claude.com/docs/en/prompt-caching)。

### 3.2. 模型

ここでは、3.1 の仕様を計算できる形にします。キャッシュの中身を「どの先頭部分が、いつまで有効か」を書いた対応表と考えるだけです。以下の定義の「部分写像」は、表に載っていない項目は単に未登録のままにしておける対応、という意味です。

<Definition id="def-prompt-cache-model" title="プロンプトキャッシュの模型">
有効期間 $\tau \gt 0$、書き込みの倍率 $w \gt 1$、読み取りの倍率 $r$（$0 \le r \lt 1$）を固定する。**キャッシュの状態**は、モデルの名前 $\mu$ とトークン列 $p$ の組（**項目**）から、期限の時刻への部分写像 $C$ である。項目 $(\mu, p)$ が時刻 $t$ に**生きている**とは、$C(\mu, p)$ が定義されていて $C(\mu, p) \gt t$ であることをいう。

時刻 $t$ に、モデル $\mu$、トークン列 $x$（長さ $n$）、ブレークポイントの位置 $b$（$1 \le b \le n$）の要求を処理すると、次のことが起こるとする。

1. **命中の長さ** $\ell$ を、時刻 $t$ に生きている項目 $(\mu, p)$ で、$p \sqsubseteq x$ かつ $|p| \le b$ を満たすものの長さ $|p|$ の最大値と定める。そのような項目が無ければ $\ell = 0$ とする。
2. **使用量**を、読み取り $\ell$、書き込み $b - \ell$、通常の入力 $n - b$ と定める。
3. **コスト**（基準の入力単価を 1 とした入力の料金）を $r\ell + w(b - \ell) + (n - b)$ と定める。
4. 項目 $(\mu, x[1..b])$ の期限を $t + \tau$ にする（新しく書くか、更新する）。$\ell \gt 0$ のとき、命中した項目 $(\mu, x[1..\ell])$ の期限も $t + \tau$ にする。

キャッシュを使わない要求のコストは $n$ とする。
</Definition>

<Remark id="rem-cache-model-assumptions" title="模型に入れた仮定">
この模型は、3.1 の仕様を、コストの計算に必要な範囲で単純にしたものです。違いを挙げます。

- **さかのぼる範囲を制限していません。** 模型は、$b$ 以下の長さの生きている項目をすべて見つけるとしています。実物は、ブレークポイントごとに 20 か所までしか調べません。1 回の追記が多数のブロックにまたがる場合は、実物では命中しないことがあり、そのときは途中にもブレークポイントを置く必要があります。
- **ブレークポイントを 1 つにしています。** 複数のブレークポイントは、それぞれの位置までのプレフィックスを項目として書く、という形で模型に足せます（7 節で、層ごとの印として使います）。
- **最小の長さを無視しています。** プレフィックスはキャッシュできる最小の長さ以上だと仮定します。
- **出力の料金を数えていません。** 出力トークンの料金はキャッシュの有無で変わらないので、差の議論には影響しません。
- **コストは料金です。** 遅延（応答が始まるまでの時間）も同じ向きに動きますが、公式ドキュメントに式として書ける規則が無いので、命題にはしません。
</Remark>

### 3.3. 前方一致と無効化

<Proposition id="prop-prefix-invalidation" title="位置 j の変更は j 以降を無効にし、j より前は影響を受けない">
トークン列 $x$ と $x'$ が、ちょうど位置 $j$ で初めて食い違うとする。すなわち、$x[1..j-1] = x'[1..j-1]$ であり、かつ、「$x$ と $x'$ の両方が長さ $j$ 以上で $x_j \ne x'_j$」または「一方の長さがちょうど $j - 1$ で他方の長さが $j$ 以上」である。時刻 $t$ に生きているモデル $\mu$ の項目が、すべて $x$ のプレフィックスであるとする。このとき、時刻 $t$ に要求 $(\mu, x', b')$ を処理すると次が成り立つ。

1. 命中の長さは $\ell \le j - 1$ である。したがって、$x'$ の位置 $j$ 以降のトークンはキャッシュから読まれない。
2. $\ell$ は、生きている項目のうち長さが $\min(j - 1, b')$ 以下のものの長さの最大値に等しい。すなわち、$j$ より前の項目は、$x$ が $x'$ に変わっても命中の候補のまま残る。
</Proposition>

直感的には、途中の 1 トークンが違えば、そこから先は別の文章になるので、キャッシュにある先頭部分が新しい要求の先頭部分でもあるのは、食い違いより手前で終わっているものだけ、ということです。証明は、この同値を先に示し、そこから 1 と 2 を読み取ります。

<Proof of="prop-prefix-invalidation">
生きている項目 $(\mu, p)$ をとります。仮定から $p \sqsubseteq x$ です。

まず、「$p \sqsubseteq x'$ $\iff$ $|p| \le j - 1$」を示します。$|p| \le j - 1$ のとき、$p = x[1..|p|]$ で、$x[1..j-1] = x'[1..j-1]$ から $x[1..|p|] = x'[1..|p|]$ なので、$p \sqsubseteq x'$ です。逆に $|p| \ge j$ とします。$p \sqsubseteq x$ なので $x$ の長さは $j$ 以上で、$p_j = x_j$ です。もし $p \sqsubseteq x'$ なら、$x'$ の長さも $j$ 以上で $p_j = x'_j$、したがって $x_j = x'_j$ となります。これは、食い違いの 2 つの場合のどちらにも反します（1 つ目は $x_j \ne x'_j$ で、2 つ目は一方の長さが $j - 1$ です）。よって $p \not\sqsubseteq x'$ です。

(1) 命中の長さ $\ell$ は、$p \sqsubseteq x'$ かつ $|p| \le b'$ を満たす生きている項目の長さの最大値（無ければ $0$）です。いま示したことから、そのような項目は $|p| \le j - 1$ を満たすので、$\ell \le j - 1$ です。読み取られるのは $x'[1..\ell]$ だけなので、位置 $j$ 以降は読まれません。

(2) 同じ同値から、条件「$p \sqsubseteq x'$ かつ $|p| \le b'$」は「$|p| \le j - 1$ かつ $|p| \le b'$」、つまり「$|p| \le \min(j-1, b')$」と同値です。
</Proof>

Claude Code のドキュメントは、この性質を、一致は厳密で、プレフィックスのどこかが変わるとそれより後ろがすべて再計算され、ファイルごと・区画ごとのキャッシュは無い、と書いています。

<Corollary id="cor-layer-order" title="層の順序の帰結">
要求が $x = x^{\mathrm{tools}} \cdot x^{\mathrm{sys}} \cdot x^{\mathrm{msg}}$ の形で、生きている項目がすべて $x$ のプレフィックスであるとする。

1. $x'$ が $x$ とツール定義の部分の中（位置 $j \le |x^{\mathrm{tools}}|$）で初めて食い違うならば、$x'$ の要求の命中の長さは $|x^{\mathrm{tools}}|$ 未満である。特に、システムプロンプトの部分とメッセージ列の部分は、1 トークンもキャッシュから読まれない。
2. $x' = x \cdot y$（末尾への追記、$|y| \ge 1$）ならば、$x$ のプレフィックスである生きている項目は、どれも $x'$ の要求の命中の候補のままである。特に、項目 $(\mu, x)$ が生きていて $b' \ge |x|$ ならば、命中の長さは $|x|$ である。
</Corollary>

<Proof of="cor-layer-order">
(1) <Ref to="prop-prefix-invalidation" /> の 1 から $\ell \le j - 1 \lt |x^{\mathrm{tools}}|$ です。システムプロンプトの部分とメッセージ列の部分の位置は $|x^{\mathrm{tools}}|$ より大きいので、読まれる範囲 $x'[1..\ell]$ に入りません。

(2) $x$ と $x'$ が初めて食い違う位置は $j = |x| + 1$ です（$x'$ の長さは $|x| + 1$ 以上で、$x$ の長さはちょうど $j - 1$）。<Ref to="prop-prefix-invalidation" /> の 2 から、命中の長さは、長さが $\min(|x|, b')$ 以下の生きている項目の長さの最大値です。$x$ のプレフィックスの長さは $|x|$ 以下なので、$b'$ 以下の長さの項目はすべて候補です。$(\mu, x)$ が生きていて $b' \ge |x|$ なら、最大値は $|x|$ です。
</Proof>

これは、コンテナイメージのビルドキャッシュの前置性（<Ref to="computer-science/software-engineering/containers-and-kubernetes#prop-cache-prefix" />）と同じ構造です。あちらでは、命令の列のうちキャッシュに当たるものが先頭からの連続した部分になり、変わった命令より後ろはすべて再実行されました。だから「変わりにくい命令を前に、変わりやすい命令を後ろに」書きます。プロンプトでも同じで、**変わりにくいものを前に、変わりやすいものを後ろに**置きます。ビルドシステムには、入力が変わっても出力が同じなら下流を再実行しない早期打ち切り（<Ref to="computer-science/software-design-testing/build-systems-and-dependencies#prop-early-cutoff" />）がありますが、プロンプトキャッシュにはそれに当たるものがありません。キーが「そこまでの内容の全体」だからです（キーが内容を決めるという健全性は <Ref to="computer-science/software-design-testing/build-systems-and-dependencies#prop-cache-key-soundness" /> と同じ形で成り立ちます）。

<Figure caption="追記だけの会話でのキャッシュ。各要求は 1 つ前の要求をプレフィックスとして含み、前回までの部分は読み取り（倍率 r）、新しい部分だけが書き込み（倍率 w）になる。4 回目で先頭のツール定義が変わると、全体が書き込みになる。">
<svg viewBox="0 0 640 230" width="100%" role="img" aria-label="4 つの要求を横棒で示した図。1 回目は全体が書き込み、2 回目と 3 回目は前回までの部分が読み取りで末尾の追記だけが書き込み、4 回目は先頭が変わったため全体が書き込みになる">
  <g font-size="13" fill="currentColor">
    <text x="10" y="42">要求 1</text>
    <text x="10" y="92">要求 2</text>
    <text x="10" y="142">要求 3</text>
    <text x="10" y="192">要求 4</text>
    <text x="70" y="18" font-size="12">ツール定義・システム</text>
    <text x="300" y="18" font-size="12">会話（末尾に足す）</text>
  </g>
  <g stroke="currentColor" stroke-width="1.5">
    <rect x="70" y="26" width="200" height="24" fill="var(--sl-color-accent)" fill-opacity="0.55" />
    <rect x="270" y="26" width="60" height="24" fill="var(--sl-color-accent)" fill-opacity="0.55" />
    <rect x="70" y="76" width="260" height="24" fill="none" />
    <rect x="330" y="76" width="60" height="24" fill="var(--sl-color-accent)" fill-opacity="0.55" />
    <rect x="70" y="126" width="320" height="24" fill="none" />
    <rect x="390" y="126" width="60" height="24" fill="var(--sl-color-accent)" fill-opacity="0.55" />
    <rect x="70" y="176" width="440" height="24" fill="var(--sl-color-accent)" fill-opacity="0.55" />
    <path d="M100 172 V204" stroke-dasharray="4 3" />
  </g>
  <g font-size="12" fill="currentColor">
    <text x="345" y="43">全体を書き込み</text>
    <text x="150" y="93">読み取り</text>
    <text x="400" y="93">追記だけ書き込み</text>
    <text x="180" y="143">読み取り</text>
    <text x="460" y="143">追記だけ書き込み</text>
    <text x="520" y="193">全体を書き込み</text>
    <text x="70" y="220">位置 j で変更（ここより後ろは読めない）</text>
  </g>
</svg>
</Figure>

出典（確認日 2026-10-10）: [Prompt caching](https://platform.claude.com/docs/en/build-with-claude/prompt-caching)、[How Claude Code uses prompt caching](https://code.claude.com/docs/en/prompt-caching)（"How the cache is organized" の節）。

## 4. コストの式

### 4.1. 追記だけの会話

<Definition id="def-append-only-conversation" title="追記だけの会話">
トークン列の列 $x_1, x_2, \ldots$ が**追記だけの会話**であるとは、各 $k \ge 2$ について、空でない列 $y_k$ があって $x_k = x_{k-1} \cdot y_k$ となることをいう。$x_1$ の長さを $s + d_1$（$s \gt 0$ は固定部分、$d_1 \ge 1$ は最初の追記）、$d_k = |y_k|$（$k \ge 2$）と書き、$L_k = |x_k| = s + \sum_{i=1}^{k} d_i$ と置く。

**標準の設定**とは、次の条件をいう。$k$ 回目の要求は、時刻 $t_k$（$t_1 \lt t_2 \lt \cdots$）に、同じモデル $\mu$ で、トークン列 $x_k$、ブレークポイントの位置 $b_k = L_k$（要求の末尾）で送られる。キャッシュを変えるのはこれらの要求だけで、時刻 $t_1$ には $\mu$ の生きている項目は無い。
</Definition>

固定部分 $s$ は、ツール定義・システムプロンプト・最初から文脈にある指示ファイルなどに当たります。$d_k$ は、$k$ 回目の要求で新しく足される分（前回の応答、ツール結果、利用者の新しいメッセージ）です。第 1 章の記号では $d_k = a_{k-1} + r_{k-1}$ に当たります（第 1 章の $r_i$ はツール結果のトークン数で、この章の倍率 $r$ とは別のものです）。

次の定理は、$k$ 回目の要求が $k-1$ 回目の要求の末尾に $d_k$ トークンを足しただけであることを使います。前回の全体 $L_{k-1}$ トークンが読み取りになり、足した $d_k$ トークンだけが書き込みになるので、1 回ごとのコストが決まり、それを足し合わせたのが合計の式です。

<Theorem id="thm-cache-cost" title="追記だけの会話の入力コスト">
<Ref to="def-append-only-conversation" /> の標準の設定で、すべての $k$ について $t_{k+1} - t_k \lt \tau$ とする。<Ref to="def-prompt-cache-model" /> の模型のもとで次が成り立つ。

1. 1 回目の要求のコストは $c_1 = w(s + d_1)$ である。$k \ge 2$ のとき、$k$ 回目の要求の命中の長さは $L_{k-1}$ で、コストは
$$
c_k = r\Bigl(s + \sum_{i=1}^{k-1} d_i\Bigr) + w\,d_k
$$
である。
2. キャッシュを使わない場合の $k$ 回目の要求のコストは $c^0_k = L_k = s + \sum_{i=1}^{k} d_i$ である。
3. $K$ 回の合計を $C_K = \sum_{k=1}^{K} c_k$、$C^0_K = \sum_{k=1}^{K} c^0_k$ とすると、
$$
C_K = w L_K + r \sum_{k=1}^{K-1} L_k = r\,C^0_K + (w - r)\,L_K
$$
である。したがって、比は $\dfrac{C_K}{C^0_K} = r + (w - r)\dfrac{L_K}{C^0_K}$ である。
</Theorem>

<Proof of="thm-cache-cost">
(1) 次の主張 $J(k)$ を、$k$ についての帰納法で示します。「$k$ 回目の要求を処理した直後、項目 $(\mu, x_k)$ の期限は $t_k + \tau$ であり、$\mu$ の項目は $(\mu, x_1), \ldots, (\mu, x_k)$ だけである」。

$k = 1$。時刻 $t_1$ に $\mu$ の生きている項目は無いので、命中の長さは $\ell = 0$ です。使用量は読み取り $0$、書き込み $b_1 - 0 = L_1 = s + d_1$、通常の入力 $L_1 - b_1 = 0$ で、コストは $c_1 = w(s + d_1)$ です。定義の 4 から $(\mu, x_1)$ の期限は $t_1 + \tau$ になります。キャッシュを変えるのはこの会話の要求だけなので、$J(1)$ が成り立ちます。

$k \ge 2$ とし、$J(k-1)$ を仮定します。$t_k - t_{k-1} \lt \tau$ なので $t_{k-1} + \tau \gt t_k$ で、項目 $(\mu, x_{k-1})$ は時刻 $t_k$ に生きています。$x_k = x_{k-1} \cdot y_k$ なので $x_{k-1} \sqsubseteq x_k$ で、長さは $L_{k-1} \le L_k = b_k$ です。したがって $\ell \ge L_{k-1}$ です。一方、$J(k-1)$ から、$\mu$ の項目は $x_1, \ldots, x_{k-1}$ のどれかで、その長さは高々 $L_{k-1}$ です（$d_i \ge 1$ なので $L_1 \lt L_2 \lt \cdots$）。したがって $\ell = L_{k-1}$ です。使用量は読み取り $L_{k-1}$、書き込み $L_k - L_{k-1} = d_k$、通常の入力 $0$ で、コストは $c_k = r L_{k-1} + w d_k$ です。定義の 4 から $(\mu, x_k)$ の期限は $t_k + \tau$ になり、新しく書かれた項目は $x_k$ だけなので $J(k)$ が成り立ちます。

(2) キャッシュを使わない要求のコストは、定義から入力の長さ $L_k$ です。

(3) 1 から
$$
C_K = w(s + d_1) + \sum_{k=2}^{K} \bigl(r L_{k-1} + w d_k\bigr) = w\Bigl(s + \sum_{k=1}^{K} d_k\Bigr) + r\sum_{k=2}^{K} L_{k-1} = w L_K + r \sum_{k=1}^{K-1} L_k
$$
です。$\sum_{k=1}^{K-1} L_k = C^0_K - L_K$ なので、$C_K = w L_K + r(C^0_K - L_K) = r\,C^0_K + (w - r) L_K$ です。両辺を $C^0_K \gt 0$ で割ると比の式になります。
</Proof>

3 の等式 $C_K = r\,C^0_K + (w - r) L_K$ は読みやすい形をしています。キャッシュありの合計は、「キャッシュなしの合計を全部 $r$ 倍にしたもの」に、「すべてのトークンが 1 回ずつ、読み取りではなく書き込みの単価で払われる分の差額 $(w - r)L_K$」を足したものです。どのトークンも、最初に現れた要求で 1 回だけ書かれ、あとは読まれるだけです。

<Corollary id="cor-cache-quadratic-term" title="2 次の係数は r 倍になる">
<Ref to="thm-cache-cost" /> の設定で、すべての $k$ について $d_k = d$（一定）とする。このとき
$$
C^0_K = \frac{d}{2}K^2 + \Bigl(s + \frac{d}{2}\Bigr)K, \qquad
C_K = \frac{r d}{2}K^2 + \Bigl(r s + w d - \frac{r d}{2}\Bigr)K + (w - r)s
$$
である。$r \gt 0$ ならばどちらも $\Theta(K^2)$ で、$K^2$ の係数はキャッシュありのほうが $r$ 倍である。また $\lim_{K \to \infty} C_K / C^0_K = r$ である。
</Corollary>

<Proof of="cor-cache-quadratic-term">
$L_k = s + kd$ なので、
$$
C^0_K = \sum_{k=1}^{K}(s + kd) = Ks + d\,\frac{K(K+1)}{2} = \frac{d}{2}K^2 + \Bigl(s + \frac{d}{2}\Bigr)K
$$
です。<Ref to="thm-cache-cost" /> の 3 から
$$
C_K = r\,C^0_K + (w - r)(s + Kd) = \frac{rd}{2}K^2 + \Bigl(rs + \frac{rd}{2} + (w - r)d\Bigr)K + (w - r)s
$$
で、$K$ の係数は $rs + \frac{rd}{2} + wd - rd = rs + wd - \frac{rd}{2}$ です。どちらも $K$ の 2 次式で、$K^2$ の係数 $d/2$ と $rd/2$ は正なので、<Ref to="computer-science/algorithms/complexity-and-big-o#prop-polynomial" /> により $\Theta(K^2)$ です（<Ref to="computer-science/algorithms/complexity-and-big-o#def-big-o" />）。比については、<Ref to="thm-cache-cost" /> の 3 から $C_K / C^0_K = r + (w - r) L_K / C^0_K$ で、
$$
0 \le \frac{L_K}{C^0_K} \le \frac{s + Kd}{\frac{d}{2}K^2} = \frac{2s}{dK^2} + \frac{2}{K}
$$
の右辺は $K \to \infty$ で $0$ に収束するので、比は $r$ に収束します。
</Proof>

キャッシュは、合計が 2 次で増えるという性質そのものは変えません。変えるのは係数です。1 ターンあたりの追記 $d$ にかかる単価は $1$ から $w$ に上がり、送り直しの部分にかかる単価が $1$ から $r$ に下がります。長い会話では後者が支配的なので、合計はほぼ $r$ 倍になります。

<Example id="ex-ten-turns" title="10 ターンの比較">
$s = 20{,}000$、$d = 2{,}000$、$w = 1.25$、$r = 0.1$ と置きます。倍率は 2026-10-10 に確認した公式ドキュメントの、5 分の有効期間の書き込みと標準の読み取りの値で、変わりえます。$s$ と $d$ は式を見るための仮の値です。単位は「基準の入力単価 × トークン」です。

| $k$ | 読み取り | 書き込み | コスト（キャッシュあり） | コスト（キャッシュなし） |
|---|---|---|---|---|
| 1 | 0 | 22,000 | 27,500 | 22,000 |
| 2 | 22,000 | 2,000 | 4,700 | 24,000 |
| 3 | 24,000 | 2,000 | 4,900 | 26,000 |
| 5 | 28,000 | 2,000 | 5,300 | 30,000 |
| 10 | 38,000 | 2,000 | 6,300 | 40,000 |
| 合計（1〜10） | | | 77,000 | 310,000 |

1 回目だけはキャッシュありのほうが高く（$27{,}500 \gt 22{,}000$）、2 回目からは 5 分の 1 以下です。合計の比は $77{,}000 / 310{,}000 \approx 0.248$ です。<Ref to="thm-cache-cost" /> の 3 で確かめると、$r\,C^0_{10} + (w - r)L_{10} = 0.1 \times 310{,}000 + 1.15 \times 40{,}000 = 31{,}000 + 46{,}000 = 77{,}000$ で一致します。表の数値は 9 節のコードの出力です。
</Example>

### 4.2. 損益分岐

キャッシュへの書き込みは、ふつうの入力より高くつきます。読まれなければ損です。何回読めば元が取れるかを求めます。

<Proposition id="prop-cache-breakeven" title="書き込みの元が取れる読み取りの回数">
長さ $L \gt 0$ のプレフィックスを、1 回目の要求で書き込み、そのあと $n \ge 0$ 回の要求で（毎回、有効期間の中で）読み取るとする。このプレフィックスにかかるコストは、キャッシュありで $(w + nr)L$、キャッシュなしで $(1 + n)L$ である。したがって
$$
(w + nr)L \lt (1 + n)L \iff n \gt \frac{w - 1}{1 - r}
$$
である。$n = 0$（1 回も読まれない）のとき、キャッシュありのほうが $(w - 1)L$ だけ高い。
</Proposition>

<Proof of="prop-cache-breakeven">
キャッシュありでは、1 回目に書き込みで $wL$、あとの $n$ 回は読み取りで $rL$ ずつなので、合計は $(w + nr)L$ です。キャッシュなしでは、$1 + n$ 回の要求のそれぞれで $L$ なので $(1 + n)L$ です。$L \gt 0$ で割ると、$w + nr \lt 1 + n$、すなわち $w - 1 \lt n(1 - r)$ です。$r \lt 1$ なので $1 - r \gt 0$ で、両辺を割って $n \gt (w - 1)/(1 - r)$ を得ます。$n = 0$ のとき、差は $wL - L = (w - 1)L$ です。
</Proof>

固定の費用を払って 1 回あたりの費用を下げ、何回使えば得かを求める、という形は、オンプレミスと従量課金の比較（<Ref to="computer-science/software-engineering/cloud-computing#prop-cost-breakeven" />）と同じです。

<Example id="ex-breakeven-numbers" title="公開されている倍率での損益分岐">
2026-10-10 に確認した倍率を入れます。

| 書き込み $w$ | 読み取り $r$ | $(w-1)/(1-r)$ | 得になる最小の $n$ |
|---|---|---|---|
| 1.25（5 分） | 0.1 | $0.25 / 0.9 \approx 0.278$ | 1 |
| 2（1 時間） | 0.1 | $1 / 0.9 \approx 1.111$ | 2 |
| 1.25（5 分） | 0.05 | $0.25 / 0.95 \approx 0.263$ | 1 |
| 2（1 時間） | 0.05 | $1 / 0.95 \approx 1.053$ | 2 |

5 分の有効期間なら 1 回読めば元が取れ、1 時間なら 2 回読めば元が取れます。料金のページにも、同じ結論が文章で書かれています。エージェントのループでは、各要求のプレフィックスが次の要求で必ず読まれる（有効期間の中で続く限り）ので、条件はほぼいつも満たされます。満たされないのは、書いた直後に会話が終わる場合と、次の要求までに有効期間が切れる場合です。
</Example>

出典（確認日 2026-10-10）: [Prompt caching](https://platform.claude.com/docs/en/build-with-claude/prompt-caching)、[Pricing](https://platform.claude.com/docs/en/about-claude/pricing)（"Prompt caching" の節）。

## 5. 有効期間

1 と 2 は、要求の間隔が決まっている場合の話です。3 は、間隔が運しだいで 5 分を超えることがある場合に、5 分と 1 時間のどちらの有効期間が平均して安くなるかを比べます。

下の動画は $\tau = 5$ 分、$w = 1.25$、$r = 0.1$ で、要求を時刻 0, 3, 7, 10, 16, 19 分に送る場合の模型の計算です。要求のたびに緑の帯（有効な期間）が延びていき、10 分から 16 分の間隔だけは 5 分を超えるので帯が切れ、5 回目の要求のコストが跳ね上がります。

<Figure caption="要求のたびに有効期間が延びる様子と、間隔が τ 以上で切れたときのコスト。コストは模型の式で計算した値（L は 10 から 2 ずつ増加、単位は千トークン）。">
<img src="/figures/cache-ttl-refresh.gif" alt="時間軸の上に 6 回の要求が並び、緑の帯が要求のたびに 5 分先まで延びる。10 分と 16 分の間だけ帯が途切れて赤くなり、下の棒グラフでは 5 回目の要求のコストだけが他の約 6 倍の高さになる。" loading="lazy" />
</Figure>

<Proposition id="prop-ttl-refresh" title="有効期間の更新と、切れたときのコスト">
<Ref to="def-append-only-conversation" /> の標準の設定で、次が成り立つ。

1. すべての $k$ について $t_{k+1} - t_k \lt \tau$ ならば、各 $k \ge 2$ の要求の時点で項目 $(\mu, x_{k-1})$ は生きている。会話がどれだけ長く続いても（$t_k - t_1$ が $\tau$ をどれだけ超えても）、キャッシュは切れない。
2. ある $k \ge 1$ について、$i \lt k$ では $t_{i+1} - t_i \lt \tau$ で、$t_{k+1} - t_k \ge \tau$ とする。このとき $k + 1$ 回目の要求の命中の長さは $0$ で、コストは $w L_{k+1}$ である。これは、切れなかった場合のコスト $r L_k + w d_{k+1}$ より $(w - r)L_k$ だけ大きい。
3. 2 種類の有効期間 $\tau_1 \lt \tau_2$ があり、書き込みの倍率が $w_1 \lt w_2$、読み取りの倍率はどちらも $r$ とする。$k + 1$ 回目の要求までの間隔 $G = t_{k+1} - t_k$ が確率変数で、$\Pr[G \lt \tau_1] = 1 - q$、$\Pr[\tau_1 \le G \lt \tau_2] = q$ とし、$k$ 回目までは切れていないとする。$k + 1$ 回目の要求のコストの期待値は、短い有効期間で $r L_k + w_1 d_{k+1} + q(w_1 - r)L_k$、長い有効期間で $r L_k + w_2 d_{k+1}$ である。したがって、長い有効期間のほうが期待値が小さいのは
$$
q \gt \frac{(w_2 - w_1)\,d_{k+1}}{(w_1 - r)\,L_k}
$$
のとき、またそのときに限る。
</Proposition>

<Proof of="prop-ttl-refresh">
(1) <Ref to="thm-cache-cost" /> の証明の主張 $J(k-1)$ から、$k - 1$ 回目の要求の直後に $(\mu, x_{k-1})$ の期限は $t_{k-1} + \tau$ で、$t_k \lt t_{k-1} + \tau$ なので時刻 $t_k$ に生きています。期限は、最初の要求の時刻からではなく、直前の要求の時刻から測られるので、$t_k - t_1$ の大きさは関係しません。

(2) $i \lt k$ の間隔は $\tau$ 未満なので、<Ref to="thm-cache-cost" /> の証明の $J(k)$ までが成り立ち、$k$ 回目の要求の直後、$\mu$ の項目は $x_1, \ldots, x_k$ だけです。$i \lt k$ の項目 $(\mu, x_i)$ の期限は、最後に書かれたか命中した時刻に $\tau$ を足したもので、$t_k + \tau$ 以下です（$x_i$ が命中するのは $i + 1$ 回目の要求だけなので、期限は $t_{i+1} + \tau \le t_k + \tau$）。$(\mu, x_k)$ の期限は $t_k + \tau$ です。$t_{k+1} \ge t_k + \tau$ なので、時刻 $t_{k+1}$ にはどれも生きていません。したがって $\ell = 0$ で、書き込みは $b_{k+1} = L_{k+1}$、コストは $w L_{k+1}$ です。$L_{k+1} = L_k + d_{k+1}$ なので、差は $w(L_k + d_{k+1}) - r L_k - w d_{k+1} = (w - r)L_k$ です。

(3) 短い有効期間 $\tau_1$ のもとでは、$G \lt \tau_1$ のとき（確率 $1 - q$）コストは $r L_k + w_1 d_{k+1}$、$G \ge \tau_1$ のとき（確率 $q$）は 2 からコストは $w_1 L_{k+1} = r L_k + w_1 d_{k+1} + (w_1 - r)L_k$ です。期待値は
$$
(1 - q)\bigl(r L_k + w_1 d_{k+1}\bigr) + q\bigl(r L_k + w_1 d_{k+1} + (w_1 - r)L_k\bigr) = r L_k + w_1 d_{k+1} + q(w_1 - r)L_k
$$
です。長い有効期間 $\tau_2$ のもとでは、仮定から $G \lt \tau_2$ が確率 $1$ で成り立つので、コストはつねに $r L_k + w_2 d_{k+1}$ です。2 つを比べると、長いほうが小さいのは $w_2 d_{k+1} \lt w_1 d_{k+1} + q(w_1 - r)L_k$、すなわち $(w_2 - w_1)d_{k+1} \lt q(w_1 - r)L_k$ のときです。$w_1 \gt 1 \gt r$ から $(w_1 - r)L_k \gt 0$ なので、割って主張の不等式を得ます。
</Proof>

3 の $q$ は模型の仮定で、実際の値は使い方で決まります。式の読み方はこうです。長い有効期間は、毎ターンの追記 $d$ に対して $(w_2 - w_1)d$ の割増しを払う保険で、保険が効くのは、間隔が $\tau_1$ を超えたときに失うはずだった $(w_1 - r)L$ です。$L$ が $d$ よりずっと大きい長い会話では、右辺は小さくなります。$w_1 = 1.25$、$w_2 = 2$、$r = 0.1$、$L_k = 40{,}000$、$d_{k+1} = 2{,}000$ なら、右辺は $0.75 \times 2{,}000 / (1.15 \times 40{,}000) \approx 0.033$ です。この数値のもとでは、ターンのあいだの休止の 3.3% 以上が 5 分を超える（1 時間は超えない）なら、1 時間の有効期間のほうが期待値は小さくなります。複数のターンにわたる合計の[期待値](/mathematics/probability/random-variables#def-expectation)は、各ターンの期待値の和です（<Ref to="mathematics/hs-probability/finite-probability#thm-linearity-expectation" />。間隔どうしが独立でなくても成り立ちます）。

Claude Code のドキュメントは、有効期間の扱いについて、要求を「主な会話」と「それ以外（サブエージェント、つまり仕事の一部を任せる別の会話や、圧縮のための要求など）」の 2 つの区分に分け、区分ごとに既定の有効期間が課金の形態に応じて決まること、利用者が設定と環境変数で区分ごとに 5 分か 1 時間を選べることを説明しています。既定の表は課金の形態に依存して変わりうるので、ここには写しません。同じページは、長い有効期間は、席を外して戻ってくる使い方では得で、5 分を超える休止のない短い作業では、高い書き込みの単価だけがかかる、と述べています。<Ref to="prop-ttl-refresh" /> の 3 は、その損得の境目を式にしたものです。

出典（確認日 2026-10-10）: [Prompt caching](https://platform.claude.com/docs/en/build-with-claude/prompt-caching)、[How Claude Code uses prompt caching](https://code.claude.com/docs/en/prompt-caching)（"Cache lifetime" の節）。

## 6. モデルの切り替えと、末尾に足す設計

<Proposition id="prop-model-switch-cost" title="モデルを切り替えたときのコスト">
<Ref to="def-append-only-conversation" /> の標準の設定で、$k$ 回目までの要求はモデル $\mu$ で、間隔は $\tau$ 未満とする。$k + 1$ 回目の要求を別のモデル $\mu' \ne \mu$ で送り、その時点で、$\mu'$ の生きている項目で $x_{k+1}$ のプレフィックスであるものは無いとする。このとき次が成り立つ。

1. $k + 1$ 回目の要求の命中の長さは $0$ で、コストは $w L_{k+1}$ である。切り替えなかった場合より $(w - r)L_k$ だけ大きい。
2. このような切り替えを $k_1 \lt k_2 \lt \cdots \lt k_m$ 回目の要求で行うと、それらの要求のコストの和は $w \sum_{j=1}^{m} L_{k_j}$ である。
</Proposition>

<Proof of="prop-model-switch-cost">
(1) <Ref to="def-prompt-cache-model" /> の 1 で、命中の候補は、要求と同じモデル $\mu'$ の項目だけです。仮定から、$\mu'$ の生きている項目で $x_{k+1}$ のプレフィックスであるものは無いので $\ell = 0$ です。モデル $\mu$ の項目 $(\mu, x_k)$ は生きていますが、モデルの名前が違うので候補になりません。書き込みは $b_{k+1} - 0 = L_{k+1}$ で、コストは $w L_{k+1}$ です。切り替えなかった場合のコストは <Ref to="thm-cache-cost" /> の 1 から $r L_k + w d_{k+1}$ で、差は $w(L_k + d_{k+1}) - r L_k - w d_{k+1} = (w - r)L_k$ です。

(2) 1 を各 $k_j$ 回目の要求に適用すると、そのコストは $w L_{k_j}$ です。和をとります。
</Proof>

コストの単位は、要求を送ったモデルの基準の入力単価です。モデルが違えば単価も違うので、金額で比べるときはそれぞれの単価を掛ける必要があります。この命題が言っているのは、**切り替えのたびに、その時点の会話の全長を書き込みの単価で払い直す**ということです。会話が長くなってからの切り替えほど高くつきます。なお、元のモデルに有効期間の中で戻る場合は、元のモデルの古い項目が生きていれば、そこまでは読めます（命題の仮定「生きている項目が無い」が成り立たない場合です）。

<Proposition id="prop-append-only-design" title="追記だけの設計は前方一致を保つ">
1. 追記だけの会話 $x_1, x_2, \ldots$（<Ref to="def-append-only-conversation" />）では、$i \le k$ ならば $x_i \sqsubseteq x_k$ である。特に、連続する 2 つの要求は、長いほうが短いほうをプレフィックスとして含む。
2. 追記だけの会話の途中で、$k + 1$ 回目の要求を、$x_k$ の位置 $j \le L_k$ 以降を書き換えた列 $x'$（$x'$ は $x_k$ と位置 $j$ で初めて食い違う）にしたとする。標準の設定で、$k$ 回目までの間隔は $\tau$ 未満、ブレークポイントは $x'$ の末尾とすると、この要求のコストは $r(j - 1) + w(|x'| - j + 1)$ 以上である。
3. 同じ場面で、書き換えの代わりに、長さ $\nu$ の通知と新しい内容 $y$ を末尾に足した列 $x_k \cdot z$（$|z| = \nu + |y|$）を送ると、コストは $r L_k + w(\nu + |y|)$ である。
</Proposition>

<Proof of="prop-append-only-design">
(1) $k - i$ についての帰納法で示します。$k = i$ のとき $x_i \sqsubseteq x_i$ です。$x_i \sqsubseteq x_{k-1}$ とすると、$x_k = x_{k-1} \cdot y_k$ から $x_{k-1} \sqsubseteq x_k$ で、プレフィックスのプレフィックスはプレフィックスなので $x_i \sqsubseteq x_k$ です。

(2) <Ref to="thm-cache-cost" /> の証明の $J(k)$ から、$k$ 回目の要求の直後、$\mu$ の項目は $x_1, \ldots, x_k$ だけで、1 からどれも $x_k$ のプレフィックスです。<Ref to="prop-prefix-invalidation" /> の 1 から、命中の長さは $\ell \le j - 1$ です。コストは $r\ell + w(|x'| - \ell) = w|x'| - (w - r)\ell$ で、$w \gt r$ なので $\ell$ について減少します。$\ell \le j - 1$ から、コストは $w|x'| - (w - r)(j - 1) = r(j-1) + w(|x'| - j + 1)$ 以上です。

(3) $x_k \cdot z$ は $x_k$ への追記なので、<Ref to="cor-layer-order" /> の 2 から命中の長さは $L_k$ です（$(\mu, x_k)$ は生きていて、ブレークポイントは末尾です）。書き込みは $|z| = \nu + |y|$ で、コストは $r L_k + w(\nu + |y|)$ です。
</Proof>

2 と 3 の差が、設計の選択を説明します。Claude Code のドキュメントによれば、ファイルの内容が文脈に入るのはモデルがそのファイルを読んだときだけで、読み取りの結果は会話に追記されます。前に読んだファイルがあとで編集されても、履歴の中の過去の読み取り結果はさかのぼって書き換えられず、ファイルが変わったことを知らせる通知が追記され、必要ならモデルが読み直します。3 の方式です。もし 2 の方式（履歴の中の古い内容を新しい内容で置き換える）を採ると、そのファイルを読んだ位置 $j$ より後ろの会話がすべて書き込みの単価で払い直しになります。早い段階で読んだファイルほど $j$ が小さく、被害が大きくなります。

<Example id="ex-rewrite-vs-append" title="さかのぼって書き換える場合と、通知を足す場合">
$L_k = 60{,}000$ の会話で、位置 $j = 25{,}001$ から始まる $3{,}000$ トークンのファイルの内容が古くなったとします。$w = 1.25$、$r = 0.1$、次のターンの新しい内容を $|y| = 2{,}000$ とします。

書き換える方式で、新しい内容が同じ $3{,}000$ トークンで先頭から違うとすると、$|x'| = 62{,}000$ で、コストは $0.1 \times 25{,}000 + 1.25 \times 37{,}000 = 2{,}500 + 46{,}250 = 48{,}750$ 以上です。通知を足す方式で、通知が $\nu = 100$ トークンなら、コストは $0.1 \times 60{,}000 + 1.25 \times 2{,}100 = 6{,}000 + 2{,}625 = 8{,}625$ です。モデルがファイルを読み直して $3{,}000$ トークンが次のターンに足されるとしても、追加は $1.25 \times 3{,}000 = 3{,}750$ で、合わせて $12{,}375$ です。追記の方式は、古い内容の $3{,}000$ トークンを文脈に残すぶんウィンドウを余計に使いますが、料金は約 4 分の 1 です。
</Example>

出典（確認日 2026-10-10）: [How Claude Code uses prompt caching](https://code.claude.com/docs/en/prompt-caching)（"Switching models"・"Editing files in your repository" の節）。

## 7. Claude Code での並べ方

### 7.1. 3 つの層

Claude Code のドキュメントは、前方一致を最大限に生かすために、各要求を、ターンのあいだで変わりにくい内容が先に来るように並べる、と説明し、次の 3 つの層を挙げています（2026-10 時点）。

| 層 | 内容 | 変わるとき |
|---|---|---|
| システムプロンプト | 中核の指示、ツール定義 | 読み込まれたツール定義の集合が変わるとき |
| プロジェクトの文脈 | CLAUDE.md、自動メモリ、範囲指定のない規則 | セッションの開始時、または `/clear`・`/compact` のあと |
| 会話 | 利用者のメッセージ、モデルの応答、ツール結果 | 毎ターン |

同じページは、会話の層の変更はシステムプロンプトとプロジェクトの文脈をキャッシュに残し、システムプロンプトの変更は、後ろの内容がすべて別のプレフィックスの後ろに来ることになるので全体を無効にする、と述べています。<Ref to="cor-layer-order" /> の 2 と 1 です。層の境目にも項目があれば（<Ref to="rem-cache-model-assumptions" /> で触れた、複数のブレークポイント）、後ろの層だけが変わったとき、前の層は読み取りで済みます。Claude Code が要求のどのブロックに印を付けているかの一覧は、公開ドキュメントには書かれていません。書かれているのは、この層の順序と、会話の途中に足すシステム文脈のかたまり（ファイルの変更の通知など）に印を付けること、です。ここではそれ以上を推測しません。

### 7.2. キャッシュを無効にする行為と保つ行為

公式ドキュメントは、次の要求がキャッシュの一部または全部を外す行為と、キャッシュを保つ行為を一覧にしています。それぞれが <Ref to="prop-prefix-invalidation" /> と「モデルごとに別のキャッシュ」から説明できることを、1 つずつ確かめます（説明の列は、公式ドキュメントが述べる理由を、この記事の命題に対応させたものです）。

| 無効にする行為 | 模型での説明 |
|---|---|
| モデルの切り替え | 項目のキーにモデルが入っている（<Ref to="prop-model-switch-cost" />） |
| effort（モデルにどれだけ深く考えさせるかの設定）の水準の変更（モデルによる） | 多くのモデルでは水準ごとに別のキャッシュになる、とされている。キーが変わるので、モデルの切り替えと同じ形 |
| fast mode を有効にする | キーの一部である要求ヘッダが足される、とされている。キーが変わる |
| MCP サーバ（外部のツールをモデルにつなぐ仕組み）の接続・削除（ツール定義が最初から読み込まれている場合） | ツール定義は先頭の層にある。食い違う位置 $j$ が先頭の層の中（<Ref to="cor-layer-order" /> の 1） |
| MCP サーバを含むプラグインの有効化・無効化 | 上と同じ |
| ツール全体の deny（ツール定義の遅延読み込みが使えない場合） | 定義が要求から取り除かれる。上と同じ |
| 会話の圧縮 | メッセージの履歴が要約に置き換わるので、会話の層は前の要求とプレフィックスを共有しない。システムプロンプトの層は（再開した会話での例外を除いて）再利用され、プロジェクトの文脈はディスクから読み直されて、開始時から変わっていなければ命中する、とされている |
| 多数の画像の蓄積 | 上限に近づくと古い画像がまとめて取り除かれ、それを含んでいたメッセージが変わる。$j$ はその最も古いメッセージの位置 |
| Claude Code の更新 | システムプロンプトやツール定義がふつう変わる。$j$ は先頭の層の中 |

| 保つ行為 | 模型での説明 |
|---|---|
| リポジトリのファイルの編集 | 過去の読み取り結果は書き換えられず、通知が追記される（<Ref to="prop-append-only-design" /> の 3） |
| セッション中の CLAUDE.md の編集 | 開始時に読んだ版が使われ続け、要求は変わらない（だから編集もその時点では反映されない） |
| 権限モードの変更 | システムプロンプトもツール定義も変わらない（plan モードの出入りでモデルが切り替わる設定を使っている場合は、モデルの切り替えになる） |
| 出力スタイルの変更 | 新しい指示が会話のメッセージとして届けられる（追記） |
| スキル・コマンドの呼び出し | 指示が、呼び出した時点の user メッセージとして注入される（追記） |
| `/recap` | 要約がコマンドの出力として追記され、履歴を置き換えない |
| `/rewind` | 会話を以前のターンまで切り詰める。残る列は、以前の要求のプレフィックスそのもの |
| サブエージェントの起動 | サブエージェントは自分のシステムプロンプトとツールで別の会話を始める。親の側には呼び出しと結果が追記されるだけ |

2 つ注意があります。1 つ目は、「保つ」行為の多くが、**設定の変更がその場では反映されない**ことと表裏であることです。CLAUDE.md を編集してもキャッシュが保たれるのは、編集が要求に入らないからで、新しい内容が読み込まれるのは次の `/clear`・`/compact`・再起動のときです。前方一致を保つことと、変更をすぐ反映することは、同じ位置については両立しません。2 つ目は、サブエージェントの最初の要求は親のキャッシュを読まないことです。システムプロンプトとツールが違えば先頭から食い違うからです。会話の全体をそのまま引き継いで枝分かれさせる fork は、親と同じプレフィックスを持つので親のキャッシュを読みます。サブエージェントの文脈の扱いは次章で扱います。

[圧縮](/computer-science/claude-code-internals/compaction-memory-subagents#def-compaction)についても、ドキュメントは模型どおりの説明をしています。要約を作るための別の要求は、会話と同じシステムプロンプト・ツール・履歴の末尾に要約の指示を足したもので、キャッシュが生きていればプレフィックスを読み取りで済ませます（<Ref to="cor-layer-order" /> の 2）。有効期間を超えた休止のあとでは、履歴の全体が通常の入力として処理されます（<Ref to="prop-ttl-refresh" /> の 2）。

**確認の方法。** 応答ごとの `cache_creation_input_tokens` と `cache_read_input_tokens` を見ます。読み取りが書き込みに対して大きければ、キャッシュは働いています。書き込みが毎ターン大きいままなら、プレフィックスのどこかが毎回変わっています。Claude Code では `/usage` の表示にも、主な会話のキャッシュの命中の割合が出ます（版の条件があります）。

出典（確認日 2026-10-10）: [How Claude Code uses prompt caching](https://code.claude.com/docs/en/prompt-caching)（"How the cache is organized"・"Actions that invalidate the cache"・"Actions that keep the cache"・"Subagents and the cache"・"Check cache performance" の節）。

## 8. ウィンドウの上限はキャッシュで変わらない

<Proposition id="prop-window-bound" title="入力の上限と、キャッシュとの独立性">
コンテキストウィンドウの大きさを $W$ とする。

1. 入力が $n$ トークンの要求で、出力のために $m$ トークンを確保する（出力が $m$ トークンに達するまではウィンドウの上限で止まらないことを保証する）には、$n \le W - m$ でなければならない。
2. <Ref to="def-prompt-cache-model" /> の模型で、ウィンドウに数えられる入力のトークン数は、読み取り・書き込み・通常の入力の和で、キャッシュの状態に依らず $n$ である。したがって、要求がウィンドウに収まるかどうかは、キャッシュの有無・倍率 $w$・$r$・有効期間 $\tau$ のどれにも依らない。逆に、<Ref to="thm-cache-cost" /> のコストの式には $W$ が現れない。
</Proposition>

<Proof of="prop-window-bound">
(1) <Ref to="def-context-window" /> から、入力 $n$ と出力 $o$ は $n + o \le W$ を満たさなければなりません。出力が $m$ に達しうることを保証するには、$o = m$ でもこの不等式が成り立つこと、つまり $n + m \le W$ が必要です。

(2) 使用量の 3 つの欄の和は $\ell + (b - \ell) + (n - b) = n$ です。これは命中の長さ $\ell$ に依りません。公式ドキュメントは、3 つの欄がすべてウィンドウに数えられると述べているので、ウィンドウに数えられる入力は $n$ です。$n$ は要求のトークン列の長さで、$C$・$w$・$r$・$\tau$ はその定義に現れません。<Ref to="thm-cache-cost" /> の式 $c_k = r L_{k-1} + w d_k$ に $W$ は現れません。
</Proof>

API のドキュメントは、この点を、キャッシュされたプレフィックスもコンテキストウィンドウを占め、キャッシュはそのトークンに払う額を変えるのであって、数に入るかどうかを変えるのではない、と書いています。したがって、第 1 章の <Ref to="computer-science/claude-code-internals/agent-loop#prop-context-growth" /> の 3（圧縮なしで続けられる呼び出しの回数の上界）は、キャッシュを使っても同じです。キャッシュは 2 次で増える料金への対処で、1 次で増える 1 回の入力の長さへの対処ではありません。

ウィンドウを超えたときの挙動も公開されています。入力だけでウィンドウを超える要求は、どのモデルでも 400 のエラーになります。入力と `max_tokens` の和が超える要求は、2026-10 時点のドキュメントによれば、新しいモデルでは受け付けられ、生成が上限に達した時点で `stop_reason` が `model_context_window_exceeded` になって止まります（第 1 章の <Ref to="computer-science/claude-code-internals/agent-loop#def-stop-reason" />）。

<Remark id="rem-context-rot" title="長い文脈についての経験的な注意">
API のドキュメントは、ウィンドウが大きいほどよいとは限らず、トークン数が増えると正確さと想起が落ちる、と述べ、これを context rot と呼んでいます。これは仕組みから導ける命題ではなく、観察に基づく主張です。この記事では定理にせず、出典つきの注意にとどめます。この主張が正しいとすると、ウィンドウに収まっていても、文脈を小さく保つ理由があることになります。それが次章の主題です。
</Remark>

出典（確認日 2026-10-10）: [Context windows](https://platform.claude.com/docs/en/build-with-claude/context-windows)。

## 9. コード

### 9.1. コストの模型（実行済み）

<Ref to="def-prompt-cache-model" /> を Python で書きます。要求を「名前とトークン数を持つ区画の列」で表し、プレフィックスの一致を区画の列の一致で判定します。API は呼びません。仕組みを確かめるための模型で、実物の実装の再現ではありません。

```python
# Python 3.9（標準ライブラリのみ）。プロンプトキャッシュのコストの模型。API は呼ばない。
def simulate(requests, w, r, ttl):
    """requests: (時刻, モデル, [(区画の名前, トークン数), ...]) の列。印は毎回、要求の末尾に置く。"""
    cache, rows = {}, []                      # (モデル, プレフィックス) -> 有効期限
    for t, model, segs in requests:
        total = sum(n for _, n in segs)
        read, hit = 0, None
        for i in range(len(segs), 0, -1):     # 生きている最長のプレフィックスを探す
            key = (model, tuple(segs[:i]))
            if cache.get(key, -1) > t:
                read, hit = sum(n for _, n in segs[:i]), key
                break
        write = total - read
        if hit: cache[hit] = t + ttl          # 命中した項目は期限が更新される
        cache[(model, tuple(segs))] = t + ttl # 印までのプレフィックスを書き込む
        rows.append((read, write, r * read + w * write, total))
    return rows

def conversation(turns, gap=60, tools=("tools", 12000), new_tools_from=None,
                 pause_before=None, switch_from=None):
    reqs, t = [], 0
    for k in range(1, turns + 1):
        t += 3600 if k == pause_before else gap
        tl = ("tools+1", 12500) if new_tools_from and k >= new_tools_from else tools
        model = "B" if switch_from and k >= switch_from else "A"
        reqs.append((t, model, [tl, ("system", 8000)] + [("turn%d" % i, 2000) for i in range(1, k + 1)]))
    return reqs

W, R, TTL = 1.25, 0.1, 300
base = simulate(conversation(10), W, R, TTL)
print(" k   read  write  cost(cache)  cost(no cache)")
for k, (rd, wr, c, tot) in enumerate(base, 1):
    print("%2d %6d %6d %12.0f %15d" % (k, rd, wr, c, tot))
print("sum %25.0f %15d  ratio %.3f" % (sum(x[2] for x in base), sum(x[3] for x in base),
                                        sum(x[2] for x in base) / sum(x[3] for x in base)))
s, d, K = 20000, 2000, 10
print("closed form:", W * (s + K * d) + R * ((K - 1) * s + d * K * (K - 1) / 2), K * s + d * K * (K + 1) // 2)
for label, kw in [("tools changed at k=5", {"new_tools_from": 5}), ("1h pause before k=6", {"pause_before": 6}),
                  ("model switch at k=6", {"switch_from": 6})]:
    rows = simulate(conversation(10, **kw), W, R, TTL)
    k = [i for i, x in enumerate(rows, 1) if x[0] == 0][1]
    print("%-21s miss at k=%d: write=%d cost=%.0f | total=%.0f (baseline %.0f)"
          % (label, k, rows[k - 1][1], rows[k - 1][2], sum(x[2] for x in rows), sum(x[2] for x in base)))
for w, r in [(1.25, 0.1), (2.0, 0.1), (1.25, 0.05), (2.0, 0.05)]:
    bound = (w - 1) / (1 - r)
    print("w=%.2f r=%.2f: (w-1)/(1-r)=%.3f -> smallest n = %d" % (w, r, bound, int(bound) + 1))
L, dd, w1, w2 = 40000, 2000, 1.25, 2.0
print("q* = %.4f" % ((w2 - w1) * dd / ((w1 - R) * L)))
```

実行結果（Python 3.9.6、2026-10-10）:

```text
 k   read  write  cost(cache)  cost(no cache)
 1      0  22000        27500           22000
 2  22000   2000         4700           24000
 3  24000   2000         4900           26000
 4  26000   2000         5100           28000
 5  28000   2000         5300           30000
 6  30000   2000         5500           32000
 7  32000   2000         5700           34000
 8  34000   2000         5900           36000
 9  36000   2000         6100           38000
10  38000   2000         6300           40000
sum                     77000          310000  ratio 0.248
closed form: 77000.0 310000
tools changed at k=5  miss at k=5: write=30500 cost=38125 | total=110075 (baseline 77000)
1h pause before k=6   miss at k=6: write=32000 cost=40000 | total=111500 (baseline 77000)
model switch at k=6   miss at k=6: write=32000 cost=40000 | total=111500 (baseline 77000)
w=1.25 r=0.10: (w-1)/(1-r)=0.278 -> smallest n = 1
w=2.00 r=0.10: (w-1)/(1-r)=1.111 -> smallest n = 2
w=1.25 r=0.05: (w-1)/(1-r)=0.263 -> smallest n = 1
w=2.00 r=0.05: (w-1)/(1-r)=1.053 -> smallest n = 2
q* = 0.0326
```

表の部分は <Ref to="ex-ten-turns" />、`closed form` の行は <Ref to="cor-cache-quadratic-term" /> の式に $K = 10$ を入れた値で、シミュレーションの合計と一致します。そのあとの 3 行は、1 回のキャッシュの外れが合計をどれだけ増やすかを示しています。5 回目の要求でツール定義が 1 つ増える（先頭の区画が $12{,}000$ から $12{,}500$ トークンに変わる）と、その要求は $30{,}500$ トークンの全体が書き込みになり（<Ref to="cor-layer-order" /> の 1）、10 回の合計は $77{,}000$ から $110{,}075$ に増えます。6 回目の前に有効期間を超える休止があった場合（<Ref to="prop-ttl-refresh" /> の 2）と、6 回目でモデルを切り替えた場合（<Ref to="prop-model-switch-cost" />）は、どちらも $32{,}000$ トークンの書き込みで、同じ額です。たった 1 回の外れが、10 回分の合計を 4 割以上増やしています。

### 9.2. Messages API で使用量の 3 つの欄を見る（未実行）

システムプロンプトにキャッシュの印を付け、同じ要求を 2 回送って、使用量の 3 つの欄を表示するコードです。**このコードは執筆時に実行していません**（API を呼んでいないので、出力は載せません）。印の書式と欄の名前は、3.1 の出典のページに従っています。API キーは環境変数 `ANTHROPIC_API_KEY` から SDK が読みます。モデル名の既定値は、2026-10 時点の公式ドキュメントの例に現れる値です（執筆時点の例で、変わりえます）。

```python
# 未実行。pip install anthropic が必要。API キーは環境変数 ANTHROPIC_API_KEY から読まれる。
import os
import anthropic

client = anthropic.Anthropic()
MODEL = os.environ.get("ANTHROPIC_MODEL", "claude-opus-5-5")   # 執筆時点の公式の例の値

# キャッシュできる最小の長さ（モデルごとに違う）を超える、長い固定の文章を用意する。
SYSTEM_TEXT = "\n".join("規約 %d: 変数名は内容が分かる英語の名詞にする。" % i for i in range(1, 801))

def ask(question):
    response = client.messages.create(
        model=MODEL,
        max_tokens=64,
        system=[{"type": "text", "text": SYSTEM_TEXT,
                 "cache_control": {"type": "ephemeral"}}],     # ここまでがキャッシュの対象
        messages=[{"role": "user", "content": question}],
    )
    u = response.usage
    print("input=%d  cache_creation=%d  cache_read=%d"
          % (u.input_tokens, u.cache_creation_input_tokens, u.cache_read_input_tokens))

ask("規約は全部でいくつありますか。数だけ答えてください。")
ask("規約は全部でいくつありますか。数だけ答えてください。")
```

仕様どおりなら、1 回目は `cache_creation` が正で `cache_read` が 0、有効期間の中で送った 2 回目は `cache_read` が正で `cache_creation` が 0 になるはずです（<Ref to="thm-cache-cost" /> の $k = 1$ と $k = 2$ で、追記が印より後ろにだけある場合）。実行して確かめるときの注意が 2 つあります。固定の文章がモデルの最小の長さに満たないと、印を付けてもキャッシュされず、エラーも出ません（両方の欄が 0 のままになります）。また、公式ドキュメントによれば、項目が使えるようになるのは最初の応答が始まってからなので、2 つの要求を同時に送ると 2 つ目も書き込みになります。

出典（確認日 2026-10-10）: [Prompt caching](https://platform.claude.com/docs/en/build-with-claude/prompt-caching)。

## 10. 演習

<Exercise id="exr-three-turns" difficulty="易">
$s = 10{,}000$、$d_1 = d_2 = d_3 = 1{,}000$、$w = 1.25$、$r = 0.1$ とする。標準の設定で間隔はすべて $\tau$ 未満とする。3 回の要求のコスト $c_1, c_2, c_3$ と合計 $C_3$ を求め、キャッシュなしの合計 $C^0_3$ と比べよ。<Ref to="thm-cache-cost" /> の 3 の等式で検算せよ。
<Solution>
$L_1 = 11{,}000$、$L_2 = 12{,}000$、$L_3 = 13{,}000$ です。$c_1 = 1.25 \times 11{,}000 = 13{,}750$、$c_2 = 0.1 \times 11{,}000 + 1.25 \times 1{,}000 = 2{,}350$、$c_3 = 0.1 \times 12{,}000 + 1{,}250 = 2{,}450$ で、$C_3 = 18{,}550$ です。キャッシュなしは $C^0_3 = 11{,}000 + 12{,}000 + 13{,}000 = 36{,}000$ です。検算: $r\,C^0_3 + (w - r)L_3 = 0.1 \times 36{,}000 + 1.15 \times 13{,}000 = 3{,}600 + 14{,}950 = 18{,}550$ で一致します。3 回でも合計は約半分です。
</Solution>
</Exercise>

<Exercise id="exr-timestamp-in-system" difficulty="標準">
<Ref to="ex-ten-turns" /> の会話（$s = 20{,}000$、$d = 2{,}000$、$w = 1.25$、$r = 0.1$、10 ターン）で、システムプロンプトの**先頭**に「現在の時刻」を毎回書き込む実装にしたとする（時刻は要求ごとに違う）。(1) 各要求の命中の長さとコストを求めよ。(2) 10 回の合計を、キャッシュなしの場合・正しく並べた場合と比べよ。(3) どう直せばよいか。
<Solution>
(1) $k$ 回目の要求の列を $x'_k$ とすると、$x'_k$ は、それまでのどの要求の列とも位置 $1$ で食い違います。<Ref to="prop-prefix-invalidation" /> の 1 で $j = 1$ なので、命中の長さは $\ell \le 0$、つまり $0$ です。毎回、全体が書き込みになり、コストは $w L_k = 1.25(20{,}000 + 2{,}000k)$ です。

(2) 合計は $1.25 \times \sum_{k=1}^{10} L_k = 1.25 \times 310{,}000 = 387{,}500$ です。キャッシュなしの $310{,}000$ より高く、正しく並べた場合の $77{,}000$ の約 5 倍です。キャッシュの印を付けているのに、1 回も読めない書き込みを毎回払っています（<Ref to="prop-cache-breakeven" /> の $n = 0$ の場合が毎ターン起きています）。

(3) 変わるものを後ろへ動かします。時刻は、その時点の user メッセージの中（会話の末尾）に書けば、追記になり、それより前のプレフィックスはそのまま読めます。Claude Code のドキュメントが、会話の途中で変わる情報をメッセージとして末尾に足すと説明しているのと同じ考え方です。
</Solution>
</Exercise>

<Exercise id="exr-tools-change-by-hand" difficulty="標準">
9.1 の出力の `tools changed at k=5` の行を、手で計算して確かめよ。すなわち、先頭の区画が 5 回目の要求から $12{,}000$ トークンでなく $12{,}500$ トークンの別の内容になるとき、(1) 5 回目の要求のコスト、(2) 6〜10 回目の要求のコストの、変更がない場合との差、(3) 10 回の合計を求めよ。
<Solution>
(1) 5 回目の要求の列は、それまでの項目のどれとも先頭の区画の中で食い違うので、命中の長さは $0$ です（<Ref to="cor-layer-order" /> の 1。この模型では区画が丸ごと変わるので、読めるのは $0$ トークンです）。長さは $12{,}500 + 8{,}000 + 5 \times 2{,}000 = 30{,}500$ で、コストは $1.25 \times 30{,}500 = 38{,}125$ です。

(2) 6 回目以降は、新しい列への追記なので、読み取りは 1 つ前の要求の全長です。固定部分が $500$ トークン増えたので、読み取りが変更なしの場合より $500$ 多く、コストは $0.1 \times 500 = 50$ ずつ高くなります。5 回分で $250$ です。

(3) 変更がない場合の合計は $77{,}000$、5 回目のコストは $5{,}300$ でした。合計は $77{,}000 - 5{,}300 + 38{,}125 + 250 = 110{,}075$ で、出力と一致します。
</Solution>
</Exercise>

<Exercise id="exr-two-breakpoints" difficulty="難">
<Ref to="def-prompt-cache-model" /> を、ブレークポイントを 2 つ持てるように広げる。要求が位置 $b^{(1)} \lt b^{(2)}$ にブレークポイントを持つとき、命中の長さは $b^{(2)}$ 以下の生きている最長の項目の長さ、コストは $r\ell + w(b^{(2)} - \ell) + (n - b^{(2)})$ とし、処理のあと $(\mu, x[1..b^{(1)}])$ と $(\mu, x[1..b^{(2)}])$ の両方の期限を $t + \tau$ にする、と定める。固定部分（長さ $s$）の末尾と要求の末尾にブレークポイントを置いた追記だけの会話を、間隔 $\tau$ 未満で $k$ 回続けたあと、会話の部分を長さ $\sigma$ の要約に置き換えた要求（長さ $s + \sigma$、同じ 2 か所にブレークポイント）を、間隔 $\tau$ 未満で送る。(1) この要求のコストを求めよ。(2) ブレークポイントが要求の末尾の 1 つだけだった場合のコストと比べよ。
<Solution>
(1) $k$ 回目の要求の直後、生きている項目には、固定部分のプレフィックス $x_k[1..s]$（毎回、期限が更新されています）があります。要約に置き換えた列 $x'$ は、$x_k$ と位置 $s + 1$ で初めて食い違うとします（要約の最初のトークンが、元の会話の最初のトークンと違うとします）。<Ref to="prop-prefix-invalidation" /> の 2 から、命中の長さは、長さ $s$ 以下の生きている項目の最大の長さ、つまり $s$ です。コストは $r s + w \sigma$ です。

(2) ブレークポイントが末尾だけなら、項目は $x_1, \ldots, x_k$ だけで、どの長さも $s + d_1 \gt s$ 以上です。命中の長さは $s$ 以下でなければならないので $\ell = 0$ で、コストは $w(s + \sigma)$ です。差は $(w - r)s$ です。$s = 20{,}000$、$w = 1.25$、$r = 0.1$ なら $23{,}000$ で、固定部分の全体を書き込みの単価で払い直すかどうかの違いです。層の境目に項目を置く意味は、後ろの層が丸ごと入れ替わる操作（圧縮や `/clear`）のあとでも、前の層を読み取りで済ませられることにあります。Claude Code のドキュメントが、圧縮のあともシステムプロンプトの層は再利用されると述べているのは、この形です。
</Solution>
</Exercise>

## 参考文献

- Anthropic, [Prompt caching](https://platform.claude.com/docs/en/build-with-claude/prompt-caching), Claude API ドキュメント — プレフィックスの順序、ブレークポイント、有効期間、倍率、最小の長さ、使用量の欄（確認日 2026-10-10）。
- Anthropic, [Pricing](https://platform.claude.com/docs/en/about-claude/pricing), Claude API ドキュメント — キャッシュの倍率の表と損益分岐の説明（確認日 2026-10-10）。
- Anthropic, [Context windows](https://platform.claude.com/docs/en/build-with-claude/context-windows), Claude API ドキュメント — ウィンドウに数えられるもの、大きさ、超過時の挙動（確認日 2026-10-10）。
- Anthropic, [How Claude Code uses prompt caching](https://code.claude.com/docs/en/prompt-caching), Claude Code ドキュメント — 層の順序、キャッシュを無効にする行為と保つ行為、有効期間の区分（確認日 2026-10-10）。
- Anthropic, [How Claude Code works](https://code.claude.com/docs/en/how-claude-code-works) および [How the agent loop works](https://code.claude.com/docs/en/agent-sdk/agent-loop), Claude Code ドキュメント — 文脈が積み上がること、変わらない部分が自動でキャッシュされること（確認日 2026-10-10）。
- A. Vaswani ほか, "Attention Is All You Need", *Advances in Neural Information Processing Systems* 30 (2017). [arXiv:1706.03762](https://arxiv.org/abs/1706.03762) — 因果マスクつきの自己注意（プレフィックスの計算が後続のトークンに依らないことの出どころ）。
