コンテンツにスキップ

文脈を保つ・減らす・分ける:要約による圧縮、CLAUDE.md とメモリ、サブエージェント

対象読者: 本テーマ第 1 章(エージェントループ)と第 3 章(コンテキストウィンドウとプロンプトキャッシュ)を読んだ人。集合の濃度と単射・全射の初歩を知っていれば十分で、実装の知識は仮定しません。

前提となる記事:エージェントループ:モデル呼び出しとツール使用の反復、コンテキストウィンドウとプロンプトキャッシュ:前方一致とコストの式

生 Markdown

AI に長い作業を任せていると、会話が長くなりすぎて、AI が一度に見られる量の上限にぶつかります。そのとき、古い部分を短くまとめる、大事なことをファイルに書いておく、調べものを別の AI に任せる、という工夫が考えられます。この記事は、この 3 つの工夫で何が確実に言えて、何が失われるかを、小さな数式と具体的な数値で確かめます。読み終えると、ある指示を会話で伝えるか、ファイルに書くか、別の AI への依頼文に書くかを、理由をつけて選べるようになります。

  • コンテキストウィンドウは有限なので、長い作業では文脈を縮める(要約による圧縮)、外に置く(CLAUDE.md と自動メモリ)、分ける(サブエージェント)の 3 つの対処が要ります。この記事は、それぞれで何が保証され、何が失われるかを整理します。
  • 圧縮を「文脈の大きさがしきい値 τ\tau 以上になったら F+σF + \sigma 以下にする」規則として模型にすると、F+σ+δ≤τF + \sigma + \delta \le \tau のもとで文脈の大きさは常に τ+δ\tau + \delta 未満で、ターン数に上限なく続けられます(定理 3.3、系 3.4)。
  • 長さ σ\sigma 以下の要約は、それより長い履歴を一意には復元できません(命題 3.7)。会話の初めの指示が圧縮で失われうるのは仕組みの帰結で、残したい指示は圧縮を通らない場所に置く必要があります。
  • 指示ファイルは上書きではなく連結されます。連結の順は一意に決まりますが(命題 4.2)、順序は「優先される」ことを保証しません。
  • サブエージェントを 1 回呼んだときの親の文脈の増加は、課題の文と最終の応答の長さだけで決まり、子が読んだ量に依りません(定理 5.3)。ただし読む仕事の量そのものは減りません(命題 5.6)。
  • この記事の命題は、すべて「公式ドキュメントが述べる仕様を模型として定式化したもの」の中での命題です。実物の内部実装についての主張ではありません。出典はすべて公式ドキュメントで、確認日は 2026-10-10 です。

エージェントループ の章で見たとおり、圧縮をしないループでは、モデルを呼ぶたびに入力が伸びます。kk 回目の呼び出しの入力は固定部分 ss に、それまでの応答とツール結果をすべて足したものでした(命題 5.2[エージェントループ])。各ターンで少なくとも cc トークン増えるなら、ウィンドウ WW のもとで続けられる呼び出しは高々 (W−s)/c+1(W - s)/c + 1 回です。

前章 のプロンプトキャッシュは、この伸びに対する料金と遅延の面での対処でした。しかしキャッシュされた部分もウィンドウを占めます(命題 8.1[コンテキストウィンドウとプロンプトキャッシュ])。ウィンドウの上限そのものには、別の対処が必要です。

公式ドキュメントが挙げる対処は 3 つあります。

  1. 縮める。古い履歴を、モデルが書いた要約に置き換える(圧縮)。
  2. 外に置く。毎回の会話の初めに読み込まれるファイル(利用者が書く CLAUDE.md と、モデルが書く自動メモリ)に、会話をまたいで残したい内容を置く。
  3. 分ける。調査などの仕事を別のコンテキストウィンドウを持つループ(サブエージェント)に任せ、結果だけを受け取る。

どれも「何かを得る代わりに何かを失う」操作です。圧縮は続けられる長さを得る代わりに履歴の細部を失い、指示ファイルは持続を得る代わりに毎回のウィンドウを占め、サブエージェントは親のウィンドウの空きを得る代わりに、親の会話の内容を子に渡せなくなります。この章では、それぞれの損得を、公開されている仕様から導ける範囲で式にします。

2. 準備:文脈の大きさを数える

Section titled “2. 準備:文脈の大きさを数える”

この章では、文脈の大きさをトークン数で測ります。トークンの定義には立ち入らず、「文字列に自然数を対応させる長さ ∣⋅∣|\cdot| で、連結について加法的(∣xy∣=∣x∣+∣y∣|xy| = |x| + |y|)なもの」としてだけ使います。

前の 2 章から、次の記号を引き継ぎます。

記号意味
WWコンテキストウィンドウ(1 回の要求でモデルが参照できるトークン数の上限。入力と出力の両方を数える)
ss要求の固定部分(システムプロンプト、ツール定義、プロジェクトの文脈)の長さ
w, rw,\ rキャッシュへの書き込みと読み取りの料金の倍率(基準の入力単価を 11 とする。w>1>rw \gt 1 \gt r)

ターンは、モデルの呼び出し 1 回と、その応答・ツール結果を履歴に足すところまでを指します。前章では τ\tau をキャッシュの有効期間に使いましたが、この章では τ\tau を圧縮を始めるしきい値に使います(有効期間は記号を使わず言葉で書きます)。

3.1. 公式ドキュメントが述べていること

Section titled “3.1. 公式ドキュメントが述べていること”

定義 3.1(圧縮)↗

圧縮(compaction)とは、会話のメッセージの履歴を、モデルが書いた要約に置き換える操作をいう。Claude Code では、文脈が限界に近づいたときに自動で行われるもの(自動圧縮)と、利用者が /compact で行うものがある。

公式ドキュメント(“How Claude Code works”・“Explore the context window”・“Model configuration”)は、圧縮について次のことを述べています(2026-10-10 確認)。

  • 限界に近づくと、まず古いツール出力を消し、それでも足りなければ会話を要約する。利用者の要求と主要なコード片は保たれ、会話の初めの詳しい指示は失われうる。
  • 圧縮で何を残すかは、CLAUDE.md の「Compact Instructions」という節か、/compact に続けて書く焦点(例: /compact focus on the API changes)で指示できる。
  • 自動圧縮が始まる点はモデルと設定で決まる。圧縮のウィンドウを設定しない場合、会話がモデルのコンテキストの上限に達したときに圧縮し、1M トークンのウィンドウを持つモデルではウィンドウが埋まる前(既定で約 967K トークン)に圧縮する、と書かれています。利用者は /autocompact などで 100K から 1M トークンの範囲の値を指定できます。
  • 1 つのファイルやツール出力が大きすぎて、要約のたびに文脈がすぐ埋まる場合、数回の試行のあと自動圧縮をやめてエラーを出す。

圧縮のあとに何が残るかは、内容がどう読み込まれたかで違います。次の表は “Explore the context window” の「What survives compaction」の表を要約したものです。

内容圧縮のあと
システムプロンプトと出力スタイルそのまま適用される
プロジェクトのルートの CLAUDE.md と、パスの指定のない rulesディスクから読み直して再注入
自動メモリディスクから読み直して再注入
paths: つきの rules、サブディレクトリの CLAUDE.md必要になったとき再び読み込む
読んだ・編集したファイル最近変更されたものから最大 5 個を読み直す
呼び出したスキルの本文再注入(1 個あたり 5,000 トークン、合計 25,000 トークンまで)
フックが以前に足した文脈会話の残りと一緒に要約される

古いツール出力を「どれを・いつ」消すかの規則は、公式ドキュメントでは確認できませんでした。この章の模型では、消去と要約をまとめて「文脈を F+σF + \sigma 以下にする 1 つの操作」として扱います。

次の定義は添字が多いので、先に読み方を述べます。ntn_t はターン tt の終わりの文脈の大きさ、ptp_t はそのターンで圧縮をするかどうかを判断する直前の大きさです。つまり pp は圧縮の前、nn は圧縮の後(圧縮しなければ同じ値)と覚えてください。この模型で示したいのは、しきい値の手前で必ず縮めれば、文脈がしきい値を超え続けることはない、という素朴な事実です。

定義 3.2(圧縮の模型)↗

自然数 FF(圧縮を通っても残る固定部分の大きさ)、σ\sigma(要約の長さの上限)、τ\tau(圧縮を始めるしきい値)、δ≥1\delta \ge 1(1 ターンで増える量の上限)を固定する。圧縮の模型とは、次の規則で決まる自然数の列 n0,p1,n1,p2,n2,…n_0, p_1, n_1, p_2, n_2, \ldots をいう。

  • n0=Fn_0 = F。
  • ターン t≥1t \ge 1 で、増分 dtd_t(0≤dt≤δ0 \le d_t \le \delta)が足される: pt=nt−1+dtp_t = n_{t-1} + d_t。
  • pt≥τp_t \ge \tau なら圧縮が行われ、ntn_t は F≤nt≤F+σF \le n_t \le F + \sigma を満たすある値になる。pt<τp_t \lt \tau なら nt=ptn_t = p_t。

