Claude Code AutoDreamとエージェントメモリ整合パターン

この記事の結論

Claude Code AutoDreamの4層メモリアーキテクチャと4フェーズ統合の仕組みを解説。自作エージェントへの応用パターンとPython実装例6本付き。

Claude Code AutoDreamとエージェントメモリ整合パターン

「エージェントを長期間動かしていたら、メモリファイルが肥大化して何が有効な情報なのかわからなくなった」という経験はないでしょうか。

短期セッションで動くエージェントなら問題になりませんが、プロジェクトをまたいで継続稼働するエージェントでは、蓄積されたメモリをどう「整理・剪定・統合」するかが設計の核心になります。Anthropicが2026年3月にClaude Codeへ段階的に展開を始めた「AutoDream」は、まさにこの問題に対するAnthropicの回答のひとつです。

この記事では、AutoDreamのアーキテクチャを分解し、その設計思想を自作エージェントに応用するPythonパターンを解説します。

エージェントメモリの基本設計についてはAIエージェントメモリタイプ別実装ガイドもあわせて読んでみてください。

AutoDreamとは何か:3行で理解する

AutoDreamは「Claude Codeのメモリファイルを、バックグラウンドのサブエージェントが24時間ごとに自動整理する機能」です。

Anthropicは内部システムプロンプトの中でこう表現しています——「You are performing a dream — a reflective pass over your memory files.」(あなたは夢を見ています——メモリファイルへの省察的な通過です)。

つまりAutoDreamは、人間のREM睡眠中に起きるメモリ統合(短期記憶→長期記憶への整理)をAIエージェントに適用した実装です。これはUC Berkeleyが2025年4月に発表した研究論文「Sleep-time Compute: Beyond Inference Scaling at Test-time」の知見——アイドル時間を使った事前計算がテスト時コンピューティングを最大5倍削減できる——に基づいています。

Claude Code 4層メモリアーキテクチャ

AutoDreamを理解するには、Claude Codeが持つ4層のメモリ構造全体を把握する必要があります。

レイヤー 内容 更新主体 役割
Layer 1: CLAUDE.md プロジェクトルール・制約・設計方針 人間(開発者) 不変の指示書
Layer 2: Auto Memory セッション中にClaudeが記録したメモ Claude(自動) ノートテイカー
Layer 3: Session Memory 会話の継続性・直前のコンテキスト セッション依存 短期記憶
Layer 4: Auto Dream 蓄積メモリの定期統合・剪定 AutoDreamサブエージェント REM睡眠(整理係)

この4層が揃って初めて「持続的な記憶を持つ作業エージェント」として機能します。Layer 1が「指示書」、Layer 2が「メモ帳」、Layer 3が「直前の会話」、Layer 4が「睡眠中の整理」。エージェント開発の観点から見ると、ほとんどのLLMエージェントは Layer 1〜3 を持ちますが、Layer 4(自動整理・剪定)を持つ実装は稀です。

AutoDreamの4フェーズ統合サイクル

AutoDreamが起動すると(条件:最後の統合から24時間以上経過 かつ 5セッション以上の蓄積)、サブエージェントが以下の4フェーズを実行します。

Phase 1: Orient(現状把握)

まずメモリディレクトリ全体を走査し、MEMORY.mdインデックスを読む。何が既に存在するかを把握してから変更を始めるための「オリエンテーション」フェーズです。変更前に全体像を掴むのは、後続フェーズで矛盾した変更や重複を避けるためです。

Phase 2: Gather Signal(信号収集)

セッションログを全読みするのではなく、狭い検索語で「重要な変化」だけをピックアップします。具体的には:

  • ユーザーによる訂正・方向転換の指示
  • 「記録して」「覚えておいて」などの明示的な記憶要求
  • 複数セッションにわたって繰り返すパターン
  • アーキテクチャ・ワークフローに関わる重要決定

トークンの無駄遣いを防ぎながら、本当に価値ある情報だけを抽出するのがポイントです。

Phase 3: Consolidate(統合)

