Memory

OpenClaw の memory(メモリ)は agent workspace 内の plain Markdown(プレーン Markdown) です。ファイルが真実の情報源であり、model(モデル)は disk(ディスク)に書き込まれたものだけを「記憶」します。

Memory search(メモリ検索)ツールは、active memory plugin(アクティブ メモリプラグイン)によって提供されます(デフォルト:memory-core)。メモリプラグインを無効にするには plugins.slots.memory = "none" を設定します。

Memory files(Markdown)

デフォルトの workspace layout(ワークスペースレイアウト)は 2 つの memory layer(メモリレイヤー)を使用します:

  • memory/YYYY-MM-DD.md
    • Daily log(デイリーログ、追記専用)。
    • Session(セッション)開始時に今日と昨日を読み込みます。
  • MEMORY.md(オプション)
    • Curated long-term memory(キュレーションされた長期記憶)。
    • main、private session(メイン、プライベートセッション)でのみ読み込み(group context(グループコンテキスト)では決して読み込まない)。

これらのファイルは workspace(agents.defaults.workspace、デフォルトは ~/.openclaw/workspace)の下にあります。完全なレイアウトについては Agent workspace を参照してください。

When to write memory(メモリを書き込むタイミング)

  • 決定、設定、永続的な事実は MEMORY.md へ。
  • 日々のメモと実行中のコンテキストは memory/YYYY-MM-DD.md へ。
  • 誰かが「これを覚えておいて」と言ったら、書き留める(RAM に保持しない)。
  • この領域はまだ進化中です。model(モデル)にメモリを保存するよう促すと、何をすべきかわかります。
  • 何かを定着させたい場合は、bot にメモリに書き込むよう依頼してください。

Automatic memory flush(自動メモリフラッシュ、pre-compaction ping)

Session(セッション)が auto-compaction に近づくと、OpenClaw は silent、agentic turn(サイレント、エージェント的なターン) をトリガーし、context(コンテキスト)が compaction(コンパクション)される前に model(モデル)に durable memory(永続的なメモリ)を書き込むよう促します。デフォルトの prompt(プロンプト)では、model(モデル)が返信できると明示していますが、通常は NO_REPLY が正しい応答であり、ユーザーはこのターンを見ることはありません。

これは agents.defaults.compaction.memoryFlush で制御されます:

{
  agents: {
    defaults: {
      compaction: {
        reserveTokensFloor: 20000,
        memoryFlush: {
          enabled: true,
          softThresholdTokens: 4000,
          systemPrompt: "Session nearing compaction. Store durable memories now.",
          prompt: "Write any lasting notes to memory/YYYY-MM-DD.md; reply with NO_REPLY if nothing to store."
        }
      }
    }
  }
}

詳細:

  • Soft threshold(ソフト閾値):flush は session token estimate(セッショントークン推定値)が contextWindow - reserveTokensFloor - softThresholdTokens を超えたときにトリガーされます。
  • Silent(サイレント)がデフォルト:prompt には NO_REPLY が含まれているため、何も配信されません。
  • Two prompts(2 つのプロンプト):user prompt(ユーザープロンプト)に system prompt(システムプロンプト)が追加されてリマインダーを付与します。
  • One flush per compaction cycle(コンパクションサイクルごとに 1 回のフラッシュ)sessions.json で追跡)。
  • Workspace must be writable(ワークスペースは書き込み可能である必要がある):session が workspaceAccess: "ro" または "none" で sandbox 化されている場合、flush はスキップされます。

完全な compaction lifecycle(コンパクションライフサイクル)については、Session management + compaction を参照してください。

Vector memory search(ベクトルメモリ検索)

