跳轉到主要內容

Memory

OpenClaw memory is plain Markdown in the agent workspace. The files are the source of truth; the model only “remembers” what gets written to disk. Memory search tools are provided by the active memory plugin (default: memory-core). 記憶體搜尋工具由目前啟用的記憶體外掛提供(預設: memory-core)。可使用 plugins.slots.memory = "none" 停用記憶體外掛。

Memory files(Markdown)

預設的工作區配置使用兩層記憶體:
  • memory/YYYY-MM-DD.md
    • 每日紀錄(僅追加)。
    • Read today + yesterday at session start.
  • MEMORY.md(選用)
    • 精選的長期記憶。
    • Only load in the main, private session (never in group contexts).
這些檔案位於工作區之下(agents.defaults.workspace,預設為 ~/.openclaw/workspace)。完整配置請參見 Agent workspace。 1. 請參閱 Agent workspace 以了解完整版面配置。

何時寫入記憶體

  • 決策、偏好與可長期保存的事實寫入 MEMORY.md
  • 日常筆記與進行中的脈絡寫入 memory/YYYY-MM-DD.md
  • 若有人說「記住這個」,就把它寫下來(不要只放在 RAM)。
  • 此區域仍在持續演進中。 3. 這有助於提醒模型儲存記憶;它會知道該怎麼做。
    1. 如果你希望某件事能被保留下來,請要求機器人把它寫入記憶中。

自動記憶體清空(預先壓縮 ping)

當一個工作階段接近自動壓縮時,OpenClaw 會觸發一個靜默的、具代理性的回合,提醒模型在內容被壓縮之前寫入持久記憶。 6. 預設提示明確指出模型 可以回覆,但通常 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.",
        },
      },
    },
  },
}
詳細說明:
  • 軟性門檻:當工作階段的權杖數估計值跨過 contextWindow - reserveTokensFloor - softThresholdTokens 時觸發清空。
  • 預設為無聲:提示包含 NO_REPLY,因此不會送達使用者。
  • 兩個提示:使用者提示+系統提示一併附加提醒。
  • 每個壓縮循環僅一次清空(於 sessions.json 追蹤)。
  • 工作區必須可寫入:若工作階段以沙箱模式執行且使用 workspaceAccess: "ro""none",則會略過清空。
完整的壓縮生命週期請見 Session management + compaction

向量記憶搜尋