これが中核フェーズ。4つの変換処理を実行します:

  1. 相対日時→絶対日時の変換:「昨日Redisに変えた」→「2026-03-26にRedisに切り替えた」。時間が経っても意味を保持するため
  2. 矛盾ファクトの削除:「APIはExpressを使っている」というメモが残っているが、3週間前にFastifyに移行済み→古い記録を削除
  3. 陳腐化メモの剪定:削除済みファイルに関するデバッグメモ、解決済みの一時的なバグ回避策
  4. 重複エントリのマージ:3つのセッションが同じビルドコマンドの注意事項を記録していれば、1つの洗練されたエントリに統合

Phase 4: Prune and Index(剪定とインデックス更新)

MEMORY.mdインデックスを200行以内に維持しつつ更新します。インデックスを「コンテンツのダンプ」ではなく「ナビゲーションガイド」として扱う——各エントリは1行・150文字以内のポインタであるべきという原則です。

実際の観測では、913セッション分のメモリを約8〜9分で統合できたとの報告があります(DEV Community, 2026年3月)。

自作エージェントへの応用:Python実装パターン4選

パターン1:基本的なメモリ層の構造(4層設計)

まずAutoDreamの思想を反映した4層メモリ構造をPythonで実装する基本骨格です。


# 動作環境: Python 3.11+
# pip install anthropic

import json
import os
from pathlib import Path
from datetime import datetime, date
from dataclasses import dataclass, field

# 注意: 本番環境で使用する前に、必ずテスト環境で動作確認してください。

@dataclass
class AgentMemoryLayer:
    """4層メモリ構造の実装"""
    base_dir: Path

    def __post_init__(self):
        self.base_dir.mkdir(parents=True, exist_ok=True)
        self.instructions_file = self.base_dir / "INSTRUCTIONS.md"
        self.session_notes_dir = self.base_dir / "session_notes"
        self.topic_files_dir = self.base_dir / "topics"
        self.index_file = self.base_dir / "MEMORY.md"

        # ディレクトリ作成
        self.session_notes_dir.mkdir(exist_ok=True)
        self.topic_files_dir.mkdir(exist_ok=True)

        # インデックス初期化
        if not self.index_file.exists():
            self.index_file.write_text("# Agent Memory Indexnn")

    def save_session_note(self, content: str, session_id: str) -> Path:
        """Layer 2: セッションメモを保存"""
        today = date.today().isoformat()
        note_path = self.session_notes_dir / f"{today}_{session_id}.md"
        timestamp = datetime.now().isoformat()
        note_path.write_text(f"---ndate: {timestamp}nsession: {session_id}n---nn{content}")
        return note_path

    def save_topic_memory(self, topic: str, content: str) -> Path:
        """トピック別メモリファイルを保存"""
        safe_topic = topic.replace("/", "-").replace(" ", "_").lower()
        topic_path = self.topic_files_dir / f"{safe_topic}.md"
        topic_path.write_text(f"---ntopic: {topic}nupdated: {datetime.now().isoformat()}n---nn{content}")
        return topic_path

    def get_recent_sessions(self, n: int = 10) -> list[str]:
        """直近nセッションのメモを取得"""
        notes = sorted(self.session_notes_dir.glob("*.md"), key=lambda p: p.stat().st_mtime, reverse=True)
        return [p.read_text() for p in notes[:n]]

    def consolidation_needed(self, min_hours: int = 24, min_sessions: int = 5) -> bool:
        """統合が必要かを判定"""
        lock_file = self.base_dir / ".dream_lock"
        if lock_file.exists():
            elapsed = (datetime.now().timestamp() - lock_file.stat().st_mtime) / 3600
            if elapsed = min_sessions

# 使用例
memory = AgentMemoryLayer(Path("./agent_memory"))
memory.save_session_note("ユーザーはFastifyへの移行を決定した(Expressから)", "session_001")
print(f"統合が必要: {memory.consolidation_needed(min_hours=0, min_sessions=1)}")

パターン2:AutoDream風の統合処理(Consolidate フェーズの実装)

Phase 3の中核ロジック——相対日時変換・矛盾削除・重複マージ——をAnthropicのClaude APIを使って実装するパターンです。


# 動作環境: Python 3.11+, anthropic>=0.45
# pip install anthropic

import anthropic
import os
from pathlib import Path
from datetime import datetime

# 注意: 本番環境で使用する前に、必ずテスト環境で動作確認してください。

client = anthropic.Anthropic(api_key=os.environ["ANTHROPIC_API_KEY"])

