10月16日、Techstrong.aiが「Agentic AI Memory in Production: Why Enterprise Agents Forget and How to Fix It」と題した記事を公開した。この記事では、エンタープライズ向けAIエージェントがなぜ文脈を「忘れる」のか、その構造的な原因と、短期・長期・エピソードメモリを組み合わせた実装による解決策について詳しく紹介されている。
AIエージェントが「忘れる」のは設計の問題だ
LLMベースのAIエージェントをプロダクション環境に投入したとき、多くのエンジニアが直面する現実がある。エージェントが直前のやり取りを覚えていない、複数セッションにまたがって状態を保持できない、長い会話の途中で文脈が壊れる——これらはモデルの「賢さ」の問題ではなく、メモリ設計の問題だ。
LLMは本質的にステートレス(状態を持たない)な推論エンジンである。各推論呼び出しは独立しており、モデル自体は何も「記憶」しない。エージェントが文脈を持てるのは、開発者がプロンプトに何らかの情報を詰め込んでいるからに過ぎない。この設計上の制約を理解せずにエージェントを構築すると、コンテキストウィンドウの溢れ、パフォーマンスの劣化、ユーザー体験の崩壊といった問題が本番で顕在化する。
こうした問題に対応するメモリ管理ライブラリとして、LangMem(LangChainエコシステム向け)や Mem0(エージェント向けのメモリレイヤーを提供するOSSライブラリ)が注目を集めている。これらはエージェントのメモリ管理を抽象化し、短期・長期の情報を統合的に扱うAPIを提供している。
エンタープライズ環境では問題の深刻さがさらに増す。数百人規模のユーザーが同一エージェントを並列利用するシナリオでは、セッションごとに全履歴をコンテキストに詰め込む設計はトークンコストの急増を招く。適切なメモリ設計なしにスケールしようとすること自体が、プロジェクトのボトルネックになりうる。
3種類のメモリ:何をどこに持つか
エージェントのメモリは、その性質と用途から大きく3種類に分類できる。
短期メモリ(Short-Term Memory)
最も基本的な形態で、現在の会話セッション内の文脈を保持する。実装上はLLMのコンテキストウィンドウそのものがこれに相当する。GPT-4oやClaude 3.5のような最新モデルは数十万トークン規模のウィンドウを持つが、長ければ長いほど推論コストが増大し、いわゆる「Lost in the Middle」問題(ウィンドウ中央部の情報をモデルが参照しにくくなる現象。詳しくは原論文を参照)も発生する。
短期メモリの実装で重要なのは、何を詰め込むかではなく何を削るかだ。全会話履歴をそのままプロンプトに連結する素朴な実装は、初期段階では動くが、会話が長くなるにつれてコストと精度の両面で破綻する。
長期メモリ(Long-Term Memory)
セッションをまたいで保持される情報で、外部ストレージ(ベクトルDB、リレーショナルDB、キーバリューストアなど)に格納される。ユーザーの過去の設定、業務上のルール、蓄積された知識などがここに入る。
実装上の核心は検索の質だ。ベクトル検索(セマンティック検索)は意味的な近さで関連情報を引けるが、精度にはばらつきがある。キーワード検索はシンプルだが意味を捉えにくい。多くのプロダクション実装では、ハイブリッド検索(ベクトル+キーワードの組み合わせ)が採用されている。長期メモリの検索基盤としてRAG(Retrieval-Augmented Generation:外部ストアから関連情報を検索してLLMの生成に組み込む手法)を採用するケースが多く、その設計指針についてはRAGの実装パターンをまとめたLlamaIndexのドキュメントも参考になる。
エピソードメモリ(Episodic Memory)
人間の「あのとき何があったか」という記憶に相当する。特定のタスクの実行ログ、過去の意思決定の経緯、エラーと修正のパターンなどを時系列で保持する。エージェントが同じ失敗を繰り返さないための仕組みとして機能する。
エピソードメモリは長期メモリの一形態だが、「何を知っているか」ではなく「何をしたか」を記録する点で性質が異なる。RAGパイプラインと組み合わせることで、過去の実行経験をエージェントの判断に反映させることができる。
実装上は、たとえば以下のようなJSON構造で各エピソードを記録し、ベクトルDBに格納するアプローチが一般的だ。
{
"episode_id": "ep_20241016_0042",
"timestamp": "2024-10-16T09:31:00Z",
"task": "顧客Aの請求書を集計してレポートを生成",
"steps": [
{ "action": "fetch_invoices", "status": "success" },
{ "action": "aggregate", "status": "error", "reason": "null値が含まれていた" },
{ "action": "sanitize_data", "status": "success" },
{ "action": "aggregate", "status": "success" }
],
"outcome": "success",
"lesson": "集計前にnullチェックが必要"
}
このように構造化しておくことで、次回類似タスクを実行する際に「nullチェックが必要」という経験をRAGで検索・参照でき、同じエラーを繰り返さない設計が実現できる。
プロダクションで効く実装パターン
記事では、エンタープライズ環境での実装において特に重要なパターンがいくつか挙げられている。
メモリの圧縮・要約:会話が長くなった際に、古い部分を要約してコンパクトな表現に置き換える。完全な履歴は別ストレージに保存しつつ、プロンプトには要約のみを渡す設計だ。
階層型メモリ管理:直近の数ターンは生の会話テキスト、それより古い部分は要約、さらに古い情報は検索可能な外部ストアに置くという多層構造。コストと文脈保持のバランスを取る現実的なアプローチだ。
メモリの有効期限と削除ポリシー:エンタープライズ用途ではGDPRや社内ポリシーへの対応が必須になる。どのメモリをいつ削除するかを設計段階で組み込む必要がある。GDPRにおけるAI・データ保持要件については欧州データ保護委員会のガイドラインも参照に値する。
見落とされがちな落とし穴
メモリ設計でよく見落とされるのがメモリの鮮度管理だ。長期ストアに蓄積した情報が古くなっても、エージェントはそれを「古い」と判断する手段を持たない。情報にタイムスタンプを付与し、検索時に鮮度を考慮するロジックを明示的に実装しなければ、エージェントは陳腐化した情報を根拠に判断を下し続ける。
もう一つはマルチエージェント環境でのメモリ共有だ。複数のエージェントが同一の長期ストアを参照・更新する場合、書き込みの競合や不整合が発生しうる。これはほぼソフトウェアエンジニアリングの古典的な分散システム問題であり、適切なロック機構やイベントソーシングの導入が求められる場面もある。
エージェントのメモリ問題は、LLMの能力の限界ではなく、アーキテクチャの問題として捉え直すことが解決の第一歩だ。ステートレスなモデルの上にステートフルなシステムをどう構築するか——これはWebアプリケーション開発がセッション管理を設計してきた問いと、構造的には同じだ。
詳細はAgentic AI Memory in Production: Why Enterprise Agents Forget and How to Fix Itを参照していただきたい。