OpenClaw 可以在 MEMORY.mdmemory/*.md 上建立小型向量索引, 使語意查詢即使措辭不同也能找到相關筆記。 預設值:
    1. 預設啟用。
    1. 監看記憶檔案的變更(去抖動)。
  • 請在 agents.defaults.memorySearch(而非頂層 memorySearch)下設定記憶體搜尋。
    1. 預設使用遠端嵌入(embeddings)。 預設使用遠端嵌入(embeddings)。 預設使用遠端嵌入。若未設定 memorySearch.provider,OpenClaw 會自動選擇:
    2. 若設定了 memorySearch.local.modelPath 且檔案存在,使用 local
    3. 若可解析 OpenAI 金鑰,使用 openai
    4. 若可解析 Gemini 金鑰,使用 gemini
    5. 若可解析 Voyage 金鑰,使用 voyage
    6. 否則在完成設定前,記憶搜尋會維持停用。
  • 本地模式使用 node-llama-cpp,且可能需要 pnpm approve-builds
  • 可用時使用 sqlite-vec 以加速 SQLite 內的向量搜尋。
遠端嵌入需要嵌入提供者的 API 金鑰。 12. OpenClaw 會從驗證設定檔、models.providers.*.apiKey,或環境變數中解析金鑰。 13. Codex OAuth 僅涵蓋聊天/補全,無法滿足用於記憶搜尋的嵌入需求。 14. 對於 Gemini,請使用 GEMINI_API_KEYmodels.providers.google.apiKey。 15. 對於 Voyage,請使用 VOYAGE_API_KEYmodels.providers.voyage.apiKey。 16. 使用自訂的 OpenAI 相容端點時,請設定 memorySearch.remote.apiKey(以及選用的 memorySearch.remote.headers)。

QMD 後端(實驗性)

設定 memory.backend = "qmd" 以將內建的 SQLite 索引器替換為 QMD:一個以本地為優先的搜尋側車,結合 BM25+向量+重新排序。Markdown 仍是唯一可信來源;OpenClaw 透過殼層呼叫 QMD 進行擷取。重點如下: 17. Markdown 仍是唯一可信來源;OpenClaw 會呼叫 QMD 進行檢索。 18. 重點: 先決條件
    1. 預設停用。 預設停用。 預設停用。需於每個設定中選擇加入(memory.backend = "qmd")。
  • 需另行安裝 QMD CLI(bun install -g https://github.com/tobi/qmd 或下載 發行版),並確保 qmd 二進位檔位於 Gateway 閘道器的 PATH
  • QMD 需要允許擴充的 SQLite 建置(macOS 使用 brew install sqlite)。
  • QMD 透過 Bun+node-llama-cpp 完全在本地執行,並在首次使用時 從 HuggingFace 自動下載 GGUF 模型(不需要獨立的 Ollama 常駐程式)。
  • Gateway 閘道器 會在 ~/.openclaw/agents/<agentId>/qmd/ 下設定 XDG_CONFIG_HOMEXDG_CACHE_HOME,於自成一體的 XDG home 中執行 QMD。
  • 作業系統支援:安裝好 Bun+SQLite 後,macOS 與 Linux 可即用。 Windows 最佳方式為 WSL2。 20. Windows 最佳支援方式為 WSL2。
側車的執行方式
  • Gateway 閘道器 會在 ~/.openclaw/agents/<agentId>/qmd/ 下寫入自成一體的 QMD home(設定+快取+ sqlite DB)。
  • 透過 qmd collection addmemory.qmd.paths (加上預設的工作區記憶體檔案)建立集合,接著在開機與可設定的間隔 (memory.qmd.update.interval,預設 5 m)執行 qmd updateqmd embed
  • 閘道器現在會在啟動時初始化 QMD 管理器,因此即使在第一次呼叫 memory_search 之前,也會啟用週期性更新計時器。
  • 開機時的重新整理現在預設在背景執行,避免阻塞聊天啟動;設定 memory.qmd.update.waitForBootSync = true 可保留先前的阻塞行為。
  • 搜尋透過 qmd query --json 執行。若 QMD 失敗或缺少二進位檔, OpenClaw 會自動回退至內建的 SQLite 管理器,確保記憶工具可繼續運作。 21. 如果所選模式在您的 QMD 建置版本中拒絕使用旗標,OpenClaw 會改以 qmd query 重試。 若 QMD 失敗或缺少二進位檔,OpenClaw 會自動回退至內建的 SQLite 管理器,確保記憶工具持續運作。
  • OpenClaw 目前未提供 QMD 的嵌入批次大小調校;批次行為由 QMD 本身控制。
  • 首次搜尋可能較慢:QMD 可能在第一次 qmd query 執行時 下載本地 GGUF 模型(重新排序/查詢擴展)。
    • OpenClaw 在執行 QMD 時會自動設定 XDG_CONFIG_HOME/XDG_CACHE_HOME
    • 若要手動預先下載模型(並暖身與 OpenClaw 相同的索引), 請使用代理程式的 XDG 目錄執行一次性查詢。 OpenClaw 的 QMD 狀態位於你的狀態目錄下(預設為 ~/.openclaw)。 OpenClaw 的 QMD 狀態位於你的 狀態目錄(預設為 ~/.openclaw)。 你可以匯出 OpenClaw 使用的相同 XDG 變數,將 qmd 指向完全相同的索引: OpenClaw 的 QMD 狀態位於你的 狀態目錄(預設為 ~/.openclaw)。 你可以匯出 OpenClaw 使用的相同 XDG 變數,將 qmd 指向完全相同的索引:
      # Pick the same state dir OpenClaw uses
      STATE_DIR="${OPENCLAW_STATE_DIR:-$HOME/.openclaw}"
      if [ -d "$HOME/.moltbot" ] && [ ! -d "$HOME/.openclaw" ] \
        && [ -z "${OPENCLAW_STATE_DIR:-}" ]; then
        STATE_DIR="$HOME/.moltbot"
      fi
      
      export XDG_CONFIG_HOME="$STATE_DIR/agents/main/qmd/xdg-config"
      export XDG_CACHE_HOME="$STATE_DIR/agents/main/qmd/xdg-cache"
      
      # (Optional) force an index refresh + embeddings
      qmd update
      qmd embed
      
      # Warm up / trigger first-time model downloads
      qmd query "test" -c memory-root --json >/dev/null 2>&1
      
設定介面(memory.qmd.*
  • command(預設 qmd):覆寫可執行檔路徑。
  • includeDefaultMemory(預設 true):自動索引 MEMORY.mdmemory/**/*.md
  • includeDefaultMemory(預設 true):自動索引 MEMORY.mdmemory/**/*.md
  • paths[]:新增額外目錄/檔案(path,選用 pattern,選用 穩定的 name)。
  • sessions:選擇加入工作階段 JSONL 索引(enabledretentionDaysexportDir)。
  • update:控制重新整理頻率與維護執行: (intervaldebounceMsonBootwaitForBootSyncembedIntervalcommandTimeoutMsupdateTimeoutMsembedTimeoutMs)。
  • limits:限制回憶負載(maxResultsmaxSnippetCharsmaxInjectedCharstimeoutMs)。
  • scope:與 session.sendPolicy 相同的結構描述。 預設僅限私訊(deny 全部、allow 直接聊天);放寬後可在群組/頻道中顯示 QMD 命中。 23. 預設為僅 DM(全部 deny,僅 allow 直接聊天);放寬設定即可在群組/頻道中顯示 QMD 命中結果。
    • match.keyPrefix 會比對正規化後的 session key(轉為小寫,並移除 開頭的 agent:<id>:)。 範例:discord:channel:
    • match.rawKeyPrefix 會比對原始的 session key(轉為小寫),包含 agent:<id>:。 範例:agent:main:discord:
    • 舊版:match.keyPrefix: "agent:..." 仍會被視為 raw-key 前綴, 但為了清楚起見,建議改用 rawKeyPrefix
  • When scope denies a search, OpenClaw logs a warning with the derived channel/chatType so empty results are easier to debug.
  • 來自工作區外的片段會以 qmd/<collection>/<relative-path> 顯示於 memory_search 結果中;memory_get 會理解該前綴並從設定的 QMD 集合根目錄讀取。
  • memory.qmd.sessions.enabled = true 時,OpenClaw 會將已去識別化的工作階段逐字稿 (使用者/助理回合)匯出到 ~/.openclaw/agents/<id>/qmd/sessions/ 下的專用 QMD 集合,讓 memory_search 能回憶近期 對話而不需觸碰內建的 SQLite 索引。
  • memory.citationsauto/on 時, memory_search 片段現在會包含 Source: <path#line> 頁尾;設定 memory.citations = "off" 可將路徑中繼資料保留為內部(代理程式仍會收到路徑以用於 memory_get,但片段文字會省略頁尾,且系統提示會警告代理程式不要引用)。