def consolidate_memory_files(memory_dir: Path, current_index: str, session_notes: list[str]) -> str:
    """
    AutoDream Phase 3 相当の統合処理。
    セッションメモとトピックファイルの矛盾・重複を解消する。
    """
    today = datetime.now().strftime("%Y-%m-%d")
    notes_text = "n---n".join(session_notes[-20:])  # 直近20件

    system_prompt = f"""あなたはエージェントのメモリファイルを整理するサブエージェントです。
今日の日付: {today}

以下のルールに従ってメモリを統合してください:
1. 相対的な日時表現(「昨日」「先週」など)は絶対日時に変換する
2. 矛盾する情報は新しい方を残し、古い方を削除する
3. 同じ内容の重複エントリは1つにまとめる
4. 解決済みの一時的な問題メモは削除する
5. インデックスは200行以内を維持する"""

    prompt = f"""現在のインデックス:
{current_index}

最新のセッションメモ:
{notes_text}

上記を統合した新しいインデックスを出力してください。"""

    response = client.messages.create(
        model="claude-haiku-4-5",  # 統合処理はHaikuで十分
        max_tokens=4096,
        system=system_prompt,
        messages=[{"role": "user", "content": prompt}]
    )

    return response.content[0].text

# 使用例
memory_dir = Path("./agent_memory")
index_path = memory_dir / "MEMORY.md"

if index_path.exists():
    current_index = index_path.read_text()
else:
    current_index = "# Memory Indexn"

# ダミーのセッションメモ
sample_notes = [
    "昨日のセッション: APIフレームワークをExpressからFastifyに変更することを決定",
    "今週: データベースはPostgreSQLを使用すると決めた",
    "先月の決定: APIフレームワークはExpressを採用"
]

new_index = consolidate_memory_files(memory_dir, current_index, sample_notes)
index_path.write_text(new_index)
print("統合完了")
print(new_index[:500])

パターン3:Gather Signal — 重要情報だけを抽出するフィルタリング

セッションログ全体を読むのではなく、「重要な変化」だけを効率的に拾い上げるPhase 2の実装です。


# 動作環境: Python 3.11+
# 注意: 本番環境で使用する前に、必ずテスト環境で動作確認してください。

import re
from pathlib import Path
from typing import Optional

# 記憶に値するシグナルのパターン
SIGNAL_PATTERNS = {
    "correction": [
        r"違います", r"それは違う", r"修正", r"間違い",
        r"no[,、]? that", r"actually[,、]?", r"instead"
    ],
    "explicit_memory": [
        r"記録して", r"覚えておいて", r"メモして", r"忘れないで",
        r"remember[,、]?", r"note that", r"important:"
    ],
    "architecture_decision": [
        r"設計方針", r"アーキテクチャ", r"に変更", r"に移行",
        r"以降は.+を使", r"we decided", r"going forward"
    ],
    "recurring_issue": [
        r"また.+エラー", r"いつも.+問題", r"毎回",
        r"recurring", r"always happens"
    ]
}

def extract_signal_from_session(session_content: str) -> Optional[dict]:
    """
    セッションログから重要シグナルを抽出する。
    AutoDreamのGather Signalフェーズの実装。
    """
    signals_found = {}

    for signal_type, patterns in SIGNAL_PATTERNS.items():
        matched_lines = []
        for line in session_content.split("n"):
            for pattern in patterns:
                if re.search(pattern, line, re.IGNORECASE):
                    matched_lines.append(line.strip())
                    break

        if matched_lines:
            signals_found[signal_type] = matched_lines

    if not signals_found:
        return None  # シグナルなし → このセッションは統合対象外

    return signals_found

def gather_signals_from_all_sessions(session_dir: Path, since_last_consolidation: float) -> list[dict]:
    """
    前回の統合以降のセッションからシグナルを収集する。
    """
    signals = []
    import time
    cutoff_time = time.time() - (since_last_consolidation * 3600)

    for session_file in sorted(session_dir.glob("*.md")):
        if session_file.stat().st_mtime < cutoff_time:
            continue  # 前回統合より古いファイルはスキップ

        content = session_file.read_text()
        signal = extract_signal_from_session(content)
        if signal:
            signal["source_file"] = session_file.name
            signals.append(signal)

    return signals

