技術 約9分で読めます

Claude Codeのコンテキスト劣化は45分後ではなく開始前から始まる

いけさん目次

Claude Codeの新しいセッションはよく動く。
最初の数十分はファイルを正しく読み、前に決めた方針も守り、編集も細かい。
それが45分くらい経つと、読んだはずのファイルをまた探し、さっき捨てた案へ戻り、返答だけ長くなる。

DEV Communityの Amit Baliyan 氏の記事「Claude Code Context Window Rot: Why Sessions Get Dumber (And How to Fix It)」は、この現象をcontext rotとして扱っている。
面白いのは、単に「長くなったら /compact しよう」ではなく、セッション開始前に入る文脈の質まで問題にしているところだ。
これは最近書いた CTXでClaude Codeに動くメモリを足す とかなり近いが、向きは逆になる。CTXは必要な文脈を後から選んで足す話で、今回の原典は最初から混ぜる文脈をどう絞るかの話だ。

45分の壁はタイマーではない

原典では「45分前後からズレ始める」という体感が出てくる。
ただし、これはClaude Codeに45分の品質タイマーがあるという意味ではない。
その時間までに会話履歴、Read結果、grep結果、bash出力、差分、エラー、やり直し指示が積み上がり、現在の作業に関係ないトークンが増える。

AnthropicのClaude Code公式ブログも、1M contextの話の中でcontext rotを説明している。
コンテキストウィンドウは、システムプロンプト、会話、ツール呼び出し、ツール出力、読んだファイルを全部含む。
そして文脈が増えるほど注意が分散し、古い不要な情報が現在の作業を邪魔する。

Claude CodeのAgent SDKドキュメント側はもっと実装寄りに書いている。
同一セッション内ではコンテキストはターンごとにリセットされない。
会話履歴、tool input、tool outputは積み上がり、上限に近づくと自動compactionで古い履歴が要約に置き換わる。
要約は便利だが、初期の細かい制約や判断がそのまま保存される保証はない。

だから「45分」は原因ではなく、たまたま濁りが見え始める地点だ。
巨大なログを何度も読ませる作業ならもっと早い。
逆に、短い編集と小さなテストだけなら1時間を超えても崩れにくい。

長いだけで落ちる

この話はClaude Code固有の愚痴で終わらない。
Chromaの技術レポート「Context Rot: How Increasing Input Tokens Impacts LLM Performance」は、GPT-4.1、Claude 4、Gemini 2.5、Qwen3など18モデルを対象に、入力長が伸びるだけで性能が不安定になることを示している。
単純なneedle-in-a-haystackだけでは見えない、意味的に近い distractor や構造化されたhaystackでの崩れ方まで見ている。

コードベースはまさにdistractorだらけだ。
似た名前の関数、古い実装、同じ責務を持つ別モジュール、失敗した修正の差分、テストログ。
モデルから見ると、どれも「それっぽい」。

Liu et al. の Lost in the Middle も効いてくる。
必要な情報がコンテキストの先頭か末尾にあると拾いやすく、中間に埋もれると落ちる。
Claude Codeの長時間セッションでは、最初に決めた「このファイルは触らない」「この設計でいく」が、ツール出力の山の真ん中へ押し込まれる。
モデルが完全に忘れたわけではないが、次の生成で効く重みは下がる。

CLAUDE.mdとツール出力が最初の重りになる

今回の原典が既存のコンテキスト管理記事と違うのは、pre-session contextを正面から扱っている点だ。
セッションが始まる前から、CLAUDE.md、MCPツール定義、スキル説明、auto-memory、追加system promptが入る。
ここが膨らむと、最初のプロンプトを打つ前に作業用の余白が減る。

このブログでは以前 CLAUDE.mdが肥大化して困ってる人のためのトークン管理ガイド で、CLAUDE.mdを結論だけにして、経緯や詳細は別ファイルへ逃がす運用を書いた。
当時は「200Kの中でどう節約するか」が主な関心だった。
今は1Mになっても同じ問題が残っている。
容量が増えても、混ざったノイズを均等に無視できるわけではないからだ。

読み込む文脈は、量より形を見るほうが効く。
原典では、Notion spec全文、関連ソース全文、Git log全文、Jiraチケット全文をまとめて渡す例と、タスク範囲・関連メソッド・設定・制約だけを構造化して渡す例を比べている。
後者のほうが少ないだけでなく、どの情報が何のためにあるかが明示される。

Claude Codeに「この機能を直して」と投げる前に、毎回プロジェクト全体の背景を貼るより、触るファイル、捨てた案、守る制約、検証コマンドだけを短く並べる。
それでも必要になったらファイルを読ませる。
これは地味だが、長時間セッションの後半で効く。

compactは修理ではなく切り替え

/compact は壊れたセッションを治す魔法ではない。
良い状態のうちに区切りを作る操作に近い。

品質が落ちた後にcompactすると、すでに混ざった誤解、試して失敗した案、冗長な説明も要約対象に入る。
要約が正しくても、何を残すべきかの判断自体が劣化したセッション上で行われる。
Anthropicの公式ブログが挙げる /clear/rewind、compact、subagentsの使い分けは、このためにある。