範例
memory: {
  backend: "qmd",
  citations: "auto",
  qmd: {
    includeDefaultMemory: true,
    update: { interval: "5m", debounceMs: 15000 },
    limits: { maxResults: 6, timeoutMs: 4000 },
    scope: {
      default: "deny",
      rules: [{ action: "allow", match: { chatType: "direct" } }]
    },
    paths: [
      { name: "docs", path: "~/notes", pattern: "**/*.md" }
    ]
  }
}
引用與回退
  • memory.citations 不論後端為何皆適用(auto/on/off)。
  • qmd 執行時,我們會標記 status().backend = "qmd", 讓診斷顯示是哪個引擎提供結果。若 QMD 子行程結束或 JSON 輸出無法解析, 搜尋管理器會記錄警告並回傳內建提供者(既有的 Markdown 嵌入),直到 QMD 恢復。 24. 如果 QMD 子程序退出或 JSON 輸出無法解析,搜尋管理器會記錄警告並回傳內建提供者(既有的 Markdown 嵌入),直到 QMD 恢復為止。

其他記憶體路徑

若要索引預設工作區配置之外的 Markdown 檔案,請新增明確路徑:
agents: {
  defaults: {
    memorySearch: {
      extraPaths: ["../team-docs", "/srv/shared-notes/overview.md"]
    }
  }
}
注意事項:
    1. 路徑可以是絕對路徑或相對於工作區的路徑。
  • 目錄會被遞迴掃描以尋找 .md 檔案。
  • 僅索引 Markdown 檔案。
  • 忽略符號連結(檔案或目錄)。