OpenClaw は MEMORY.mdmemory/*.md(およびオプトインした追加のディレクトリやファイル)に対して小さな vector index(ベクトルインデックス)を構築できるため、semantic queries(セマンティッククエリ)は言い回しが異なっていても関連するメモを見つけることができます。

デフォルト:

  • デフォルトで有効。
  • memory file(メモリファイル)の変更を監視(debounce 処理あり)。
  • デフォルトで remote embeddings(リモート埋め込み)を使用。memorySearch.provider が設定されていない場合、OpenClaw は自動的に以下を選択します:
    1. memorySearch.local.modelPath が設定され、ファイルが存在する場合は local
    2. OpenAI key が解決できる場合は openai
    3. Gemini key が解決できる場合は gemini
    4. それ以外の場合、設定されるまで memory search は無効のまま。
  • Local mode は node-llama-cpp を使用し、pnpm approve-builds が必要な場合があります。
  • sqlite-vec(利用可能な場合)を使用して SQLite 内の vector search(ベクトル検索)を高速化します。

Remote embeddings(リモート埋め込み)には embedding provider(埋め込みプロバイダー)の API key が必要です。OpenClaw は auth profiles、models.providers.*.apiKey、または environment variables(環境変数)から key を解決します。Codex OAuth は chat/completions のみをカバーし、memory search の embeddings は満たしません。Gemini の場合は、GEMINI_API_KEY または models.providers.google.apiKey を使用してください。カスタム OpenAI 互換エンドポイントを使用する場合は、memorySearch.remote.apiKey(およびオプションの memorySearch.remote.headers)を設定してください。

Additional memory paths(追加のメモリパス)

デフォルトの workspace layout 以外の Markdown files(Markdown ファイル)をインデックス化したい場合は、explicit path(明示的なパス)を追加してください:

agents: {
  defaults: {
    memorySearch: {
      extraPaths: ["../team-docs", "/srv/shared-notes/overview.md"]
    }
  }
}

注意:

  • Path(パス)は absolute(絶対パス)または workspace-relative(ワークスペース相対パス)が可能です。
  • Directory(ディレクトリ)は .md ファイルを再帰的にスキャンします。
  • Markdown files のみがインデックス化されます。
  • Symlink(シンボリックリンク)は無視されます(ファイルまたはディレクトリ)。

Gemini embeddings(native)

Provider を gemini に設定すると、Gemini embeddings API を直接使用します:

agents: {
  defaults: {
    memorySearch: {
      provider: "gemini",
      model: "gemini-embedding-001",
      remote: {
        apiKey: "YOUR_GEMINI_API_KEY"
      }
    }
  }
}

注意:

  • remote.baseUrl はオプションです(デフォルトは Gemini API base URL)。
  • remote.headers では必要に応じて追加のヘッダーを追加できます。
  • デフォルト model:gemini-embedding-001

カスタム OpenAI 互換エンドポイント(OpenRouter、vLLM、または proxy)を使用したい場合は、OpenAI provider で remote configuration(リモート設定)を使用できます:

agents: {
  defaults: {
    memorySearch: {
      provider: "openai",
      model: "text-embedding-3-small",
      remote: {
        baseUrl: "https://api.example.com/v1/",
        apiKey: "YOUR_OPENAI_COMPAT_API_KEY",
        headers: { "X-Custom-Header": "value" }
      }
    }
  }
}

API key を設定したくない場合は、memorySearch.provider = "local" を使用するか、memorySearch.fallback = "none" を設定してください。

Fallback(フォールバック):

  • memorySearch.fallbackopenaigeminilocal、または none が可能です。
  • fallback provider(フォールバックプロバイダー)は、primary embedding provider(プライマリ埋め込みプロバイダー)が失敗したときにのみ使用されます。

Batch indexing(バッチインデックス作成、OpenAI + Gemini):

  • OpenAI と Gemini embeddings ではデフォルトで有効です。無効にするには agents.defaults.memorySearch.remote.batch.enabled = false を設定してください。
  • デフォルトの動作は batch completion(バッチ完了)を待機します。必要に応じて remote.batch.waitremote.batch.pollIntervalMsremote.batch.timeoutMinutes を調整してください。
  • remote.batch.concurrency を設定して、並行して送信する batch job(バッチジョブ)の数を制御します(デフォルト:2)。
  • Batch mode は memorySearch.provider = "openai" または "gemini" のときに適用され、対応する API key を使用します。
  • Gemini batch job は async embeddings batch endpoint を使用し、Gemini Batch API の可用性が必要です。

OpenAI batch が高速 + 安価である理由:

  • 大規模な backfill の場合、OpenAI は通常、私たちがサポートする中で最も高速なオプションです。なぜなら、1 つの batch job で多数の embedding request(埋め込みリクエスト)を送信し、OpenAI が非同期で処理できるためです。
  • OpenAI は Batch API workload に対して割引価格を提供しているため、大規模なインデックス作成実行は通常、同じリクエストを同期的に送信するよりも安価です。
  • 詳細については、OpenAI Batch API ドキュメントと価格設定を参照してください:

Config 例:

agents: {
  defaults: {
    memorySearch: {
      provider: "openai",
      model: "text-embedding-3-small",
      fallback: "openai",
      remote: {
        batch: { enabled: true, concurrency: 2 }
      },
      sync: { watch: true }
    }
  }
}

Tool(ツール):

  • memory_search — file + line range 付きの snippet(スニペット)を返します。
  • memory_get — path(パス)で memory file content(メモリファイルコンテンツ)を読み取ります。

Local mode:

  • agents.defaults.memorySearch.provider = "local" を設定します。
  • agents.defaults.memorySearch.local.modelPath(GGUF または hf: URI)を提供します。
  • オプション:agents.defaults.memorySearch.fallback = "none" を設定して remote fallback(リモートフォールバック)を回避します。

How the memory tools work(メモリツールの仕組み)

  • memory_searchMEMORY.md + memory/**/*.md から Markdown chunks(Markdown チャンク、約 400 token target、80 token overlap)を semantically search(セマンティック検索)します。snippet text(スニペットテキスト、約 700 文字に制限)、file path、line range、score、provider/model、local → remote embeddings から fallback したかどうかを返します。完全なファイルペイロードは返されません。
  • memory_get は特定の memory Markdown file(workspace-relative)を読み取ります。オプションで開始行から N 行を読み取ります。MEMORY.md / memory/ 以外のパスは、memorySearch.extraPaths に明示的にリストされている場合にのみ許可されます。
  • 両方のツールは、agent の memorySearch.enabled が true と解決される場合にのみ有効です。

