OpenClaw Memory 系统深度解析:让 Agent 跨会话记住你
OpenClaw Memory 系统深度解析:让 Agent 跨会话记住你
🧠 你的 OpenClaw Agent 每次对话都从零开始?告诉它的偏好转头就忘?本文从底层原理到实战配置,完整解析 OpenClaw 的"记忆大脑"——让 Agent 从"金鱼记忆"进化为"永不遗忘的助手"
📑 文章目录
- 问题:为什么 Agent 总是"失忆"
- 核心理念:文件即记忆,Markdown 即真相
- 两层记忆架构:日志 + 长期记忆
- 记忆工具:memory_search 与 memory_get
- Embedding 与语义搜索:让 Agent "理解"记忆
- 混合搜索:BM25 + 向量的完美组合
- Memory Flush:压缩前的"抢救性存档"
- 实战:从零配置完整记忆系统
- 进阶:Embedding Provider 选择与配置
- 进阶:QMD 后端——本地优先的搜索引擎
- 最佳实践:让记忆真正"活"起来
- 常见问题排查
1. 问题:为什么 Agent 总是"失忆"
如果你读过我之前写的 Context Compaction(上下文压缩) 那篇文章,你已经知道了一个残酷的事实:
上下文(Context)是一次请求中模型能看到的全部内容——系统提示、项目指导文件(AGENTS.md、SOUL.md)、对话历史和用户的当前消息。它的范围限于单次会话,而且相对紧凑。
记忆(Memory)则是跨会话持久存在的东西。它保存在你的本地磁盘上——过去的完整对话历史、Agent 处理过的文件和用户偏好。
换句话说:
没有 Memory 的 Agent:
🧑 第 1 天:我喜欢代码用 4 空格缩进,变量用 camelCase
🤖:好的,记住了!
🧑 第 2 天:帮我写个函数
🤖:(用 2 空格缩进,snake_case 变量名)
🧑:…… 😤
🧑 第 3 天:我们上周不是讨论过数据库迁移方案吗?
🤖:抱歉,我没有之前对话的记录 🤷
AI Agent 每次会话都是全新醒来的。上下文压缩会在对话中途吞掉较旧的消息。你的 Agent 会忘记你昨天告诉它的事情。
OpenClaw 的 Memory 系统就是为了解决这个根本问题。
2. 核心理念:文件即记忆,Markdown 即真相
OpenClaw 的记忆架构做了一个与众不同的设计决策。
设计哲学
OpenClaw 的记忆是 Agent 工作空间中的纯 Markdown 文件。这些文件是唯一的真相来源;模型只"记住"写入磁盘的内容。
这意味着:
传统 RAG 系统 vs OpenClaw Memory:
📦 传统方式(Mem0、Zep 等)
├── 记忆存储为 embedding 向量
├── 向量是唯一副本
├── 你无法阅读 Agent 记住了什么
├── 无法手动修复错误记忆
└── 黑盒 🔒
📝 OpenClaw 方式
├── 记忆存储为 Markdown 文件
├── 文件是唯一真相来源
├── 你可以用任何文本编辑器打开、阅读
├── 你可以直接编辑、删除、修正错误记忆
├── 可以 git diff、grep、版本控制
└── 完全透明 🔓
所有记忆都以纯 Markdown 文件的形式存储在本地文件系统中。每次会话后,AI 会自动将更新写入这些 Markdown 日志。你——以及任何开发者——可以打开、编辑、重组、删除或优化它们。
同时,向量数据库在旁边为这些文件创建和维护检索索引。每当 Markdown 文件发生变化,系统就会检测到变化并自动重新索引。
💡 最重要的实用建议:如果你想让某件事被记住,让 Agent 写下来。
3. 两层记忆架构:日志 + 长期记忆
OpenClaw 使用两层记忆布局。文件是唯一的真相来源;记忆搜索工具由活跃的记忆插件提供(默认为 memory-core)。
3.1 文件结构
工作空间的典型目录结构如下:
~/.openclaw/workspace/ ← 默认工作空间路径
├── AGENTS.md ← Agent 行为指令(每次加载)
├── SOUL.md ← Agent 个性定义(每次加载)
├── USER.md ← 用户信息档案(每次加载)
├── MEMORY.md ← 📌 长期记忆(每次加载,仅私有会话)
└── memory/ ← 📌 每日日志目录
├── 2026-03-17.md ← 昨天的日志
├── 2026-03-18.md ← 今天的日志
├── 2026-03-15.md ← 更早的日志
└── ...
3.2 第一层:每日日志(Daily Log)
memory/YYYY-MM-DD.md 是每日日志,以追加方式记录当天发生的事情。
<!-- memory/2026-03-18.md -->
## 10:30 - 项目讨论
- 用户决定将数据库从 MySQL 迁移到 PostgreSQL
- 迁移截止日期:4 月 15 日
- 需要先完成数据备份脚本
## 14:00 - 代码审查
- 发现 auth 模块有内存泄漏
- 用户偏好:所有修复都需要先写测试
## 16:00 - 环境配置
- 用户的 staging 环境 IP 更新为 10.0.1.25
- 部署脚本路径:~/deploy/staging.sh
每日日志的特点:
- 每日日志是日记。它们适合保持几天内的连续性,特别是当你进行大量来回讨论时。你可以打开昨天的文件,查看讨论了什么内容和做了什么决定。
- 今天和昨天的日志会在会话启动时自动加载。
- 它们是原始观察记录,不经过精心策划。
3.3 第二层:长期记忆(MEMORY.md)
决策、偏好和持久事实写入 MEMORY.md。每日笔记和运行上下文写入 memory/YYYY-MM-DD.md。
<!-- MEMORY.md -->
## 用户偏好
- 代码风格:4 空格缩进,camelCase 命名
- 语言偏好:中文对话,英文代码注释
- 工作时间:每天 9:00-18:00,周末不打扰
## 项目信息
- 主项目:电商平台后端重构
- 技术栈:Node.js + TypeScript + PostgreSQL
- Git 仓库:github.com/user/ecommerce-backend
- CI/CD:GitHub Actions
## 重要决策
- 2026-03-10:决定使用 PostgreSQL 替代 MySQL
- 2026-03-15:API 版本策略确定为 URL 路径版本控制
- 2026-03-18:auth 模块重构优先于新功能开发
## 联系人
- 后端负责人:小王(钉钉群 ID: xxx)
- DBA:老李(负责数据库迁移审批)
长期记忆的特点:
- MEMORY.md 在每次对话中都会被加载到上下文中。建议精心维护,控制在约 100 行以内。
- MEMORY.md 应该保持精简和稳定。它是你希望长期保持为真的内容。
- 重要安全机制:MEMORY.md 仅在私有会话中加载,永远不会在群组上下文中加载,以保护敏感信息。
3.4 两层的关系
┌─────────────────────────────────────────────────────────┐
│ 记忆层次架构 │
│ │
│ 📌 Tier 1: MEMORY.md — 始终加载 │
│ ├── 用户偏好、项目信息、重要决策 │
│ ├── 精心策划,~100 行 │
│ └── 每次会话自动加载到上下文 │
│ │
│ 📅 Tier 2: memory/YYYY-MM-DD.md — 自动加载今天+昨天 │
│ ├── 每日流水日志,追加写入 │
│ ├── 原始记录,不需要精心维护 │
│ └── 今天和昨天自动加载;更早的通过搜索召回 │
│ │
│ 🔍 Tier 3: 语义搜索 — 按需召回 │
│ ├── 向量索引覆盖所有 memory/*.md + MEMORY.md │
│ ├── Agent 需要时通过 memory_search 检索 │
│ └── 过去几周的对话、旧日志,按相关性召回 │
└─────────────────────────────────────────────────────────┘
💡 如果 MEMORY.md 和 memory.md 同时存在于工作空间根目录,OpenClaw 只加载 MEMORY.md。小写的 memory.md 仅在 MEMORY.md 不存在时作为回退使用。
4. 记忆工具:memory_search 与 memory_get
记忆搜索工具由活跃的记忆插件提供(默认为 memory-core)。
OpenClaw 向 Agent 暴露两个记忆工具:memory_search —— 对索引片段的语义召回。memory_get —— 对特定 Markdown 文件/行范围的定向读取。
4.1 memory_search — 语义搜索
当 Agent 需要回忆某件事时,它会调用 memory_search:
Agent 内部调用过程:
🧑 用户:"我们之前讨论的数据库迁移方案是什么?"
🤖 Agent 思考:
→ 调用 memory_search("数据库迁移方案")
→ 返回相关片段:
[1] memory/2026-03-10.md: "决定将数据库从 MySQL 迁移到 PostgreSQL"
[2] memory/2026-03-12.md: "迁移脚本初稿完成,需要处理 UTF-8 编码"
[3] MEMORY.md: "迁移截止日期 4 月 15 日"
→ 组合这些信息回复用户
memory_search 是一个语义召回系统。它允许 AI 助手使用自然语言查询在索引的 Markdown 文件中搜索,从你的个人知识库中检索最相关的信息。与传统的关键词搜索不同,memorySearch 使用向量嵌入来理解查询的语义含义。
4.2 memory_get — 定向读取
memory_get 读取特定的记忆 Markdown 文件(工作空间相对路径),可选地从指定行开始读取 N 行。MEMORY.md / memory/ 之外的路径会被拒绝。
典型调用:
memory_get("memory/2026-03-10.md") → 读取整个文件
memory_get("memory/2026-03-10.md", line=15, count=10) → 读取第 15-24 行
memory_get("MEMORY.md") → 读取长期记忆
memory_get 在文件不存在时会优雅降级(例如今天的日志在第一次写入之前还不存在)。内置管理器和 QMD 后端都会返回 { text: "", path } 而不是抛出 ENOENT 错误,这样 Agent 可以处理"尚无记录"的情况并继续工作流。
4.3 工具启用条件
两个工具仅在 memorySearch.enabled 对该 Agent 解析为 true 时启用。
5. Embedding 与语义搜索:让 Agent "理解"记忆
仅仅把记忆写成文件还不够——Agent 需要能快速找到相关记忆。这就是 Embedding(嵌入向量)和语义搜索的作用。
5.1 什么是 Embedding?
OpenClaw 使用文本嵌入来驱动语义搜索和记忆检索系统。嵌入将文本转换为捕捉语义含义的数值向量,使 Agent 能够在精确词汇不同的情况下也能找到相关的记忆和文档。
传统关键词搜索 vs 语义搜索:
🔤 关键词搜索:
查询 "数据库迁移"
✅ 匹配 "数据库迁移方案"
❌ 不匹配 "MySQL 转 PostgreSQL 的计划"(没有 "数据库迁移" 这几个字)
🧠 语义搜索(Embedding):
查询 "数据库迁移"
✅ 匹配 "数据库迁移方案"
✅ 匹配 "MySQL 转 PostgreSQL 的计划"(语义相关)
✅ 匹配 "需要把生产环境的数据搬到新系统"(语义相关)
5.2 索引机制
文件类型:仅 Markdown(MEMORY.md, memory/**/*.md)。索引存储:每个 Agent 的 SQLite,位于 ~/.openclaw/memory/<agentId>.sqlite(可通过 agents.defaults.memorySearch.store.path 配置,支持 {agentId} 占位符)。
freshness:监视 MEMORY.md + memory/ 的文件变化(1.5 秒防抖)。同步在会话启动时、搜索时或定时触发,异步运行。
索引流程:
Markdown 文件写入/修改
↓ (文件监视器, 1.5s 防抖)
标记索引为 dirty
↓ (会话启动 / 搜索触发 / 定时)
分块 (chunking)
↓ (默认 512 tokens, 128 tokens 重叠)
Embedding 计算
↓ (本地 GGUF 或 远程 API)
写入 SQLite (向量表 + FTS 表)
↓
可搜索 ✅
5.3 自动重建索引
重索引触发条件:索引会存储嵌入提供者/模型 + 端点指纹 + 分块参数。如果其中任何一项发生变化,OpenClaw 会自动重置并重新索引整个存储。
⚠️ 这意味着如果你从 OpenAI 切换到 Gemini 的嵌入模型,整个索引会自动重建。这是正确的行为——不同模型的向量维度不兼容。
6. 混合搜索:BM25 + 向量的完美组合
记忆系统使用混合搜索,结合了向量相似度(语义匹配)和 BM25 关键词相关性(精确词匹配)来找到最相关的历史上下文。
6.1 为什么需要混合?
向量搜索擅长"语义相同":比如 “Mac Studio 运行网关” 和 “运行网关的那台机器”。BM25(全文搜索)则相反:擅长精确词匹配,但对释义较弱。混合搜索是务实的中间方案:同时使用两种检索信号,这样无论是"自然语言"查询还是"大海捞针"查询都能获得好结果。
6.2 融合权重
默认权重(来自 memorySearch.query.hybrid):vectorWeight: 0.7,textWeight: 0.3,candidateMultiplier: 3.0(检索 3 倍候选后合并)。
混合搜索流水线:
查询 "数据库迁移方案"
│
├── 🧠 向量搜索 (权重 0.7)
│ → 基于语义相似度的 top N×3 候选
│
├── 🔤 BM25 搜索 (权重 0.3)
│ → 基于关键词的 top N×3 候选
│
↓ 融合分数 = 0.7 × 向量分 + 0.3 × BM25 分
│
├── 🎯 MMR 多样性重排(避免重复片段)
│
├── ⏳ 时间衰减(新记忆优先)
│
↓ 返回 top N 结果
6.3 后处理:MMR 和时间衰减
MMR(最大边际相关性)功能确保搜索结果多样化,而不仅仅是彼此相似。这在搜索广泛主题时特别有用,因为你希望获得不同角度的结果。
时间衰减功能使较新的记忆稍微比较旧的更相关,可配置的半衰期默认为 30 天。这帮助你的助手优先考虑最近的信息,同时在相关时仍然能访问较旧的记忆。
常青文件(MEMORY.md、memory/ 中的非日期文件)永远不会被衰减。
7. Memory Flush:压缩前的"抢救性存档"
这是 OpenClaw Memory 系统最巧妙的设计之一。
7.1 问题:压缩 = 丢失
当会话变长时,LLM 最终需要压缩它们的上下文窗口。它们会总结较早的对话以为新信息腾出空间。但那些重要但没有进入摘要的细节怎么办?
7.2 解决方案:Flush
OpenClaw 通过在压缩前自动进行记忆刷写来解决这个问题。系统在压缩对话历史之前,将重要的上下文写入今天的每日日志。原本会消失的信息被保存到了文件系统中。
当会话接近自动压缩时,OpenClaw 会触发一个静默的 Agent 回合,提醒模型在上下文被压缩之前写入持久化记忆。
7.3 好路径 vs 坏路径
┌─────────────────────────────────────────────────────────┐
│ 上下文快满了……接下来会发生什么? │
│ │
│ ✅ 好路径:维护性压缩 │
│ ├── 上下文接近限制 │
│ ├── Memory Flush 先触发 │
│ ├── Agent 静默地将重要信息写入 memory/YYYY-MM-DD.md │
│ ├── 然后压缩总结旧对话历史 │
│ └── Agent 继续工作:摘要 + 最近消息 + 磁盘上的记忆 │
│ │
│ ❌ 坏路径:溢出恢复 │
│ ├── 上下文已经太大,API 拒绝了请求 │
│ ├── OpenClaw 进入紧急处理模式 │
│ ├── 一次性压缩所有内容,只为恢复工作 │
│ ├── 没有 Memory Flush,没有预先保存 │
│ └── 最大程度的上下文丢失 💀 │
└─────────────────────────────────────────────────────────┘
7.4 Flush 配置
Memory Flush 配置(agents.defaults.compaction.memoryFlush):enabled 启用预压缩 flush(默认 true),softThresholdTokens 触发 flush 的压缩前 token 数(默认 4000)。
当会话接近阈值时(计算公式:contextWindow - reserveTokensFloor - softThresholdTokens)触发。对于 200K 上下文窗口使用默认设置(20K 预留,4K 软阈值),大约在 176K tokens 时触发。
每次压缩周期只进行一次 flush(在 sessions.json 中追踪)。工作空间必须可写:如果会话以沙箱模式运行(workspaceAccess: “ro” 或 “none”),flush 会被跳过。
💡 当上下文达到 softThresholdTokens(40k)时,Agent 会将会话提炼到 memory/YYYY-MM-DD.md。flush 提示告诉 Agent 应该记住什么:关注决策、状态变化和经验教训——而不是例行交流。
8. 实战:从零配置完整记忆系统
8.1 创建工作空间目录
# 创建记忆目录结构
mkdir -p ~/.openclaw/workspace/memory
# 创建长期记忆文件
cat > ~/.openclaw/workspace/MEMORY.md << 'EOF'
# 长期记忆
## 用户偏好
- 待填写
## 项目信息
- 待填写
## 重要决策
- (Agent 会在对话中自动填充)
EOF
8.2 启用 memorySearch
编辑 ~/.openclaw/openclaw.json:
{
"agents": {
"defaults": {
// 工作空间路径
"workspace": "~/.openclaw/workspace",
// ===== 记忆搜索配置 =====
"memorySearch": {
"enabled": true,
// 嵌入提供者(见下一节详细选择)
// 如果不设置,OpenClaw 会自动选择
// "provider": "openai",
// 搜索参数
"query": {
"maxResults": 20, // 每次搜索最多返回 20 条结果
"minScore": 0.3, // 最低相关性分数(0-1)
"hybrid": {
"enabled": true, // 启用混合搜索
"vectorWeight": 0.7, // 向量搜索权重
"textWeight": 0.3, // 关键词搜索权重
"candidateMultiplier": 3
}
}
},
// ===== Memory Flush 配置 =====
"compaction": {
"memoryFlush": {
"enabled": true, // 压缩前自动存档(强烈建议开启)
"softThresholdTokens": 4000
}
}
}
}
}
8.3 验证
# 检查配置
openclaw doctor
# 检查记忆系统状态
openclaw memory status
# 输出示例:
# provider: openai (text-embedding-3-small)
# indexed files: 3
# total chunks: 47
# last sync: 2 min ago
8.4 测试记忆
启动 OpenClaw 后,试试这些对话:
💬 你:请记住,我的项目使用 4 空格缩进,TypeScript 严格模式
🤖 Agent:好的,我已将编码偏好记录到 MEMORY.md:
- 缩进:4 空格
- TypeScript:严格模式(strict: true)
--- 新会话 ---
💬 你:帮我写个 TypeScript 函数
🤖 Agent:[调用 memory_search("用户编码偏好")]
→ 找到 MEMORY.md 中的偏好记录
→ 使用 4 空格缩进 + 严格模式编写代码 ✅
9. 进阶:Embedding Provider 选择与配置
记忆搜索配置在 agents.defaults.memorySearch 下(不是顶级的 memorySearch)。默认使用远程嵌入。
9.1 自动选择顺序
如果 memorySearch.provider 未设置,OpenClaw 会按以下顺序自动选择:local(如果配置了 memorySearch.local.modelPath 且文件存在)→ openai(如果能解析到 OpenAI key)→ gemini(如果能解析到 Gemini key)→ voyage(如果能解析到 Voyage key)→ mistral(如果能解析到 Mistral key)。
否则记忆搜索会保持禁用状态,直到被配置。
9.2 Provider 对比
默认模型:OpenAI 用 text-embedding-3-small(1536 维);Gemini 用 gemini-embedding-001(768 维);Voyage 用 voyage-4-large(1024 维);本地用 embeddinggemma-300m-qat-Q8_0.gguf(约 600 MB)。
| Provider | 模型 | 维度 | 隐私 | 成本 | 质量 |
|---|---|---|---|---|---|
| local | embeddinggemma-300M | — | ✅ 完全本地 | 免费 | ⭐⭐⭐ |
| openai | text-embedding-3-small | 1536 | ❌ 发送到远程 | 极低 | ⭐⭐⭐⭐ |
| gemini | gemini-embedding-001 | 768 | ❌ 发送到远程 | 免费额度 | ⭐⭐⭐⭐ |
| voyage | voyage-4-large | 1024 | ❌ 发送到远程 | 低 | ⭐⭐⭐⭐⭐ |
| ollama | 自选 | 取决于模型 | ✅ 完全本地 | 免费 | ⭐⭐⭐ |
9.3 配置示例
方式 A:使用 OpenAI(推荐,简单且质量高)
{
"agents": {
"defaults": {
"memorySearch": {
"enabled": true,
"provider": "openai",
"model": "text-embedding-3-small"
}
}
}
}
确保设置了 OPENAI_API_KEY 环境变量或在 models.providers.openai.apiKey 中配置。
方式 B:使用 Gemini(有免费额度)
{
"agents": {
"defaults": {
"memorySearch": {
"enabled": true,
"provider": "gemini",
"model": "gemini-embedding-001"
}
}
}
}
⚠️ 使用 Gemini 免费额度或其他有速率限制的提供者进行向量记忆搜索可能导致嵌入服务失败,进而引发连锁故障。如果遇到此问题,建议切换到 OpenAI 或本地模型。
方式 C:完全本地(隐私优先,配合上一篇 Ollama 文章)
{
"agents": {
"defaults": {
"memorySearch": {
"enabled": true,
"provider": "local"
// 默认模型:embeddinggemma-300M-Q8_0.gguf(~600MB)
// 首次运行会自动从 HuggingFace 下载
}
}
}
}
当 memorySearch.provider = “local” 时,node-llama-cpp 解析 modelPath;如果 GGUF 文件缺失,它会自动下载到缓存目录(或 local.modelCacheDir 如果设置了),然后加载。下载支持断点续传。
本地模式使用 node-llama-cpp,可能需要运行 pnpm approve-builds。
方式 D:使用 Ollama 嵌入(配合本地 Ollama 实例)
memorySearch.provider = “ollama” 也支持本地/自托管 Ollama 嵌入(/api/embeddings),但不会被自动选择。
{
"agents": {
"defaults": {
"memorySearch": {
"enabled": true,
"provider": "ollama"
// 使用 Ollama 已拉取的嵌入模型
}
}
}
}
9.4 嵌入缓存
嵌入缓存:本地 SQLite 数据库存储计算好的嵌入,避免重复 API 调用,最多保存 50,000 条。缓存满时,使用 LRU(最近最少使用)策略淘汰。
9.5 降级与回退
回退配置(memorySearch.fallback)支持:“openai” 尝试 OpenAI 作为回退、“gemini” 尝试 Gemini、“local” 尝试本地模型、“none” 不回退,直接降级为纯全文搜索。
如果所有嵌入提供者都失败了,系统会优雅降级到纯 BM25 关键词搜索,而不是完全崩溃。
10. 进阶:QMD 后端——本地优先的搜索引擎
设置 memory.backend = "qmd" 可以使用 QMD 替代内置 SQLite 管理器。QMD 是一个本地优先的搜索 sidecar,结合了 BM25 + 向量 + 重排序。
10.1 QMD 是什么?
QMD(Query Memory Documents)是一个独立于 OpenClaw 的搜索引擎二进制,专为记忆搜索优化。
关键区别:OpenClaw 通过 shell 调用 qmd CLI(必须在 PATH 中);QMD 管理自己的 SQLite 数据库和 GGUF 模型;支持三种搜索模式:search(默认)、vsearch、query;首次运行时自动下载 reranker 模型。
10.2 配置 QMD
{
"memory": {
"backend": "qmd",
"citations": "auto", // 搜索结果包含来源引用
"qmd": {
"includeDefaultMemory": true,
"update": {
"interval": "5m", // 每 5 分钟同步
"debounceMs": 15000
},
"limits": {
"maxResults": 6,
"timeoutMs": 4000
}
}
}
}
10.3 QMD 回退机制
如果 QMD 失败或二进制缺失,OpenClaw 会自动回退到内置 SQLite 管理器,确保记忆工具继续工作。
注意:首次搜索可能较慢——QMD 可能需要在首次 qmd query 运行时下载本地 GGUF 模型(reranker/查询扩展)。
10.4 会话转录索引
当 memory.qmd.sessions.enabled = true 时,OpenClaw 会将净化的会话转录(用户/助手回合)导出到 ~/.openclaw/agents/<id>/qmd/sessions/ 下的专用 QMD 集合中,使 memory_search 可以在不触及内置 SQLite 索引的情况下回忆最近的对话。
11. 最佳实践:让记忆真正"活"起来
11.1 三条黄金法则
法则一:持久规则放文件,不放聊天。 你的 MEMORY.md 和 AGENTS.md 在压缩后仍然存在。聊天中输入的指令则不会。
法则二:主动让 Agent 记住重要的事。
如果有人说"记住这个",就写下来(不要只保存在内存中)。提醒模型存储记忆很有帮助——它会知道该怎么做。如果你想让某件事留下来,让 Agent 写入记忆。
法则三:定期维护,避免噪声。
OpenClaw 的记忆很强大,但它不会自我清理。每日日志如果从不修剪或总结,会变得嘈杂。
11.2 MEMORY.md 的编写规范
<!-- ✅ 好的 MEMORY.md -->
## 编码偏好
- 4 空格缩进, camelCase
- TypeScript strict mode
- 函数优先于类
## 项目上下文
- 电商后端重构, PostgreSQL, Node.js 20
- 部署: GitHub Actions → AWS ECS
## 关键决策
- 2026-03-10: MySQL → PostgreSQL
- 2026-03-18: auth 重构优先
<!-- ❌ 不好的 MEMORY.md -->
今天我们讨论了很多内容,首先是关于数据库的问题,
用户说他可能想要切换到 PostgreSQL 但还不确定,
然后我们又聊了聊天气,然后回到项目讨论上...
(← 太啰嗦、太随意、像日志不像策划的长期记忆)
11.3 高级记忆目录组织
Tier 3 深度知识可以组织为 memory/people/、projects/、topics/、decisions/ 等子目录。通过向量嵌入搜索,在相关时被检索,而不是默认加载。
memory/
├── 2026-03-18.md ← 今日日志(自动加载)
├── 2026-03-17.md ← 昨日日志(自动加载)
├── people/ ← 按需搜索
│ ├── wang-xiaoming.md ← 小王的信息
│ └── li-dba.md ← 老李的信息
├── projects/ ← 按需搜索
│ ├── ecommerce-backend.md ← 电商项目
│ └── migration-plan.md ← 迁移方案
└── decisions/ ← 按需搜索
├── 2026-03-10-db-switch.md
└── 2026-03-15-api-versioning.md
11.4 Memory + Self-Improving-Agent 联合使用
如果你读过我之前写的 Self-Improving-Agent 那篇文章,你可以把两者结合起来:
Memory 系统:记住"什么发生了"
→ MEMORY.md: 用户偏好、项目信息、决策记录
→ memory/YYYY-MM-DD.md: 每日事件流水
Self-Improving-Agent:记住"什么做错了"
→ 错误日志:Agent 犯过的错误和修正方式
→ 改进记录:每次修正后更新的行为规则
两者结合 = Agent 越用越聪明:
✅ 记住你的偏好(Memory)
✅ 记住项目上下文(Memory)
✅ 不重复犯错(Self-Improving-Agent)
✅ 持续优化工作流(Self-Improving-Agent)
11.5 隐私边界
架构自动强制执行隐私边界。你不需要自己记得保护隐私。系统会替你做。
- MEMORY.md 仅在私有会话中加载,群组对话无法访问
- 工作空间可以按 Agent 隔离
- 沙箱模式下 Memory Flush 会被跳过
12. 常见问题排查
问题 1:Agent 不使用记忆(“金鱼脑”)
# 1. 确认 memorySearch 已启用
openclaw doctor
# 查看 Memory search 部分是否显示 ✅
# 2. 确认 MEMORY.md 存在
ls -la ~/.openclaw/workspace/MEMORY.md
# 3. 确认嵌入提供者已配置
openclaw memory status
# 如果显示 "no embedding provider",参考第 9 节
在修改任何配置之前,在 OpenClaw 会话中运行 /context list。这是诊断记忆"不保留"问题的最快方法。检查 MEMORY.md 是否在加载——如果显示"missing"或不在列表中,说明它不在上下文中。
问题 2:搜索结果不相关
// 降低最低分数阈值,获取更多结果
{
"agents": {
"defaults": {
"memorySearch": {
"query": {
"minScore": 0.15, // 从 0.3 降到 0.15
"maxResults": 30 // 从 20 增到 30
}
}
}
}
}
问题 3:嵌入提供者报错
如果 openclaw doctor 显示"Memory search is enabled but no embedding provider is configured",修复方法(任选其一):设置 OPENAI_API_KEY 或 GEMINI_API_KEY 环境变量;添加凭证:openclaw auth add --provider openai;配置本地嵌入:设置 agents.defaults.memorySearch.provider 和本地模型路径;禁用:openclaw config set agents.defaults.memorySearch.enabled false。
问题 4:Memory Flush 没有触发
# 确认工作空间可写
ls -la ~/.openclaw/workspace/
# 如果是只读,flush 会被跳过
# 确认 flush 已启用
# 在 openclaw.json 中检查:
# agents.defaults.compaction.memoryFlush.enabled = true
问题 5:文件截断
检查是否有内容被截断。单个文件超过 20,000 字符会被截断。
如果你的 MEMORY.md 太长,考虑拆分到 memory/ 子目录下的专题文件中。
问题 6:切换嵌入提供者后搜索失败
如果你从 OpenAI 切换到 Voyage 嵌入,现有的缓存向量与新向量不兼容。缓存必须清除,所有内容必须重新嵌入。
OpenClaw 会自动处理重索引,但如果遇到问题:
# 手动清除索引并重建
rm ~/.openclaw/memory/*.sqlite
# 重启 Gateway,索引会自动重建
📋 速查卡:一页纸看完记忆系统
文件结构:
~/.openclaw/workspace/
├── MEMORY.md ← 长期记忆(每次加载,仅私有会话)
├── memory/YYYY-MM-DD.md ← 每日日志(今天+昨天自动加载)
└── memory/topics/*.md ← 专题记忆(按需搜索)
两个工具:
memory_search("查询语句") ← 语义搜索所有记忆
memory_get("memory/2026-03-18.md") ← 读取特定文件
记忆写入规则:
持久偏好/决策 → MEMORY.md
每日上下文 → memory/YYYY-MM-DD.md
"记住这个" → Agent 写入磁盘
关键配置路径:
agents.defaults.memorySearch.enabled ← 开关
agents.defaults.memorySearch.provider ← 嵌入提供者
agents.defaults.memorySearch.query.hybrid ← 混合搜索参数
agents.defaults.compaction.memoryFlush ← 压缩前存档
memory.backend ← "qmd" 或默认 SQLite
嵌入提供者优先级(自动选择):
local → openai → gemini → voyage → mistral
诊断命令:
openclaw doctor ← 全局健康检查
openclaw memory status ← 记忆系统状态
/context list ← 查看当前加载的上下文
// 最小可用配置(~/.openclaw/openclaw.json)
{
"agents": {
"defaults": {
"memorySearch": {
"enabled": true
// provider 不设置 = 自动选择
},
"compaction": {
"memoryFlush": {
"enabled": true
}
}
}
}
}
📚 参考资料
- OpenClaw Memory 官方文档
- OpenClaw 源码 - memory 模块
- Deep Dive: How OpenClaw’s Memory System Works
- OpenClaw Memory Architecture Guide
- VelvetShark: OpenClaw Memory Masterclass
- Milvus Blog: We Extracted OpenClaw’s Memory System (memsearch)
- OpenClaw memorySearch Complete Guide (DEV.to)
- 12 层记忆架构项目
如果觉得有帮助,欢迎 点赞 👍 收藏 ⭐ 关注 🔔,有问题评论区见!
本文为原创内容,转载请注明出处。
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐



所有评论(0)