Gemini 嵌入(原生)

將提供者設定為 gemini 以直接使用 Gemini 嵌入 API:
agents: {
  defaults: {
    memorySearch: {
      provider: "gemini",
      model: "gemini-embedding-001",
      remote: {
        apiKey: "YOUR_GEMINI_API_KEY"
      }
    }
  }
}
注意事項:
  • remote.baseUrl 為選用(預設為 Gemini API 基底 URL)。
  • remote.headers 可在需要時新增額外標頭。
  • 預設模型:gemini-embedding-001
若要使用 自訂的 OpenAI 相容端點(OpenRouter、vLLM 或代理), 可搭配 OpenAI 提供者使用 remote 設定:
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 金鑰,請使用 memorySearch.provider = "local" 或設定 memorySearch.fallback = "none" 回退:
  • memorySearch.fallback 可為 openaigeminilocalnone
  • 回退提供者僅在主要嵌入提供者失敗時使用。
批次索引(OpenAI+Gemini):
  • 預設為停用。 對 OpenAI 與 Gemini 嵌入預設啟用。 OpenAI 與 Gemini 嵌入預設啟用。設定 agents.defaults.memorySearch.remote.batch.enabled = false 可停用。
  • 預設行為會等待批次完成;必要時可調整 remote.batch.waitremote.batch.pollIntervalMsremote.batch.timeoutMinutes
  • 設定 remote.batch.concurrency 以控制並行提交的批次工作數量(預設:2)。
  • memorySearch.provider = "openai""gemini" 時會套用批次模式,並使用對應的 API 金鑰。
  • Gemini 批次工作使用非同步嵌入批次端點,且需要 Gemini Batch API 可用。
為何 OpenAI 批次又快又便宜: 設定範例:
agents: {
  defaults: {
    memorySearch: {
      provider: "openai",
      model: "text-embedding-3-small",
      fallback: "openai",
      remote: {
        batch: { enabled: true, concurrency: 2 }
      },
      sync: { watch: true }
    }
  }
}
工具:
  • memory_search — 回傳包含檔案+行範圍的片段。
  • memory_get — 依路徑讀取記憶體檔案內容。
本地模式:
  • 設定 agents.defaults.memorySearch.provider = "local"
  • 提供 agents.defaults.memorySearch.local.modelPath(GGUF 或 hf: URI)。
  • 選用:設定 agents.defaults.memorySearch.fallback = "none" 以避免遠端回退。