# 使用例
session_dir = Path("./agent_memory/session_notes")
signals = gather_signals_from_all_sessions(session_dir, since_last_consolidation=24)
print(f"検出されたシグナル数: {len(signals)}")
for s in signals:
    print(f"  ファイル: {s.get('source_file')}, タイプ: {list(s.keys())}")

パターン4:AutoDream全サイクルのオーケストレーション

上記のパターン1〜3を組み合わせた、完全なAutoDreamライクな統合オーケストレーターです。


# 動作環境: Python 3.11+, anthropic>=0.45
# 注意: 本番環境で使用する前に、必ずテスト環境で動作確認してください。

import anthropic
import json
import os
import time
from pathlib import Path
from datetime import datetime

client = anthropic.Anthropic(api_key=os.environ["ANTHROPIC_API_KEY"])

class AutoDreamConsolidator:
    """
    AutoDream風のメモリ統合オーケストレーター。
    24時間 + 5セッション以上の蓄積で自動起動する。
    """
    def __init__(self, memory_dir: Path, min_hours: int = 24, min_sessions: int = 5):
        self.memory_dir = memory_dir
        self.min_hours = min_hours
        self.min_sessions = min_sessions
        self.lock_file = memory_dir / ".dream_lock"
        self.state_file = memory_dir / "dream_state.json"

    def _load_state(self) -> dict:
        if self.state_file.exists():
            return json.loads(self.state_file.read_text())
        return {"last_consolidation": None, "consolidation_count": 0}

    def _save_state(self, state: dict):
        self.state_file.write_text(json.dumps(state, ensure_ascii=False, indent=2))

    def should_consolidate(self) -> bool:
        """統合条件チェック"""
        state = self._load_state()

        # 時間チェック
        if state["last_consolidation"]:
            elapsed = (time.time() - state["last_consolidation"]) / 3600
            if elapsed = self.min_sessions

        return False

    def run(self) -> dict:
        """AutoDream 4フェーズを実行"""
        if not self.should_consolidate():
            return {"status": "skipped", "reason": "条件未達"}

        # ロック取得
        self.lock_file.touch()

        try:
            result = {
                "start_time": datetime.now().isoformat(),
                "phases": {}
            }

            # Phase 1: Orient
            index_path = self.memory_dir / "MEMORY.md"
            current_index = index_path.read_text() if index_path.exists() else "# Memory Indexn"
            result["phases"]["orient"] = f"インデックス読み込み完了 ({len(current_index)}文字)"

            # Phase 2: Gather Signal
            session_dir = self.memory_dir / "session_notes"
            sessions = []
            if session_dir.exists():
                for f in sorted(session_dir.glob("*.md"), key=lambda p: p.stat().st_mtime)[-20:]:
                    sessions.append(f.read_text())
            result["phases"]["gather"] = f"{len(sessions)}セッションから信号収集"

            # Phase 3 & 4: Consolidate + Prune
            if sessions:
                new_index = self._llm_consolidate(current_index, sessions)
                # 200行制限を適用
                lines = new_index.split("n")
                if len(lines) > 200:
                    new_index = "n".join(lines[:200]) + "n...(truncated)"
                index_path.write_text(new_index)
                result["phases"]["consolidate"] = f"統合完了 ({len(lines)}行)"
            else:
                result["phases"]["consolidate"] = "スキップ(セッションなし)"

            # 状態更新
            state = self._load_state()
            state["last_consolidation"] = time.time()
            state["consolidation_count"] += 1
            self._save_state(state)

            result["status"] = "completed"
            return result

        finally:
            self.lock_file.unlink(missing_ok=True)

    def _llm_consolidate(self, current_index: str, sessions: list[str]) -> str:
        """LLMを使った実際の統合処理"""
        today = datetime.now().strftime("%Y-%m-%d")
        notes_text = "n---NEXT SESSION---n".join(sessions[-10:])

        response = client.messages.create(
            model="claude-haiku-4-5",
            max_tokens=4096,
            messages=[{
                "role": "user",
                "content": f"""今日: {today}

現在のメモリインデックス:
{current_index}

最新セッションメモ(新→古):
{notes_text}

統合ルール:
- 相対日時を絶対日時に変換
- 矛盾は新しい情報を優先
- 重複エントリをマージ
- 200行以内に収める
- 各エントリは1行150文字以内

統合後のメモリインデックスを出力:"""
            }]
        )
        return response.content[0].text