自分の運用で一番近いのは、古い Claude Codeセッション管理、どうしてる? に書いた「圧縮される前にまとめてgitに残す」やり方だ。
あの記事はかなり古く、最後に ## まとめ まで付けていて今の文体ルールから見ると直したいが、考え方自体は残っている。
セッションを記憶装置にしない。
判断や進捗はファイルやgitへ逃がし、新しいセッションへ短い引き継ぎとして渡す。

subagentも同じ方向の道具だ。
AnthropicのAgent SDK docsでは、subagentは別の会話として始まり、独自のコンテキストを持つ。
調査や大きなログ読みをsubagentへ逃がせば、メインセッションに巨大なツール出力を積まなくて済む。
ただし結果を長々と戻したら同じなので、返すのは判断に必要な差分だけにする。

圧縮プロキシとメモリツールは別の層

今回の話は Compresr Context GatewayはAIエージェントのコンテキスト枯渇をどう解決するか ともつながる。
CompresrはエージェントとLLM APIの間で、会話履歴やツール出力を圧縮する。
CTXはClaude Codeのhookで関連文脈を直前に差し込む。
どちらも「全部そのまま渡すな」という方向では同じだ。

ただ、失敗の種類は違う。

失敗しやすいところ近い対策
開始前の文脈CLAUDE.md、spec、チケット、ツール定義が大きすぎるルールを短くし、詳細は参照先へ逃がす
セッション中の文脈Read結果、grep結果、エラー出力、失敗差分が残り続けるsubagent、短い調査結果、早めの区切り
セッション跨ぎ昨日の判断や捨てた案を忘れるgit、handoff、CTX、明示的なメモリ
上限付近compactionで初期制約や細部が落ちる壊れる前にclear/compact/rewind

全部を1つのメモリツールで解決しようとすると、また文脈が肥大化する。
「何を残すか」より先に、「今の1ターンに何を入れないか」を決めるほうが効く場面は多い。

兆候は再読とやり直しに出る

モデル名やベンチマークを見るより、自分のセッションログを見るほうが早い。

同じファイルを何度も読み直す。
前に決めた設計を知らない顔で提案する。
エラーを直すたびに別のエラーを増やす。
説明は長いのに、編集は浅い。
「その方針はさっき却下した」と何度も言う必要が出る。

これが出たら、次のプロンプトを足して粘るより、現在の作業状態を短く外へ出す。
触ったファイル、採用した案、捨てた案、残っているエラー、次に実行する検証だけでいい。
その引き継ぎを持って /clear するか、新しいセッションで始める。

Claude Codeの1M contextはありがたい。
でも、1Mは「全部突っ込んでも同じ精度で読める」という意味ではない。
長いセッションを続けるほど、エージェントは過去の作業ログを読むのではなく、過去の作業ログに引っ張られる。

CLAUDE.mdはルールと参照先だけでいい

最近のCLAUDE.md運用で効いているのは、短い絶対ルールと参照先だけを書く方式だ。
テンプレートやスキルの詳細はCLAUDE.mdから分離して、必要なときに都度読ませる。

前述の「pre-session contextを絞る」話と同じ方向だ。
CLAUDE.mdに「Astro 5、TypeScript、Tailwind CSS 4で作ったブログ」と書いてあれば十分で、Astroのルーティング仕様を全文貼る必要はない。
スキルの手順をCLAUDE.mdに展開すると、関係ないタスクのときもそのトークンを背負う。
.claude/skills/style-check/SKILL.md を参照」の1行で済むなら、それが正解だ。

このブログのCLAUDE.mdも肥大化した時期があった。
ガードレール、テンプレート、ワークフロー、全部入りで数千トークン。
セッション冒頭の余白が狭く、最初の指示を出す前からコンテキストが重い。
今は各スキルのSKILL.mdに詳細を分離し、CLAUDE.mdにはルールの要点と参照先だけを残している。

全部入りのCLAUDE.mdは、開発者にとっては安心感がある。
でもモデルにとっては、毎回全ページを開いた辞書を渡されているのと同じだ。
必要なページだけ開けばいい。

勝手に仕事を切り上げようとする

コンテキスト劣化と直接関係があるかは不明だが、Claude Codeには仕事を即座に切り上げようとする癖がある。
タスクの途中で「今日はお疲れ様でした」と言い出す。
1つ直しただけで「他に何かありますか?」と終了モードに入る。

sycophancy(過剰な迎合性)の一種だろう。
温かみチューニングや協調的ペルソナがsycophancyを強める話を前に書いたが、ここでも同じだ。
ユーザーの負担を減らしたい、区切りを作ってあげたい、という方向に振れすぎている。
作業を依頼しているのに、勝手に「もう十分ですよね?」と判断されるのは困る。

コンテキストが重くなったセッション後半で特に出やすい。
文脈が増えてモデルの次トークン予測が拡散し、作業続行よりも安全な区切りを選んでいる気配がある。
RLHFの報酬設計で「親切な終了」が高く評価されすぎている可能性もある。

対処としては、指示を明確にするしかない。
「終わったら言うからそれまで続けて」「自分から切り上げるな」をCLAUDE.mdに入れておく。
根本的には、モデルがタスク完了の判断精度を上げるか、ユーザーの明示的な終了指示を待つようになるまで続く。

参考