MemGPTを用いて仮想的にコンテキストを最大限に拡張する

目次

はじめに

ChatGPTに長い相談をしていたら、途中で「先ほどの話」をすっかり忘れられた。100ページを超えるPDFを丸ごとAIに読ませたいのに、トークン制限で弾かれてしまう。LLMを実務で使い込むほど、こうした「記憶力の壁」にぶつかった経験はないでしょうか。

この課題に対し、UC Berkeleyの研究チームが2023年に提案したのがMemGPTです。OSのメモリ管理(仮想メモリやページング)の仕組みをLLMに持ち込み、限られたコンテキストウィンドウを仮想的に拡張するという画期的なアプローチで注目を集めました。

本記事では、MemGPTの論文が提案するコア概念から3層メモリアーキテクチャ、LLM自身がメモリを操作する自律的な仕組みまでを徹底的に解説し、後半ではDifyで同様の概念を再現する方法にも触れていきます。

この記事で分かること

  • MemGPTのコア概念:OSの仮想メモリをLLMに応用する「3層メモリアーキテクチャ」の仕組み
  • Difyを使ったMemGPT風チャットボットの具体的な構築手順
  • MemGPT / RAG / コンテキスト長拡張 / 会話要約の4手法比較と用途別の使い分け
  • 後継プロジェクト「Letta」の最新動向とMem0との違い

1. MemGPTの全体像:何ができて、何ができないのか

LLMの「記憶の壁」という前提

コンテキストウィンドウ(LLMが1回の会話で読める文字数の上限)は年々拡大していますが、長期記憶の問題は解決していません。

モデル(2026年4月時点)コンテキストウィンドウ
GPT-4o / Claude Opus 4128K〜200Kトークン
GPT-4.1 / Gemini 2.5 Pro1M〜2Mトークン
Llama 4 Scout10Mトークン

トークン数は増えていますが、コスト増大(1Mトークンで約125倍)、応答速度の低下、中間部の情報を見落とす「Lost in the Middle」問題により、「大きいウィンドウで全部入れる」は実用的な解決策になりません。必要なのは、どの情報をいつコンテキストに入れるかを制御する仕組みです。

MemGPTでできること・できないこと

UC Berkeleyが2023年に発表したMemGPTarXiv:2310.08560)は、OSの仮想メモリ・ページングの仕組みをLLMに応用し、コンテキストを仮想的に拡張します。本章の詳細な仕組みに入る前に、MemGPTで何ができて、何ができないのかを整理しておきます。

観点MemGPTでできることMemGPTでできないこと
長期記憶外部ストレージに情報を永続保存し、何ヶ月後でも参照可能コンテキストウィンドウ自体を物理的に拡張すること
自律的管理LLM自身が「何を覚え・忘れ・探すか」をFunction Callingで判断判断ミスの完全排除(LLMの能力に依存)
情報の更新会話中にリアルタイムでメモリを書き換え古い詳細情報の完全な再現(アーカイブで要約化される場合あり)
大規模ドキュメント対応必要な部分だけコンテキストに呼び出して処理ドキュメント全体を一度にLLMに読ませること
開発者の負担メモリ管理ロジックの設計が不要ゼロから実装する場合の設計コスト

従来のRAGが「開発者がルールベースでメモリを管理」するのに対し、MemGPTはLLM自身がFunction Callingでメモリを自律管理する点が本質的な違いです。OSのアナロジーで表現すると以下のようになります。

OSのメモリ管理    : RAM(高速・容量小)       ↔ ディスク(低速・容量大)  管理者=OSカーネル
MemGPTのメモリ管理: コンテキスト(高速・容量小) ↔ 外部DB(低速・容量大)   管理者=LLM自身

3層メモリアーキテクチャ

MemGPTのメモリは、OSのメモリ階層を模した3層構造です。

階層名称役割OS概念
第1層メインコンテキストLLMが直接読み書きする作業領域。システムプロンプト+ワーキングメモリ(LLMが編集可能)+直近の会話履歴RAM
第2層リコールメモリ過去の全会話履歴を保存・検索するDBファイルキャッシュ
第3層アーカイバルメモリ長期保存用の外部ストレージ(ベクトルDB等)ディスク
3層メモリアーキテクチャの概略図

LLMが自分でメモリを操作する仕組み

LLMには以下のような関数が公開されており、LLM自身が判断して呼び出します。