What gets indexed(何がインデックス化されるか、いつ)

  • File type(ファイルタイプ):Markdown のみ(MEMORY.mdmemory/**/*.md、および memorySearch.extraPaths 下の .md ファイル)。
  • Index storage(インデックスストレージ):~/.openclaw/memory/<agentId>.sqlite の agent ごとの SQLite(agents.defaults.memorySearch.store.path で設定可能、{agentId} トークンをサポート)。
  • Freshness(新鮮度):MEMORY.mdmemory/、および memorySearch.extraPaths の watcher がインデックスを dirty とマーク(debounce 1.5 秒)。Sync は session 開始時、検索時、または interval で schedule され、非同期で実行されます。Session transcript は delta threshold を使用して background sync をトリガーします。
  • Reindex trigger(再インデックストリガー):インデックスは embedding provider/model + endpoint fingerprint + chunking params を保存します。これらのいずれかが変更されると、OpenClaw は自動的に store 全体をリセットして再インデックス化します。

Hybrid search(BM25 + vector)

有効にすると、OpenClaw は次を組み合わせます:

  • Vector similarity(ベクトル類似性)(semantic match、言い回しは異なっていてもよい)
  • BM25 keyword relevance(BM25 キーワード関連性)(ID、env vars、code symbols などの exact token)

full-text search(全文検索)が platform で利用できない場合、OpenClaw は vector-only search にフォールバックします。

Why hybrid?(なぜハイブリッドなのか?)

Vector search は「これは同じ意味」に優れています:

  • "Mac Studio gateway host" vs "the machine running the gateway"
  • "debounce file updates" vs "avoid indexing on every write"