ptp_t はターン tt の圧縮の前の文脈の大きさ、ntn_t はターン tt の終わりの文脈の大きさである。この模型は、公式ドキュメントの「限界に近づいたら要約に置き換える」という記述を抽象化したもので、τ\tau と σ\sigma の値は記号のまま扱う。この章の τ\tau は圧縮のしきい値(トークン数)で、前章の τ\tau(キャッシュの有効期間)とは別の量である。

τ\tau は 3.1 節の「自動圧縮が始まる点」にあたり、利用者が設定できる量です。σ\sigma にあたる数値は公式ドキュメントで確認できませんでした。

定理 3.3(圧縮のもとでの文脈長の上界)✓

圧縮の模型(定義 3.2) で F+σ+δ≤τF + \sigma + \delta \le \tau とする。このとき次が成り立つ。

  1. すべての t≥0t \ge 0 で nt<τn_t \lt \tau。
  2. すべての t≥1t \ge 1 で pt<τ+δp_t \lt \tau + \delta。
  3. ターン uu とターン u′u'(u<u′u \lt u')で圧縮が行われ、その間のターンでは行われないとすると、u′−u≥⌈(τ−F−σ)/δ⌉u' - u \ge \lceil (\tau - F - \sigma)/\delta \rceil。
証明(定理 3.3)

1 を tt についての帰納法で示します。t=0t = 0 のとき、n0=F≤τ−σ−δ<τn_0 = F \le \tau - \sigma - \delta \lt \tau です(δ≥1\delta \ge 1 を使いました)。nt−1<τn_{t-1} \lt \tau と仮定します。pt<τp_t \lt \tau なら nt=pt<τn_t = p_t \lt \tau です。pt≥τp_t \ge \tau なら圧縮が行われ、nt≤F+σ≤τ−δ<τn_t \le F + \sigma \le \tau - \delta \lt \tau です。どちらの場合も nt<τn_t \lt \tau が成り立ちます。

2 は 1 から出ます。pt=nt−1+dt<τ+δp_t = n_{t-1} + d_t \lt \tau + \delta です(nt−1<τn_{t-1} \lt \tau と dt≤δd_t \le \delta)。

3 を示します。ターン uu で圧縮が行われたので nu≤F+σn_u \le F + \sigma です。u<t<u′u \lt t \lt u' のターンでは圧縮が行われないので nt=pt=nt−1+dtn_t = p_t = n_{t-1} + d_t で、これを繰り返すと

