前言

在 AI Agent 的开发过程中,一个核心痛点是:Agent 没有持久记忆。每次对话都是全新的,无法记住用户的偏好、历史决策或之前的工作内容。

OpenClaw 通过一个优雅的方案解决了这个问题:Memory 就是纯 Markdown 文件。文件是真理之源,模型只”记住”写入磁盘的内容。

本文基于 OpenClaw 官方文档,深入介绍 Memory 的工作原理、配置方法和最佳实践。


1. 什么是 OpenClaw Memory?

OpenClaw Memory 是存储在 Agent 工作区中的纯 Markdown 文件,作为 Agent 记忆的来源。

核心设计理念:

  • 文件即真理:所有记忆都存储在 Markdown 文件中
  • 人类可读:可以随时查看、编辑、版本控制
  • 自动检索:支持语义搜索,自动找到相关记忆

Memory 搜索工具由活动的 memory 插件提供(默认:memory-core)。如果需要禁用,可以设置 plugins.slots.memory = "none"


2. 记忆文件结构

OpenClaw 使用双层记忆结构,模拟人类的记忆系统:

2.1 默认工作区布局

1
2
3
4
5
6
workspace/
├── MEMORY.md # 精选的长期记忆(可选)
└── memory/
├── 2026-02-18.md # 每日日志
├── 2026-02-17.md
└── 2026-02-16.md
文件类型 用途 加载时机
MEMORY.md 精选的长期记忆 仅在私密主会话中加载
memory/YYYY-MM-DD.md 每日日志(追加写入) 会话启动时读取今天 + 昨天的日志

安全边界:

  • MEMORY.md 包含敏感信息(个人偏好、决策等),只在私密主会话中加载
  • 在群聊、共享上下文中,**不会加载 MEMORY.md**,避免隐私泄露
  • memory/ 目录下的日志是日常工作记录,可以在任何上下文中访问

这些文件位于工作区(agents.defaults.workspace,默认 ~/.openclaw/workspace)。


3. 何时写入记忆

3.1 写入 MEMORY.md(长期记忆)

适合存储长期有效的重要信息:

  • 重要的用户偏好
  • 关键的技术决策
  • 长期有效的规则
1
2
3
4
5
6
7
8
9
10
# MEMORY.md

## 用户偏好
- 编程语言:优先使用 TypeScript
- 框架偏好:React + Next.js
- 代码风格:函数式编程,避免 class

## 重要决策
- 2026-02-15: 决定使用 PostgreSQL 作为主数据库
- 2026-02-10: 项目迁移到 monorepo 架构

3.2 写入 memory/YYYY-MM-DD.md(每日日志)

适合记录每日工作:

  • 每日工作日志
  • 临时的想法和笔记
  • 问题记录和解决方案
1
2
3
4
5
6
7
8
9
# 2026-02-18

## 今日工作
- 完成了用户认证模块
- 修复了 3 个 bug
- 与团队讨论了新的 API 设计

## 遇到的问题
- WebSocket 连接不稳定,需要排查

3.3 关键规则

如果你希望 Agent 记住某些内容,一定要写进文件。

❌ 错误做法:

1
2
3
用户:记住,以后都用 TypeScript
Agent:好的,我记住了。
(下次会话忘记了)

✅ 正确做法:

1
2
3
用户:记住,以后都用 TypeScript
Agent:已更新 MEMORY.md,记录了您的偏好。
(下次会话能检索到)

4. 自动记忆刷新

当会话接近自动压缩时,OpenClaw 会触发一个静默的 agent 轮次,提醒模型在上下文压缩前写入持久记忆。

4.1 工作原理

默认配置(agents.defaults.compaction.memoryFlush):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
{
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.",
},
},
},
},
}

4.2 关键细节

  • 软阈值:当会话 token 估算值超过 contextWindow - reserveTokensFloor - softThresholdTokens 时触发
  • 默认静默:提示包含 NO_REPLY,所以不会向用户发送消息
  • 两个提示:用户提示 + 系统提示追加提醒
  • 每个压缩周期一次:在 sessions.json 中跟踪
  • 工作区必须可写:如果会话以 workspaceAccess: "ro""none" 运行,则跳过刷新