しかし、exact、high-signal token に弱い場合があります:

  • ID(a828e60b3b9895a…
  • code symbol(memorySearch.query.hybrid
  • error string("sqlite-vec unavailable")

BM25(full-text)はその逆です:exact token に強く、言い換えに弱いです。 Hybrid search は実用的な中間地点です:両方の retrieval signal を使用することで、「自然言語」クエリと「針を探す」クエリの両方で良好な結果が得られます。

How we merge results(結果のマージ方法、現在の設計)

Implementation sketch(実装スケッチ):

  1. 両側から candidate pool(候補プール)を取得:
  • Vector:cosine similarity で top maxResults * candidateMultiplier
  • BM25:FTS5 BM25 rank で top maxResults * candidateMultiplier(低いほど良い)。
  1. BM25 rank を 0..1 っぽいスコアに変換:
  • textScore = 1 / (1 + max(0, bm25Rank))
  1. chunk id で candidate を union し、weighted score を計算:
  • finalScore = vectorWeight * vectorScore + textWeight * textScore

注意:

  • vectorWeight + textWeight は config resolution で 1.0 に正規化されるため、weight はパーセンテージとして機能します。
  • embedding が利用できない場合(または provider が zero-vector を返す場合)、BM25 を実行して keyword match を返します。
  • FTS5 が作成できない場合、vector-only search を維持します(hard failure なし)。

これは「IR 理論的に完璧」ではありませんが、シンプルで高速で、実際のメモで recall/precision を改善する傾向があります。 後でより洗練されたものにしたい場合、一般的な次のステップは Reciprocal Rank Fusion(RRF)または score normalization(min/max または z-score)を混合前に行うことです。

Config:

agents: {
  defaults: {
    memorySearch: {
      query: {
        hybrid: {
          enabled: true,
          vectorWeight: 0.7,
          textWeight: 0.3,
          candidateMultiplier: 4
        }
      }
    }
  }
}

Embedding cache(埋め込みキャッシュ)

OpenClaw は chunk embeddings を SQLite にキャッシュできるため、再インデックス化と頻繁な更新(特に session transcript)が unchanged text を再埋め込みしません。

Config:

agents: {
  defaults: {
    memorySearch: {
      cache: {
        enabled: true,
        maxEntries: 50000
      }
    }
  }
}

Session memory search(experimental)

オプションで session transcript をインデックス化し、memory_search 経由で表示できます。 これは experimental flag でゲートされています。

agents: {
  defaults: {
    memorySearch: {
      experimental: { sessionMemory: true },
      sources: ["memory", "sessions"]
    }
  }
}

注意:

  • Session indexing は opt-in(デフォルトではオフ)。
  • Session update は debounce され、delta threshold を超えると非同期でインデックス化されます(best-effort)。
  • memory_search はインデックス化でブロックされません。background sync が完了するまで結果がわずかに古い場合があります。
  • 結果には snippet のみが含まれます。memory_get は memory file に制限されたままです。
  • Session indexing は agent ごとに分離されます(その agent の session log のみがインデックス化されます)。
  • Session log は disk(~/.openclaw/agents/<agentId>/sessions/*.jsonl)に保存されます。filesystem access を持つプロセス/ユーザーはそれらを読み取ることができるため、disk access を trust boundary として扱ってください。より厳格な分離のためには、別の OS ユーザーまたは host で agent を実行してください。

Delta threshold(デフォルトを表示):

agents: {
  defaults: {
    memorySearch: {
      sync: {
        sessions: {
          deltaBytes: 100000,   // ~100 KB
          deltaMessages: 50     // JSONL line
        }
      }
    }
  }
}

SQLite vector acceleration(sqlite-vec)

sqlite-vec extension が利用可能な場合、OpenClaw は embedding を SQLite virtual table(vec0)に保存し、database で vector distance query を実行します。これにより、すべての embedding を JS にロードすることなく検索を高速に保ちます。

Configuration(オプション):

agents: {
  defaults: {
    memorySearch: {
      store: {
        vector: {
          enabled: true,
          extensionPath: "/path/to/sqlite-vec"
        }
      }
    }
  }
}

注意:

  • enabled はデフォルトで true です。無効にすると、stored embedding を介した in-process cosine similarity に検索がフォールバックします。
  • sqlite-vec extension が欠落している、またはロードに失敗した場合、OpenClaw はエラーをログに記録し、JS fallback で続行します(vector table なし)。
  • extensionPath は bundled sqlite-vec path をオーバーライドします(custom build または非標準インストール場所に便利)。

Local embedding auto-download(ローカル埋め込み自動ダウンロード)

  • デフォルトの local embedding model:hf:ggml-org/embeddinggemma-300M-GGUF/embeddinggemma-300M-Q8_0.gguf(約 0.6 GB)。
  • memorySearch.provider = "local" の場合、node-llama-cppmodelPath を解決します。GGUF が欠落している場合、cache(または設定されている場合は local.modelCacheDir)に自動ダウンロードしてからロードします。ダウンロードは retry 時に再開されます。
  • Native build requirement:pnpm approve-builds を実行し、node-llama-cpp を選択してから pnpm rebuild node-llama-cpp を実行します。
  • Fallback:local setup が失敗し、memorySearch.fallback = "openai" の場合、自動的に remote embeddings(オーバーライドされていない限り openai/text-embedding-3-small)に切り替え、理由を記録します。

Custom OpenAI-compatible endpoint example(カスタム OpenAI 互換エンドポイントの例)

agents: {
  defaults: {
    memorySearch: {
      provider: "openai",
      model: "text-embedding-3-small",
      remote: {
        baseUrl: "https://api.example.com/v1/",
        apiKey: "YOUR_REMOTE_API_KEY",
        headers: {
          "X-Organization": "org-id",
          "X-Project": "project-id"
        }
      }
    }
  }
}

注意:

  • remote.*models.providers.openai.* よりも優先されます。
  • remote.headers は OpenAI header とマージされます。key の競合では remote が優先されます。OpenAI デフォルトを使用するには remote.headers を省略してください。