関数名操作説明
core_memory_append(key, value)追記ワーキングメモリに新しい情報を追加
core_memory_replace(old, new)更新ワーキングメモリ内の情報を書き換え
archival_memory_insert(text)書込長期保存用ストレージに情報を保存
archival_memory_search(query)検索セマンティック検索で関連情報を取得
conversation_search(query)検索過去の会話履歴からキーワード検索

実際の動作例:

# === ターン1:ユーザーが自己紹介 ===
User: "田中太郎です。東京のAI開発会社で働いています。"
→ LLMが自律的に判断: core_memory_append(key="user_info", value="田中太郎, AI開発会社")

# === ターン30:転職を報告 ===
User: "先月転職して、大阪のフィンテック企業に移りました。"
→ LLMが自律的に判断: core_memory_replace(old="AI開発会社", new="大阪のフィンテック企業")

# === ターン100:過去の議論を参照 ===
User: "以前話したDB設計方針、覚えてますか?"
→ LLMが自律的に判断: conversation_search(query="DB設計方針")
→ 検索結果を踏まえて回答

重要なのは、これらの関数呼び出しはLLM自身が「保存すべき」と判断して実行している点です。システムプロンプトにメモリ操作のガイドラインが含まれており、LLMはそれに従って自律的に行動します。


2. DifyでMemGPTの概念を再現する

Difyが備える会話変数・Variable Assigner・LLMノードを組み合わせれば、MemGPTの「自己編集メモリ」の概念をGUIだけで再現できます。ここでは、チャットフローを使って「MemGPT風の記憶を持つチャットボット」を構築する手順をStep形式で解説します。

チャットフロー全体像

チャットフロー全体図

Step 1:チャットフローアプリを新規作成し、会話変数を定義する

Difyダッシュボードで「スタジオ」→「アプリを作成」→ 「チャットフロー」 を選択します。

次に、会話変数(Conversation Variables)を定義します。これがMemGPTのコアメモリに相当します。チャットフロー画面の右上「変数」パネルから、以下の会話変数を追加してください。

変数名初期値役割
core_memoryString{"user_name":"","user_role":"","preferences":"","project_context":""}MemGPTのコアメモリ。ユーザー情報やプロジェクト状況を保持

JSON形式で複数のキーを持たせることで、MemGPTのcore_memory_append/core_memory_replaceのような操作をDify上で再現できます。

Step 2:ナレッジ検索ノードの配置(ドキュメントや長期記憶の参照)

開始ノードの次にナレッジ検索ノードを追加します。社内ドキュメントや過去に蓄積した情報など、大量のデータから必要な部分だけを取り出す役割です(MemGPTのアーカイバルメモリに相当)。シンプルな会話ボットでナレッジベースが不要な場合は、このノードをスキップしてStep 3に直接繋いで構いません。