5. 向量记忆搜索

OpenClaw 可以为 MEMORY.mdmemory/*.md 构建小型向量索引,使语义查询即使措辞不同也能找到相关笔记。

5.1 默认行为

  • 默认启用
  • 监视记忆文件变化(防抖)
  • agents.defaults.memorySearch 下配置(非顶层 memorySearch
  • 默认使用远程 embeddings。如果未设置 memorySearch.provider,OpenClaw 自动选择:
    1. local:如果配置了 memorySearch.local.modelPath 且文件存在
    2. openai:如果可以解析 OpenAI key
    3. gemini:如果可以解析 Gemini key
    4. voyage:如果可以解析 Voyage key
    5. 否则记忆搜索保持禁用直到配置

5.2 Embedding 提供商

OpenAI:

1
2
3
4
5
6
7
8
9
10
11
12
13
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" }
}
}
}
}

Gemini:

1
2
3
4
5
6
7
8
9
10
11
agents: {
defaults: {
memorySearch: {
provider: "gemini",
model: "gemini-embedding-001",
remote: {
apiKey: "YOUR_GEMINI_API_KEY"
}
}
}
}

本地模式:

1
2
3
4
5
6
7
8
9
10
11
agents: {
defaults: {
memorySearch: {
provider: "local",
local: {
modelPath: "/path/to/model.gguf"
},
fallback: "none"
}
}
}

5.3 批量索引

OpenAI、Gemini、Voyage 支持批量索引:

  • 默认禁用
  • 设置 agents.defaults.memorySearch.remote.batch.enabled = true 启用
  • OpenAI Batch API 更快更便宜(批量请求有折扣)
1
2
3
4
5
6
7
8
9
10
11
12
agents: {
defaults: {
memorySearch: {
provider: "openai",
model: "text-embedding-3-small",
remote: {
batch: { enabled: true, concurrency: 2 }
},
sync: { watch: true }
}
}
}

6. QMD 后端(实验性)

设置 memory.backend = "qmd" 可以将内置 SQLite 索引器替换为 QMD:一个本地优先的搜索 sidecar,结合 BM25 + 向量 + 重排序

6.1 前置要求

  • 默认禁用,需要手动启用:memory.backend = "qmd"
  • 单独安装 QMD CLI:bun install -g https://github.com/tobi/qmd
  • QMD 需要支持扩展的 SQLite(macOS:brew install sqlite
  • QMD 通过 Bun + node-llama-cpp 完全本地运行,首次使用时自动下载 GGUF 模型
  • 操作系统支持:macOS 和 Linux 开箱即用,Windows 建议通过 WSL2

6.2 工作原理

  • Gateway 在 ~/.openclaw/agents/<agentId>/qmd/ 下创建独立的 QMD home
  • 通过 qmd collection addmemory.qmd.paths 创建集合
  • qmd update + qmd embed 在启动和可配置间隔运行(默认 5 分钟)
  • 搜索通过 memory.qmd.searchMode 运行(默认 qmd search --json
  • 如果 QMD 失败或二进制文件缺失,自动回退到内置 SQLite 管理器

6.3 配置示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
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" } },
{ action: "deny", match: { keyPrefix: "discord:channel:" } },
]
},
paths: [
{ name: "docs", path: "~/notes", pattern: "**/*.md" }
]
}
}

7. 混合搜索(BM25 + 向量)

启用时,OpenClaw 结合两种检索信号:

7.1 为什么需要混合搜索?

搜索类型 优势 劣势
向量搜索 语义匹配,措辞可以不同 对精确 token(ID、代码符号)较弱
BM25 精确 token 匹配 对语义相似但措辞不同较弱

混合搜索取长补短:

  • “Mac Studio gateway host” vs “运行 gateway 的机器” → 向量搜索强
  • ID(a828e60)、代码符号(memorySearch.query.hybrid)→ BM25 强

