AIコーディングとエージェント

[AIコンテキスト #6] AIエージェントのメモリ設計、コンテキストの外に置く技術(計画ファイル・メモリ・RAG)

ここまでシリーズを読んできたなら、共通するパターンに気づくはずです。コンテキストウィンドウ内に置くものを最小限にする、ということです。第3回の「/clearの前に状態をファイルへ」、第4回の「本文ではなくポインタだけ」、第5回の「プロセスはサブエージェントに任せ、結論だけをメインへ」は、すべて同じ方向を示しています。ただし、コンテキストの外へ移した情報の置き場所については、まだきちんと扱っていませんでした。

読了 6 分
[AIコンテキスト #6] AIエージェントのメモリ設計、コンテキストの外に置く技術(計画ファイル・メモリ・RAG)のカバー画像

ここまでシリーズを読んできたなら、共通するパターンに気づくはずです。コンテキストウィンドウ内に置くものを最小限にする、ということです。第3回の「/clearの前に状態をファイルへ」、第4回の「本文ではなくポインタだけ」、第5回の「プロセスはサブエージェントに任せ、結論だけをメインへ」は、すべて同じ方向を示しています。ただし、コンテキストの外へ移した情報の置き場所については、まだきちんと扱っていませんでした。

今回のテーマは、その置き場所です。セッション終了後も残すべき知識を、どこにどう置くか。たとえるなら、コンテキストウィンドウは作業台で、ファイルシステムは倉庫です。作業台は狭く高価で、セッションが終わると片づけられます。倉庫は広く安価で、ずっと残ります。優れたエージェント運用とは、結局のところ作業台と倉庫の間の物流設計です。

計画ファイル、長いタスクの生命線

最も基本的な外部化が計画ファイルです。タスク開始時に、目標、確定した決定事項、残りの手順をPLAN.mdのようなファイルにまとめ、進行に合わせて更新させます。

このファイル1つで、複数の問題を一度に解決できます。まず、セッションリセットを乗り越えられます。コンテキストがいっぱいになって/clearを実行しても、ノートPCを閉じて翌日に新しいセッションを開いても、計画ファイルを読ませれば作業を続けられます。第3回で扱ったauto-compactの不確かな要約とは異なり、何を残すかを自分で管理できる正確な記録である点が重要です。

副次的な効果もあります。エージェントが各ステップで計画ファイルを更新して読み直すと、全体の目標がコンテキストの末尾付近に繰り返し現れます。第2回で見たように、モデルの注意はコンテキストの終端に強く向きます。この性質を逆に利用して、「今何をしていたのか」を常に視界に置くのです。数十ステップのタスクを任せると、エージェントが途中で本来の目標を忘れて脱線する問題への処方箋になります。実際、長いタスクを扱うエージェント製品では、やることリストをファイルに置き、絶えず書き換えるパターンが使われています。

メモリ、セッションを越えて蓄積する知識

計画ファイルが1つのタスクの寿命を延ばすなら、メモリはプロジェクト全体にわたって知識を蓄積します。Claude Codeをはじめとするエージェントはメモリディレクトリ機能をサポートしており、原理は単純です。知った事実を1つずつ別のファイルに書き、要約インデックスだけを常時ロードし、本文は関連するタスクで必要になったときに読みます。第4回のポインタ原則がここでも適用されます。

重要なのは保存基準です。何でも書けば、メモリはすぐにごみ溜めになります。合格ラインは「他の場所から導出できない情報」です。コード構造はコードを読めば分かるので不採用、過去のコミット履歴はgitが覚えているので不採用です。一方、「このプロジェクトのdevサーバーは必ずmainワークツリーから起動する」という運用ルール、「ユーザーは丁寧語を望んでいる」という好み、試行錯誤の末に分かった環境固有の落とし穴には、メモリに記録する価値があります。どこにも記録されていないからです。

古くなったメモリの問題も計画に含める必要があります。半年前に書いた事実が、今も正しいとは限りません。メモリの読み書きルールに「参照したメモリが現実と食い違っていたら更新または削除する」を含めることで、第2回のcontext poisoningとして誤った記憶が戻ってくるのを防げます。

下ろしておき、必要なときだけ再び上げます。計画ファイル・メモリ・RAGに共通する原則
下ろしておき、必要なときだけ再び上げます。計画ファイル・メモリ・RAGに共通する原則

RAG、倉庫が図書館規模になったら

計画ファイルとメモリは、数十個のファイル規模の話です。では、倉庫が図書館ほどの大きさだったらどうでしょう。社内Wiki数千ページ、論文数万件、顧客問い合わせ記録数十万件。必要な情報がそのどこかにあることは確かですが、すべてをコンテキストに載せることはできません。

このとき使う手法がRAG(Retrieval-Augmented Generation、検索拡張生成)です。質問が来たら、まず倉庫から関連する断片を検索し、見つかった数個だけをコンテキストに載せて回答を生成します。検索には通常、embeddingという手法を使います。テキストを意味空間の座標に変換しておけば、「返金規定」という質問と「決済キャンセルポリシー」という文書は表現が違っても近い座標に置かれるため、キーワードが一致しなくても見つけられます。

しばらくの間、RAGは長文書を扱う唯一の正解と考えられていました。しかしコーディングエージェントの領域では、面白い逆転が起きました。ツールを使えるエージェントは、embedding検索なしでもgrepとファイル探索を繰り返し、必要なコードをかなりうまく見つけられることが分かったのです。そのため、現在の実務的な感覚はハイブリッドです。正確な識別子があるコードにはエージェントの直接探索が強く、表現がばらばらな自然言語文書の集合にはembedding検索が強い。どちらの場合も、「すべてを載せず、クエリ時点で関連部分だけを載せる」という原則は同じです。

セッション終了後も残る記録が、長いタスクの生命線です
セッション終了後も残る記録が、長いタスクの生命線です

まとめ

  • コンテキストは作業台で、ファイルは倉庫です。セッション終了後も残すべき知識は、コンテキストではなくファイルへ下ろすのが基本です。
  • 計画ファイルは長いタスクをセッションリセットから救い、コンテキストの末尾付近に目標を繰り返し表示して、脱線を防ぎます。
  • メモリには他から導出できない情報だけを書き、インデックスだけを常時ロードし、古い項目は更新・削除ルールで管理します。
  • 倉庫が非常に大きい場合は、RAGでクエリ時点に関連する断片だけを載せます。コードには直接探索が、自然言語文書の集合にはembedding検索が強いです。

シリーズの最後の回が残っています。これまでは品質のためにコンテキストを管理してきましたが、最後はお金の話です。同じコンテキストでも積み上げ方によってAPIコストが何倍も変わるプロンプトキャッシュの仕組みと、コンテキストの前半を不用意に変更してはいけない理由を扱います。

あわせて読みたい