AI News HubLIVE
站内改写8 分で読了

コンテキスト崩壊時:エージェントに記憶喪失の検出と復旧を教える

本稿はエージェンティックエンジニアリングシリーズの第8回目であり、複雑なマルチステップ作業を行うAIエージェントにおけるコンテキスト喪失問題を扱います。著者は外部化・認識・再水和(ERR)パターンを提案します:エージェントの状態をディスクに保存し、コンテキストの劣化を検出し、ファイルから復旧します。歴史的な類推(640Kメモリ制限)と実際のCopilotクラッシュ事例を用いて問題を説明します。記事では、実行継続性(現在のステップ)とタスク継続性(全体的な目標)という2層の状態外部化を詳細に説明します。

ソースO'Reilly AI & ML Radar著者: Andrew Stellman

本稿はエージェンティックエンジニアリングとAI駆動開発に関するシリーズの第8回目です。第1回、第2回、第3回、第4回、第5回、第6回、第7回をお読みください。

「640Kあれば誰にとっても十分だ」—ビル・ゲイツ(とされる)

複雑なマルチステップ作業を行うAIエージェントを構築しているなら、コンテキスト喪失に直面するでしょう。エージェントのワーキングメモリが満杯になり、古い情報が静かに削除または圧縮され、エージェントは何かを忘れたことに気づかずに動作を続けます。本稿は、コンテキスト管理に関するレーダー記事三部作の第3弾であり、私が改良してきた問題検出と復旧のパターン、すなわち外部化・認識・再水和パターン(ERR、エラー復旧パターンとしてかなり良い頭字語だと思います)について説明します:エージェントの状態をディスク上のファイルに保存し、コンテキストが劣化したことを検出し、それらのファイルから再読み込みして復旧します。個々の技法はエージェントおよびスキルエンジニアリングの標準的な手法(チェックポイント、進捗ファイル、状態検証)ですが、本当の力はそれらを一貫したワークフローに組み合わせ、ライブで使用したりエージェントに組み込んだりできる点にあります。各ステップについて、独自のエージェントやコーディングセッションに適応できる具体的なプロンプトとともに説明します。

これが記憶の話につながります。ゲイツは冒頭の引用を実際に言ったことはないと何度も述べていますが、それが生き残っているのは、その時代の核心的な制約、人々が常に苦闘し、今では笑い話にできる制約を捉えているからです。その頃、私は1MBのRAMを搭載した286を使用していました。メガバイトです。ギガバイトではありません。MS-DOS 3.3は640Kのコンベンショナルメモリと384Kのアッパーメモリを提供し、私はそのすべてのビットを使いこなす方法を考えるのに多くの時間を費やしました。メモリマネージャを設定し、デバイスドライバを高位にロードし、常駐プログラム(TSR)を使用(および作成!)してコンベンショナルメモリから自身を移動させてスペースを解放し、一般的にメモリを積極的かつ意図的なエンジニアリングを必要とするリソースとして扱いました。640Kに収まらないやりたいことがたくさんあり、当時のほとんどの人と同様に、メモリ制限を補うためにかなりの努力をしました。

私たちはAI開発の640K段階にいます。コンテキストウィンドウが新しいRAMの天井です。今日のほとんどのモデルは200Kから2Mトークンのワーキングメモリを提供し(1980年代末から1990年代初頭のメモリと同様に、これらの数字は常に増加しています)、複雑なマルチステップ作業を行うエージェントを構築しているなら、その天井にぶつかるでしょう。そのとき、AIは圧縮を開始します:会話の古い部分を圧縮または削除してスペースを確保します。286でコンベンショナルメモリを使い果たしたときと同様に、物事が正しく動作しなくなり、その理由がわかりません。

20年後、私たちは今日の貧弱なコンテキストウィンドウを振り返り、2020年代の開発者がわずか数百万トークンでどうやって何かを成し遂げていたのか不思議に思うでしょう。なぜなら、これは何も新しいことではないからです。信じられないなら、1970年代初頭に父がプリンストン大学でEvans and Sutherland LDS-1グラフィックスコンピュータ(最初の商用ベクターグラフィックスマシン)をPDP-10メインフレームに接続して作業している写真をご覧ください:

