Home 論文解説: MemGPT — OS仮想メモリ概念でLLMエージェントの長期記憶を実現する
投稿
キャンセル

📄 論文解説: MemGPT — OS仮想メモリ概念でLLMエージェントの長期記憶を実現する

本記事は arXiv:2310.03744 MemGPT: Towards LLMs as Operating Systems の解説記事です。

論文概要(Abstract)

著者ら(Charles Packer, Vivian Fang, Shishir G. Patil, Kevin Lin, Sarah Wooders, Joseph E. Gonzalez, UC Berkeley, 2023年10月)は、大規模言語モデル(LLM)の固定長コンテキストウィンドウという根本的制約に対し、オペレーティングシステム(OS)の仮想メモリとページング機構からインスピレーションを得たメモリ管理アーキテクチャ「MemGPT」を提案している。LLM自身がメモリ管理関数を呼び出すことで、コンテキスト外の情報を外部ストレージとの間でページイン・ページアウトし、実質的に無限長のコンテキストを実現する。

この記事は Zenn記事: LangGraph Store APIで実装するマルチエージェントRAGの共有メモリと長期記憶 の深掘りです。

情報源

背景と動機(Background & Motivation)

LLMのコンテキストウィンドウは有限であり、GPT-4の場合でも最大128Kトークンに制限されている。この制約は2つの場面で深刻な問題を引き起こす。第一に、数十回を超える長期会話ではメッセージ履歴がコンテキストに収まらなくなり、過去の文脈を「忘却」する。第二に、書籍全体のような大規模文書の分析では、単純なRAGによるチャンク分割だけでは文書全体の一貫した理解が困難である。

著者らは、この問題がOSにおける物理メモリの制約と構造的に等価であることに着目した。OSはプロセスが物理RAMを超えるメモリを使用する際、ディスクとのページング(ページイン・ページアウト)によって仮想的に無限のメモリ空間を提供する。MemGPTはこのアナロジーを直接LLMのコンテキスト管理に適用する。

主要な貢献(Key Contributions)

  • 貢献1: LLMのコンテキスト管理をOSの仮想メモリ階層にマッピングする設計パラダイムの提案。Main Context(物理RAM相当)とExternal Storage(ディスク相当)の2層構造を定義
  • 貢献2: LLM自身がFunction Callingを通じてメモリ管理を自律的に行うself-directed memory managementの実現。core_memory_append, archival_memory_search等のメモリ操作関数を設計
  • 貢献3: Deep Conversationベンチマーク(長期会話一貫性)とDocument Analysisタスク(大規模文書処理)の2つの評価タスクで有効性を実証

技術的詳細(Technical Details)

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

MemGPTは3層のメモリ階層を定義している。

1. Main Context(メインコンテキスト) — 物理RAM相当

LLMのコンテキストウィンドウ内に常に存在する情報。以下のセクションで構成される。

\[\text{MainContext} = \text{SystemPrompt} \oplus \text{CoreMemory} \oplus \text{ConversationBuffer} \oplus \text{WorkingContext}\]

ここで、

  • $\oplus$: テキストの連結操作
  • SystemPrompt: タスク指示と振る舞い定義(固定長)
  • CoreMemory: ユーザープロファイルやタスク固有の重要情報(可変長、LLMが編集可能)
  • ConversationBuffer: 直近のメッセージ履歴(FIFO、上限あり)
  • WorkingContext: 検索結果や一時的な計算結果(揮発性)

2. Recall Storage(リコールストレージ) — ディスクキャッシュ相当

ConversationBufferからオーバーフローした過去のメッセージ履歴を保持する。時系列順に索引付けされ、LLMがconversation_search(query)conversation_search_date(start_date, end_date)で検索できる。

3. Archival Storage(アーカイバルストレージ) — 外部ディスク相当

無制限に拡張可能な外部ベクトルストレージ。LLMがarchival_memory_insert(content)で書き込み、archival_memory_search(query, page)でセマンティック検索を行う。ページネーション機能により大量の検索結果を段階的に閲覧できる。

メモリ管理関数のインターフェース

著者らが設計したFunction Callingインターフェースは以下の通りである。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
# Core Memory操作(常時コンテキスト内、LLMが直接編集)
def core_memory_append(name: str, content: str) -> str:
    """Core Memoryの指定セクションに情報を追記

    Args:
        name: セクション名("human" or "persona")
        content: 追記する内容

    Returns:
        更新後のCore Memory状態
    """
    ...

def core_memory_replace(name: str, old_content: str, new_content: str) -> str:
    """Core Memoryの内容を部分的に置換

    Args:
        name: セクション名
        old_content: 置換対象の文字列
        new_content: 置換後の文字列

    Returns:
        更新後のCore Memory状態
    """
    ...