記憶工具如何運作

  • memory_search 會對來自 MEMORY.mdmemory/**/*.md 的 Markdown 區塊 進行語意搜尋(目標約 400 權杖、80 權杖重疊)。它會回傳片段文字(上限約 700 字元)、 檔案路徑、行範圍、分數、提供者/模型,以及是否從本地→遠端嵌入回退。 不會回傳完整檔案內容。 28. 回傳的內容包含片段文字(上限約 700 字元)、檔案路徑、行號範圍、分數、提供者/模型,以及是否從本地 → 遠端嵌入回退。 29. 不會回傳完整檔案內容。
  • memory_get 會讀取特定的記憶體 Markdown 檔案(相對於工作區), 可選擇指定起始行與行數。位於 MEMORY.mdmemory/ 之外的路徑會被拒絕。 30. 位於 MEMORY.md / memory/ 之外的路徑會被拒絕。
  • 兩個工具僅在代理程式的 memorySearch.enabled 解析為 true 時啟用。

會被索引的內容(以及時機)

  • 檔案類型:僅 Markdown(MEMORY.mdmemory/**/*.md)。
  • 索引儲存:每個代理程式一個 SQLite,位於 ~/.openclaw/memory/<agentId>.sqlite (可透過 agents.defaults.memorySearch.store.path 設定,支援 {agentId} 權杖)。
  • 新鮮度:對 MEMORY.md + memory/ 的監看器會將索引標記為需要更新(去抖動 1.5 秒)。 32. 同步會在工作階段開始、搜尋時或依間隔排程,並以非同步方式執行。 33. 工作階段逐字稿使用增量閾值來觸發背景同步。
  • 重新索引觸發:索引會儲存嵌入 提供者/模型+端點指紋+分塊參數。 只要其中任一變更,OpenClaw 會自動重設並重新索引整個儲存區。 34. 若其中任何一項變更,OpenClaw 會自動重置並重新索引整個儲存庫。

混合搜尋(BM25+向量)

啟用時,OpenClaw 會結合:
  • 向量相似度(語意匹配,措辭可不同)
  • BM25 關鍵字關聯性(精確權杖,如 ID、環境變數、程式碼符號)
若平台不支援全文搜尋,OpenClaw 會回退為僅向量搜尋。

為何要混合?

向量搜尋很擅長「意思相同」:
  • 「Mac Studio gateway host」vs「執行 Gateway 閘道器 的機器」
  • 「去抖檔案更新」vs「避免每次寫入就索引」