実際のLDS-1は背景の大きなキャビネット内、モニターの真後ろにあります。その隣、写真の外には、16Kの磁気コアメモリ(厳密には8Kワード)を搭載したメモリユニットを収めるさらに大きなキャビネットがあります。

したがって、わずか10年後に、デスクトップに収まる小型PCの640Kが贅沢に見えたことが想像できるでしょう。

本シリーズの過去2回の記事(「なぜ誰も開発者にコンテキスト管理を教えないのか?」および「あなたのAIエージェントはすでに伝えたことの半分を忘れている」)では、コンテキストとは何か、なぜコンテキスト管理が重要なのかを説明し、重要な情報をAIのコンテキストウィンドウに残さずファイルに保存するための実用的なテクニックとプロンプトを共有しました。本稿はより技術的です。これらの戦略に基づいて、コンテキストを失ったことを検出し、自律的に復旧できるエージェントを構築する方法について説明します。

力ずくでコンテキスト喪失に対処する

私はこの種のコンテキスト管理を、これから説明する特定のツールが存在するずっと前から行ってきました。しかし、最近のクラッシュは、そのプロセスが最も力ずくの形でどのように見えるかを明確に示す例を提供しました。

Copilotで7ステップの計画に取り組んでいて、ステップごとに進め、各ステップを別のAIにレビューさせてから次に進んでいました。ステップ1と2は順調でした。ステップ3のプロンプトを与えたところ、それは直接ステップ4に飛びました。この種のことは非常にイライラさせられます。なぜなら、複雑な機能をコードで実装できるほど賢いAIが(ええと)4まで数えられるはずだからです。

AIがステップを見失ったり、プロンプト間で数えられなくなったりしたときにイライラしないための鍵は、AIが何を得意とし、どのように記憶するかを覚えておくことです。使用しているAIがそのような動作をした場合、会話履歴を確認してください。おそらく、最後のメッセージの上あたりに「会話履歴を要約中」または「会話を圧縮中」と表示されているでしょう。それは、AIがどこにいたかのカウントが文字通りメモリからパージされたため、見失ったことを示しています。

AIは指示を実行するのが得意です。長い会話の中で自分の状態を追跡するのは苦手であり、メモリの管理方法がその大きな理由です。本稿は、AIが最も苦手なことに依存しないようにAIツールを構築する方法を見つけることについてです。

しかし、圧縮だけがAIがコンテキストを失う唯一の方法ではありません。数週間前、私はCopilotでの長いセッションに没頭し、マルチフェーズのコードレビューに取り組んでいました。コードベースと共同で行った決定についてAIとコンテキストを構築するのにかなりの時間を費やしました。次のフェーズに移ろうとしたところ、次のメッセージが表示されました:

コンテキスト全体が消去されました。これは非常にイライラする問題になる可能性がありました。なぜなら、セッションの長い履歴があり、私たちが行っていることについて多くの知識を蓄積していたからです。これはOpus 4.6とCopilotの会話履歴との相互作用のバグであることが判明し、他の人々も同じ問題に遭遇しているのを見ました。私は空の新しいプロンプトを見つめていました。

そこで私は、振り返ってみると本稿全体のテーマの力ずくの良いバージョンと言えることをしました。コンテキストが失われたことを認識し(会話全体が消えたので見逃しようがありません)、会話全体をCopilotからコピーしてテキストファイルに貼り付けました。そして新しいセッションに次のプロンプトを与えました:

長い会話の途中でエラーが発生し、コンテキスト全体が消去されました。#file:chat_history.txtに会話のコピーを保存したので、それを読んで状況を把握してください。

そして、それは機能しました!新しいセッションは必要な場所に戻りました。

この単純なエラーと復旧は、コンテキスト喪失に対処するためのかなり良いパターンを実際に示しています:

状態を外部化する。重要な情報を会話から取り出し、ディスク上のファイルに保存します。これにより、コンテキストウィンドウが再編成されても情報は消えません。

喪失を認識する。エージェントの作業コンテキストが消去または劣化したことに気づきます。それは明白(クラッシュなど)な場合も、微妙(出力が静かに意味をなさなくなるなど)な場合もあります。

ファイルから再水和する。新しいセッションをそのファイルに向け、記録された内容から理解を再構築させます。