設定項目
クエリ変数{{#sys.query#}}(ユーザーの入力)
ナレッジベース検索対象のナレッジベースを選択
検索方式ベクトル検索(推奨)

Step 3:メインLLMノード(回答生成)

ユーザーへの回答を生成するLLMノードを追加します。ポイントはコアメモリ(会話変数)をシステムプロンプトに埋め込むことです。

Step 3:メインLLMノード(回答生成)

システムプロンプト:

あなたは、ユーザーの情報を長期的に記憶するパーソナルアシスタントです。

## コアメモリ(あなたが記憶しているユーザー情報)
{{#core_memory#}}

## ルール
1. コアメモリに記載されている情報を最優先で活用し、パーソナライズされた回答をしてください
2. コアメモリの情報を使って回答する場合は「記憶している情報によると〜」のように、
   記憶を使っていることが自然に伝わる表現を含めてください
3. コアメモリが空(全フィールドが空文字)の場合は、初対面として丁寧に対応してください
4. ユーザーが自己紹介や状況変化を伝えてきた場合、自然に会話を続けてください
   (メモリへの保存は別のシステムが自動で行います)
5. コアメモリに載っていない事実については、一般知識から回答してOKですが
   「一般的な情報ですが〜」と前置きしてください

ユーザープロンプト:

{{#sys.query#}}
設定項目推奨値
モデルGPT-4oやClaude Sonnet等の高性能モデル
メモリオフ(無効化)
コンテキストStep 2のナレッジ検索結果を参照

⚠️ 重要:Difyの会話メモリ(TokenBufferMemory)はオフにしてください
今回の実装では、会話の記憶をDify標準の会話メモリではなく会話変数(core_memory)で管理します。会話メモリをオンにすると「会話履歴から情報を拾っているだけなのか、core_memoryから取得しているのか」が区別できなくなるため、MemGPT的なメモリ管理が本当に機能しているかを検証できなくなります。

なお、{{#core_memory#}} は会話変数の値がリアルタイムで展開されるため、Step 6でメモリが更新されると次回の会話からこの部分の内容が変わります。これがMemGPTの「ワーキングメモリが動的に更新される」仕組みの再現です。

Step 4:メモリマネージャーLLMノード(記憶の判断)

ここが本記事の最も重要なStepであり、MemGPTの「OS的メモリ管理」を再現する核心部分です。

なぜ「メモリマネージャー」が必要なのか

通常のチャットボットでは、「ユーザーが重要な情報を伝えたかどうか」を判定するロジックは開発者がルールベースで書く必要があります。たとえば「名前が含まれていたら保存」「数字が含まれていたら保存」といった条件分岐です。しかし、この方法では想定外の情報(「阪神ファンです」のような好み)を拾えません。

MemGPTの革新的な点は、この判断をLLM自身に委ねることです。本チャットフローでは、メインLLM(Step 3)とは別にメモリ管理専用のLLMノードを配置し、毎回の会話を分析させます。

メモリマネージャーの役割

[毎回の会話]
   ↓
[メモリマネージャーLLM が自律的に判断]
   ├── 「田中です」→ user_name を更新すべき → JSON出力
   ├── 「阪神ファンです」→ preferences を更新すべき → JSON出力
   ├── 「マーケ部に異動しました」→ user_role を更新すべき → JSON出力
   └── 「今日は暑いですね」→ 保存不要 → NONE出力

つまりメモリマネージャーは、MemGPTにおけるOSのカーネルに相当します。ユーザーには見えない裏側で、毎回の会話を監視し、「何を覚えるか・何を忘れるか」を自律的に判断し続けるのです。

Step 4:メモリマネージャーLLMノード(記憶の判断)

プロンプトの設計

メモリマネージャーLLMのプロンプト設計は、このチャットフロー全体の品質を左右する最重要ポイントです。以下の3つの要素を明確に指示する必要があります。

  1. 現在のコアメモリの内容(何を既に知っているか)
  2. 出力形式の厳密な制約(JSONまたはNONEのみ)
  3. 判断基準の具体例(何を保存し、何を無視するか)

システムプロンプト:

あなたはメモリマネージャーです。会話内容を分析し、コアメモリを更新してください。

## 現在のコアメモリ(JSON)
{{#core_memory#}}

## タスク
会話から新しい情報を抽出し、コアメモリを更新した結果を**JSON形式のみ**で出力してください。
更新がない場合は NONE とだけ出力してください。

## 出力ルール
- 更新がある場合:更新後のコアメモリ全体をJSONで出力(既存情報は保持しつつ新情報を反映)
- 更新がない場合:NONE とだけ出力
- JSON以外のテキスト(説明、前置き、マークダウン装飾)は一切出力しないこと

## 更新すべき情報の例
- user_name: ユーザーの名前(「田中です」→ user_nameを更新)
- user_role: 職業・役職・所属(「マーケティング部で働いています」→ user_roleを更新)
- preferences: 好み・趣味・関心事(「阪神ファンです」→ preferencesを更新)
- project_context: 進行中のプロジェクトや相談内容(既存に追記)

## 更新しない情報
- 一時的な雑談(「今日は暑いですね」)
- 既にコアメモリに保存済みの情報
- AIへの質問(「〜を教えてください」)

ユーザープロンプト:

以下の会話を分析し、コアメモリの更新が必要か判断してください。

ユーザー: {{#sys.query#}}
アシスタント: {{#メインLLMノード.text#}}
設定項目推奨値
モデルGPT-4o-miniやClaude Haiku等の軽量モデル
温度(Temperature)0(JSON出力の安定性のため)

メモリマネージャーの出力例

実際にメモリマネージャーがどのようなJSONを出力するか、具体例を示します。

例1:ユーザーが「阪神タイガースファンです」と発言した場合

{"user_name":"","user_role":"","preferences":"阪神タイガースファン","project_context":""}

preferencesフィールドだけが更新され、他のフィールドは既存値を保持しています。

例2:ユーザーが「今日は暑いですね」と雑談した場合

NONE

→ 保存すべき情報がないため、NONEのみ出力。この場合、Step 5のIF/ELSEで更新ルートをスキップし、core_memoryは変更されません。

例3:既にuser_nameが保存済みの状態で「転職してマーケ部になりました」と発言した場合

{"user_name":"田中太郎","user_role":"マーケティング部","preferences":"阪神タイガースファン","project_context":""}

user_roleが新たに更新され、既存のuser_namepreferencesはそのまま保持されています。これがMemGPTのcore_memory_replaceに相当する動作です。

モデル選定とコスト最適化

設定項目推奨値理由
モデルGPT-4o-miniやClaude Haiku等の軽量モデル毎回の会話で呼び出されるため、コスト影響が大きい
温度(Temperature)0JSON出力の安定性を最大化するため
max_tokens500core_memoryのJSON全体が収まれば十分

メインLLM(GPT-4o等)には回答生成を任せ、メモリマネージャー(GPT-4o-mini等)にはJSON出力だけを任せるという役割分担によるコスト最適化が、MemGPT的設計の実務的なメリットです。

⚠️ 注意:メモリマネージャーの品質が全体を左右する
メモリマネージャーの判断が不正確だと「保存すべき情報を見逃す」「雑談を保存してメモリがノイズだらけになる」といった問題が起きます。本番運用では、Difyのログ機能でメモリマネージャーの出力を定期的に確認し、プロンプトの判断基準を微調整してください。

Step 5:IF/ELSEノード(メモリ更新の判定)

メモリマネージャーLLMの出力がuser_nameを含むJSONなら更新ルートへ、それ以外はスキップします。

Step 5:IF/ELSEノード(メモリ更新の判定)
設定項目
IF条件{{#メモリマネージャーLLM.text#}}user_name含む(contains)
IFルート→ Step 6(Variable Assigner)へ
ELSEルート→ Step 7(回答出力)へ

💡 なぜ { で始まる(start with)ではなく user_name を含む(contains)なのか?
{で始まるかどうかだけで判定すると、メモリマネージャーが {"NONE": true}{"error": "判断できません"} のような想定外のJSONを返した場合にも更新ルートに進んでしまい、core_memoryが壊れるリスクがあります。user_nameはcore_memoryのJSONに必ず含まれるキーなので、「正しいcore_memory形式のJSONが出力された」ことを確認する判定として機能します。

より厳密にしたい場合は、user_name かつ preferences を含む(AND条件)にすると、さらに誤判定を減らせます。

Step 6:Variable Assignerノード(メモリ更新の実行)

IF条件を通過した場合、会話変数 core_memory を更新します。

Step 6:Variable Assignerノード(メモリ更新の実行)
設定項目
対象変数core_memory(会話変数)
操作上書き(Overwrite)
{{#メモリマネージャーLLM.text#}}(LLMが生成したJSON)

⚠️ 注意:この簡略化版で起こり得る3つのリスク
本記事ではメモリマネージャーLLMの出力をそのままcore_memoryに上書きしています。概念を理解するための簡略化ですが、本番運用ではこの方式に以下のリスクがあります。

リスク発生例影響
既存メモリの消失LLMがuser_nameを含め忘れたJSONを出力 → 名前が空文字に戻る蓄積した情報が一瞬で消える
不正なJSONによる破損LLMがJSON以外のテキスト(「以下が更新後のメモリです:」等)を混ぜて出力core_memoryが壊れ、以降の会話で全Stepがエラーに
意図しない上書きユーザーが「名前は田中です」と冗談で言った情報を真に受けて保存ユーザー情報が不正確になる

本番運用では、Step 5と6の間にコードノードを挟み、以下の安全策を入れることを強く推奨します。

💡 上級者向けTips:コードノードによる安全なメモリ更新
上記3つのリスク(既存メモリの消失・不正JSONによる破損・意図しない上書き)を防ぐには、Step 5(IF/ELSE)とStep 6(Variable Assigner)の間にコードノードを挟み、以下の処理を行うのが有効です。

import json

def main(new_memory_text: str, current_memory: str) -> dict:
    # 1. 現在のコアメモリをパース
    try:
        current = json.loads(current_memory)
    except json.JSONDecodeError:
        current = {"user_name":"","user_role":"","preferences":"","project_context":""}

    # 2. メモリマネージャーの出力をパース(失敗時は更新しない)
    try:
        new_data = json.loads(new_memory_text)
    except json.JSONDecodeError:
        return {"result": current_memory}  # 不正な出力の場合は現状維持

    # 3. 空文字でないフィールドだけを上書き(既存情報の消失を防止)
    for key in current:
        if key not in new_data:
            continue
        new_value = new_data[key]
        # 文字列型かつ空文字のフィールドはスキップ(0やFalseは正規の値として扱う)
        if isinstance(new_value, str) and new_value == "":
            continue
        current[key] = new_value

    return {"result": json.dumps(current, ensure_ascii=False)}

このコードが防ぐリスク:

  • 既存メモリの消失防止:新しい値が空文字の場合は上書きしない
  • 不正JSON対策:パース失敗時は現在のメモリをそのまま返す
  • 部分更新の実現:変更があったフィールドだけを安全に更新

Step 7:回答出力ノード(Answer)

Step 3のメインLLMノードの出力テキストを、ユーザーへの回答として返します。

Step 7:回答出力ノード(Answer)
設定項目
回答内容{{#メインLLMノード.text#}}

メモリ更新はバックグラウンドで行われ、ユーザーに見えるのはStep 3の回答だけです。裏側ではMemGPT的なメモリ管理が自動的に動いており、これがMemGPTの「OSが裏でメモリを管理する」構図の再現になっています。

振り返り:MemGPTの各メモリ層をDifyのどの機能で代替したか

Step 1〜7で構築したチャットフローは、第1章で紹介したMemGPTのメモリ層を以下のようにDifyの機能で再現しています。

MemGPTのメモリ層役割Difyでの代替機能
メインコンテキストLLMが直接参照する作業メモリTokenBufferMemory(トークン数ベースで会話履歴を制限)※今回はオフ
コアメモリユーザー情報・システム設定の常時参照会話変数(Conversation Variables、JSON形式で永続保存)
リコールメモリ過去の会話履歴の検索Dify内蔵の会話履歴機能
アーカイバルメモリ大量データの長期保存・検索ナレッジベース(RAG、ベクトル検索で必要な情報を取得)
メモリ管理OSメモリの読み書き・圧縮を自律制御LLMノード(メモリマネージャー役)+ Variable Assigner

動作イメージ:Before / After

Before(通常のチャットボット)

[セッション1] ユーザー: 田中太郎です。マーケティング部門で働いています。
              AI: 田中さん、よろしくお願いします!
[セッション2] ユーザー: 前回話した私のこと、覚えてますか?
              AI: 申し訳ありませんが、以前の会話内容はわかりません。 ← 忘れている

After(MemGPT風メモリ搭載 ※同一セッション内での動作)

[ターン1] ユーザー: 田中太郎です。マーケティング部門で働いています。
          AI: 田中さん、よろしくお願いします!
          (裏側) メモリマネージャー: core_memoryを更新
[ターン2] ユーザー: 私のこと、覚えてますか?
          AI: 記憶している情報によると、田中太郎さん、マーケティング部門にお勤めですね。 ← 覚えている

セッション横断の長期記憶については後述のテスト③で検証します。

テスト結果:4つの観点で実際に動かして検証

上記のチャットフローを構築し、Difyの会話メモリ(TokenBufferMemory)をオフにした状態で動作検証を行いました。会話メモリをオフにすることで、「記憶しているのは会話履歴ではなく、会話変数(core_memory)のおかげである」ことを明確に切り分けられます。

以下の4つの観点でテストしました。

#検証観点検証内容
基本動作:情報の保存と参照ユーザー情報を伝え、後から参照できるか
情報の上書き既存の情報が新しい情報で正しく更新されるか
セッションをまたいだ永続性新しいセッション(新規チャット)でも記憶が残っているか
矛盾した情報の入力前と異なる情報を伝えた場合、どう処理されるか

① 基本動作:情報の保存と参照

ターン1: 「私は阪神タイガースファンです」
ターン2: 「私の好きなプロ野球チームの監督を教えて」

ターン1の応答:

阪神タイガースファンなんですね。これからはその前提を意識してお話しますね。

裏側のメモリマネージャー出力:

{"user_name":"","user_role":"","preferences":"阪神タイガースファン","project_context":""}

preferencesが更新された ✅

ターン2の応答:

記憶している情報によると、あなたの好きなプロ野球チームは阪神タイガースです。
一般的な情報ですが、阪神タイガースの監督は藤川球児さんです。

実際の出力例1
確認項目結果
メモリマネージャーがpreferencesを更新した
メインLLMが「記憶している情報によると」と区別した
LLMの一般知識を「一般的な情報ですが」と区別した

② 情報の上書き

①の続きで、ユーザーが名前を伝えた場合。

ターン3: 「田中太郎です。マーケティング部で働いています」

裏側のメモリマネージャー出力:

{"user_name":"田中太郎","user_role":"マーケティング部","preferences":"阪神タイガースファン","project_context":""}

user_nameuser_roleが新たに追加され、既存のpreferences(阪神タイガースファン)は保持された ✅

実際の出力例2

ターン4: 「私のことを教えて」

応答:

記憶している情報によると、田中太郎さんですね。マーケティング部でお勤めで、阪神タイガースのファンでいらっしゃいます。

実際の出力例3
確認項目結果
新しいフィールド(user_name, user_role)が追加された
既存のフィールド(preferences)が消えていない
全フィールドを統合して応答できた

③ セッションをまたいだ永続性

②のセッション終了後、Difyの「新規チャット」ボタンで新しいセッションを開始します。

新セッション ターン1: 「私の好きな野球チームは?」

応答:

現時点では、あなたの好きな野球チームについては記憶していません。よければ教えてください。

実際の出力例4
確認項目結果
新しいセッションでもcore_memoryの内容が残っている❌ リセットされた
前のセッションで保存した「阪神タイガースファン」を参照できた

⚠️ Difyの仕様上の制約:会話変数はセッション単位でリセットされる
実際にテストした結果、Difyの会話変数(Conversation Variables)は同じセッション内では永続するが、「新規チャット」で新しいセッションを開始すると初期値にリセットされることが分かりました。これはMemGPTの論文が想定する「真のセッション横断型長期記憶」とは異なります。

この制約を回避するには、会話変数ではなく外部ストレージにメモリを永続化する必要があります。主な選択肢は以下の3つです。

方法説明難易度
Mem0プラグインDify Marketplaceのプラグインで、外部のメモリストレージに自動保存・検索◎ 簡単
HTTPリクエストノード + 外部DBStep 6の代わりに自社DBへAPIで書き込み、Step 3の前にAPIで読み出し△ 中級
Difyのナレッジベースに動的書き込みDataset APIを使って重要情報をナレッジベースに追加し、RAGで検索△ 中級

最も手軽なMem0プラグインによる解決策は、このあとのセクション「Mem0プラグインでセッション横断の長期記憶を実現する」で具体的に解説します。


④ 矛盾した情報の入力

②で user_name=田中太郎 / user_role=マーケティング部 / preferences=阪神タイガースファン が保存されたセッションに戻り、そこで矛盾する情報を伝えた場合の動作を検証します。

ターン5: 「実は来月から転職して、営業部に移ることになりました」

裏側のメモリマネージャー出力:

{"user_name":"田中太郎","user_role":"営業部(来月から転職)","preferences":"阪神タイガースファン","project_context":""}

user_roleが「マーケティング部」から「営業部(来月から転職)」に上書きされた ✅

ターン6: 「私の職業を教えて」

応答:

記憶している情報によると、田中太郎さんは来月から営業部に転職されるとのことです。

実際の出力例5
確認項目結果
矛盾する情報で既存フィールドが正しく上書きされた
古い情報(マーケティング部)が残っていない
「来月から転職」という時間的文脈も保持された

ただし、矛盾情報の処理精度はプロンプト設計とモデルに依存します。たとえば「転職したのは冗談です」と後から言われた場合、元に戻せるかどうかは現在の簡略化版では保証されません。そのようなケースにはStep 6で解説したコードノードによるバージョン管理が有効です。


総合評価

検証観点結果コメント
① 基本動作情報の保存・参照・コアメモリとLLM知識の区別、すべて正常
② 情報の上書き新フィールドの追加と既存フィールドの保持が両立
③ セッション永続性Difyの会話変数は「新規チャット」でリセットされる。セッション横断にはMem0等の外部ストレージが必要
④ 矛盾情報の処理✅(条件付き)基本的な上書きは正常。複雑な矛盾(冗談・訂正)はプロンプト改善やコードノード追加が必要

今回の実装で再現できたのは「LLMがメモリを自律管理する」部分であり、「セッション横断の長期記憶」を実現するには次に紹介するMem0プラグイン等が必要です。MemGPTの完全な再現ではなく概念の部分的な再現ですが、同一セッション内での自律的メモリ管理は通常のチャットボットでは実現できない大きな進歩です。

Mem0プラグインでセッション横断の長期記憶を実現する

テスト③で判明した「会話変数はセッション間でリセットされる」という制約を解決するのが、Dify Marketplaceで公開されているMem0プラグインです。

Mem0は、LLMアプリケーションに長期メモリを追加するためのミドルウェアです。メモリデータはmem0 Cloud(またはセルフホスト環境)に永続化されるため、Difyのセッションがリセットされても記憶が消えません。

Mem0プラグインが提供する3つのアクション

アクション説明MemGPTとの対応
Add Memory会話内容をユーザーID別に保存。mem0が自動的に重要情報を抽出・構造化core_memory_append
Retrieve Memoryクエリに関連するメモリをセマンティック検索で取得archival_memory_search
Get All Memories指定ユーザーの全メモリを一覧取得

チャットフローへの組み込み方

Step 1〜7で構築したチャットフローと比較すると、mem0プラグインを使う場合はメモリマネージャーLLM・IF/ELSE・Variable Assignerが不要になります。

mem0方式では、メモリの「何を保存するか」の判断をmem0のアルゴリズムに委ねる形になります。Step 4のメモリマネージャーLLMのようにプロンプトで細かく制御することはできませんが、セットアップは大幅に簡単になります。

セットアップに必要なもの

項目説明取得方法
Mem0 API Keymem0のAPIにアクセスするための認証キーmem0.aiでアカウント作成後に取得
User IDユーザーを識別する任意の文字列{{#sys.user_id#}}やメールアドレス等を使用

Dify Marketplaceからmem0プラグインをインストールし、API Keyを設定すれば、ワークフロー内のツールノードとして「Add Memory」「Retrieve Memory」が使えるようになります。

Step 1〜7方式 vs mem0方式の比較

比較項目Step 1〜7(会話変数方式)mem0プラグイン方式
セッション横断❌ リセットされる✅ 永続(mem0 Cloudに保存)
実装の複雑さ7ノード構築が必要2アクション追加のみ
メモリ管理の制御プロンプトで自由に設計可能mem0のアルゴリズムに依存
コストLLM呼び出し2回(メイン+メモリマネージャー)mem0 API利用料 + LLM 1回
MemGPTの概念理解◎ 仕組みを深く理解できる△ ブラックボックス的

どちらを選ぶべきか

ユースケース推奨
MemGPTの仕組みを理解したい・学習目的Step 1〜7方式
セッション内の記憶で十分(FAQ・タスク管理等)Step 1〜7方式
セッション横断の長期記憶が必要(パーソナルアシスタント等)mem0方式
最短で記憶付きチャットボットを作りたいmem0方式
両方のいいとこ取りハイブリッド(Step 1〜7の構成にmem0を追加)

本記事のStep 1〜7はMemGPTのコア概念を理解するための教材として価値があります。仕組みを理解した上でmem0プラグインに移行すれば、「mem0が裏で何をしているか」を想像できるようになり、トラブルシューティングやプロンプトチューニングの精度が格段に上がります。


3. MemGPTの強みと限界:従来手法との比較

3.1 4手法の比較表

比較項目MemGPT単純なRAGコンテキスト長拡張(Gemini 1M等)会話要約
メモリ操作検索・書き込み・更新・削除すべて可能検索のみなし(全文をコンテキストに投入)要約の生成のみ
長期記憶✅ 外部ストレージに永続保存✅ ベクトルDBに保存❌ セッション内のみ△ 要約は残るが詳細は消失
情報の精度◎ 元データを保持しつつ要約も活用○ 検索精度に依存◎ 全文を参照可能△ 要約時に情報が損失
コスト効率○ 必要な情報だけ出し入れ○ 検索コストは低い✕ トークン数に比例してコスト増大◎ コンテキストを最小化
レイテンシ△ メモリ操作分のオーバーヘッドあり○ 検索は高速✕ 大量トークンの処理で遅延○ 要約済みで高速
実装の複雑さ✕ OS的な設計が必要○ 比較的シンプル◎ モデルを変えるだけ◎ プロンプト追加のみ
自律的な管理✅ LLMが自分でメモリを管理❌ 人間が検索設計を行う❌ 管理不要だが制御もできない△ 要約タイミングは固定的

3.2 用途別の使い分けガイド

ユースケース推奨手法理由
長期間のパーソナルアシスタントMemGPT / Lettaユーザー情報の蓄積・更新が不可欠
社内ドキュメントのQ&A単純なRAG情報の書き換えは不要、検索精度が重要
長文ドキュメントの一括分析コンテキスト長拡張全体を俯瞰する必要がある場面に最適
カジュアルなチャットボット会話要約コスト重視、詳細な記憶は不要
複数セッションにわたるプロジェクト管理MemGPT + RAGコアメモリで進捗管理、RAGで資料参照
コスト制約が厳しい大規模運用RAG + 会話要約メモリ操作の追加コストを避けつつ記憶を維持

4. MemGPTの現在と未来:Lettaへの進化

MemGPTは研究プロジェクトとしての役割を終え、Lettaという本格的なエージェントフレームワークへと進化しました。

4.1 MemGPT → Letta統合の経緯

時期出来事
2023年10月論文「MemGPT: Towards LLMs as Operating Systems」公開(arXiv)
2023年後半OSSプロジェクトとしてGitHubで急速に成長
2024年開発チームがLetta社を設立、ステルスモードから登場
2024年1,000万ドル(約15億円)の資金調達を完了
2024年以降MemGPTのコア技術をLettaフレームワークに統合。MemGPTリポジトリはLettaに移行

4.2 Lettaの新機能:MemFS

Lettaが導入した注目すべき新アーキテクチャがMemFS(Memory File System)です。

💡 MemFSとは?
エージェントのメモリをGitバックのファイルシステムとして管理する仕組みです。メモリの各要素をファイルとして扱い、Gitのようにバージョン管理・差分追跡・ブランチ分岐が可能になります。

MemFSにより、以下のことが可能になります。

  • メモリの変更履歴を追跡:いつ、何が、なぜ変更されたかを完全に記録
  • メモリのロールバック:誤った更新を元に戻せる
  • コンテキスト別のメモリ分岐:同じエージェントが異なるプロジェクトで別のメモリセットを持てる

4.3 Letta vs Mem0:比較表

比較項目Letta(旧MemGPT)Mem0
ポジショニングエージェントフレームワーク全体メモリレイヤー(ミドルウェア)
提供範囲メモリ管理 + エージェント構築 + ツール呼び出しメモリの保存・検索・更新に特化
メモリ管理方式OS的な階層型メモリフラットなキーバリュー型メモリ
バージョン管理MemFSによるGitライクな履歴管理なし(最新状態のみ)
導入の容易さ△ フレームワーク全体の学習が必要◎ API数行で統合可能
Difyとの連携概念の再現は可能(直接統合なし)Marketplaceにプラグインあり
適したユースケース複雑な自律エージェントの構築既存アプリへのメモリ機能追加

💬 実践Tips: 「既存のチャットボットに記憶機能を追加したい」→ Mem0がシンプルで導入しやすい選択です。「自律的に判断・行動するエージェントを一から構築したい」→ Lettaのフレームワークが適しています。Difyユーザーの場合、まずはMem0プラグインから試し、要件が複雑化した段階でLettaの概念をワークフローに取り入れるのが現実的なアプローチです。


5. まとめ

  • 課題: LLMの固定長コンテキストウィンドウは「作業メモリ」に相当し、長期的な情報保持ができないという根本的な制約がある
  • 解決策: MemGPTは、OSの仮想メモリ管理からヒントを得て、メインコンテキスト・リコールメモリ・アーカイバルメモリの3層構造でこの制約を突破。LLM自身がFunction Callingでメモリを読み書きする自己編集メモリを実現した
  • Difyでの再現: 会話変数、Variable Assigner、LLMノード(メモリマネージャー)、ナレッジベースを組み合わせることで、MemGPTの概念をDify上で再現可能。Mem0プラグインも有力な選択肢
  • 比較と選定: MemGPTは万能ではなく、単純なRAG・コンテキスト長拡張・会話要約と比較した上で、ユースケースに応じた使い分けが重要

MemGPTが示した「LLMにOSのようなメモリ管理を持たせる」というアイデアは、単なる小手先の技術ではありません。AIが人間のように経験を積み重ね、文脈を理解しながら使い続けられるようになるための基盤となる発想です。Lettaへの進化、MemFSの登場、そしてDifyのようなプラットフォームでの実装可能性。賢いけれどその場限りのAIから、継続的に付き合えるAIへ。その移行は着実に進んでいます。

参考文献

  1. Packer, C. et al. (2023). “MemGPT: Towards LLMs as Operating Systems.” arXiv:2310.08560. https://arxiv.org/abs/2310.08560
  2. Letta公式ブログ “MemGPT is now part of Letta” https://www.letta.com/blog/memgpt-and-letta
  3. Letta Documentation https://docs.letta.com/concepts/memgpt
  4. Dify Marketplace – mem0 Plugin https://marketplace.dify.ai/plugin/yevanchen/mem0

最後に

私たちは、単にシステムを組むだけの開発会社ではありません。低コストで高品質なAIツールの構築から、ROI(投資対効果)を最大化する導入ロードマップの策定、社内スタッフが自らAIを運用・改善できる体制の構築まで、AI導入の成功に必要なすべてを最初から最後まで丸ごと支援いたします。

実は、ご相談いただく方のほとんどが「何が分からないかも分からない」という状態からのスタートです。構想段階でも、ただのアイデアベースでも構いません。
まずは、あなたのお困りごとをそのまま聞かせていただけませんか?貴社のビジネスを加速させるパートナーとして伴走いたします。
👉 無料オンライン相談で、最適な導入プランを相談する

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

この記事を書いた人

目次