コンテキストウィンドウは記憶ではない:AIエージェント開発者が理解すべきこと
この記事では、大きなコンテキストウィンドウがエージェントの記憶と同じではない理由と、検索、圧縮、要約の技術がエージェントの認知スタックでどのように連携するかを説明し、真の記憶の永続化を実現する方法を紹介します。
この記事では、大きなコンテキストウィンドウがエージェントの記憶と同等ではない理由と、検索、圧縮、要約の各技術がエージェントの認知スタックにおいてどのように異なる役割を果たし、効果的なコンテキスト管理を実現するかを深く解説します。オフィスにまつわる比喩を用いて、開発者が直感的に理解できるように説明します。
まず、コンテキストウィンドウは机の表面やステートレスのメモ帳に例えられます。AIモデルは本質的に完全にステートレスであり、API呼び出しごとにゼロから開始します。大量の会話履歴をコンテキストウィンドウに詰め込んでも、モデルが本当に「記憶」しているわけではなく、単に全履歴を素早く再読しているだけです。この戦略に長期的に依存すると、三つの危険な落とし穴があります。モデルが巨大なプロンプトの最初と最後だけに注目し、中間部の情報を無視する「怠け者」のように振る舞うこと、会話が成長するにつれて毎ステップで全履歴を再送信する必要が生じる「雪だるま効果」、そして巨大なテキストに対してモデルが最初の単語を生成するまでに時間がかかるレイテンシ問題です。記事ではコード例を用いて、47ステップ目で46回前のやり取りを全て再送信しなければならない雪だるま効果を具体的に示しています。
検索拡張生成(RAG)は、オフィス内の本棚に例えられ、リアルタイムで関連データを取得できます。しかし、エージェントのループ内では、ベクトル類似性が必ずしも意味的真実と一致するとは限りません。例えば、ユーザーが最初に会議を金曜日に変更するよう指示し、後でAliceの病気により木曜日の会議をキャンセルするよう指示した場合、RAGは矛盾する両方の指示を返す可能性があります。より信頼性の高いパターンは、生成前にタイムスタンプを比較して最新の指示を優先するなど、矛盾を解決することです。記事では、取得したチャンクから最新のタイムスタンプを持つものを選択するコードスニペットを示し、これによりエージェントが古い指示を繰り返すのを防げると説明しています。
圧縮はファイルのZIP圧縮に類似しており、アルゴリズムを使用してトークン数を削減しながら、重要なデータはそのまま保持します。例えば、15,000トークンのJSONペイロードを5,000トークンに圧縮し、モデルに作業スペースを確保します。実際には、大きなペイロードがメインプロンプトに到達する前に、LLMLinguaなどの圧縮モデルを経由させることで実現します。圧縮後の事実は完全に保持され、デスク上の占有スペースだけが小さくなります。
一方、要約はオリジナルデータを削除し抽象化に置き換えるため、不可逆的な一方通行です。良い実践方法は、分岐ストレージを使用することです。生のトランスクリプトをS3などの安価なストレージに保存し、アクティブプロンプトには合成された要約のみを渡します。記事では、要約関数のコード例を示しています。第一に生のトランスクリプトをコールドストレージに永続化し、第二に要約を生成してアクティブプロンプトにのみ戻します。これにより、後で詳細が必要になった場合でもS3から取得でき、アクティブプロンプト内から再構築する必要がありません。
記憶の永続化には、エージェントがデータベース自体ではなく、データベース管理者として振る舞う必要があります。例えば、ユーザーが「私の犬の名前はGoofyだが、Plutoに改名するかもしれない」と言った場合、エージェントは明示的にツール呼び出しをトリガーし、エンティティグラフを更新すべきです。SQLテーブル、知識グラフ、Redisのいずれであっても、エージェントは各ターンの開始時に状態をクエリし、終了時に変更をコミットするように設計されるべきです。記事では、最初にエンティティグラフから現在の状態をクエリし、応答を生成し、最後にツール呼び出しに基づいてグラフを更新するループのコード例を示しています。
まとめると、この記事の教訓は単純です。1000万トークンの巨大な机を買おうとするのではなく、普通の机を用意し、エージェントに鋭い鉛筆を与え、ファイルキャビネットを開けてその内容を最適に活用する方法を教えることです。