CodexはCompaction問題をどう解決しているか
CodexがClaude Codeと異なるコンテキスト超過の処理方法を調べました。AES暗号化、セッション引き継ぎパターン、KVキャッシュの工夫が鍵です。
Claude Codeで本格的なコーディングセッションをしたことがあれば、必ず見かけているはずです。ターミナルに「Compacting conversation…」と表示され、そこから何かがおかしくなります。10分前に話し合ったことをモデルが忘れ始め、レスポンスの遅延が増し、一緒にリファクタリングしたばかりの関数について聞くと、初めて聞いたかのような返答が返ってきます。
これはClaude Codeの20万トークンのコンテキストウィンドウが、多くの人の想定より早く埋まってしまうために起きます。大規模なリファクタリングセッション、いくつかのファイル読み込み、冗長な出力を伴うツール呼び出しを重ねれば、すぐに容量に達してしまいます。閾値(おおよそウィンドウの75〜92%ですが、65%で発動するケースも確認しています)に達すると、Claude Codeは会話を要約し、元のメッセージを破棄して要約だけを残して処理を続けます。要約に含まれなかった情報は完全に失われます。
OpenAIのCodexはこの問題を別の方法で扱っているという話を聞き続けていたので、公開されている分析資料を徹底的に調べました。最も興味深い成果は、KraftonのCAIOであるKangwook Leeによるもので、プロンプトインジェクションを用いて実際のパイプラインをリバースエンジニアリングしています。
コンパクションで失われるものとその影響
核心的な問題はシンプルです。要約は非可逆圧縮です。Claude Codeがコンパクションを実行するとき、会話全体をバックグラウンドで要約し、コンパクションブロックを生成して、それより前の内容をすべて破棄します。CLAUDE.mdファイルはディスクから再読み込みされるため残りますが、会話の中だけで言及したことは、要約者が捉えていない限り消えてしまいます。
最も影響が大きいのはツール呼び出しの結果です。Claude Codeにファイルを読ませると、ファイルの全内容がコンテキストに入ります。コマンドを実行すると、その全出力がコンテキストに入ります。これらのツール実行結果は会話の中で最も情報密度が高い部分であり、要約によって最も平坦化される部分でもあります。500行のファイル読み込みが「設定ファイルを読み込み、データベース設定を確認した」という一文になってしまいます。具体的な値、議論したエッジケース、参照した行番号はすべて消えます。
これを何十回も目の当たりにしてきました。コンパクション後に「さっき調べたヘルパー関数の戻り値の型は何でしたか?」と聞くと、自信たっぷりに間違った答えが返ってきます。モデルが通常の意味でハルシネーションを起こしているわけではありません。自分が尋ねていることを本当に含んでいない要約をもとに答えているだけです。
長いセッションで9回以上のコンパクションが重なると、問題は複利的に悪化します。各要約が前の要約をさらに圧縮します。セッション序盤の意思決定の根拠は完全に失われていきます。10時間のセッションの終盤では、アプローチAとBのトレードオフを20分かけて話し合っていても、なぜAを選んだのかをモデルはまったく覚えていません。
Codexの暗号化コンパクションパイプラインの内部
Kangwook Leeの分析は巧妙でした。2つのプロンプトインジェクションを連鎖させて、Codexのコンパクションシステムの内部動作を解明したのです。
最初のインジェクションはコンパクターLLM自体を標的にしました。Codexがコンパクションをトリガーすると、ローカルで要約するのではなく、OpenAIのサーバー上にある別のLLMに会話を送り、要約を生成させます。Leeのインジェクションはこのコンパクターを騙し、自分のシステムプロンプトを要約出力に含めさせました。サーバーはこの要約(流出したプロンプトを含む)をAES暗号化して不透明なブロブとして返します。
2つ目のインジェクションは復号ステップを利用しました。暗号化されたブロブと細工したユーザーメッセージをResponses APIに渡すと、サーバーがブロブを復号してモデルのコンテキストを組み立てます。最初のインジェクションでコンパクターのシステムプロンプトが要約内に埋め込まれていたため、復号されたコンテキストからパイプライン全体の仕組みが明らかになりました。
判明した内容は次のとおりです。CodexのCompact() APIを呼び出すと、別のLLMが会話を要約し、その結果がAES暗号化されて返ってきます。次のターンでサーバーがこのブロブを復号し、ハンドオフプロンプト(「以前の会話の要約です」)を先頭に付けて、全体をモデルに渡します。暗号化キーはOpenAIのサーバー上に存在します。クライアントは平文の要約を見ることができません。
コンパクションプロンプト自体は、非Codexモデル向けのオープンソースCodex CLIのコンパクションテンプレートとほぼ同一でした。プロンプトエンジニアリングに秘密の工夫はありません。興味深いのはアーキテクチャです。要約のサーバーサイド暗号化、サーバーサイドでの復号と注入、そしてクライアントが検査や変更をできないまま受け渡す不透明なブロブという構造です。
なぜ暗号化するのか。Leeの分析はこの点の決定的な答えを出していません。一つの仮説は、暗号化ブロブにはテキスト要約以上のもの、つまりツール呼び出しの復元データ、内部状態マーカー、OpenAIが公開したくない構造化メタデータが含まれているというものです。もう一つの可能性は、暗号化ブロブによってユーザーが要約を改ざんしてモデルの動作を操作することを防いでいるというものです。後者の説明の方が妥当だと感じますが、どちらも確認されていません。
OpenAIはResponses APIを通じてこれをサーバーサイドでもサポートしています。compact_thresholdの値を設定すると、トークン数がそれを超えた時点でサーバーがインラインでコンパクションを実行します。コンパクションアイテムはレスポンス内でストリームバックされ、以降のリクエストにそれを追加します。最新のコンパクションアイテムより前のアイテムは安全に破棄できます。
Claude Codeのアプローチと比べると、コンパクションブロックは人間が読める形式です。内容を確認でき、instructionsパラメータやCLAUDE.mdへのカスタムコンパクションディレクティブ追加によってコンパクションの動作をカスタマイズできます。より透明性が高いですが、根本的な情報損失は同じです。
セッション引き継ぎパターン
コンパクションの仕組みはさておき、より興味深い問題はコンテキストを失わずに新しいセッションを開始する必要がある場合です。ここで、ある開発者の自動化の仕組みを知り、問題への考え方が変わりました。
パターンはこうです。コンパクションがトリガーされる直前に、プリコンパクトフックがすべての書き込みツールをブロックします。これにより、モデルが部分的な認識状態にあるときにコード変更が行われることを防ぎます。これは私自身何度も経験した失敗モードです。リファクタリングの途中でコンパクションが発動し、モデルがすでに変更したファイルを把握できなくなり、競合する編集を書き込んでしまうのです。
書き込みがブロックされた状態で、JSONLセッションログからユーザーメッセージと思考ブロックだけを抽出します。他のすべて(ツール呼び出し、ファイル内容、アシスタントの応答)は破棄します。これによりログが元のサイズの約2%に圧縮されます。
次に3つのサブエージェントが並行して動作し、それぞれが元の非圧縮JSONLログを検索して抽出で見落とされた情報を探します。探しているのはギャップです。ユーザーメッセージには残っていないが議論されたアーキテクチャ上の決定、ツール出力にしか現れなかったエラーパターン、却下されたアプローチの根拠などです。これらのエージェントは発見内容をresume-prompt.mdファイルにまとめます。このファイルにはセッション要約、ギャップ分析の結果、変更されたファイルのリストが含まれます。
VS Codeのファイルウォッチャーが新しいresume-prompt.mdを検知し、それを初期コンテキストとして読み込んだ新しいセッションを開きます。新しいセッションは、前のセッションがどこで終わったかの明確で完全な全体像から始まります。
報告されている改善は、ビルド効率の10倍向上です。この数値を独立して検証することは難しいですが、アーキテクチャは理にかなっています。劣化し続ける一つの要約ではなく、ギャップチェック済みの引き継ぎドキュメントを持つ新鮮なコンテキストウィンドウで始められるのです。
自分でも簡易版を実装してみました。価値が集中しているのはギャップ分析のステップです。それなしでは、コンパクションがすでに行っていることを別のフォーマットでやっているだけです。それがあれば、要約で失われた情報を積極的に回収できます。私の版は3つではなく1つのサブエージェントを使っており、生のコンパクションよりは明らかに優れた結果が得られますが、3エージェントによる完全なアプローチほど網羅的ではないかもしれません。
KVキャッシュという隠れたコストレバー
ほとんどの議論が見落としているパフォーマンス上の側面があります。KVキャッシュ(アテンション計算時に生成されるキーバリューペア)は、プロンプトのプレフィックスが同一であればリクエスト間で再利用できます。同じ冒頭トークンを持つ2つのリクエストは、それらのトークンの再計算をスキップできます。
数値は顕著です。安定したシステムプロンプトと変化するシステムプロンプトを比較した制御実験では、安定したプレフィックスで85%のキャッシュヒット率と中央値953msの最初のトークン生成時間(TTFT)を達成しました。変化するプレフィックスでは、キャッシュヒット率0%、TTFT 2,727msです。リクエストあたりのコストは$0.033から$0.009に低下しました。プロンプトのプレフィックスを一定に保つだけで、レイテンシーが65%、コストが71%削減されます。
これはセッション引き継ぎパターンに直接影響します。resume-prompt.mdが常に同じ構造のプレフィックス(システムプロンプト、ハンドオフ指示、その後に可変コンテンツ)で始まっていれば、固定部分がキャッシュされます。新しいセッションの後続リクエストはすべてそのキャッシュの恩恵を受けます。プレフィックス構造をランダムにしたり、早い段階で可変コンテンツを注入したりすると、すべてのリクエストが最初から再計算されます。
このインサイトをもとにセッションフォルダー構造を設計しました。セッションIDベースのアーカイブで引き継ぎドキュメントを整理し、resumeプロンプトの固定プレフィックス規約により、新しいセッションの最初の4〜5万トークンが毎回KVキャッシュにヒットします。サブエージェントが過去のセッションを検索する際の取得ステップを高速化するために、セッションアーカイブをQMD(別途取り上げたツール)で事前インデックス化しています。
本当に重要なこと
本質的な教訓は、CodexのアプローチがClaude Codeより優れているとか劣っているということではありません。どちらもコンパクション時に情報を失います。どちらも長いセッションに苦労します。アーキテクチャの違い(暗号化された不透明なブロブ対人間が読めるコンパクションブロック)は設計思想の違いを反映していますが、根本的な制限は同じです。コンテキストウィンドウは有限であり、要約は非可逆です。
重要なのは、その制限のまわりに何を構築するかです。セッション引き継ぎパターン、ギャップ分析、JSONLベースの取得、KVキャッシュ最適化は、どれだけモデルが改善されても完全には解決できない問題へのエンジニアリング的な解答です。50万や100万トークンのコンテキストウィンドウは問題を先送りするだけで、解消はしません。
AIコーディングツールのボトルネックはモデルの知性ではありません。コンテキスト管理です。忘れられた情報を確実に取得するシステムを構築することは、より正確に要約するシステムを構築することよりも価値があります。実際に目の当たりにしてきましたが、優れた取得機能を持つ平凡な要約は、取得機能のない優れた要約に必ず勝ります。
技術的な詳細はKangwook Leeの分析と、OpenAIおよびAnthropicの公開APIドキュメントを参照しています。
ニュースレターに登録
最新のAIに関するインサイトをお届けします。