# Archival Memory操作(外部ベクトルストレージ)
def archival_memory_insert(content: str) -> str:
    """Archival Storageに情報を永続保存

    Args:
        content: 保存するテキスト(自動的にembedding化される)

    Returns:
        保存確認メッセージ
    """
    ...

def archival_memory_search(query: str, page: int = 0) -> list[str]:
    """Archival Storageをセマンティック検索

    Args:
        query: 検索クエリ
        page: ページ番号(0始まり、1ページ5件)

    Returns:
        関連度順の検索結果リスト
    """
    ...

# Recall Memory操作(過去の会話履歴検索)
def conversation_search(query: str) -> list[str]:
    """過去の会話履歴をセマンティック検索"""
    ...

def conversation_search_date(
    start_date: str, end_date: str
) -> list[str]:
    """日付範囲で会話履歴を検索"""
    ...

イベントループとページング制御

MemGPTのコアは、LLMの出力を解析してメモリ操作を実行するイベントループである。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
async def memgpt_event_loop(
    user_message: str,
    main_context: MainContext,
    archival_store: VectorStore,
    recall_store: RecallStore,
) -> str:
    """MemGPTのメインイベントループ

    Args:
        user_message: ユーザーからの入力メッセージ
        main_context: メインコンテキスト(可変)
        archival_store: アーカイバルストレージ
        recall_store: リコールストレージ

    Returns:
        ユーザーへの最終応答テキスト
    """
    # ConversationBufferに新メッセージ追加
    main_context.conversation_buffer.append(user_message)

    # オーバーフロー時にRecall Storageへページアウト
    while main_context.token_count() > MAX_CONTEXT_TOKENS:
        oldest_msg = main_context.conversation_buffer.popleft()
        recall_store.insert(oldest_msg)  # ページアウト

    while True:
        # LLMにメインコンテキスト全体を渡して推論
        response = await llm.generate(
            context=main_context.render(),
            functions=MEMORY_FUNCTIONS,
        )

        if response.has_function_call():
            # メモリ操作関数を実行
            result = execute_function(
                response.function_call,
                main_context=main_context,
                archival_store=archival_store,
                recall_store=recall_store,
            )
            # 関数の実行結果をコンテキストに追加
            main_context.working_context.update(result)
        else:
            # 関数呼び出しなし → ユーザーへの応答
            return response.text

LangGraph Store APIとの設計対応

MemGPTのメモリ階層はLangGraph Store APIに以下のように対応する。