# 使用例
consolidator = AutoDreamConsolidator(
    memory_dir=Path("./agent_memory"),
    min_hours=0,   # テスト用に制限を外す
    min_sessions=0
)
result = consolidator.run()
print(json.dumps(result, ensure_ascii=False, indent=2))

メモリ整合のベストプラクティス

AutoDreamを自作エージェントに応用する際に、実装して効果があったパターンをまとめます。

1. インデックスはナビゲーションガイドとして保つ

AutoDreamの設計原則:MEMORY.mdはコンテンツのダンプではなく、「どこに何があるか」のポインタ集です。各エントリは1行・150文字以内のリンク付きポインタ。詳細はトピックファイルに分散させます。

2. 絶対日時への変換を徹底する

「先週決めた」「昨日修正した」は時間が経つと無価値になります。統合フェーズで必ず絶対日時に変換するルールを入れること。これを怠ると、3ヶ月後のエージェントが古いメモを「最近の情報」として誤読します。

3. 矛盾検出は「同一キーワードの複数エントリ」で発見する

同じAPIエンドポイント・フレームワーク名・設定値が複数のメモに出てきたら矛盾の可能性が高い。定期的にgrepベースの重複チェックを走らせることで、LLMによる統合の前に候補を絞り込めます。

4. 統合処理にはコスト効率の良いモデルを使う

AutoDreamの統合処理は高度な推論を必要としません。claude-haiku-4-5やgemini-2.5-flash(低thinking_budget)など、コスト効率の良いモデルで十分です。メモリ整合は「精度より速度と頻度」が重要なタスクです。

【要注意】メモリ整合でよくある失敗パターン

失敗1:統合処理がソースコードにも手を出す

❌ LLMベースの統合エージェントが、プロジェクトのソースコードまで「古いから削除」と判断してしまう事故。

⭕ 統合処理はメモリディレクトリのみに限定。ソースコードへの書き込み権限を与えない。AutoDreamも「Read-only project code」を安全機構として明記しています。

失敗2:並行実行による競合

❌ 複数のセッションが同時に統合処理を起動して、メモリファイルが破損する。

⭕ ロックファイル(.dream_lock)を使って排他制御。AutoDreamも同様の仕組みを持ちます。

失敗3:有効なメモリまで剪定してしまう

❌ 「古い情報は削除」ルールが厳しすぎて、長期プロジェクトの重要な設計決定が消えてしまう。

⭕ 「PERMANENT」タグをつけたエントリは統合処理の削除対象外にするルールを設ける。

失敗4:インデックスが際限なく肥大化する

❌ 統合のたびに行数が増えて、起動時のコンテキストロードコストが上がり続ける。

⭕ 200行ハードリミットを設定し、それを超えたら古いエントリをアーカイブファイルに移す。

参考・出典

まとめ:今日から始める3つのアクション

  1. 今日やること:パターン1のAgentMemoryLayerをローカルで動かし、自作エージェントの4層メモリ構造を定義する。まずLayer 1(INSTRUCTIONS.md)と Layer 2(session_notes)だけでも実装してみる
  2. 今週中:既存エージェントのメモリファイルを手動でPattern 3のシグナル抽出にかけて、どんな情報が「重要シグナル」として検出されるか確認。統合ルールの設計指針にする
  3. 今月中:パターン4のAutoDreamConsolidatorを本番エージェントに組み込み、最低でも週1回の自動統合サイクルを稼働させる。1ヶ月後にメモリファイルの品質変化を評価する

あわせて読みたい:


著者: 佐藤傑(さとう・すぐる)
株式会社Uravation代表取締役。X(@SuguruKun_ai)フォロワー10万人超。
100社以上の企業向けAI研修・導入支援。著書累計3万部突破。
SoftBank IT連載7回執筆(NewsPicks最大1,125ピックス)。
ご質問・ご相談は お問い合わせフォーム からお気軽にどうぞ。

Need help moving from reading to rollout?

この記事を読んで導入イメージが固まってきた方へ

Uravationでは、AIエージェントの要件整理、PoC設計、社内導入、研修まで一気通貫で支援しています。

この記事をシェア

X Facebook LINE

※ 本記事の情報は2026年3月時点のものです。サービスの料金・仕様は変更される可能性があります。最新情報は各サービスの公式サイトをご確認ください。

関連記事