但對於精確且高訊號的權杖較弱:
  • ID(a828e60b3b9895a…
  • 程式碼符號(memorySearch.query.hybrid
  • 錯誤字串(「sqlite-vec unavailable」)
BM25(全文檢索)則相反:對精確詞元很強,對同義改寫較弱。 混合搜尋是務實的折衷方案:同時使用兩種檢索訊號,以便在「自然語言」查詢與「大海撈針」式查詢中都能獲得良好結果。

我們如何合併結果(目前設計)

  1. 實作草圖:
  2. 從兩側各自擷取候選池:
  • 向量:依餘弦相似度取前 maxResults * candidateMultiplier
  • BM25:依 FTS5 BM25 排名取前 maxResults * candidateMultiplier(數值越低越好)。
  1. 將 BM25 排名轉為近似 0..1 的分數:
  • textScore = 1 / (1 + max(0, bm25Rank))
    1. 依 chunk id 合併候選項並計算加權分數:
  • finalScore = vectorWeight * vectorScore + textWeight * textScore
注意事項:
  • vectorWeighttextWeight 於設定解析時正規化為 1.0, 因此權重行為等同百分比。
  • 若嵌入不可用(或提供者回傳零向量),仍會執行 BM25 並回傳關鍵字匹配。
  • 若無法建立 FTS5,則保留僅向量搜尋(不會硬性失敗)。
這並非「IR 理論上完美」,但它簡單、快速,且在真實筆記上往往能提升召回率/精確率。 若之後想做得更進階,常見的下一步是 Reciprocal Rank Fusion(RRF)或在混合前進行分數正規化(min/max 或 z-score)。 設定:
agents: {
  defaults: {
    memorySearch: {
      query: {
        hybrid: {
          enabled: true,
          vectorWeight: 0.7,
          textWeight: 0.3,
          candidateMultiplier: 4
        }
      }
    }
  }
}

Embedding cache

OpenClaw 可在 SQLite 中快取 區塊嵌入,讓重新索引與頻繁更新 (尤其是工作階段逐字稿)不必為未變更的文字重新嵌入。 設定:
agents: {
  defaults: {
    memorySearch: {
      cache: {
        enabled: true,
        maxEntries: 50000
      }
    }
  }
}

工作階段記憶搜尋(實驗性)

You can optionally index session transcripts and surface them via memory_search. This is gated behind an experimental flag.
agents: {
  defaults: {
    memorySearch: {
      experimental: { sessionMemory: true },
      sources: ["memory", "sessions"]
    }
  }
}
注意事項:
  • Session indexing is opt-in (off by default).
  • 工作階段更新會去抖,並在跨過差量門檻後 非同步索引(盡力而為)。
  • memory_search 從不等待索引完成;在背景同步完成前,結果可能略為過時。
  • 結果仍僅包含片段;memory_get 仍僅限記憶體檔案。
  • Session indexing is isolated per agent (only that agent’s session logs are indexed).
  • 工作階段紀錄會存於磁碟(~/.openclaw/agents/<agentId>/sessions/*.jsonl)。任何具有檔案系統存取權的程序/使用者都可讀取, 因此請將磁碟存取視為信任邊界。若需更嚴格隔離,請以不同 OS 使用者或主機執行代理程式。 Any process/user with filesystem access can read them, so treat disk access as the trust boundary. Any process/user with filesystem access can read them, so treat disk access as the trust boundary. For stricter isolation, run agents under separate OS users or hosts.
Delta thresholds (defaults shown):
agents: {
  defaults: {
    memorySearch: {
      sync: {
        sessions: {
          deltaBytes: 100000,   // ~100 KB
          deltaMessages: 50     // JSONL lines
        }
      }
    }
  }
}

SQLite 向量加速(sqlite-vec)

當 sqlite-vec 擴充可用時,OpenClaw 會將嵌入儲存在 SQLite 虛擬表(vec0)中,並在資料庫內執行向量距離查詢。 這能在不將每個嵌入載入到 JS 的情況下保持搜尋效能。 This keeps search fast without loading every embedding into JS. This keeps search fast without loading every embedding into JS. 設定(選用):
agents: {
  defaults: {
    memorySearch: {
      store: {
        vector: {
          enabled: true,
          extensionPath: "/path/to/sqlite-vec"
        }
      }
    }
  }
}
注意事項:
  • enabled 預設為 true;停用時,搜尋會回退為在處理序內 對已儲存嵌入進行餘弦相似度計算。
  • 若 sqlite-vec 擴充缺失或載入失敗,OpenClaw 會記錄錯誤並以 JS 回退繼續 (不使用向量表)。
  • extensionPath 可覆寫隨附的 sqlite-vec 路徑(適用於自訂建置 或非標準安裝位置)。

本地嵌入自動下載

  • 預設本地嵌入模型:hf:ggml-org/embeddinggemma-300M-GGUF/embeddinggemma-300M-Q8_0.gguf(約 0.6 GB)。
  • memorySearch.provider = "local" 時,node-llama-cpp 會解析 modelPath; 若缺少 GGUF,會 自動下載 至快取(或設定的 local.modelCacheDir), 然後載入。下載可在重試時續傳。 Downloads resume on retry. Downloads resume on retry.
  • 原生建置需求:執行 pnpm approve-builds,選擇 node-llama-cpp, 接著 pnpm rebuild node-llama-cpp
  • 回退:若本地設定失敗且 memorySearch.fallback = "openai",我們會自動切換至遠端嵌入 (除非覆寫,預設為 openai/text-embedding-3-small),並記錄原因。

自訂 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 標頭合併;發生金鑰衝突時以遠端為準。 省略 remote.headers 可使用 OpenAI 的預設值。 Omit remote.headers to use the OpenAI defaults. Omit remote.headers to use the OpenAI defaults.