Memory(記憶體)
OpenClaw 記憶體是代理工作區中的純 Markdown。檔案是真實來源;模型只「記得」寫入磁碟的內容。 記憶體搜尋工具由活動的記憶體外掛提供(預設:memory-core)。使用 plugins.slots.memory = "none" 停用記憶體外掛。
Memory tools(記憶體工具)
OpenClaw 為這些 Markdown 檔案公開兩個代理端工具:memory_search— 對索引片段進行語義回想。memory_get— 針對特定 Markdown 檔案/行範圍的目標讀取。
memory_get 現在在檔案不存在時優雅降級(例如,第一次寫入前的今天日誌)。內建管理器和 QMD 後端都返回 { text: "", path },而不是拋出 ENOENT,因此代理可以處理「尚未記錄任何內容」並繼續其工作流程,無需將工具呼叫包裝在 try/catch 邏輯中。
Memory files(記憶體檔案)(Markdown)
預設工作區佈局使用兩個記憶體層:memory/YYYY-MM-DD.md- 每日日誌(僅追加)。
- 在會話開始時讀取今天 + 昨天。
MEMORY.md(可選)- 精選的長期記憶體。
- 僅在主私人會話中載入(絕不在群組上下文中載入)。
agents.defaults.workspace,預設 ~/.openclaw/workspace)。請參閱 Agent workspace 了解完整佈局。
何時寫入記憶體
- 決策、偏好和持久事實進入
MEMORY.md。 - 日常備註和執行上下文進入
memory/YYYY-MM-DD.md。 - 如果有人說「記住這個」,請寫下來(不要保留在 RAM 中)。
- 此區域仍在發展中。提醒模型儲存記憶體是有幫助的;它會知道該怎麼做。
- 如果您想讓某件事固定下來,要求機器人將其寫入記憶體。
Automatic memory flush(自動記憶體刷新)(壓縮前 ping)
當會話接近自動壓縮時,OpenClaw 會觸發一個靜默、代理式輪次,提醒模型在上下文被壓縮之前寫入持久記憶體。預設提示明確指出模型可以回覆,但通常NO_REPLY 是正確的回應,這樣使用者就不會看到此輪次。
這由 agents.defaults.compaction.memoryFlush 控制:
- Soft threshold(軟閾值):當會話 token 估計超過
contextWindow - reserveTokensFloor - softThresholdTokens時觸發刷新。 - Silent(靜默) 預設:提示包含
NO_REPLY以便不交付任何內容。 - Two prompts(兩個提示):一個使用者提示加上一個系統提示追加提醒。
- One flush per compaction cycle(每個壓縮週期一次刷新)(在
sessions.json中追蹤)。 - Workspace must be writable(工作區必須可寫):如果會話以
workspaceAccess: "ro"或"none"在沙盒中運行,則跳過刷新。
Vector memory search(向量記憶體搜尋)
OpenClaw 可以對MEMORY.md 和 memory/*.md 建立一個小型向量索引,以便語義查詢可以找到相關備註,即使措辭不同。
預設值:
- 預設啟用。
- 監視記憶體檔案的更改(防抖)。
- 在
agents.defaults.memorySearch下配置記憶體搜尋(不是頂層memorySearch)。 - 預設使用遠端 embeddings。若未設定
memorySearch.provider,OpenClaw 會自動選擇:local(若設定了memorySearch.local.modelPath且檔案存在)。openai(若可解析 OpenAI key)。gemini(若可解析 Gemini key)。voyage(若可解析 Voyage key)。mistral(若可解析 Mistral key)。- 否則記憶體搜尋保持停用,直至配置。
- 本地模式使用 node-llama-cpp,可能需要
pnpm approve-builds。 - 使用 sqlite-vec(可用時)加速 SQLite 內的向量搜尋。
memorySearch.provider = "ollama"也支援本地/自架 Ollama embeddings(/api/embeddings),但不會自動選擇。
models.providers.*.apiKey 或環境變數解析 key。Codex OAuth 僅涵蓋聊天/補全,並不滿足記憶體搜尋的 embeddings。對於 Gemini,使用 GEMINI_API_KEY 或 models.providers.google.apiKey。對於 Voyage,使用 VOYAGE_API_KEY 或 models.providers.voyage.apiKey。對於 Mistral,使用 MISTRAL_API_KEY 或 models.providers.mistral.apiKey。Ollama 通常不需要真實 API key(當本地政策需要時,OLLAMA_API_KEY=ollama-local 此類佔位符就足夠了)。
使用自訂 OpenAI 相容端點時,設定 memorySearch.remote.apiKey(及可選的 memorySearch.remote.headers)。
QMD backend(實驗性)
設定memory.backend = "qmd" 以將內建 SQLite 索引器替換為 QMD:結合 BM25 + vectors + reranking 的本地優先搜尋 sidecar。Markdown 保持真實來源;OpenClaw shell 出到 QMD 以進行檢索。關鍵點:
Prereqs(先決條件)
- 預設停用。按配置選擇加入(
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 daemon)。 - Gateway 在
~/.openclaw/agents/<agentId>/qmd/下設定XDG_CONFIG_HOME和XDG_CACHE_HOME以在自包含的 XDG 主目錄中執行 QMD。 - 作業系統支援:macOS 和 Linux 在安裝 Bun + SQLite 後開箱即用。Windows 最好透過 WSL2 支援。
- Gateway 在
~/.openclaw/agents/<agentId>/qmd/下寫入自包含的 QMD 主目錄(設定 + 快取 + sqlite DB)。 - 集合透過
qmd collection add從memory.qmd.paths建立(加上預設工作區記憶體檔案),然後qmd update+qmd embed在啟動時和可設定的間隔(memory.qmd.update.interval,預設 5 m)執行。 - Gateway 現在在啟動時初始化 QMD 管理器,因此定期更新計時器即使在第一個
memory_search呼叫前也會武裝。 - 啟動重新整理現在預設在背景執行,因此聊天啟動不會被阻塞;設定
memory.qmd.update.waitForBootSync = true保持先前的阻塞行為。 - 搜尋透過
memory.qmd.searchMode執行(預設qmd search --json;也支援vsearch和query)。若選定的模式在你的 QMD 建置上拒絕旗標,OpenClaw 重試使用qmd query。若 QMD 失敗或二進制檔遺漏,OpenClaw 自動回退到內建 SQLite 管理器,以便記憶體工具持續運作。 - OpenClaw 目前不公開 QMD embed batch-size 調整;批次行為由 QMD 本身控制。
- First search may be slow(首次搜尋可能較慢):QMD 可能在首次
qmd query執行時下載本地 GGUF 模型(reranker/query expansion)。-
OpenClaw 在執行 QMD 時自動設定
XDG_CONFIG_HOME/XDG_CACHE_HOME。 -
若想手動預先下載模型(並預熱 OpenClaw 使用的同一索引),執行一個一次性查詢,使用 agent 的 XDG 目錄。
OpenClaw 的 QMD 狀態位於你的狀態目錄(預設
~/.openclaw)。 你可以透過匯出 OpenClaw 使用的相同 XDG vars 指向完全相同的索引:
-
OpenClaw 在執行 QMD 時自動設定
memory.qmd.*)
command(預設qmd):覆寫可執行檔路徑。searchMode(預設search):選擇哪個 QMD 指令支援memory_search(search、vsearch、query)。includeDefaultMemory(預設true):自動索引MEMORY.md+memory/**/*.md。paths[]:新增額外目錄/檔案(path、選用pattern、選用穩定name)。sessions:選擇加入會話 JSONL 索引(enabled、retentionDays、exportDir)。update:控制重新整理頻率和維護執行: (interval、debounceMs、onBoot、waitForBootSync、embedInterval、commandTimeoutMs、updateTimeoutMs、embedTimeoutMs)。limits:鉗制回想負載(maxResults、maxSnippetChars、maxInjectedChars、timeoutMs)。scope:與session.sendPolicy相同的 schema。 預設為僅 DM(deny所有、allow直接聊天);放寬它以在群組/頻道中顯示 QMD 命中。match.keyPrefix匹配正規化的會話鍵(小寫,移除任何前導agent:<id>:)。例:discord:channel:。match.rawKeyPrefix匹配原始會話鍵(小寫),包括agent:<id>:。例:agent:main:discord:。- 舊版:
match.keyPrefix: "agent:..."仍被視為原始鍵前綴,但偏好rawKeyPrefix以明確性。
- 當
scope拒絕搜尋時,OpenClaw 記錄警告,包含衍生的channel/chatType,以便空結果更易除錯。 - 工作區外取得的片段在
memory_search結果中顯示為qmd/<collection>/<relative-path>;memory_get理解此前綴並從配置的 QMD 集合根讀取。 - 當
memory.qmd.sessions.enabled = true時,OpenClaw 將清理後的會話轉錄(User/Assistant 輪次)匯出到~/.openclaw/agents/<id>/qmd/sessions/下的專用 QMD 集合,以便memory_search可以回想最近的對話,無需觸及內建 SQLite 索引。 memory_search片段現在在memory.citations為auto/on時包含Source: <path#line>頁腳;設定memory.citations = "off"以保持路徑元資料內部(agent 仍接收路徑以用於memory_get,但片段文字省略頁腳,系統提示警告 agent 不引用它)。
memory.citations不論後端而適用(auto/on/off)。- QMD 執行時,我們標記
status().backend = "qmd",以便診斷顯示哪個引擎服務結果。若 QMD 子程序結束或 JSON 輸出無法解析,搜尋管理器記錄警告並返回內建提供商(現有 Markdown embeddings)直至 QMD 恢復。
Additional memory paths(額外記憶體路徑)
若想對預設工作區佈局外的 Markdown 檔案建立索引,新增明確路徑:- 路徑可以是絕對或工作區相對。
- 目錄遞迴掃描以找
.md檔案。 - 預設僅索引 Markdown 檔案。
- 若
memorySearch.multimodal.enabled = true,OpenClaw 也索引extraPaths下支援的圖片/音訊檔案。預設記憶體根(MEMORY.md、memory.md、memory/**/*.md)保持僅 Markdown。 - 符號連結被忽略(檔案或目錄)。
Multimodal memory files(多模態記憶體檔案)(Gemini image + audio)
OpenClaw 可在使用 Gemini embedding 2 時索引memorySearch.extraPaths 的圖片和音訊檔案:
- 多模態記憶體目前僅支援
gemini-embedding-2-preview。 - 多模態索引僅適用於透過
memorySearch.extraPaths探索的檔案。 - 此階段支援的模態:圖片和音訊。
memorySearch.fallback必須在啟用多模態記憶體時保持"none"。- 匹配的圖片/音訊檔案位元組在索引時上傳到配置的 Gemini embedding 端點。
- 支援的圖片副檔名:
.jpg、.jpeg、.png、.webp、.gif、.heic、.heif。 - 支援的音訊副檔名:
.mp3、.wav、.ogg、.opus、.m4a、.aac、.flac。 - 搜尋查詢保持文字,但 Gemini 可比較這些文字查詢與索引的圖片/音訊 embeddings。
memory_get仍僅讀 Markdown;二進制檔案可搜尋但不作為原始檔案內容返回。
Gemini embeddings(原生)
將提供商設定為gemini 以直接使用 Gemini embeddings API:
remote.baseUrl為可選(預設為 Gemini API base URL)。remote.headers允許你在需要時新增額外標頭。- 預設模型:
gemini-embedding-001。 gemini-embedding-2-preview也支援:8192 token 限制和可設定維度(768 / 1536 / 3072,預設 3072)。
Gemini Embedding 2(preview)
⚠️ Re-index required(需要重新索引): 從若想使用自訂 OpenAI 相容端點(OpenRouter、vLLM 或代理),你可使用 OpenAI 提供商的gemini-embedding-001(768 維度)切換到gemini-embedding-2-preview(3072 維度)會改變向量大小。若你在 768、1536 和 3072 之間改變outputDimensionality也一樣。 OpenClaw 會在偵測到模型或維度改變時自動重新索引。
remote 配置:
memorySearch.provider = "local" 或設定 memorySearch.fallback = "none"。
Fallbacks(備用):
memorySearch.fallback可為openai、gemini、voyage、mistral、ollama、local或none。- 備用提供商僅在主要 embedding 提供商失敗時使用。
- 預設停用。設定
agents.defaults.memorySearch.remote.batch.enabled = true以啟用大型語料庫索引(OpenAI、Gemini 和 Voyage)。 - 預設行為等待批次完成;若需要,調整
remote.batch.wait、remote.batch.pollIntervalMs和remote.batch.timeoutMinutes。 - 設定
remote.batch.concurrency以控制我們並行提交多少個批次工作(預設:2)。 - 當
memorySearch.provider = "openai"或"gemini"時,批次模式適用,並使用相應的 API key。 - Gemini 批次工作使用非同步 embeddings 批次端點,需要 Gemini Batch API 可用。
- 對於大型回填,OpenAI 通常是我們支援的最快選項,因為我們可在單個批次工作中提交許多 embedding 請求,讓 OpenAI 非同步處理。
- OpenAI 為 Batch API 工作量提供折扣定價,因此大型索引執行通常比同步傳送相同請求便宜。
- 見 OpenAI Batch API 文檔和定價詳情:
memory_search— 返回帶檔案 + 行範圍的片段。memory_get— 按路徑讀取記憶體檔案內容。
- 設定
agents.defaults.memorySearch.provider = "local"。 - 提供
agents.defaults.memorySearch.local.modelPath(GGUF 或hf:URI)。 - 選用:設定
agents.defaults.memorySearch.fallback = "none"以避免遠端備用。
How the memory tools work(記憶體工具如何運作)
memory_search對MEMORY.md+memory/**/*.md的 Markdown 區塊進行語義搜尋(約 400 token 目標,80 token 重疊)。返回片段文字(上限約 700 字元)、檔案路徑、行範圍、評分、提供商/模型,以及我們是否從本地回退到遠端 embeddings。不返回完整檔案負載。memory_get讀取特定記憶體 Markdown 檔案(工作區相對),選擇性地從起始行開始讀取 N 行。僅當在memorySearch.extraPaths中明確列出時,才允許MEMORY.md/memory/外的路徑。- 僅當代理的
memorySearch.enabled解析為 true 時,兩工具才啟用。
What gets indexed(and when)(什麼被索引(以及何時))
- File type(檔案類型):僅 Markdown(
MEMORY.md、memory/**/*.md)。 - Index storage(索引儲存):每代理 SQLite 於
~/.openclaw/memory/<agentId>.sqlite(透過agents.defaults.memorySearch.store.path可設定,支援{agentId}token)。 - Freshness(新鮮度):
MEMORY.md+memory/上的監視者標記索引髒值(防抖 1.5 秒)。同步安排在會話開始、搜尋時或間隔上執行,且非同步執行。會話轉錄使用 delta 閾值觸發背景同步。 - Reindex triggers(重新索引觸發器):索引儲存 embedding 提供商/模型 + 端點指紋 + 區塊參數。若其中任何改變,OpenClaw 自動重設並重新索引整個儲存。
Hybrid search(混合搜尋)(BM25 + vector)
啟用時,OpenClaw 結合:- Vector similarity(向量相似度)(語義匹配,措辭可不同)
- BM25 keyword relevance(BM25 關鍵字相關性)(精確 token,如 ID、環境變數、程式碼符號)
Why hybrid?(為什麼混合?)
向量搜尋擅長「這意味著相同的事」:- 「Mac Studio gateway host」vs「執行 Gateway 的機器」
- 「debounce file updates」vs「避免每次寫入都索引」
- ID (
a828e60、b3b9895a…) - 程式碼符號(
memorySearch.query.hybrid) - 錯誤字串(「sqlite-vec unavailable」)
How we merge results(目前的設計)(我們如何合併結果(目前的設計))
實作草圖:- 從雙方檢索候選池:
- Vector:按餘弦相似度取前
maxResults * candidateMultiplier個。 - BM25:按 FTS5 BM25 rank(越低越好)取前
maxResults * candidateMultiplier個。
- 將 BM25 rank 轉為 0..1-ish 評分:
textScore = 1 / (1 + max(0, bm25Rank))
- 按 chunk id 合併候選者,計算加權評分:
finalScore = vectorWeight * vectorScore + textWeight * textScore
vectorWeight+textWeight在配置解析中正規化為 1.0,因此權重表現如百分比。- 若 embeddings 不可用(或提供商返回零向量),我們仍執行 BM25 並返回關鍵字匹配。
- 若無法建立 FTS5,我們保持僅向量搜尋(無致命失敗)。
Post-processing pipeline(後處理管線)
在向量和關鍵字評分合併後,兩個選用後處理階段在結果到達 agent 前精煉結果清單:MMR re-ranking(多樣性)
混合搜尋傳回結果時,多個區塊可能包含相似或重疊內容。 例如,搜尋「home network setup」可能傳回五個幾乎相同的片段,來自不同日期的筆記,都提及相同路由器設定。 MMR(Maximal Marginal Relevance) 重新排名結果以平衡相關性與多樣性,確保頂部結果涵蓋查詢的不同方面,而不是重複相同資訊。 運作方式:- 結果按其原始相關性評分(向量 + BM25 加權評分)。
- MMR 迭代選取最大化的結果:
λ × 相關性 − (1−λ) × 選定的最大相似性。 - 結果之間的相似性使用符號化內容上的 Jaccard 文字相似性測量。
lambda 參數控制權衡:
lambda = 1.0→ 純相關性(無多樣性懲罰)lambda = 0.0→ 最大多樣性(忽略相關性)- 預設:
0.7(平衡,略偏相關性)
memory_search 傳回冗餘或近似複製片段,特別是日記檔案經常跨天重複相似資訊。
Temporal decay(時間衰退)(recency boost)
累積數百個日期檔案的 agent 隨時間增長。無衰退,六個月前的措辭良好筆記可超越昨天對相同主題的更新。 Temporal decay(時間衰退)基於每個結果的年齡將指數乘數應用於評分,以便最近記憶體自然排名更高,舊記憶體淡去:λ = ln(2) / halfLifeDays。
預設半衰期 30 天:
- 今天的筆記:100% 原始評分
- 7 天前:~84%
- 30 天前:50%
- 90 天前:12.5%
- 180 天前:~1.6%
MEMORY.md(根記憶體檔案)memory/中非日期檔案(例如memory/projects.md、memory/network.md)- 這些包含應始終正常排名的持久參考資訊。
memory/YYYY-MM-DD.md) 使用從檔案名稱提取的日期。
其他來源(例如會話轉錄)回退到檔案修改時間 (mtime)。
Example(範例)— query: “what’s Rod’s work schedule?”
給定這些記憶體檔案(今天是 Feb 10):
Configuration(配置)
兩功能在memorySearch.query.hybrid 下配置:
- MMR only(僅 MMR) — 有許多相似筆記但年齡無關時有用。
- Temporal decay only(僅時間衰退) — 當回顯性重要但結果已多樣化時有用。
- Both(兩者) — 對有大型、長期執行日誌歷史的 agent 推薦。
Embedding cache(Embedding 快取)
OpenClaw 可在 SQLite 中快取區塊 embeddings,以便重新索引和頻繁更新(特別是會話轉錄)無須重新 embed 未改變的文字。 Config:Session memory search(會話記憶體搜尋)(實驗性)
你可選擇對會話轉錄建立索引,並透過memory_search 顯示它們。
這位在實驗性旗標後。
- 會話索引是選擇加入(預設關閉)。
- 會話更新防抖及在跨 delta 閾值後非同步建立索引(盡力而為)。
memory_search永不阻塞索引;結果在背景同步完成前可略微陳舊。- 結果仍僅含片段;
memory_get仍限於記憶體檔案。 - 會話索引按 agent 隔離(僅該 agent 的會話日誌被索引)。
- 會話日誌位於磁碟(
~/.openclaw/agents/<agentId>/sessions/*.jsonl)。任何具檔案系統存取的程序/用戶可讀,故視磁碟存取為信任邊界。更嚴格隔離,在不同 OS 用戶或主機下執行 agent。
SQLite vector acceleration(SQLite 向量加速)(sqlite-vec)
當 sqlite-vec 擴展可用時,OpenClaw 儲存 embeddings 於 SQLite 虛擬表(vec0)且在資料庫執行向量距離查詢。這在不將每個 embedding 載入 JS 的情況下保持搜尋快速。
Configuration(可選):
enabled預設 true;停用時,搜尋回退到儲存 embeddings 上的程序內餘弦相似度。- 若 sqlite-vec 擴展遺漏或載入失敗,OpenClaw 記錄錯誤並繼續 JS 備用(無向量表)。
extensionPath覆寫綁定 sqlite-vec 路徑(對自訂建置或非標準安裝位置有用)。
Local embedding auto-download(本地 embedding 自動下載)
- 預設本地 embedding 模型:
hf:ggml-org/embeddinggemma-300m-qat-q8_0-GGUF/embeddinggemma-300m-qat-Q8_0.gguf(~0.6 GB)。 - 當
memorySearch.provider = "local"時,node-llama-cpp解析modelPath;若 GGUF 遺漏,自動下載到快取(或local.modelCacheDir若已設定),然後載入。下載在重試時繼續。 - 原生建置需求:執行
pnpm approve-builds,選node-llama-cpp,然後pnpm rebuild node-llama-cpp。 - 備用:若本地設定失敗且
memorySearch.fallback = "openai",我們自動切換到遠端 embeddings(openai/text-embedding-3-small除非覆寫)並記錄原因。
Custom OpenAI-compatible endpoint example(自訂 OpenAI 相容端點範例)
remote.*優先於models.providers.openai.*。remote.headers與 OpenAI 標頭合併;衝突時遠端優先。省略remote.headers以使用 OpenAI 預設。