7.2 合并算法

  1. 从两边检索候选池:

    • 向量:按余弦相似度取 top maxResults * candidateMultiplier
    • BM25:按 FTS5 BM25 排名取 top maxResults * candidateMultiplier
  2. 将 BM25 排名转换为 0..1 分数:

    • textScore = 1 / (1 + max(0, bm25Rank))
  3. 按 chunk id 合并候选并计算加权分数:

    • finalScore = vectorWeight * vectorScore + textWeight * textScore

7.3 后处理管道

1
Vector + Keyword → Weighted Merge → Temporal Decay → Sort → MMR → Top-K Results

7.4 MMR 重排序(多样性)

当混合搜索返回结果时,多个 chunk 可能包含相似或重叠的内容。

MMR(最大边际相关性)重新排序结果,平衡相关性和多样性:

  • 确保顶部结果涵盖查询的不同方面
  • 避免重复相同信息

8. 记忆工具

语义搜索 Markdown chunks(~400 token 目标,80-token 重叠):

  • 返回片段文本(上限 ~700 字符)
  • 返回文件路径、行范围、分数
  • 返回 provider/model,是否从 local → remote embeddings 回退

8.2 memory_get

读取特定的记忆 Markdown 文件:

  • 工作区相对路径
  • 可选起始行和行数
  • 拒绝 MEMORY.md / memory/ 之外的路径

9. 索引存储与刷新

9.1 索引存储

  • 文件类型:仅 Markdown(MEMORY.mdmemory/**/*.md
  • 索引存储:每个 agent 的 SQLite,位于 ~/.openclaw/memory/<agentId>.sqlite
  • 可通过 agents.defaults.memorySearch.store.path 配置(支持 {agentId} token)

9.2 刷新机制

  • MEMORY.md + memory/ 上的监视器标记索引为脏(防抖 1.5s)
  • 同步在会话启动、搜索或按间隔调度,异步运行
  • 会话脚本使用增量阈值触发后台同步

9.3 重新索引触发

索引存储 embedding provider/model + endpoint fingerprint + chunking params。如果其中任何一项更改,OpenClaw 自动重置并重新索引整个存储。


10. 额外记忆路径

如果想索引默认工作区布局之外的 Markdown 文件:

1
2
3
4
5
6
7
agents: {
defaults: {
memorySearch: {
extraPaths: ["../team-docs", "/srv/shared-notes/overview.md"]
}
}
}

注意事项:

  • 路径可以是绝对路径或工作区相对路径
  • 目录递归扫描 .md 文件
  • 仅索引 Markdown 文件
  • 忽略符号链接(文件或目录)

11. 最佳实践

11.1 写下来,不要靠”脑记”

规则: 如果你希望 Agent 记住某些内容,一定要写进文件

11.2 何时写入记忆

内容类型 写入位置
决策、偏好、持久事实 MEMORY.md
日常笔记、运行上下文 memory/YYYY-MM-DD.md
别人说”记住这个” 写入记忆(不要保存在 RAM 中)

11.3 安全边界

  • MEMORY.md 仅在主会话中加载(从不在群组上下文中)
  • 避免在群聊中泄露私人信息

11.4 启用混合搜索

推荐启用混合搜索以获得更好的检索效果。

11.5 选择合适的 Embedding 后端

提供商 优点 缺点
OpenAI 质量高,稳定,批量便宜 需要 API Key
Gemini 质量高,支持批量 需要 API Key
QMD(本地) 免费,隐私,混合搜索 需要本地资源
local 完全本地,无需网络 需要下载模型

总结

OpenClaw Memory 提供了一个简单、透明、强大的 AI Agent 记忆方案:

特性 优势
纯 Markdown 文件 人类可读,可版本控制
双层结构 安全边界,隐私保护
向量搜索 语义检索,智能匹配
混合搜索 BM25 + 向量,更高的准确性
MMR 重排序 结果多样性,避免重复
QMD 后端 本地优先,无需外部服务

核心理念: 文件即真理。如果你希望 Agent 记住,就写进文件里。


参考资料


记忆是智能的基础。OpenClaw Memory 让你的 AI Agent 不再”失忆”,成为真正可靠的助手。