OpenClaw 专题第六期 :OpenClaw 是如何存储、更新、调用和约束记忆的
前面几期,我们已经讲了 OpenClaw 的主链路、上下文装配、Prompt、Agent 和工具调用。
这一期进入另一个真正决定系统能不能长期稳定运行的部分:`记忆系统`。
因为一个真正可用的记忆系统,必须回答的不只是“记住什么”,而是:
记忆不是模型脑子里的隐藏状态,而是 Workspace 里的可见文件,加上一层可检索、可约束、可分作用域的 Runtime 机制。
这也是它和“普通聊天机器人只留历史记录”的根本区别。
一、先把概念立住:OpenClaw 的记忆不是黑盒,而是外部状态系统
官方文档对 Memory 的定义很直接:OpenClaw 通过在 Agent Workspace 里写 Markdown 文件来“记住事情”,模型只会记住真正落盘的内容,没有隐藏记忆状态。
所以,OpenClaw 的 Memory 本质上不是“神秘的模型能力”,而是一套由 Runtime 管理的外部状态系统。
按照官方文档,OpenClaw 当前有三类主要记忆文件。
这类信息不是“今天有效、明天就过期”的临时上下文,而是值得长期保留的内容。
2. `memory/YYYY-MM-DD.md`
官方文档明确说明,OpenClaw 会自动加载今天和昨天的 daily notes。
这两个层次如果不分,系统很快就会被昨天的临时事项污染长期记忆。
这是可选文件,主要用于 Dream Diary 和 dreaming sweep summary,不是普通会话的主记忆入口。
所以从实现结构看,OpenClaw 不是把所有记忆塞进一个数据库字段,而是先把记忆做成几类可读文件,再围绕它们建立索引、检索和调用机制。
“OpenClaw 的 Memory 只能存在本地 Markdown 文件里。”
OpenClaw 默认把 Markdown 文件作为记忆的事实源,但它的记忆检索层和后端能力并不一定局限在本地文件本身。
也就是说,OpenClaw 默认不是把记忆藏在一个远程黑盒数据库里,而是先把“记住了什么”落成可读文件。
这是一个很重要的设计选择,因为它天然适合工程治理。
官方文档里有 `memorySearch.extraPaths` 配置。
这意味着,除了默认 workspace,OpenClaw 还可以把 workspace 之外的 Markdown 目录纳入记忆索引。
都可以成为 OpenClaw 的 memory source。
官方文档给出的 memory backend 不止默认 builtin engine 一种,还有:
本地优先的 sidecar,支持更强的检索能力,也支持索引 workspace 外目录
偏平台级的 AI-native memory backend,支持 cross-session memory、user modeling、multi-agent awareness
所以,OpenClaw 当前最核心的设计,不是“memory 必须在本地”,而是:
这比一开始就把所有记忆都丢进远程黑盒,更适合长期治理。
四、OpenClaw 怎么把记忆变成“可检索记忆”
OpenClaw 的做法是:`文件是事实源,索引是检索层。`
按照官方 Builtin Memory Engine 和 Memory Search 文档,默认 builtin engine 会做几件事。
官方文档写得很清楚,builtin engine 使用的是 `per-agent SQLite database`。
这件事非常关键,因为它天然体现了第一层作用域边界:
记忆索引默认按 Agent 隔离,而不是全局共享一个大记忆池。
-
切成大约 `400 tokens` 的 chunk
-
chunk 之间保留大约 `80 tokens` overlap
OpenClaw 的 `memory_search` 不是单一路径。
这很重要,因为真实记忆召回里,很多内容不是“语义像”就够了。
例如某个工单号、某个配置项、某个错误字符串,靠向量检索经常不稳定,必须保留 lexical path。
官方明确把这套机制叫 hybrid search。
也就是说,它不是“有 embedding 就全靠 embedding”,而是:
语义召回和关键词召回一起跑,再由 Runtime 合并结果。
这种情况下,Agent 会把内容写到合适的记忆文件里。
这说明 OpenClaw 允许“显式记忆写入”,而不是只能靠系统自己猜。
官方 Builtin Memory Engine 文档里写得很清楚:
-
embedding provider、model、chunking 配置变化时,会自动全量重建索引
这意味着,OpenClaw 的记忆更新不是“写完文件,检索层还不知道”,而是文件和索引保持联动。
这是 OpenClaw 很关键、也很像 Runtime 能力的一点。
根据官方 Compaction 和 Session Management Deep Dive 文档,在会话接近上下文上限、即将 compaction 之前,OpenClaw 会先触发一次 `silent memory flush turn`。
在对话被压缩总结之前,先把值得长期保留的信息提醒 Agent 写到记忆文件里,避免 compaction 把关键信息冲掉。
这比很多系统“先压缩,压缩后再想办法补记忆”稳得多。
-
`MEMORY.md` 会在每个 DM session 开始时加载
-
今天和昨天的 `memory/YYYY-MM-DD.md` 会自动加载
也就是在正式进入当前对话之前,先把最稳定、最接近当前时间窗口的记忆作为底座带进来。
如果基础加载不够,Agent 可以调用 `memory_search` 做按需召回。
这时候系统不该全量展开所有记忆,而是通过检索拿回相关片段。
OpenClaw 还有一个更主动的能力:`Active Memory`。
根据官方文档,它是一个 `optional plugin-owned blocking memory sub-agent`,会在主回复之前先跑一轮受限记忆子代理。
-
而是在主回复前插入一个受限 recall step
默认 builtin engine 使用 `per-agent SQLite database`。
-
一个执行 Agent 读到另一个 Agent 的长期偏好
前面第四期已经讲过,OpenClaw 的运行是 `single serialized run per session`。
而且所有 persistence 都先落到 session 轨道里。
-
不是所有 session 痕迹都会直接升级为长期记忆
这一步非常关键,因为“会话连续性”不等于“长期记忆沉淀”。
默认 `allowedChatTypes: [“direct”]`。
也就是说,Active Memory 默认只在 direct-message style sessions 里跑,而不是默认在 group 或 channel 里全开。
4. Runtime Eligibility 作用域
Active Memory 不是只要开插件就会跑。
-
chat type 命中 allowedChatTypes
-
当前 session 必须是 eligible interactive persistent chat session
-
heartbeat/background runs
-
generic internal agent-command paths
-
sub-agent/internal helper execution
也就是说,OpenClaw 很明确地区分了用户交互场景、后台执行场景和内部工作场景,不是所有地方都适合记忆调用。
系统先确定这条消息属于哪个 session,以及是不是一个符合条件的交互式持久会话。
第三步:如果启用了 Active Memory,先跑受限记忆子代理
它的输出不是直接回复用户,而是给主 Agent 一份“这轮是否需要引用长期记忆”的受限结果。
如果主 Agent 仍然需要查更细的历史,它还可以显式调用 `memory_search`。
完成本轮任务,把消息、工具调用、结果、事件等写回 session transcript。
第七步:接近上下文上限时,先 memory flush,再 compaction
-
先 silent flush durable facts to memory files
-
再 compaction conversation
这样即使旧对话被压缩,关键事实也已经进了可检索记忆层。
九、从本地代码看,OpenClaw 当前已经体现出的“记忆前提”是什么
虽然当前仓库里没有完整展开一个独立的 Memory Service,但本地代码已经能看出几件很重要的事。
在 [weekly-report-runner.mjs](/Users/liuyuhui/Work/Workspace/OpenClaw/scripts/weekly-report-runner.mjs) 里,可以直接看到:
这说明这套系统不是“把所有信息都塞进记忆”,而是先区分:
因为只有先把配置、状态、结果和记忆分开,后面才不会把一切都错误地写成 memory。
在 [weekly-report.page.mjs](/Users/liuyuhui/Work/Workspace/OpenClaw/config/weekly-report.page.mjs) 里,可以看到它会先检查:
因为如果把“这次页面有没有登录”“这次 DOM 有没有读到 bookId”这种临时结果直接写成长期记忆,系统只会越来越脏。
在 [recruitment-agent-simple-sop.md](/Users/liuyuhui/Work/Workspace/OpenClaw/docs/recruitment-agent-simple-sop.md) 里,主控 Agent、需求分析 Agent、审批协同 Agent、人才搜寻 Agent、简历评估 Agent 等角色边界是分开的。
这虽然不是 Memory 文档,但它说明 OpenClaw 当前整体设计已经默认接受一个事实:
不同 Agent 的职责不同,因此它们能读、能写、该保留的上下文也不应该天然共享。
这和官方文档里 `per-agent` 记忆索引的思路是对齐的。
十、为什么很多 Agent 的记忆最后会变成污染源
记忆系统翻车,通常不是因为“没记住”,而是因为“记住了不该记的东西”。
聊天、日志、错误、工具输出、用户偏好、知识片段混在一起。
昨天的临时问题、上周的任务痕迹、半年前的长期偏好全部混在一起,模型很难判断哪个更该优先。
一个用户在私聊里的偏好,被召回到群里;一个 Agent 的历史,被另一个 Agent 用到;一个 session 的临时状态,被升级成全局记忆。
用户早就改口了,系统还按旧偏好执行;某个规则早就失效了,系统还在持续召回。
一次 OCR 失败、一次接口超时、一次网页结构异常,如果被写进长期记忆,后面就会反复污染决策。
OpenClaw 当前的设计路线,恰恰是在避免这些问题:
这套组合的核心目标不是“多记”,而是“记得住、找得到、有边界”。
下一期我们继续把镜头拉回 OpenClaw 本体:
《从周报自动化脚本看 OpenClaw:Browser Runtime、页面适配层与任务调度》
-
OpenClaw 为什么不是只会调 API 的 Agent
-
Browser Runtime 在它的执行体系里扮演什么角色
-
cron 与交互式 Agent Run 是怎么接起来的
-
这些能力说明 OpenClaw 已经成型了哪些运行时机制