Memory
Memory trong OpenClaw là các file Markdown thông thường trong workspace của agent. Các file này là nguồn dữ liệu chính thống; model chỉ “nhớ” những gì được ghi vào đĩa.
Các công cụ tìm kiếm memory được cung cấp bởi plugin memory đang hoạt động (mặc định: memory-core). Để tắt plugin memory, đặt plugins.slots.memory = "none".
File memory (Markdown)
Layout workspace mặc định sử dụng hai lớp memory:
memory/YYYY-MM-DD.md- Nhật ký hàng ngày (chỉ ghi thêm).
- Đọc ngày hôm nay + ngày hôm qua khi session bắt đầu.
MEMORY.md(tùy chọn)- Memory dài hạn được quản lý.
- Chỉ load trong session chính, riêng tư (không bao giờ trong ngữ cảnh nhóm).
Các file này nằm trong workspace (agents.defaults.workspace, mặc định là ~/.openclaw/workspace). Xem Agent workspace để biết layout đầy đủ.
Khi nào nên ghi memory
- Các quyết định, sở thích và thông tin lâu dài thì ghi vào
MEMORY.md. - Ghi chú hàng ngày và context đang chạy thì ghi vào
memory/YYYY-MM-DD.md. - Nếu ai đó nói “nhớ cái này”, hãy ghi xuống (đừng giữ trong RAM).
- Phần này vẫn đang phát triển. Việc nhắc model lưu memory sẽ giúp ích; nó sẽ biết phải làm gì.
- Nếu các bạn muốn điều gì đó được lưu lại, yêu cầu bot ghi nó vào memory.
Tự động flush memory (pre-compaction ping)
Khi một session sắp tới auto-compaction, OpenClaw kích hoạt một lượt agentic im lặng để nhắc model ghi memory lâu dài trước khi context bị nén. Các prompt mặc định nói rõ là model có thể trả lời, nhưng thường thì NO_REPLY là phản hồi đúng để người dùng không thấy lượt này.
Điều này được kiểm soát bởi 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.",
},
},
},
},
}
Chi tiết:
- Soft threshold: flush được kích hoạt khi ước tính token của session vượt qua
contextWindow - reserveTokensFloor - softThresholdTokens. - Im lặng theo mặc định: các prompt bao gồm
NO_REPLYnên không có gì được gửi đi. - Hai prompt: một user prompt cộng với một system prompt để thêm lời nhắc.
- Một lần flush mỗi chu kỳ compaction (được theo dõi trong
sessions.json). - Workspace phải có quyền ghi: nếu session chạy trong sandbox với
workspaceAccess: "ro"hoặc"none", flush sẽ bị bỏ qua.
Để biết toàn bộ vòng đời compaction, xem Session management + compaction.
Vector memory search
OpenClaw có thể xây dựng một vector index nhỏ trên MEMORY.md và memory/*.md (cộng với bất kỳ thư mục hoặc file bổ sung nào các bạn chọn) để các truy vấn ngữ nghĩa có thể tìm thấy các ghi chú liên quan ngay cả khi cách diễn đạt khác nhau.
Mặc định:
- Được bật theo mặc định.
- Theo dõi các file memory để phát hiện thay đổi (debounced).
- Sử dụng embeddings từ xa theo mặc định. Nếu
memorySearch.providerkhông được đặt, OpenClaw tự động chọn:localnếumemorySearch.local.modelPathđược cấu hình và file tồn tại.openainếu có thể resolve được OpenAI key.gemininếu có thể resolve được Gemini key.- Nếu không, memory search sẽ bị tắt cho đến khi được cấu hình.
- Chế độ local sử dụng node-llama-cpp và có thể yêu cầu
pnpm approve-builds. - Sử dụng sqlite-vec (khi có sẵn) để tăng tốc vector search trong SQLite.
Embeddings từ xa yêu cầu API key cho embedding provider. OpenClaw resolve key từ auth profiles, models.providers.*.apiKey, hoặc biến môi trường. Codex OAuth chỉ bao gồm chat/completions và không đáp ứng embeddings cho memory search. Với Gemini, dùng GEMINI_API_KEY hoặc models.providers.google.apiKey. Khi sử dụng custom OpenAI-compatible endpoint, đặt memorySearch.remote.apiKey (và tùy chọn memorySearch.remote.headers).
Đường dẫn memory bổ sung
Nếu các bạn muốn index các file Markdown ngoài layout workspace mặc định, thêm các đường dẫn rõ ràng:
agents: {
defaults: {
memorySearch: {
extraPaths: ["../team-docs", "/srv/shared-notes/overview.md"]
}
}
}
Lưu ý:
- Đường dẫn có thể là tuyệt đối hoặc tương đối với workspace.
- Thư mục được quét đệ quy để tìm file
.md. - Chỉ các file Markdown được index.
- Symlink bị bỏ qua (file hoặc thư mục).
Gemini embeddings (native)
Đặt provider thành gemini để sử dụng Gemini embeddings API trực tiếp:
agents: {
defaults: {
memorySearch: {
provider: "gemini",
model: "gemini-embedding-001",
remote: {
apiKey: "YOUR_GEMINI_API_KEY"
}
}
}
}
Lưu ý:
remote.baseUrllà tùy chọn (mặc định là Gemini API base URL).remote.headerscho phép các bạn thêm header bổ sung nếu cần.- Model mặc định:
gemini-embedding-001.
Nếu các bạn muốn sử dụng custom OpenAI-compatible endpoint (OpenRouter, vLLM, hoặc proxy), các bạn có thể dùng cấu hình remote với OpenAI provider:
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" }
}
}
}
}
Nếu các bạn không muốn đặt API key, dùng memorySearch.provider = "local" hoặc đặt memorySearch.fallback = "none".
Fallback:
memorySearch.fallbackcó thể làopenai,gemini,local, hoặcnone.- Fallback provider chỉ được sử dụng khi primary embedding provider thất bại.
Batch indexing (OpenAI + Gemini):
- Được bật theo mặc định cho OpenAI và Gemini embeddings. Đặt
agents.defaults.memorySearch.remote.batch.enabled = falseđể tắt. - Hành vi mặc định chờ batch hoàn thành; điều chỉnh
remote.batch.wait,remote.batch.pollIntervalMs, vàremote.batch.timeoutMinutesnếu cần. - Đặt
remote.batch.concurrencyđể kiểm soát số lượng batch job mình submit song song (mặc định: 2). - Batch mode áp dụng khi
memorySearch.provider = "openai"hoặc"gemini"và sử dụng API key tương ứng. - Gemini batch job sử dụng async embeddings batch endpoint và yêu cầu Gemini Batch API khả dụng.
Tại sao OpenAI batch nhanh + rẻ:
- Với các lần backfill lớn, OpenAI thường là lựa chọn nhanh nhất mà mình hỗ trợ vì mình có thể submit nhiều embedding request trong một batch job duy nhất và để OpenAI xử lý chúng bất đồng bộ.
- OpenAI cung cấp giá ưu đãi cho Batch API workload, nên các lần indexing lớn thường rẻ hơn so với gửi cùng số request đồng bộ.
- Xem tài liệu OpenAI Batch API và bảng giá để biết chi tiết:
Ví dụ config:
agents: {
defaults: {
memorySearch: {
provider: "openai",
model: "text-embedding-3-small",
fallback: "openai",
remote: {
batch: { enabled: true, concurrency: 2 }
},
sync: { watch: true }
}
}
}
Công cụ:
memory_search— trả về các snippet với file + line range.memory_get— đọc nội dung file memory theo đường dẫn.
Chế độ local:
- Đặt
agents.defaults.memorySearch.provider = "local". - Cung cấp
agents.defaults.memorySearch.local.modelPath(GGUF hoặchf:URI). - Tùy chọn: đặt
agents.defaults.memorySearch.fallback = "none"để tránh remote fallback.
Cách các công cụ memory hoạt động
memory_searchtìm kiếm ngữ nghĩa các chunk Markdown (mục tiêu ~400 token, overlap 80 token) từMEMORY.md+memory/**/*.md. Nó trả về snippet text (giới hạn ~700 ký tự), đường dẫn file, line range, điểm số, provider/model, và liệu mình có fallback từ local → remote embeddings hay không. Không trả về toàn bộ nội dung file.memory_getđọc một file Markdown memory cụ thể (tương đối với workspace), tùy chọn từ dòng bắt đầu và cho N dòng. Các đường dẫn ngoàiMEMORY.md/memory/chỉ được phép khi được liệt kê rõ ràng trongmemorySearch.extraPaths.- Cả hai công cụ chỉ được bật khi
memorySearch.enabledresolve thành true cho agent.
Những gì được index (và khi nào)
- Loại file: Chỉ Markdown (
MEMORY.md,memory/**/*.md, cộng với bất kỳ file.mdnào trongmemorySearch.extraPaths). - Lưu trữ index: SQLite per-agent tại
~/.openclaw/memory/<agentId>.sqlite(có thể cấu hình quaagents.defaults.memorySearch.store.path, hỗ trợ token{agentId}). - Độ mới: watcher trên
MEMORY.md,memory/, vàmemorySearch.extraPathsđánh dấu index là dirty (debounce 1.5s). Sync được lên lịch khi session bắt đầu, khi search, hoặc theo interval và chạy bất đồng bộ. Session transcript sử dụng delta threshold để kích hoạt background sync. - Trigger reindex: index lưu trữ embedding provider/model + endpoint fingerprint + chunking params. Nếu bất kỳ thứ gì trong số đó thay đổi, OpenClaw tự động reset và reindex toàn bộ store.
Hybrid search (BM25 + vector)
Khi được bật, OpenClaw kết hợp:
- Vector similarity (khớp ngữ nghĩa, cách diễn đạt có thể khác)
- BM25 keyword relevance (token chính xác như ID, biến môi trường, ký hiệu code)
Nếu full-text search không khả dụng trên nền tảng của các bạn, OpenClaw fallback về vector-only search.
Tại sao hybrid?
Vector search rất tốt ở “cái này có nghĩa giống nhau”:
- “Mac Studio gateway host” vs “the machine running the gateway”
- “debounce file updates” vs “avoid indexing on every write”
Nhưng nó có thể yếu ở các token chính xác, có tín hiệu cao:
- ID (
a828e60,b3b9895a…) - ký hiệu code (
memorySearch.query.hybrid) - chuỗi lỗi (“sqlite-vec unavailable”)
BM25 (full-text) thì ngược lại: mạnh ở token chính xác, yếu hơn ở paraphrase. Hybrid search là giải pháp thực tế ở giữa: sử dụng cả hai tín hiệu retrieval để các bạn có kết quả tốt cho cả truy vấn “ngôn ngữ tự nhiên” và truy vấn “tìm kim trong đống cỏ khô”.
Cách mình merge kết quả (thiết kế hiện tại)
Phác thảo implementation:
- Lấy một candidate pool từ cả hai phía:
- Vector: top
maxResults * candidateMultipliertheo cosine similarity. - BM25: top
maxResults * candidateMultipliertheo FTS5 BM25 rank (thấp hơn là tốt hơn).
- Chuyển đổi BM25 rank thành điểm số 0..1-ish:
textScore = 1 / (1 + max(0, bm25Rank))
- Union candidate theo chunk id và tính điểm số có trọng số:
finalScore = vectorWeight * vectorScore + textWeight * textScore
Lưu ý:
vectorWeight+textWeightđược chuẩn hóa thành 1.0 trong config resolution, nên các trọng số hoạt động như phần trăm.- Nếu embeddings không khả dụng (hoặc provider trả về zero-vector), mình vẫn chạy BM25 và trả về keyword match.
- Nếu FTS5 không thể tạo được, mình giữ vector-only search (không có hard failure).
Đây không phải “IR-theory perfect”, nhưng nó đơn giản, nhanh, và có xu hướng cải thiện recall/precision trên các ghi chú thực tế. Nếu mình muốn fancy hơn sau này, các bước tiếp theo phổ biến là Reciprocal Rank Fusion (RRF) hoặc score normalization (min/max hoặc z-score) trước khi trộn.
Config:
agents: {
defaults: {
memorySearch: {
query: {
hybrid: {
enabled: true,
vectorWeight: 0.7,
textWeight: 0.3,
candidateMultiplier: 4
}
}
}
}
}
Embedding cache
OpenClaw có thể cache chunk embeddings trong SQLite để reindex và các cập nhật thường xuyên (đặc biệt là session transcript) không phải re-embed text không thay đổi.
Config:
agents: {
defaults: {
memorySearch: {
cache: {
enabled: true,
maxEntries: 50000
}
}
}
}
Session memory search (experimental)
Các bạn có thể tùy chọn index session transcript và hiển thị chúng qua memory_search. Tính năng này được bảo vệ bởi experimental flag.
agents: {
defaults: {
memorySearch: {
experimental: { sessionMemory: true },
sources: ["memory", "sessions"]
}
}
}
Lưu ý:
- Session indexing là opt-in (tắt theo mặc định).
- Session update được debounce và index bất đồng bộ khi chúng vượt qua delta threshold (best-effort).
memory_searchkhông bao giờ block trên indexing; kết quả có thể hơi cũ cho đến khi background sync hoàn thành.- Kết quả vẫn chỉ bao gồm snippet;
memory_getvẫn giới hạn ở các file memory. - Session indexing được cô lập theo agent (chỉ session log của agent đó được index).
- Session log nằm trên đĩa (
~/.openclaw/agents/<agentId>/sessions/*.jsonl). Bất kỳ process/user nào có quyền truy cập filesystem đều có thể đọc chúng, nên hãy coi disk access là ranh giới tin cậy. Để cô lập chặt chẽ hơn, chạy agent dưới các OS user hoặc host riêng biệt.
Delta threshold (mặc định hiển thị):
agents: {
defaults: {
memorySearch: {
sync: {
sessions: {
deltaBytes: 100000, // ~100 KB
deltaMessages: 50 // JSONL lines
}
}
}
}
}
SQLite vector acceleration (sqlite-vec)
Khi sqlite-vec extension khả dụng, OpenClaw lưu trữ embeddings trong SQLite virtual table (vec0) và thực hiện vector distance query trong database. Điều này giữ cho search nhanh mà không cần load mọi embedding vào JS.
Cấu hình (tùy chọn):
agents: {
defaults: {
memorySearch: {
store: {
vector: {
enabled: true,
extensionPath: "/path/to/sqlite-vec"
}
}
}
}
}
Lưu ý:
enabledmặc định là true; khi tắt, search fallback về in-process cosine similarity trên stored embeddings.- Nếu sqlite-vec extension bị thiếu hoặc không load được, OpenClaw log lỗi và tiếp tục với JS fallback (không có vector table).
extensionPathghi đè đường dẫn sqlite-vec được bundle (hữu ích cho custom build hoặc vị trí cài đặt không chuẩn).
Local embedding auto-download
- Model embedding local mặc định:
hf:ggml-org/embeddinggemma-300M-GGUF/embeddinggemma-300M-Q8_0.gguf(~0.6 GB). - Khi
memorySearch.provider = "local",node-llama-cppresolvemodelPath; nếu GGUF bị thiếu, nó tự động download vào cache (hoặclocal.modelCacheDirnếu được đặt), sau đó load nó. Download tiếp tục khi retry. - Yêu cầu native build: chạy
pnpm approve-builds, chọnnode-llama-cpp, sau đópnpm rebuild node-llama-cpp. - Fallback: nếu local setup thất bại và
memorySearch.fallback = "openai", mình tự động chuyển sang remote embeddings (openai/text-embedding-3-smalltrừ khi được ghi đè) và ghi lại lý do.
Ví dụ custom OpenAI-compatible endpoint
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"
}
}
}
}
}
Lưu ý:
remote.*được ưu tiên hơnmodels.providers.openai.*.remote.headersmerge với OpenAI header; remote thắng khi có xung đột key. Bỏ quaremote.headersđể sử dụng OpenAI mặc định.