個々のメカニズムは、認知科学(認知オフローディング、タスク再開)、ソフトウェアエンジニアリング(Mementoパターン、Reactハイドレーション)、知識管理(SECIモデル)で十分に文書化されています。私はそれらのいずれかを発明したとは主張しません。しかし、これら3つのフェーズを統一された名前付きパターンに抽象化し、AIコンテキスト管理に適用することは、私の知る限り新しいものです。それは発明ではなく、統合と体系化です。

この場合、コピー&ペーストで行いました。これは特にエレガントではありませんが、私には有効でした。しかし、これは粗い道具です。生の会話ダンプは多すぎる情報と少なすぎる情報の両方を含みます:多すぎるのはツールコール、行き止まり、もはや重要ではないやりとりなどのノイズでいっぱいだからです。少なすぎるのは、セッション中に静かに圧縮されたコンテキストがすでに失われているからです。これらのメカニズムをエージェントやスキルに組み込む場合、はるかに巧妙で自動化された方法で実行できます。

外部化:エージェントに2層の状態を追加する

外部化、つまりエージェントの状態を定期的に保存するというアイデアは、オープンソースのAIコーディングスキルであるQuality Playbook(構造化コードレビューを実行)を構築中にAIアシスタントとの会話から生まれました。Playbookは構造化コードレビューを単一のプロセスとして実行しますが、すべてを一度に実行しようとすると、1500万トークンのリクエストに簡単になる可能性があります。本シリーズの前回の記事で、これを6つのフェーズに分割した方法を説明しましたが、それが可能だったのは各フェーズのコンテキストがすでに外部化されていたからです。各フェーズはファイルから入力を読み取り、作業を行い、出力をファイルに書き込み、停止します。次のフェーズは、エージェントが覚えているものではなく、ファイルから情報を取得します。これが、実装を依頼する前にAIに計画を依頼するという一般的なアドバイスに聞こえるなら、それは同じ原則をコンテキスト管理に適用したものです。各ステップを分離し、出力を永続化することで、それを検査でき、次のステップはエージェントのメモリに依存しません。

しかし、それらのファイルには何を含めるべきでしょうか?AIはそれを理解するのが実際に得意であることがわかりました。ある時点で、私はアシスタントに次のように尋ねました:

エージェントが進行に応じてより多くのコンテキストをファイルに記録し、途中で何も失われないようにすることは理にかなっていますか?個別のプロンプトに分割しても機能するはずです。各ステップの結果が永続化されるからです。さらに、デバッグと改善のために推論を監査できます。

そのプロンプトだけで十分でした。アシスタントはファイル構造を自分で設計しました:アクティブなフェーズと完了したタスクを記録する進捗トラッカー、各パスが出力を追加するJSONLアーティファクトファイル(JSONLはJSONオブジェクトの束を1行に1レコードずつ格納するファイル)、および各フェーズの目的を説明する簡単なドキュメントセットです。これを過剰に設計する必要はありません。保存したい内容をエージェントに伝え、ファイルレイアウトを考えさせてください。

結果として現れたのは、実行継続性とタスク継続性という2つのカテゴリです:

実行継続性:エージェントがタスクの途中で作業を再開するために必要な状態:現在のステップ、完了したこと、これまでに行った決定。これらのファイルはエージェントの作業に応じて常に変化します。

タスク継続性:実行中に変化しない広範なコンテキスト:タスク全体の目的、成功の定義、構造的制約。これらのファイルは一度書き込まれ、再開のたびに読み取られます。

圧縮が疑われる後にエージェントが再開する必要がある場合、両方の層を読み戻します。タスク継続性ファイルは、取り組み全体が何に関するものかを再確認させます。実行継続性ファイルは、作業の途中に戻します。これらを合わせることで、エージェントは圧縮された可能性のあるものに依存せずに続行するのに十分な情報を得られます。

重要なのは、外部化はタスクの開始時に一度行うものではないということです。エージェントに頻繁なチェックポイントで状態を保存させ、途中で圧縮が発生した場合に最新のチェックポイントがエージェントが作業していた場所に近いようにします。以下は、レコードを1つずつ処理するタスクに対してエージェントに与えた指示の例です:

各レコードの後に進捗ファイルを更新し、バッチでは更新しないでください。最初に出力行を書き込み、次に新しいカーソルで進捗ファイルを更新し、

[AIコスト制御のため本文はここで終了]