pu′=nu+∑t=u+1u′dt≤F+σ+(u′−u) δp_{u'} = n_u + \sum_{t = u+1}^{u'} d_t \le F + \sigma + (u' - u)\,\delta

です。ターン u′u' で圧縮が行われたので pu′≥τp_{u'} \ge \tau です。2 つを合わせると (u′−u) δ≥τ−F−σ(u' - u)\,\delta \ge \tau - F - \sigma、すなわち u′−u≥(τ−F−σ)/δu' - u \ge (\tau - F - \sigma)/\delta です。u′−uu' - u は整数なので、u′−u≥⌈(τ−F−σ)/δ⌉u' - u \ge \lceil (\tau - F - \sigma)/\delta \rceil です。

1 と 2 は「文脈の大きさが決まった範囲から出ない」という不変条件で、証明の型は 表現不変条件の帰納法(定理 6.2)[契約による設計] と同じです(初期状態で成り立ち、各操作が保つ)。3 は、圧縮が毎ターン起きるわけではないことの保証です。圧縮のたびにモデルの呼び出しが 1 回余分に要るので、間隔の下界は余分な費用の上界になります。

系 3.4(ターン数に上限のないセッション)✓

圧縮の模型(定義 3.2) で F+σ+δ≤τF + \sigma + \delta \le \tau とし、出力のために確保する量を mm とする。τ+δ≤W−m\tau + \delta \le W - m ならば、すべてのターンで要求の入力は W−mW - m 未満で、ターン数に上限はない。

証明(系 3.4)

ターン tt のモデルの呼び出しの入力は、その時点の文脈で、大きさは高々 ptp_t です。定理 3.3 の 2 により pt<τ+δ≤W−mp_t \lt \tau + \delta \le W - m で、これはすべての t≥1t \ge 1 について成り立ちます。入力 nn が n≤W−mn \le W - m を満たせば n+m≤Wn + m \le W なので、出力が mm トークン以下である限り、その要求はウィンドウに収まります(命題 8.1[コンテキストウィンドウとプロンプトキャッシュ] の 1 の条件)。したがって、どのターンもウィンドウの制約で止まりません。

この系が数えているのは、各ターンのモデルの呼び出しだけです。要約を作る呼び出しは、模型の中では 1 つの操作にまとめてあります。その呼び出し自身(圧縮の前の文脈に要約の指示を足したもの)がウィンドウに収まることは、模型の外の仮定です。

圧縮なしの模型では、続けられる呼び出しの回数が (W−s)/c+1(W - s)/c + 1 で抑えられていました(命題 5.2[エージェントループ])。圧縮は、この有限の上限を取り除きます。ただし取り除かれるのはウィンドウによる制約だけです。ループが止まるかどうかは別の問題で、ターンの上限を置かない限り保証されないこと(定理 4.1[エージェントループ])は変わりません。

例 3.5(文脈の大きさの推移(仮の値))

F=20,000F = 20{,}000、σ=5,000\sigma = 5{,}000、δ=8,000\delta = 8{,}000、τ=150,000\tau = 150{,}000 と置きます。これらは計算のための仮の値で、実物の値ではありません。 F+σ+δ=33,000≤τF + \sigma + \delta = 33{,}000 \le \tau なので 定理 3.3 が使えます。

毎ターンちょうど 8,0008{,}000 増えるとすると、pt=20,000+8,000 tp_t = 20{,}000 + 8{,}000\,t で、p16=148,000<τp_{16} = 148{,}000 \lt \tau、p17=156,000≥τp_{17} = 156{,}000 \ge \tau です。ターン 17 で初めて圧縮が起き、n17=25,000n_{17} = 25{,}000(要約が上限いっぱいの場合)になります。次の圧縮は、25,000+8,000 j≥150,00025{,}000 + 8{,}000\,j \ge 150{,}000 となる最小の j=16j = 16 ターン後、ターン 33 です。下界 ⌈(150,000−25,000)/8,000⌉=⌈15.625⌉=16\lceil (150{,}000 - 25{,}000)/8{,}000 \rceil = \lceil 15.625 \rceil = 16 と一致します。圧縮の前の最大値 156,000156{,}000 は、上界 τ+δ=158,000\tau + \delta = 158{,}000 より小さくなっています。

τF + σ173349ターン文脈
圧縮の模型での文脈の大きさ(例の仮の値)。しきい値 τ 以上になると F + σ 以下に戻る。

定理 3.3 の仮定 F+σ+δ≤τF + \sigma + \delta \le \tau は、「圧縮のあと、少なくとも 1 ターンは進める」という条件です。これが破れる典型は、圧縮しても縮まない大きな塊があるときです。

命題 3.6(縮まない塊があると圧縮は進捗を生まない)✓

圧縮の模型(定義 3.2) を次のように変える。圧縮のあと、次のモデルの呼び出しまでに必ず文脈に戻る塊があり、その大きさを UU とする。圧縮で作られた要約の長さを σ′\sigma'(0≤σ′≤σ0 \le \sigma' \le \sigma)とすると、圧縮の直後の文脈の大きさは n′=F+σ′+Un' = F + \sigma' + U である。このとき次が成り立つ。

  1. n′≥τn' \ge \tau であることと U≥τ−F−σ′U \ge \tau - F - \sigma' は同値である。とくに要約が上限いっぱい(σ′=σ\sigma' = \sigma)なら、U≥τ−F−σU \ge \tau - F - \sigma のとき圧縮の直後に再びしきい値以上になる。
  2. U≥τ−FU \ge \tau - F なら、要約をどれだけ短くしても(σ′=0\sigma' = 0 でも)圧縮の直後にしきい値以上になる。
  3. 1 の条件が毎回成り立つあいだ、圧縮を何回繰り返しても、圧縮と圧縮の間にターンは 1 つも進まない。
証明(命題 3.6)

1: n′=F+σ′+U≥τn' = F + \sigma' + U \ge \tau を UU について解くと U≥τ−F−σ′U \ge \tau - F - \sigma' です。σ′=σ\sigma' = \sigma を代入すると後半が出ます。

2: σ′≥0\sigma' \ge 0 なので n′=F+σ′+U≥F+U≥τn' = F + \sigma' + U \ge F + U \ge \tau です。

3: 圧縮の直後に n′≥τn' \ge \tau なら、模型の規則により、増分 d=0d = 0 のままでも圧縮の条件(文脈が τ\tau 以上)が成り立ち、ターンを進める前に次の圧縮が行われます。その結果も同じ形 F+σ′′+UF + \sigma'' + U で、仮定により再び τ\tau 以上です。帰納的に、圧縮だけが続き、ターンは進みません。

公式ドキュメントは、1 つのファイルやツール出力が大きすぎて要約のたびに文脈がすぐ埋まる場合、数回の試行のあと自動圧縮をやめてエラーを出す、と述べています。これは 命題 3.6 の 3 の状況(止まらない圧縮の繰り返し)に対して、回数の上限という変量を置いて停止させる対処だと読めます。何回で打ち切るかは書かれていないので、ここでは書きません。「次の呼び出しまでに必ず戻る塊」という仮定は模型のもので、実物でどの内容がそうなるかは公式ドキュメントでは確認できませんでした。

次のコードは、3.2 節と 3.3 節の模型をそのまま実装したものです。API は呼んでいません。打ち切りの回数 max_retry=3 は模型の仮の値です。

# 圧縮の模型のシミュレーション(仕組みを理解するための模型。実物の実装の再現ではない)
def simulate(F, sigma, tau, deltas, pinned=0, max_retry=3):
"""deltas: ターンごとの増分。pinned: 圧縮のたびに文脈へ戻る「縮まない塊」の大きさ。
戻り値: (圧縮前の最大の文脈長, 圧縮したターンの列, スラッシングで止まったか)"""
n, peak, compactions = F, F, []
for t, d in enumerate(deltas, start=1):
n += d # 1 ターン分が末尾に足される
peak = max(peak, n)
retry = 0
while n >= tau: # しきい値以上なら圧縮する
n = F + sigma + pinned # 要約(sigma 以下)と、戻ってくる塊
compactions.append(t)
retry += 1
if retry == max_retry: # 進まない圧縮を数回で打ち切る
return peak, compactions, True
return peak, compactions, False
F, sigma, tau, delta = 20_000, 5_000, 150_000, 8_000
peak, comps, thrash = simulate(F, sigma, tau, [delta] * 60)
print("圧縮前の最大の文脈長:", peak, " 上界 tau + delta:", tau + delta)
print("圧縮したターン:", comps, " スラッシング:", thrash)
gaps = [b - a for a, b in zip(comps, comps[1:])]
print("圧縮の間隔:", gaps, " 下界 ceil((tau - F - sigma) / delta):", -(-(tau - F - sigma) // delta))
peak, comps, thrash = simulate(F, sigma, tau, [delta] * 60, pinned=130_000)
print("縮まない塊 130,000: 圧縮したターン", comps, " スラッシング:", thrash)

実行した出力(Python 3.9、2026-10-10 実行):

圧縮前の最大の文脈長: 156000 上界 tau + delta: 158000
圧縮したターン: [17, 33, 49] スラッシング: False
圧縮の間隔: [16, 16] 下界 ceil((tau - F - sigma) / delta): 16
縮まない塊 130,000: 圧縮したターン [17, 17, 17] スラッシング: True

2 つ目の実行では U=130,000≥τ−F−σ=125,000U = 130{,}000 \ge \tau - F - \sigma = 125{,}000 なので、ターン 17 で圧縮が 3 回続き、進まないまま打ち切られています。

命題 3.7(要約から履歴は一意に復元できない)✓

トークンの種類の数を v≥2v \ge 2 とし、σ≥0\sigma \ge 0、n>σn \gt \sigma とする。長さ nn の履歴(トークン列)の全体を HnH_n、長さ σ\sigma 以下の要約の全体を S≤σS_{\le \sigma} とする。このとき、どんな写像 sum:Hn→S≤σ\mathrm{sum} : H_n \to S_{\le \sigma} も単射でない。すなわち、相異なる履歴 h≠h′h \ne h' で sum(h)=sum(h′)\mathrm{sum}(h) = \mathrm{sum}(h') となるものがある。したがって、要約だけを入力とするどんな復元の手続きも、hh と h′h' の少なくとも一方を正しく復元できない。

証明(命題 3.7)

まず個数を数えます。∣Hn∣=vn|H_n| = v^n です。長さ jj の列は vjv^j 個あるので

∣S≤σ∣=∑j=0σvj|S_{\le \sigma}| = \sum_{j=0}^{\sigma} v^j

です。この和を TT と書くと、(v−1) T=∑j=0σvj+1−∑j=0σvj=vσ+1−1(v - 1)\,T = \sum_{j=0}^{\sigma} v^{j+1} - \sum_{j=0}^{\sigma} v^{j} = v^{\sigma+1} - 1(途中の項が打ち消し合う)なので、T=(vσ+1−1)/(v−1)T = (v^{\sigma+1} - 1)/(v - 1) です。v≥2v \ge 2 より v−1≥1v - 1 \ge 1 で、T≤vσ+1−1<vσ+1T \le v^{\sigma+1} - 1 \lt v^{\sigma+1} です。n>σn \gt \sigma は整数なので n≥σ+1n \ge \sigma + 1、したがって ∣S≤σ∣<vσ+1≤vn=∣Hn∣|S_{\le \sigma}| \lt v^{\sigma+1} \le v^n = |H_n| です。

∣Hn∣>∣S≤σ∣|H_n| \gt |S_{\le \sigma}| なので、鳩の巣原理(定理 7.5)[数え上げと母関数](k=1k = 1 の場合)により、写像 sum\mathrm{sum} は単射でありません。つまり h≠h′h \ne h' で sum(h)=sum(h′)\mathrm{sum}(h) = \mathrm{sum}(h') となるものがあります。

復元の手続きを写像 rec:S≤σ→Hn\mathrm{rec} : S_{\le \sigma} \to H_n とします。rec(sum(h))=rec(sum(h′))\mathrm{rec}(\mathrm{sum}(h)) = \mathrm{rec}(\mathrm{sum}(h')) で、この値は 1 つの列なので、hh と h′h' の両方に等しいことはありません(h≠h′h \ne h')。よって少なくとも一方は正しく復元されません。

この命題は、要約を作るのがどれほど優れたモデルであっても成り立ちます(写像についての命題で、写像の中身に依らない)。数の差は大きく、正しく復元できる履歴は高々 ∣S≤σ∣<vσ+1|S_{\le \sigma}| \lt v^{\sigma + 1} 個で、全体 vnv^n に対する割合は vσ+1−nv^{\sigma + 1 - n} 未満です。

公式ドキュメントが「会話の初めの詳しい指示は失われうる。持続させたい規則は会話の履歴に頼らず CLAUDE.md に置く」と勧めていることの根拠は、ここにあります。会話の中だけで与えた指示は履歴の一部で、圧縮を通ります。プロジェクトのルートの CLAUDE.md は、3.1 節の表のとおり圧縮のあとディスクから読み直されるので、要約という写像を通りません。

注意 3.8

失われるのは「モデルの文脈から」です。公式ドキュメントによれば、セッションの各メッセージ・ツール使用・結果はローカルのファイルに書かれるので、ディスク上の記録が圧縮で消えるわけではありません。また、この命題は「どの情報が失われるか」については何も言いません。要約がどの部分を残すかはモデルの出力で決まり、命題で保証できるのは「全部は残せない」ことだけです。

3.5. 圧縮とプロンプトキャッシュ

Section titled “3.5. 圧縮とプロンプトキャッシュ”

前章の命題(命題 3.3[コンテキストウィンドウとプロンプトキャッシュ])によれば、要求のある位置の内容が変わると、それ以降のブレークポイントは命中しません。圧縮は会話の層をまるごと別の列に置き換える操作なので、キャッシュに影響します。

次の命題の大まかな内容は、「要約を作るための要求は前の要求の続きなので安く済むが、圧縮のあとの要求は会話の部分が別物になるので、その部分のキャッシュは使えない」です。記号の PP は会話より前の共通の部分、CC は圧縮前の会話、SS は要約です。

命題 3.9(圧縮とキャッシュ)✓

圧縮の直前の要求をトークン列 R=P CR = P\,C(PP は会話より前の層、CC は会話の層)とし、RR の末尾までがキャッシュに書かれているとする。

  1. 要約を作る要求が R IR\,I(RR の末尾に要約の指示 II を足したもの)の形なら、RR はその接頭辞で、キャッシュが有効期間内なら RR の末尾のブレークポイントに命中する。前章の模型のとおり、新しく足した部分を末尾のブレークポイントまで書き込むとすると、このときの入力コストは r ∣R∣+w ∣I∣r\,|R| + w\,|I|、有効期間が切れていれば w (∣R∣+∣I∣)w\,(|R| + |I|) である。
  2. 圧縮のあとの要求を P′ S DP'\,S\,D(SS は要約、DD は新しい追記)とする。CC と SS の最初に食い違う位置より後ろにあるブレークポイントは、どれも命中しない。P′=PP' = P なら PP の末尾までのブレークポイントは命中しうるが、P′≠PP' \ne P なら、食い違う位置より後ろはすべて命中しない。
証明(命題 3.9)

1: R IR\,I の先頭 ∣R∣|R| トークンは RR そのものなので、RR は接頭辞です。命中の条件はブレークポイントまでの内容の完全一致(前章の定義)なので、RR の末尾のブレークポイントについて条件が満たされます。入力のうち ∣R∣|R| トークンは読み取り(倍率 rr)、新しい ∣I∣|I| トークンは書き込み(倍率 ww)で、コストは r ∣R∣+w ∣I∣r\,|R| + w\,|I| です。有効期間が切れていれば読める接頭辞が無く、全体 ∣R∣+∣I∣|R| + |I| トークンが書き込みになり、コストは w (∣R∣+∣I∣)w\,(|R| + |I|) です(定理 4.2[コンテキストウィンドウとプロンプトキャッシュ] の最初の要求の場合と同じ計算)。

2: 新しい要求と古い要求 RR が最初に食い違う位置を jj とします。P′=PP' = P のとき、jj は PP の長さに「CC と S DS\,D の共通の接頭辞の長さ」を足した位置です。命題 3.3[コンテキストウィンドウとプロンプトキャッシュ] により、位置 jj 以降のブレークポイントはすべて命中せず、jj より前のブレークポイントは影響を受けません。P′≠PP' \ne P のときは、食い違う位置が PP の中にあり、同じ命題によりそれ以降はすべて命中しません。

公式ドキュメント(“How Claude Code uses prompt caching”)は、この 2 点をそのまま述べています。要約を作る別の要求は、同じシステムプロンプト・ツール・履歴に要約の指示を最後の user メッセージとして足したもので、キャッシュが温かければ接頭辞をキャッシュから読む。圧縮のあとは会話の層が設計上無効になる。プロジェクトの文脈はディスクから読み直され、CLAUDE.md とメモリがセッションの開始時から変わっていなければ命中する(2 の P′=PP' = P の場合)。長い休止のあとの /compact が高くつくのは、1 の「有効期間が切れている」場合にあたるからです。

4. 外に置く:CLAUDE.md と自動メモリ

Section titled “4. 外に置く:CLAUDE.md と自動メモリ”

定義 4.1(指示ファイルと自動メモリ)↗

指示ファイル(CLAUDE.md)は、利用者が書く、会話をまたいで持続させたい指示のファイルである。自動メモリ(auto memory)は、モデルが自分のために書くメモで、索引のファイル MEMORY.md と、話題ごとのファイルからなる。どちらも毎回の会話の開始時に読み込まれる。

公式ドキュメント(“How Claude remembers your project”、2026-10-10 確認)から、仕組みに関わる事実を挙げます。

  • 強制される設定ではない。両方とも「文脈として扱われ、強制される設定ではない」と明記されています。CLAUDE.md の内容は、システムプロンプトの一部としてではなく、システムプロンプトのあとの user メッセージとして渡され、厳密に従う保証は無い、とあります。確実に止めたい行為は、第 2 章 の権限規則か、次章 のフックを使います。
  • 置き場所。読み込みの順に、組織の管理者が置くもの(OS ごとの決まったパス)、利用者のもの(~/.claude/CLAUDE.md)、プロジェクトのもの(./CLAUDE.md または ./.claude/CLAUDE.md)、プロジェクトの中の個人用(./CLAUDE.local.md)の 4 種類が表に挙げられています。
  • 大きさ。1 ファイル 200 行未満が目安とされています。4 MiB までのファイルは全文を読み、それより大きいファイルは読みません。
  • 他のツール向けのファイル。作業ディレクトリとその上に CLAUDE.md が無いとき、既定では AGENTS.md を読みます(版の条件があります)。

次の命題の 1 は、複数の指示ファイルをどの順に並べて読み込むかが、一通りに決まることを言っています。2 は、ファイルが別のファイルを取り込む指定(@path)を何段も繰り返しても、展開が必ず止まり、読むファイルの数にも上限があることを言っています。取り込みの段数を深さと呼び、取り込みを枝とする木の頂点を数えるだけの話です。

公式ドキュメントは、読み込みの規則を次のように述べています。

  • 作業ディレクトリと、その上のすべてのディレクトリの CLAUDE.md と CLAUDE.local.md を読む。
  • 見つかったファイルは、互いを上書きするのではなく、すべて連結されて文脈に入る。ディレクトリの木の上では、ファイルシステムのルートから作業ディレクトリへの順に並ぶ。同じディレクトリの中では CLAUDE.local.md が CLAUDE.md のあとに足される。
  • 作業ディレクトリより下のディレクトリのファイルは起動時には読まず、モデルがそのディレクトリのファイルを読む・書く・編集したときに読み込む。
  • ファイルの中の @path という記法で他のファイルを取り込める。相対パスは、取り込みを書いたファイルの場所から解決する。取り込まれたファイルがさらに取り込むこともでき、深さは最大 4 hop。取り込まれたファイルも起動時に読み込まれるので、取り込みは文脈のコストを減らさない。

命題 4.2(指示ファイルの連結順の一意性と、取り込みの展開の停止)✓

  1. 作業ディレクトリへの道をルートから順に D0,D1,…,DkD_0, D_1, \ldots, D_k(DkD_k が作業ディレクトリ)とし、ファイルの種類を j∈{0,1}j \in \{0, 1\}(00 は CLAUDE.md、11 は CLAUDE.local.md)とする。見つかったファイルの集合 M⊆{0,…,k}×{0,1}M \subseteq \{0, \ldots, k\} \times \{0, 1\} に対し、「ルートから作業ディレクトリへ、同じディレクトリでは種類 00 が先」という規則は MM の上の全順序を定める。したがって連結の結果は、MM と各ファイルの内容だけで一意に決まり、ファイルを見つけた順序に依らない。
  2. 取り込みの深さの上限を hh、1 つのファイルに書ける取り込みの数の上限を b≥1b \ge 1 とする。取り込みを「深さが hh のファイルの取り込みは展開しない」という規則で展開すると、取り込みが循環していても展開は停止し、展開で読まれるファイルの数(重複を含めて数える)は 1 つの指示ファイルにつき高々 ∑j=0hbj\sum_{j=0}^{h} b^j である。
証明(命題 4.2)

1: MM の元 (i,j)(i, j) と (i′,j′)(i', j') について、「i<i′i \lt i'、または i=i′i = i' かつ j<j′j \lt j'」のとき (i,j)(i, j) が先、と定めます。これは自然数の組の辞書式順序で、相異なる 2 つの組は必ずどちらかが先になります(i≠i′i \ne i' なら ii の大小で、i=i′i = i' なら j≠j′j \ne j' なので jj の大小で決まる)。推移性は自然数の大小の推移性から出ます。よって全順序です。有限集合の上の全順序は、小さい順に並べる並べ方をただ 1 通り定めるので、その順に内容を連結した文字列は MM と内容だけで決まります。この定義は発見の順序を使っていないので、結果は発見の順序に依りません。

2: 展開を木として表します。根は元の指示ファイル(深さ 00)で、深さ d<hd \lt h の頂点のファイルに書かれた取り込みのそれぞれが、深さ d+1d + 1 の子になります。深さ hh の頂点は子を持ちません。各頂点の子は高々 bb 個なので、帰納的に、深さ dd の頂点は高々 bdb^d 個です(深さ 00 は 1=b01 = b^0 個。深さ dd が高々 bdb^d 個なら、深さ d+1d + 1 は高々 b⋅bd=bd+1b \cdot b^d = b^{d+1} 個)。頂点の総数は高々 ∑d=0hbd\sum_{d=0}^{h} b^d です。親から子へ進むたびに h−dh - d が 11 ずつ減り、00 になると先へ進まないので、h−dh - d は 変量(定義 5.1)[契約による設計] で、展開は停止します。同じファイルが別の深さに何度現れても(循環していても)、この議論は変わりません。

1 の「順序に依らない」という性質は、出力を入力の内容だけの関数にするという、決定的な生成の考え方(定義 5.1[事例研究])と同じです。出現順で番号を振る方式が決定的であること(命題 5.2[事例研究])と対比できます。

注意 4.3(順序は優先を保証しない)

連結の順は決まりますが、それは「後ろのものが勝つ」ことを意味しません。公式ドキュメントは、作業ディレクトリに近い指示ほど後に読まれると述べる一方で、2 つの指示が矛盾する場合はモデルがどちらかを任意に選びうる、とも述べています。第 2 章 の権限規則の判定が規則の集合の関数として決まる(定理 3.4[ツールと権限])のとは性質が違います。指示ファイルで決まるのは「どの文字列がどの順で文脈に入るか」までで、その先はモデルの出力です。

この模型に入れていない事柄もあります。組織の管理者のファイルと利用者のファイルは、公式の表ではプロジェクトのファイルより前に読み込まれます。同じディレクトリの ./CLAUDE.md と ./.claude/CLAUDE.md の間の順は、公式ドキュメントで確認できませんでした。循環した取り込みを重複として除くかどうかも書かれていないので、2 の個数は上界としてだけ使ってください。「最大 4 hop」は、ここでは h=4h = 4(元のファイルから数えて 4 回まで取り込みをたどる)と読んでいます。

/repo1. CLAUDE.md/repo/app(作業ディレクトリ)2. CLAUDE.md3. CLAUDE.local.md/repo/app/webCLAUDE.md(起動時には読まない)
例のフォルダ構成と起動時に読み込まれる順。作業ディレクトリは /repo/app で、その下の web のファイルは起動時には読まれない。

例 4.4(3 つの階層にある指示ファイル)

/repo/app で起動し、/repo/CLAUDE.md、/repo/app/CLAUDE.md、/repo/app/CLAUDE.local.md、/repo/app/web/CLAUDE.md があるとします。/repo/CLAUDE.md は docs/git.md を取り込み、docs/git.md は(誤って)/repo/CLAUDE.md を取り込んでいるとします。次のコードは、命題 4.2 の規則をそのまま実装した評価器です(模型であり、実物の実装の再現ではありません)。

# 指示ファイルの連結順と @path 取り込みの展開の模型。実物の実装の再現ではない。
import posixpath
FILES = { # パス -> 本文(@x は取り込み)
"/repo/CLAUDE.md": "R: pnpm を使う @docs/git.md",
"/repo/docs/git.md": "G: main に直接 push しない @../CLAUDE.md", # 循環
"/repo/app/CLAUDE.md": "A: API は src/api に置く",
"/repo/app/CLAUDE.local.md": "L: 自分用の検証 URL",
"/repo/app/web/CLAUDE.md": "W: 起動時には読まれない(作業ディレクトリより下)",
}
MAX_HOPS = 4 # 取り込みの深さの上限(公式ドキュメントの値。2026-10 時点)
def ancestors(cwd):
parts = [p for p in cwd.split("/") if p]
return ["/"] + ["/" + "/".join(parts[:i]) for i in range(1, len(parts) + 1)]
def load_order(cwd):
"""ルートから cwd へ。同じディレクトリでは CLAUDE.md の次に CLAUDE.local.md。"""
order = []
for d in ancestors(cwd):
for name in ("CLAUDE.md", "CLAUDE.local.md"):
p = posixpath.join(d, name)
if p in FILES:
order.append(p)
return order
def expand(path, hops=0, out=None):
"""path を読み、@ 取り込みを深さ MAX_HOPS まで展開する。読んだファイルの列を返す。"""
out = [] if out is None else out
out.append((hops, path))
if hops == MAX_HOPS:
return out
for word in FILES[path].split():
if word.startswith("@"):
target = posixpath.normpath(posixpath.join(posixpath.dirname(path), word[1:]))
if target in FILES:
expand(target, hops + 1, out)
return out
order = load_order("/repo/app")
print("起動時に読む順:")
for i, p in enumerate(order, 1):
print(f" {i}. {p}")
print("/repo/CLAUDE.md の展開(深さ, パス):")
for hops, p in expand("/repo/CLAUDE.md"):
print(f" {hops} {p}")
b, h = 1, MAX_HOPS
print("展開されるファイル数:", len(expand("/repo/CLAUDE.md")), " 上界:", sum(b ** j for j in range(h + 1)))

実行した出力(Python 3.9、2026-10-10 実行):

起動時に読む順:
1. /repo/CLAUDE.md
2. /repo/app/CLAUDE.md
3. /repo/app/CLAUDE.local.md
/repo/CLAUDE.md の展開(深さ, パス):
0 /repo/CLAUDE.md
1 /repo/docs/git.md
2 /repo/CLAUDE.md
3 /repo/docs/git.md
4 /repo/CLAUDE.md
展開されるファイル数: 5 上界: 5

/repo/app/web/CLAUDE.md は作業ディレクトリより下にあるので、起動時の列には現れません。循環した取り込みは深さ 4 で止まり、読まれるファイルの数は b=1b = 1、h=4h = 4 のときの上界 ∑j=041j=5\sum_{j=0}^{4} 1^j = 5 に一致しています。

4.3. 自動メモリは先頭だけが読み込まれる

Section titled “4.3. 自動メモリは先頭だけが読み込まれる”

公式ドキュメントによれば、自動メモリはプロジェクトごとのディレクトリ(~/.claude/projects/<project>/memory/)に置かれ、索引 MEMORY.md の「最初の 200 行、または最初の 25KB の、先に達したほう」が毎回の会話の開始時に読み込まれます。それを超えた部分は開始時には読み込まれません。話題ごとのファイルは開始時には読まず、必要になったときにモデルがファイル用のツールで読みます。

次の命題が言うのは、「索引は先頭から上限までが読まれ、上限より後ろに何を書き足しても読まれる内容は変わらない」ことです。証明は、行数の上限が先に来る場合とバイト数の上限が先に来る場合に分けて、どちらでも読まれる範囲が同じになることを確かめるだけです。

命題 4.5(読み込まれるのは索引の接頭辞である)✓

索引の内容をバイト列 xx とし、行数の上限を ℓ\ell、バイト数の上限を BB とする。xx の ℓ\ell 個目の改行の直後の位置(先頭からその改行までのバイト数。改行を含む)を eℓ(x)e_\ell(x)(xx に改行が ℓ\ell 個なければ eℓ(x)=∣x∣e_\ell(x) = |x|)、c(x)=min⁡(eℓ(x), B, ∣x∣)c(x) = \min(e_\ell(x),\ B,\ |x|) とし、読み込まれる内容を load(x)=x\mathrm{load}(x) = x の先頭 c(x)c(x) バイト、と定める。このとき次が成り立つ。

  1. load(x)\mathrm{load}(x) は xx の接頭辞である。
  2. c(x)<∣x∣c(x) \lt |x|(上限を超えている)ならば、任意のバイト列 zz について load(load(x) z)=load(x)\mathrm{load}(\mathrm{load}(x)\,z) = \mathrm{load}(x)。すなわち、上限を超えた位置には何を書いても、読み込まれる内容は変わらない。
証明(命題 4.5)

1 は定義そのものです(先頭 c(x)c(x) バイト)。

2: y=load(x)y = \mathrm{load}(x)、x′=y zx' = y\,z とします。c(x)<∣x∣c(x) \lt |x| なので、c(x)=min⁡(eℓ(x),B)c(x) = \min(e_\ell(x), B) で、∣y∣=c(x)|y| = c(x) です。場合を分けます。

(行数の上限が先の場合)c(x)=eℓ(x)≤Bc(x) = e_\ell(x) \le B のとき、eℓ(x)<∣x∣e_\ell(x) \lt |x| なので xx には改行が ℓ\ell 個以上あり、yy は xx の先頭から ℓ\ell 個目の改行までです。x′x' の先頭 ∣y∣|y| バイトは yy なので、x′x' の ℓ\ell 個目の改行も同じ位置にあり、eℓ(x′)=∣y∣e_\ell(x') = |y| です。∣y∣≤B|y| \le B、∣y∣≤∣x′∣|y| \le |x'| なので c(x′)=∣y∣c(x') = |y|、したがって load(x′)=y\mathrm{load}(x') = y です。

(バイト数の上限が先の場合)c(x)=B<eℓ(x)c(x) = B \lt e_\ell(x) のとき、xx の先頭 BB バイトの中に ℓ\ell 個目の改行はありません。x′x' の先頭 BB バイトは yy で、xx の先頭 BB バイトと同じなので、x′x' でも先頭 BB バイトの中に ℓ\ell 個目の改行は無く、eℓ(x′)≥Be_\ell(x') \ge B です(ℓ\ell 個目の改行が BB より後ろにあるか、x′x' に改行が ℓ\ell 個なく eℓ(x′)=∣x′∣≥Be_\ell(x') = |x'| \ge B)。よって c(x′)=min⁡(eℓ(x′),B,∣x′∣)=Bc(x') = \min(e_\ell(x'), B, |x'|) = B で、load(x′)=y\mathrm{load}(x') = y です。

この命題から、索引の使い方が決まります。読み込まれる量が固定なので、索引に詳細を書き足していくと、ある点から先は読み込まれません。公式ドキュメントが述べる構成(索引は 1 項目 1 行にして、詳細は話題ごとのファイルに移す。上限を超えると、書き込みは成功するが索引を書き直すようモデルにエラーを返す)は、この制約のもとでの帰結です。

ここで ℓ=200\ell = 200、B=25 KBB = 25\,\mathrm{KB} が公開されている値です(2026-10 時点)。25KB の境界が行の途中に来たときの切り方は公式ドキュメントで確認できなかったので、模型ではバイト単位で切るとしました。CLAUDE.md にはこの上限は当てはまりません(4.1 節の 4 MiB の規則だけです)。

5.1. 公式ドキュメントが述べていること

Section titled “5.1. 公式ドキュメントが述べていること”

定義 5.1(サブエージェントと fork)↗

サブエージェントとは、自分のコンテキストウィンドウ、自分のシステムプロンプト、決まったツールの集合、独立した権限で動く、別のエージェントループをいう。親のループは、サブエージェントを起動するツール(公式ドキュメントでは Agent)を課題の文とともに呼び出し、サブエージェントの最終の応答をそのツールの結果として受け取る。fork は、新しい文脈で始める代わりに、親の会話をそのまま継いで始めるサブエージェントである。

公式ドキュメント(“Create custom subagents”・“Subagents in the SDK”・“Explore the context window”、2026-10-10 確認)から、文脈に関わる事実を挙げます。

項目fork でないサブエージェント
受け取るもの自分のシステムプロンプト、Agent ツールに渡された課題の文、CLAUDE.md(組み込みの Explore と Plan は読まない。定義で読まない設定にもできる)、ツール定義、定義で指定したスキルの本文
受け取らないもの親の会話の履歴とツール結果、親のシステムプロンプト、親が呼び出し済みのスキル、主セッションの自動メモリ
親に戻るもの最終のメッセージと、小さな付帯情報(トークン数・所要時間)。途中のツール呼び出しと結果は子の中にとどまる

公式ドキュメントは「親から子へ渡す内容は Agent ツールの課題の文字列だけなので、子に必要なファイルのパス・エラーの文・決定事項は、その文字列に直接書くこと」と述べています。fork は親と同じシステムプロンプト・ツール・モデル・メッセージの履歴を見ますが、fork 自身のツール呼び出しは親の会話に入らず、最終の結果だけが戻ります。

定義ファイルは YAML の frontmatter つきの Markdown で、必須の欄は name と description、本文がシステムプロンプトになります。同じ名前の定義が複数の場所にあるときは、優先度の高い場所のものが使われます(組織の管理設定、コマンドラインの指定、プロジェクト、利用者、プラグインの順)。組み込みのものとして、読み取り専用の Explore と Plan、汎用の general-purpose などが挙げられています。実行は前面(終わるまで親が待つ)と背面(並行に動く)があります。

定義 5.2(サブエージェントの模型)↗

親のメッセージ列を MM とする。親がサブエージェントを 1 回呼ぶことを、次の 3 段階として定める。

  1. 親のモデルが、課題の文 qq を入力とする Agent の呼び出し call(q)\mathrm{call}(q) を出力する。MM の末尾に call(q)\mathrm{call}(q) が足される。
  2. 子のループが、メッセージ列 M′=(z, q)M' = (z,\ q) から始まる。ここで zz は子の固定の文脈(子のシステムプロンプト、指示ファイル、ツール定義など)で、構成だけで決まり、MM に依らない。子はツールを使って量 XX の内容(ファイルやツール出力)を自分のメッセージ列に読み込み、最終の応答 aa を出力する。子のモデルとツールを写像と見て、a=Child(z,q,E)a = \mathrm{Child}(z, q, E) と書く(EE はファイルシステムなどの環境)。
  3. ハーネスが、aa と付帯情報 μ\mu から結果 res(a,μ)\mathrm{res}(a, \mu) を作り、MM の末尾に足す。

この模型は、5.1 節の公式ドキュメントの記述(子が受け取るのは課題の文と構成で決まる文脈だけ、親に戻るのは最終の応答だけ)を定式化したものである。fork は 2 の M′M' が MM を含むので、この模型の対象外とする。

定理 5.3(サブエージェントによる文脈の分離)✓

サブエージェントの模型(定義 5.2) で次が成り立つ。

  1. 親の文脈の増加は ∣call(q)∣+∣res(a,μ)∣|\mathrm{call}(q)| + |\mathrm{res}(a, \mu)| で、子が読み込んだ量 XX に依らない。
  2. 子から親へ渡る文字列は res(a,μ)\mathrm{res}(a, \mu) だけである。子が読んだ内容のうち、aa に書かれなかったものは親のメッセージ列に現れない。
  3. 親の 2 つの履歴 M1≠M2M_1 \ne M_2 から、同じ課題の文 qq、同じ構成 zz、同じ環境 EE で子を呼ぶと、子の最終の応答は同じである。すなわち、子の出力は、親の会話の内容に qq と EE を通してしか依存しない。
証明(定理 5.3)

1: 模型の 3 段階のうち、MM に内容を足すのは 1(call(q)\mathrm{call}(q))と 3(res(a,μ)\mathrm{res}(a, \mu))だけです。2 で子が読み込む内容は M′M' に足され、MM には足されません。長さは連結について加法的なので、MM の長さの増加は ∣call(q)∣+∣res(a,μ)∣|\mathrm{call}(q)| + |\mathrm{res}(a, \mu)| です。この式に XX は現れません。

2: MM に足される文字列のうち、子の実行のあとに作られるのは res(a,μ)\mathrm{res}(a, \mu) だけで、これは aa と μ\mu から作られます。子が読んだ内容は M′M' の中にあり、M′M' から MM へ内容を写す段階は 3 のほかにありません。

3: 子のメッセージ列の初期値は M′=(z,q)M' = (z, q) で、定義により zz は MM に依りません。M1M_1 と M2M_2 のどちらから呼んでも、zz、qq、EE が同じなら子のループの初期状態と環境が同じで、a=Child(z,q,E)a = \mathrm{Child}(z, q, E) は写像の値として同じです。MM が aa に影響できるのは、親のモデルが MM をもとに qq を選ぶこと、および親がそれまでのツール呼び出しで EE を変えていること、の 2 つの道だけです。

3 は、利点と制約の両方を表しています。利点は、子の仕事の質が親の会話の長さや脱線に左右されないことです。制約は、親の会話で決めたこと(「この関数は触らない」「原因は認証の層にある」など)は、課題の文に書かない限り子に伝わらないことです。公式ドキュメントが「必要なことは課題の文に直接書く」と勧める理由は、この命題の 3 です。

注意 5.4(模型の仮定と実物の対応)

  • Child\mathrm{Child} を写像としたのは、モデルの出力の揺らぎ(サンプリング)を固定して考えるためです。実物では同じ入力でも応答が変わりえますが、「親の会話の内容が入力に入らない」という構造は変わりません。
  • zz には、公式ドキュメントが挙げる、会話の内容以外のセッションの状態が入ります(他に動いている名前つきのエージェントの一覧、フックが子の開始時に足す文脈など)。
  • 3 の段階でハーネスが aa に手を加える場合があります。公式ドキュメントによれば、子の最終のメッセージは親が読む前に検査され、ハーネスだけが出す制御用のタグを模した部分などは無効化され、検査に当たったことを示す行が前に足されます(削除や言い換えはしない、と書かれています)。模型では、これを res\mathrm{res} の中に含めています。
  • 環境 EE は親と子で共有されます。分離されるのは文脈(メッセージ列)で、ファイルシステムではありません。

次のコードは、親のループと子のループを別のメッセージ列として持つ模型です。モデルは決まった応答を返す関数で代用していて、API は呼んでいません。長さは文字数で数えています。

# 親のループと子のループを別のメッセージ列として持つ模型。
# モデルは決まった応答を返す関数で代用している(API は呼んでいない)。
def tokens(messages): # 模型でのトークン数 = 文字数
return sum(len(m["content"]) for m in messages)
def child_model(messages, files_left):
return ("tool", files_left[0]) if files_left else ("final", "要約: タイムアウトは config.ts の 30 分。")
def run_child(task, files):
messages = [{"role": "user", "content": task}] # 子に渡るのは課題の文だけ
left = list(files)
while True:
kind, value = child_model(messages, left)
if kind == "final":
return value, tokens(messages) # 親に戻るのは最終の応答だけ
left.pop(0)
messages.append({"role": "assistant", "content": "read " + value})
messages.append({"role": "user", "content": "x" * files[value]}) # ファイルの中身
def run_parent(files):
parent = [{"role": "user", "content": "セッションのタイムアウトの扱いを調べて"}]
before = tokens(parent)
task = "session のタイムアウトの設定箇所を調べ、1 行で報告せよ"
final, child_size = run_child(task, files)
parent.append({"role": "assistant", "content": "Agent(" + task + ")"})
parent.append({"role": "user", "content": final}) # tool_result に相当
return tokens(parent) - before, child_size, len(task) + len("Agent()") + len(final)
for sizes in ([2_000, 3_000], [20_000, 20_000, 20_000], [200_000] * 5):
files = {f"f{i}.ts": n for i, n in enumerate(sizes)}
grow, child_size, predicted = run_parent(files)
print(f"子が読んだ量 X = {sum(sizes):>9,} 子の文脈 = {child_size:>9,} 親の増加 = {grow} (課題 + 応答 = {predicted})")

実行した出力(Python 3.9、2026-10-10 実行):

子が読んだ量 X = 5,000 子の文脈 = 5,052 親の増加 = 68 (課題 + 応答 = 68)
子が読んだ量 X = 60,000 子の文脈 = 60,062 親の増加 = 68 (課題 + 応答 = 68)
子が読んだ量 X = 1,000,000 子の文脈 = 1,000,082 親の増加 = 68 (課題 + 応答 = 68)

子が読む量を 200 倍にしても、親の増加は変わりません(定理 5.3 の 1)。child_model を Messages API の呼び出しに置き換えれば、第 1 章 のループを 2 回使う実装になります。その版は、この記事では実行していません。

例 5.5(60,000 トークンの調査を任せる)

60,000 トークン分のファイルを読む調査を考えます(数値は例のための仮の値です)。親が自分で読むと、親の文脈は 60,000 トークン増え、そのあとの親の要求はすべてこの 60,000 トークンを運びます。課題の文が 100 トークン、最終の応答が 400 トークンのサブエージェントに任せると、親の増加は付帯情報を除いて 100+400=500100 + 400 = 500 トークンです。3.2 節の仮の値(τ=150,000\tau = 150{,}000、F=20,000F = 20{,}000)のもとでは、前者は圧縮までの余裕 τ−F=130,000\tau - F = 130{,}000 の約 46% を 1 回で使い、後者は約 0.4% しか使いません。

親のウィンドウの占有は減りますが、読むという仕事が無くなるわけではありません。

次の命題の記号は、親に関するものと子に関するものに分けて読んでください。ss は親の固定部分、s′s' は子の固定部分で、qq は親が子に渡す課題の文、aa は子が返す最終の応答です。XX は調査で読む量、kk は読む回数、TT は調査のあとに親が続けて呼ぶ回数です。命題が言うのは、読む仕事の分は親が読んでも子に任せても同じだけかかるが、調査のあとも親の仕事が続くなら、任せたほうが親の文脈が軽くなって得をする、ということです。

命題 5.6(サブエージェントと入力トークンの総量)✓

量 XX の内容を、kk 回のツール呼び出しで等分に(1 回あたり X/kX/k)読む調査を考える。応答の長さは 00 とし(両方の方式で同じ項になるので省く)、キャッシュは考えない。親の固定部分を ss、子の固定部分を s′s'、課題の文の長さを qq、最終の応答の長さを aa とする。

  1. 親が自分で読む場合、調査の k+1k + 1 回のモデル呼び出しの入力の合計は A=(k+1) (s+X/2)A = (k + 1)\,(s + X/2)。
  2. サブエージェントに任せる場合、子の k+1k + 1 回の呼び出しと、親の 2 回の呼び出し(起動の前と結果を受け取ったあと)の入力の合計は B=(k+1) (s′+q+X/2)+2s+q+aB = (k + 1)\,(s' + q + X/2) + 2s + q + a。
  3. B−A=(k+1) (s′+q−s)+2s+q+aB - A = (k + 1)\,(s' + q - s) + 2s + q + a。XX に依る項 (k+1) X/2(k + 1)\,X/2 は両方に同じだけ現れ、任せても減らない。とくに s′+q≥ss' + q \ge s なら B>AB \gt A である。
  4. 調査のあとに親がさらに TT 回モデルを呼ぶとき、その TT 回の入力の合計は、任せた場合のほうが T (X−q−a)T\,(X - q - a) だけ小さい。
証明(命題 5.6)

1: 親の jj 回目(j=0,1,…,kj = 0, 1, \ldots, k)の呼び出しの時点で、jj 回分の読み込み j X/kj\,X/k が文脈にあるので、入力は s+j X/ks + j\,X/k です(命題 5.2[エージェントループ] の式で、応答の長さを 00、結果の長さを X/kX/k としたもの)。合計は

A=∑j=0k(s+jXk)=(k+1) s+Xk⋅k(k+1)2=(k+1)(s+X2)A = \sum_{j=0}^{k} \Bigl(s + \frac{jX}{k}\Bigr) = (k+1)\,s + \frac{X}{k}\cdot\frac{k(k+1)}{2} = (k+1)\Bigl(s + \frac{X}{2}\Bigr)

です。

2: 子の jj 回目の呼び出しの入力は s′+q+j X/ks' + q + j\,X/k で、合計は同じ計算で (k+1)(s′+q+X/2)(k+1)(s' + q + X/2) です。親は、起動を決める呼び出し(入力 ss)と、結果を受け取ったあとの呼び出し(入力 s+q+as + q + a)を行うので、2s+q+a2s + q + a が加わります。

3: 2 から 1 を引くと、(k+1) X/2(k+1)\,X/2 が打ち消し合って B−A=(k+1)(s′+q−s)+2s+q+aB - A = (k+1)(s' + q - s) + 2s + q + a です。s′+q≥ss' + q \ge s なら第 1 項は 00 以上で、2s+q+a>02s + q + a \gt 0(s>0s \gt 0)なので B>AB \gt A です。

4: 調査のあとの親の文脈は、自分で読んだ場合は s+Xs + X 以上の同じ追記つき、任せた場合は s+q+as + q + a に同じ追記つきです。以後の各呼び出しで、入力の差は X−(q+a)X - (q + a) で、TT 回の合計の差は T (X−q−a)T\,(X - q - a) です。

読む仕事 (k+1)X/2(k+1)X/2 は、どちらの方式でも誰かが払います。合計が kk について 1 次ではなく、XX が大きいほど重くなるのは、第 1 章で見た「入力の合計は 2 次で増える」という性質の現れです(X/kX/k を一定にすると (k+1)X/2(k+1)X/2 は kk の 2 次)。サブエージェントが得をするのは 4 の項、つまり調査のあとも親の仕事が続く場合です。TT が大きいほど、また XX が q+aq + a に比べて大きいほど得になります。これは、仕事を独立な部分に分けることの利得(定理 5.2[LLMとプログラミング]、命題 7.1[AI時代のITエンジニアの生存戦略])を、文脈という資源について述べたものと見ることができます。

系 5.7(サブエージェントとキャッシュ)✓

fork でないサブエージェントの最初の要求は、親の要求と先頭の内容が異なる限り、親が書いたキャッシュに命中しない。fork の最初の要求は、親の直前の要求を接頭辞として含むので、有効期間内なら親のキャッシュに命中する。どちらの場合も、親のメッセージ列には末尾への追記しか起きないので、親のキャッシュは無効にならない。

証明(系 5.7)

fork でないサブエージェントの要求は、子のシステムプロンプトとツール定義から始まります。これが親の要求の先頭と異なれば、最初に食い違う位置は要求の先頭の層の中にあり、命題 3.3[コンテキストウィンドウとプロンプトキャッシュ] により、それ以降のブレークポイントは命中しません。fork は親のシステムプロンプト・ツール・履歴をそのまま継ぐので、その要求は親の直前の要求を接頭辞として含み、同じ命題により親のブレークポイントは影響を受けません。親の側では、定理 5.3 の 1 のとおり MM の末尾に call(q)\mathrm{call}(q) と res(a,μ)\mathrm{res}(a, \mu) が足されるだけで、それより前の内容は変わらないので、親の既存のブレークポイントは命中し続けます。

公式ドキュメント(“How Claude Code uses prompt caching”)は、この 3 点(子は自分のキャッシュを温める、fork は親のキャッシュを読む、親のキャッシュは影響を受けない)を述べています。

サブエージェントは、自分のサブエージェントを起動できます。公式ドキュメントによれば、既定では主会話の下 3 層まで入れ子にでき(環境変数 CLAUDE_CODE_MAX_SUBAGENT_SPAWN_DEPTH で変更。上限の層ではサブエージェントから Agent ツールが取り除かれる)、1 つのセッションで同時に動くサブエージェントは既定で 20 個まで(CLAUDE_CODE_MAX_CONCURRENT_SUBAGENTS。超える起動は失敗し、再試行しないようモデルに伝えられる)です。セッション全体で起動できる総数には上限がない、とも書かれています(2026-10 時点)。

命題 5.8(同時に存在するエージェントの数の上界)✓

主会話を深さ 00 とし、入れ子の深さの上限を DD とする。

  1. 各エージェントが同時に持てる子の数が高々 cc ならば、同時に存在するエージェントの数は高々 ∑j=0Dcj\sum_{j=0}^{D} c^j。
  2. セッション全体で同時に動くサブエージェントの数が高々 NN ならば、同時に存在するエージェントの数は高々 1+N1 + N。両方の制約があれば、上界は 1+min⁡(N, ∑j=1Dcj)1 + \min\bigl(N,\ \sum_{j=1}^{D} c^j\bigr)。
証明(命題 5.8)

1: 同時に存在するエージェントは、起動の関係で根つき木をなします(各サブエージェントの親はちょうど 1 つ)。深さ jj のエージェントの数を NjN_j とすると、N0=1N_0 = 1 で、深さ j+1j + 1 のエージェントは深さ jj のどれかの子なので Nj+1≤c NjN_{j+1} \le c\,N_j です。帰納法で Nj≤cjN_j \le c^j、深さは DD 以下なので合計は高々 ∑j=0Dcj\sum_{j=0}^{D} c^j です。

2: 主会話が 1 つ、サブエージェントが高々 NN 個なので合計は高々 1+N1 + N です。1 の議論でサブエージェント(深さ 11 以上)の数は高々 ∑j=1Dcj\sum_{j=1}^{D} c^j でもあるので、小さいほうが上界になります。

公開されている既定値は 2 の形(セッション全体で N=20N = 20、D=3D = 3)なので、命題の仮定がそのまま成り立つなら、同時に存在するエージェントは高々 21 です。ただし公式ドキュメントは、この上限の数え方に例外があることも述べています(2026-10 時点)。特定の動作設定のセッションでは上限が適用されないこと、利用者が自分で始めた fork は枠を使うが上限では止められないこと、終了したサブエージェントの再開は上限を確かめずに枠を取ること、ワークフローやエージェントチームのエージェントは別の上限に従うことです。したがって 21 は「上限が適用されるセッションで、Agent ツールによる新しい起動だけが行われる場合」の値で、実物についての保証ではありません。c≥2c \ge 2 のとき ∑j=0Dcj=(cD+1−1)/(c−1)\sum_{j=0}^{D} c^j = (c^{D+1} - 1)/(c - 1) で(命題 3.7 の証明と同じ計算)、DD について指数的に増えます。深さと同時実行数の上限は、この増え方に対する歯止めです。1 つの依頼が、命題 5.6 の BB の形の費用を木の頂点の数だけ生むからです。

Agent SDK でサブエージェントを定義して呼ぶ最小の形は、公式ドキュメント(“Subagents in the SDK”、2026-10-10 確認)の書式では次のとおりです。このコードは、この記事では実行していません(API を呼ぶため。出力も載せません)。API キーは環境変数から読まれます。

# 未実行。Agent SDK の公式ドキュメントの書式(2026-10 時点)に合わせた最小の形。
import asyncio
from claude_agent_sdk import query, ClaudeAgentOptions, AgentDefinition
async def main():
options = ClaudeAgentOptions(
allowed_tools=["Read", "Grep", "Glob", "Agent"], # Agent を許可すると委譲できる
agents={
"timeout-finder": AgentDefinition(
description="タイムアウトの設定箇所を探す。調査だけを行う。",
prompt="設定箇所を探し、ファイル名と行を 3 行以内で報告する。",
tools=["Read", "Grep", "Glob"], # 読み取り専用
)
},
max_turns=10, # 親のループのターンの上限
)
async for message in query(
prompt="timeout-finder エージェントを使って、セッションのタイムアウトの設定箇所を調べて",
options=options,
):
if hasattr(message, "result"):
print(message.result)
asyncio.run(main())
対処得るもの失うもの・払うものこの章の命題
縮める(圧縮)ウィンドウによるターン数の上限が無くなる履歴の細部(一意に復元できない)。会話の層のキャッシュ。要約を作る呼び出し 1 回定理 3.3、命題 3.7、命題 3.9
外に置く(指示ファイル・メモリ)会話と圧縮をまたいだ持続毎回の要求で文脈を占める。従うかどうかはモデルの出力による命題 4.2、命題 4.5
分ける(サブエージェント)親の文脈が子の読んだ量に依らない親の会話の内容は課題の文に書いた分しか伝わらない。読む仕事の量は減らない定理 5.3、命題 5.6

次章 で扱うスキルと MCP ツールの遅延読み込みも、同じ資源の節約として読めます。

Claude API にも、サーバ側で古いターンを要約に置き換える圧縮の機能があります。公式ドキュメント(“Compaction overview”、2026-10-10 確認)は、利用者の要求で行う方式と、入力トークンが設定した値に達したときに API が行う方式を挙げ、どちらもベータであると述べています。この記事では方式があることだけを記し、細部は出典に任せます。

演習 7.1易

圧縮の模型(定義 3.2) で F=30,000F = 30{,}000、σ=10,000\sigma = 10{,}000、τ=180,000\tau = 180{,}000、毎ターンの増分をちょうど δ=10,000\delta = 10{,}000 とする(仮の値)。圧縮のたびに nt=F+σn_t = F + \sigma になるとして、最初の圧縮が起きるターンと、100 ターンの間に起きる圧縮の回数を求めよ。

解答

pt=30,000+10,000 t≥180,000p_t = 30{,}000 + 10{,}000\,t \ge 180{,}000 となる最小の tt は t=15t = 15 なので、最初の圧縮はターン 15 です。圧縮のあとは 40,00040{,}000 から始まり、40,000+10,000 j≥180,00040{,}000 + 10{,}000\,j \ge 180{,}000 となる最小の j=14j = 14 ターンごとに圧縮が起きます(定理 3.3 の 3 の下界 ⌈140,000/10,000⌉=14\lceil 140{,}000/10{,}000 \rceil = 14 と一致)。圧縮のターンは 15,29,43,57,71,85,9915, 29, 43, 57, 71, 85, 99 で、100 ターンの間に 7 回です。

演習 7.2標準

トークンの種類を v=2v = 2 とする。長さ n=10n = 10 の履歴のうち、長さ σ=3\sigma = 3 以下の要約から正しく復元できるものは、どんな要約と復元の組でも高々何個か。全体に対する割合も求めよ。

解答

長さ 3 以下の列は 20+21+22+23=152^0 + 2^1 + 2^2 + 2^3 = 15 個です。復元の手続きは要約 1 つにつき履歴を 1 つしか返さないので、正しく復元できる履歴は高々 15 個です。全体は 210=10242^{10} = 1024 個なので、割合は高々 15/1024≈1.5%15/1024 \approx 1.5\% です。命題 3.7 の証明の評価 ∣S≤σ∣<vσ+1=16|S_{\le \sigma}| \lt v^{\sigma+1} = 16 と合っています。

演習 7.3標準

命題 5.6 の記号で、s=20,000s = 20{,}000、s′=6,000s' = 6{,}000、q=200q = 200、a=500a = 500、X=60,000X = 60{,}000、k=5k = 5 とする(仮の値)。(1) AA と BB を求めよ。(2) 調査のあとに親が TT 回モデルを呼ぶとき、入力の合計が「任せたほうが小さい」となる TT の条件を求めよ。

解答

(1) A=6×(20,000+30,000)=300,000A = 6 \times (20{,}000 + 30{,}000) = 300{,}000。B=6×(6,000+200+30,000)+40,000+200+500=217,200+40,700=257,900B = 6 \times (6{,}000 + 200 + 30{,}000) + 40{,}000 + 200 + 500 = 217{,}200 + 40{,}700 = 257{,}900。この例では s′+q<ss' + q \lt s なので B<AB \lt A で、調査の時点ですでに任せたほうが小さくなっています(B−A=6×(−13,800)+40,700=−42,100B - A = 6 \times (-13{,}800) + 40{,}700 = -42{,}100)。

(2) 調査のあとの差は T (X−q−a)=59,300 TT\,(X - q - a) = 59{,}300\,T だけ任せたほうが小さいので、合計の差は −42,100−59,300 T<0-42{,}100 - 59{,}300\,T \lt 0 で、すべての T≥0T \ge 0 で任せたほうが小さくなります。逆に s′=30,000s' = 30{,}000 なら B−A=6×10,200+40,700=101,900B - A = 6 \times 10{,}200 + 40{,}700 = 101{,}900 で、101,900<59,300 T101{,}900 \lt 59{,}300\,T、すなわち T≥2T \ge 2 のとき任せたほうが小さくなります。子の固定部分が大きいと、調査のあとの仕事が続かない限り得になりません。

演習 7.4易

次の 3 つを、会話の中で伝える・プロジェクトのルートの CLAUDE.md に書く・サブエージェントへの課題の文に書く、のどれにすべきかを、この章の命題を根拠に答えよ。(a) 「テストは pnpm test で実行する」。(b) 「いま調べている不具合は、認証の層ではなく設定の読み込みにあると分かった」ことを、調査を任せるサブエージェントに伝える。(c) 「この 1 回だけ、出力を表にしてほしい」。

解答

(a) CLAUDE.md。毎回の会話で必要で、圧縮のあとも残したい内容です。会話の中だけで伝えると履歴の一部になり、圧縮で失われえます(命題 3.7)。(b) 課題の文。親の会話の内容は、課題の文に書いた分しか子に伝わりません(定理 5.3 の 3)。(c) 会話の中。1 回限りの指示を CLAUDE.md に書くと、以後のすべての要求で文脈を占めます。

いずれも公式の一次資料で、確認日は 2026-10-10 です。版や時期で内容が変わるので、数値や規則を使うときは該当のページで確かめてください。

このテーマの 100 本ノック(40 問)

執筆: Claude Code(Opus 5.5)、Claude Code(Sonnet 5.5)・監査 3 回(Claude Code)・最終 2026-10-12

この記事の誤りを報告する ・運営: 夢現技研合同会社 ・料金 ・利用条件 ・特定商取引法に基づく表記

© 2026 夢現技研合同会社 ・コード例は MIT ライセンスです。