MemGPTLangGraph操作
Core MemoryState(Checkpointer経由)スレッド内の短期メモリ
Archival StorageStore(put/searchクロススレッドの長期メモリ
Recall StorageCheckpointer履歴会話履歴の永続化
archival_memory_search(query)store.search(namespace, query=query)セマンティック検索
archival_memory_insert(content)store.put(namespace, key, value)メモリの永続保存
core_memory_replace()State更新コンテキスト内情報の更新

著者らのCore Memory(常時コンテキスト内)とArchival Storage(外部ベクトルDB)の分離は、LangGraphのCheckpointer(短期メモリ)とStore(長期メモリ)の2層アーキテクチャと設計思想が一致している。

実装のポイント(Implementation)

pgvector対応の本番実装

MemGPTの公開実装であるLetta(旧MemGPT)は、pgvector拡張付きPostgreSQLをArchival Storageのバックエンドとしてサポートしている。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
from letta import create_client

# Letta clientの初期化(PostgreSQL + pgvector バックエンド)
client = create_client()

# エージェント作成時にArchival StorageとしてPostgreSQLを指定
agent = client.create_agent(
    name="rag-memory-agent",
    memory=ChatMemory(
        human="ユーザーはMLエンジニアで、RAGシステムの設計に関心がある",
        persona="私はRAGアーキテクチャの専門家です"
    ),
    # Archival Storageは自動的にpgvector付きPostgreSQLに永続化
)

# Archival Memoryへの書き込み
client.insert_archival_memory(
    agent_id=agent.id,
    memory="LangGraph Store APIはput/get/searchの3操作を提供する"
)

# Archival Memoryのセマンティック検索
results = client.get_archival_memory(
    agent_id=agent.id,
    query="LangGraph メモリ管理",
    limit=5,
)

コンテキストオーバーフロー制御の注意点

著者らは論文中で以下の実装上の課題を指摘している。

  1. ページアウトのタイミング: ConversationBufferのトークン数がMaxContextの80%を超えた時点でプロアクティブにページアウトすることが推奨される。100%に達してからでは、ページアウト処理自体がコンテキストを消費する
  2. Core Memoryの肥大化防止: core_memory_appendを繰り返すとCore Memoryが肥大化する。定期的な要約・圧縮処理が必要
  3. 検索精度とembeddingモデルの選択: Archival Storageの検索精度はembeddingモデルに依存する。著者らの実装ではOpenAI text-embedding-ada-002を使用しているが、pgvectorの本番環境ではVoyage AIやCohere Embed v3等の高精度モデルへの差し替えが推奨される

Production Deployment Guide

AWS実装パターン(コスト最適化重視)

トラフィック量別の推奨構成:

規模月間リクエスト推奨構成月額コスト主要サービス
Small~3,000 (100/日)Serverless$50-150Lambda + Bedrock + DynamoDB
Medium~30,000 (1,000/日)Hybrid$300-800Lambda + ECS Fargate + ElastiCache
Large300,000+ (10,000/日)Container$2,000-5,000EKS + Karpenter + EC2 Spot

Small構成の詳細(月額$50-150):

  • Lambda: 1GB RAM, 60秒タイムアウト($20/月)— MemGPTイベントループのステートレス実行
  • Bedrock: Claude 3.5 Haiku, Prompt Caching有効($80/月)— Core Memory部分を固定プレフィックスとしてキャッシュ
  • Aurora PostgreSQL + pgvector: db.t4g.medium($60/月)— Archival Storage + Recall Storage
  • CloudWatch: 基本監視($5/月)

コスト削減テクニック:

  • Prompt Caching: Core MemoryとSystemPromptは変更頻度が低いため、キャッシュヒット率80%以上が見込める(30-90%削減)
  • pgvectorインデックス: HNSWインデックス使用で検索レイテンシを10ms以下に抑制
  • Spot Instances: Large構成でg5.xlarge Spot使用時、最大90%削減

コスト試算の注意事項: 上記は2026年2月時点のAWS ap-northeast-1(東京)リージョン料金に基づく概算値です。実際のコストはトラフィックパターン、リージョン、バースト使用量により変動します。最新料金は AWS料金計算ツール で確認してください。

Terraformインフラコード

Small構成 (Serverless): Lambda + Bedrock + Aurora PostgreSQL

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
# --- Aurora PostgreSQL + pgvector ---
module "aurora" {
  source  = "terraform-aws-modules/rds-aurora/aws"
  version = "~> 9.0"

  name           = "memgpt-archival-store"
  engine         = "aurora-postgresql"
  engine_version = "15.4"
  instance_class = "db.t4g.medium"
  instances      = { 1 = {} }

  vpc_id  = module.vpc.vpc_id
  subnets = module.vpc.private_subnets

  storage_encrypted   = true
  apply_immediately   = true
  skip_final_snapshot = false

  # pgvector拡張の有効化
  enabled_cloudwatch_logs_exports = ["postgresql"]
}

# --- Lambda関数(MemGPTイベントループ) ---
resource "aws_lambda_function" "memgpt_handler" {
  filename      = "memgpt_lambda.zip"
  function_name = "memgpt-event-loop"
  role          = aws_iam_role.lambda_role.arn
  handler       = "handler.main"
  runtime       = "python3.12"
  timeout       = 120
  memory_size   = 1024

  environment {
    variables = {
      AURORA_ENDPOINT  = module.aurora.cluster_endpoint
      BEDROCK_MODEL_ID = "anthropic.claude-3-5-haiku-20241022-v1:0"
      PGVECTOR_DIMS    = "1024"
    }
  }

  vpc_config {
    subnet_ids         = module.vpc.private_subnets
    security_group_ids = [aws_security_group.lambda_sg.id]
  }
}

# --- IAMロール(最小権限) ---
resource "aws_iam_role_policy" "bedrock_invoke" {
  role = aws_iam_role.lambda_role.id
  policy = jsonencode({
    Version = "2012-10-17"
    Statement = [{
      Effect   = "Allow"
      Action   = ["bedrock:InvokeModel", "bedrock:InvokeModelWithResponseStream"]
      Resource = "arn:aws:bedrock:ap-northeast-1::foundation-model/anthropic.claude-3-5-haiku*"
    }]
  })
}

運用・監視設定

CloudWatch Logs Insightsクエリ(メモリ操作の監視):

1
2
3
4
fields @timestamp, function_name, duration_ms, memory_operation
| filter function_name = "memgpt-event-loop"
| stats count(*) as ops, avg(duration_ms) as avg_latency by memory_operation
| sort ops desc

CloudWatchアラーム:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import boto3

cloudwatch = boto3.client('cloudwatch')

# MemGPTイベントループの異常検知
cloudwatch.put_metric_alarm(
    AlarmName='memgpt-loop-iterations',
    ComparisonOperator='GreaterThanThreshold',
    EvaluationPeriods=1,
    MetricName='LoopIterations',
    Namespace='MemGPT/Custom',
    Period=300,
    Statistic='Maximum',
    Threshold=20,  # 20回以上のループは異常(無限ループの可能性)
    AlarmDescription='MemGPTイベントループの反復回数異常'
)

コスト最適化チェックリスト

アーキテクチャ選択:

  • ~100 req/日 → Lambda + Aurora Serverless v2($50-150/月)
  • ~1000 req/日 → ECS Fargate + Aurora Provisioned($300-800/月)
  • 10000+ req/日 → EKS + Spot + Aurora Multi-AZ($2,000-5,000/月)

リソース最適化:

  • Aurora Serverless v2: アイドル時0.5 ACU($43/月)まで自動スケールダウン
  • pgvector HNSWインデックス: m=16, ef_construction=64で構築(10万件以下)
  • Lambda メモリ: 1024MB推奨(コスト/性能の最適バランス)
  • Bedrock Prompt Caching: SystemPrompt + Core Memoryを固定プレフィックスに

LLMコスト削減:

  • Prompt Caching有効化(Core Memory固定で30-90%削減)
  • モデル選択: 簡易タスクはHaiku、複雑タスクはSonnet
  • max_tokens制限: メモリ操作時は512、回答生成時は4096
  • Batch API: 非リアルタイムのメモリ整理処理に50%割引適用

監視・アラート:

  • CloudWatch: イベントループ回数異常検知
  • AWS Budgets: 月額予算設定(80%で警告)
  • Cost Anomaly Detection: 自動異常検知

実験結果(Results)

Deep Conversation(長期会話一貫性)

著者らは、50ターン以上の長期会話において、過去の会話内容への質問に正確に回答できるかを評価している。

手法Fixed Context(4K)MemGPT(4K + External)
過去の事実想起12/50 (24%)43/50 (86%)
感情の一貫性低い高い
ユーザー嗜好の反映なしあり

論文Section 5.1より、MemGPTは固定コンテキストのみのベースラインと比較して、長期会話での事実想起率を24%から86%に向上させたと報告されている。

Document Analysis(大規模文書処理)

著者らは、書籍全体(約30万トークン)を対象としたQAタスクを評価している。コンテキストウィンドウが4096トークンに制限された条件下で、MemGPTのページング機構により文書全体を段階的に処理し回答を生成できることを示した。

手法全文入力(128K)RAG(Top-5)MemGPT(4K + Paging)
QA正答率85%62%78%

論文の実験では、MemGPTは128Kの全文入力に近い精度を4Kコンテキストで達成している。ただし、ページング回数が多いケース(10回以上)では回答精度が低下する傾向があると著者らは指摘している。

実運用への応用(Practical Applications)

MemGPTのメモリ管理パラダイムは、Zenn記事で解説したLangGraph Store APIの設計思想と直接的に対応する。

LangGraph Store設計への示唆:

  • Core Memoryのhuman/personaセクション → LangGraph Storeの名前空間 ("rag", "users", user_id, "preferences") に相当
  • Archival Storageのセマンティック検索 → store.search(namespace, query=query) でpgvectorベクトル検索を活用
  • Recall Storageの時系列検索 → Checkpointerのメッセージ履歴検索に相当

マルチエージェントRAGへの拡張: MemGPTはシングルエージェント設計だが、Archival Storageを複数エージェントで共有することで、LangGraphの名前空間ベースのクロスエージェントメモリ共有と同等のアーキテクチャが実現可能である。Lettaの実装ではagent_idによるメモリの分離・共有制御が提供されている。

関連研究(Related Work)

  • Generative Agents(Park et al., 2023): エピソード記憶ストリーム + 反省 + 計画を持つ生成エージェント。MemGPTとの違いは、メモリ管理がLLM自身ではなく外部スケジューラで制御される点
  • Mem0(Yadav et al., 2025): pgvector + Neo4j + KVストアを統合したプロダクション向けメモリレイヤ。MemGPTのアーキテクチャを発展させ、メモリの矛盾解決や自動抽出機能を追加
  • LangGraph Store API: MemGPTのArchival Storage設計を名前空間ベースのAPIとして汎用化し、Checkpointerとの2層アーキテクチャで短期/長期メモリを明確に分離

まとめと今後の展望

著者らは、OSの仮想メモリ概念をLLMのコンテキスト管理に適用するという明確なアナロジーにより、固定長コンテキストの制約を克服するアーキテクチャを提案した。Core Memory / Archival Storage / Recall Storageの3層構造は、LangGraph StoreのState / Store / Checkpointerの設計と思想的に一致しており、現在のLLMエージェントメモリ管理の標準的なパラダイムとなっている。

今後の研究方向として、マルチエージェント間でのArchival Storage共有時の一貫性制御、メモリの自動要約・圧縮アルゴリズムの改善、および読み込み頻度に基づく適応的なページング戦略が挙げられる。

参考文献

この投稿は CC BY 4.0 でライセンスされています。