我花了 5 天时间调试 OpenClaw Agent 的记忆功能,以下是我学到的所有经验

@code_rams
英语5个月前 · 2026年2月22日
212K
859
78
40
2.7K

TL;DR

一份关于优化 OpenClaw AI Agent 记忆功能的综合指南。涵盖了修复上下文压缩、实现混合搜索以及建立写入规范,确保 Agent 能够保留长期知识。

我的代理叫 Chiti。它在 Telegram 上运行,处理两个 SaaS 产品的客户支持、起草推文、管理发票,并与我的联合创始人跨时区协作。它是我最接近初级员工的东西。

但连续几周,它一直忘事。

不是那种微妙的忘记。我会花一个小时配置一个每日定时任务,切换模型,然后下一次会话中 Chiti 表现得好像我们从未交谈过。我提起两天前的一个决定,它会一脸茫然。我让它继续一个任务,它会从头开始。

于是我停止构建功能,一有空就花了 5 天时间只修复记忆。这是我发现的一切、我搞砸的一切、以及真正有效的一切。

第 1 天:长篇对话后代理忘记一切

第一个问题描述起来简单,诊断起来却痛苦。

在长对话后,Chiti 会开始丢失早期的上下文。不是逐渐丢失,而是突然消失。我 20 条消息前告诉它的事情不见了。我们在会话开始时做的决定?从没发生过。

罪魁祸首是压缩。当对话填满上下文窗口时,OpenClaw 将旧消息压缩成摘要,以腾出空间给新消息。摘要抓住了要点,但丢掉了细节。名字、数字、确切的决定——都没了。

这是设计使然。上下文窗口是有限的。但默认行为对所有内容一视同仁,这意味着你精心编写的第 3 条消息指令,会和第 7 条消息的随意闲聊得到同样的处理。

我做了什么:

我在压缩之前启用了内存刷新。这会告诉代理在压缩器运行之前将重要的上下文写入磁盘。

json
1{
2 "compaction": {
3 "memoryFlush": {
4 "enabled": true,
5 "softThresholdTokens": 4000
6 }
7 }
8}

当会话接近上下文限制时,OpenClaw 触发一个静默轮次,提醒代理在压缩清除之前将持久性事实保存到 memory/YYYY-MM-DD.md。代理写入重要的内容,压缩运行,即使上下文摘要丢失了重要信息,磁盘上的内容也能幸存下来。

我学到的:

压缩不是你的敌人。在压缩过程中丢失信息才是。解决方案是确保任何值得记住的东西在压缩器触及它之前被写入文件。如果它只在上下文窗口中,它是临时的。如果它在磁盘上,它就能幸存。

第 2 天:搜索返回垃圾结果

随着每日日志的积累和 MEMORY.md 的增长,我需要代理真正找到东西。内置的记忆搜索返回了不相关的结果,或者错过了明显的匹配项。

问题出在搜索后端。OpenClaw 默认的基于 SQLite 的搜索使用向量嵌入(语义相似度)来查找相关片段。它对宽泛的查询有效,但很难处理精确匹配。我搜索一个特定的客户名称,却得到了一个完全不同主题的结果,只是恰好使用了类似的语言。

我做了什么:

我将记忆搜索后端切换为 QMD。QMD 结合了 BM25(关键词匹配)和向量嵌入以及一个重新排序器。所以当我搜索“Charles payment failure”时,它能找到同时包含这些确切单词的结果,以及语义相关的结果,然后按相关性重新排序。

我还配置了 QMD 路径,包含我的学习文件夹:

json
1{
2 "memory": {
3 "qmd": {
4 "paths": [
5 {
6 "path": "/Users/ramya/clawd",
7 "name": "memory-root",
8 "pattern": "MEMORY.md"
9 },
10 {
11 "path": "/Users/ramya/clawd",
12 "name": "memory-alt",
13 "pattern": "memory_alt.md"
14 },
15 {
16 "path": "/Users/ramya/clawd/memory",
17 "name": "memory-dir",
18 "pattern": "**/*.md"
19 },
20 {
21 "path": "/Users/ramya/clawd/learnings",
22 "name": "learnings",
23 "pattern": "**/*.md"
24 }
25 ]
26 }
27 }
28}

我学到的:

纯语义搜索在理论上听起来不错,但在专有名词、具体数字和精确短语上会失败。混合搜索(关键词 + 向量 + 重新排序)对于真实世界的代理记忆来说要好得多。如果你的代理找不到你确信在其文件中的内容,搜索后端很可能是瓶颈,而不是文件本身。

第 3 天:代理找到了但不用

这是最令人沮丧的一天。我确认搜索是正常工作的,我可以手动查询并得到正确的结果。但在实际对话中,Chiti 不会检索相关的上下文,即使它显然存在于记忆中。

问题在于检索不是自动的。代理必须决定去搜索。如果对话没有触发正确的线索,它就不会去查找。

我做了什么:

我在启动序列中添加了明确的检索指令。而不是希望代理在需要时搜索,我告诉它何时搜索:

在开始任何任务之前:

  • 搜索每日日志以获取相关上下文
  • 检查 LEARNINGS.md 中关于此类任务的规则
  • 如果提到了某个客户,搜索其历史记录

我还构建了一个检索测试。我会在每日日志中植入一个特定的标记——比如“MARKER: 2026-02-20 — 记得在声称代码已推送之前检查 git 状态。”然后我等待,开始一个新的会话,并问:“昨天的标记是什么?”如果代理找到了,检索就正常。如果没有,那就出问题了。

我学到的:

“信息存在”和“代理使用信息”之间有区别。你需要两者。搜索基础设施处理第一部分。启动指令和检索习惯处理第二部分。分别测试两者。

第 4 天:使其对压缩安全

到目前为止,我已经有了内存刷新、混合搜索和检索指令。但我仍然在一种特定场景中丢失上下文:很长的会话中压缩运行了多次。

问题在于内存刷新在每个压缩周期中只触发一次。如果会话足够长,经历了两次或三次压缩,只有第一次压缩得到了刷新处理。之后的所有内容都处于风险中。

我做了什么:

我配置了上下文修剪与压缩协同工作:

json
1{
2 "contextPruning": {
3 "mode": "cache-ttl",
4 "ttl": "6h",
5 "keepLastAssistants": 3
6 }
7}

这会在 6 小时后激进地修剪旧上下文,同时保留最后 3 条助手回复。结合内存刷新,这意味着代理早期将重要内容写入磁盘,旧上下文在导致溢出之前被清理掉。

我还添加了一个 MARKER 测试协议:在任何重大配置更改之后,我在每日日志中植入一个标记,并测试跨越压缩边界的检索。如果标记幸存,更改生效。如果没有,出问题了。

我学到的:

长时间的会话才是真正考验记忆系统的地方。短对话很少触及压缩。是那些 2 小时的深度工作会话中你丢失上下文却不知道为什么。在负载下测试你的记忆系统,而不仅仅是在快速聊天中。

第 5 天:系统提示膨胀了 28%

这一天一切豁然开朗。我运行了 /context detail,盯着那些数字。

我的代理在读取我的消息之前,已经加载了 11,887 个 token 的系统提示。51 个技能,其中 20 个我从未使用过。MEMORY.md 有 200 行的公司维基,每个会话都加载。而且我有两个相互冲突的启动序列——一个在 BOOT.md 中(OpenClaw 甚至不识别),另一个深埋在 AGENTS.md 的 200 行之后。

最糟糕的是,每次我切换模型时,Chiti 都会忘记一切。没有交接协议。没有当前上下文的写回。直接消失。

根本原因:

OpenClaw 在每个新会话中自动读取这些文件:AGENTS.md, SOUL.md, TOOLS.md, IDENTITY.md, HEARTBEAT.md, MEMORY.md。

其他所有文件——LEARNINGS.md、每日日志、文档、参考文件——代理必须使用工具自己读取。如果读取这些文件的指令不在自动加载的文件中(特别是 AGENTS.md),代理永远不会看到它们。

我的 BOOT.md 中有完整的启动序列。但 OpenClaw 不会自动加载 BOOT.md。所以这些指令就闲置在那里,从未被读取,毫无作用。

我做了什么:

我进行了全面的审计和清理:

  1. 将启动序列移动到 AGENTS.md 的顶部(唯一可靠的启动指令位置)
  2. 删除了 BOOT.md(OpenClaw 不识别)
  3. 删除了 BOOTSTRAP.md(一次性引导文件,已完成,每个会话浪费 361 tokens)
  4. 将 MEMORY.md 从 200 行缩减到 90 行,将参考文档移到 docs/ 文件夹
  5. 移除了 20 个未使用的营销技能,它们每个会话消耗 3000 tokens
  6. 添加了写入纪律:每个任务记录其结果,每个错误变成一条规则
  7. 添加了交接协议:在模型切换或会话结束前,代理将当前上下文写入每日日志

现在的启动序列如下:

在做任何事情之前:

  1. 读取 USER.md
  2. 读取 learnings/LEARNINGS.md
  3. 读取 memory/YYYY-MM-DD.md(今天 + 昨天)
  4. 读取 MEMORY.md(仅主会话,绝不在群组中)
  5. 读取 PROTOCOL_COST_EFFICIENCY.md
  6. 打印:LOADED: USER | LEARNINGS | DAILY | MEMORY | PROTOCOL

写入纪律:

每个任务之后:

  1. 记录决策 + 结果 → memory/YYYY-MM-DD.md
  2. 如果是错误 → 追加到 learnings/LEARNINGS.md
  3. 如果是重要上下文 → 更新 MEMORY.md(仅在心跳回顾期间,绝不在任务期间直接操作)

交接协议:

会话结束或模型切换前:

将 HANDOVER 部分写入 memory/YYYY-MM-DD.md:

  • 讨论了什么
  • 决定了什么
  • 待办任务及确切细节
  • 剩余下一步

结果:

  • 系统提示:11,887 → 8,529 tokens
  • 技能:51 → 32
  • 会话 tokens:18,280 → 14,627
  • 减轻了 28%。同一个代理。同样的模型。只是噪音少了。

我学到的:

真正的解决方案不是添加更多文件。而是移除那些没有作用的文件。系统提示中的每个 token 都是代理在每条消息上携带的开销。未使用的技能、臃肿的记忆文件、系统甚至不读取的文件——它们都在悄悄累积。

我希望第一天就知道的规则

在经历了 5 天的搞破坏和修复之后,以下是我会给任何设置 OpenClaw 记忆的人的建议:

1. 只有这些文件会自动加载:AGENTS.md, SOUL.md, TOOLS.md, IDENTITY.md, USER.md, HEARTBEAT.md, MEMORY.md。

其他所有文件都需要在 AGENTS.md 中有明确的读取指令。如果它不在启动序列中,代理就不会看到它。BOOT.md 在 OpenClaw 中不是真实存在的东西。我曾经有一个,持续了几周,毫无作用。

2. 启动序列放在 AGENTS.md 的顶部。

不要放在中间,不要放在底部。最顶部。自动加载的文件会被注入到系统提示中,所以启动指令需要是代理处理的第一个东西。

3. 写入纪律比读取纪律更重要。

大多数人会设置文件供代理读取,但从不强制写回。如果代理不把决策、结果和错误记录到磁盘,这些东西只存在于上下文窗口中。而上下文窗口会被压缩。写回是临时上下文变成永久记忆的方式。

4. 绝不在任务期间直接写入 MEMORY.md。

每日日志是原始的、只能追加的。MEMORY.md 是精心策划的长期记忆。如果你让代理随意倾倒任何东西到 MEMORY.md,它会在几周内膨胀成 200 行的混乱。通过定期回顾(心跳或定时任务)来策划 MEMORY.md,从最近的每日日志中提炼出见解。我是从另一位 OpenClaw 用户那里学到的,他抓到自己的代理正是这样做的——用未经策划的噪音膨胀 MEMORY.md,直到它变得毫无用处。

5. LEARNINGS.md 是最被低估的文件。

代理犯的每一个错误都应该变成一条单行规则。“在没有检查 git 状态的情况下,绝不要声称代码已推送。”“不要在群聊中读取完整的 MEMORY.md。”“在安排任务之前,务必确认用户的时区。”这些规则会累积。几周后,你的代理就拥有了一本从自身失败中构建的个人操作手册。

6. 测试检索,而不仅仅是存储。

存储信息和检索信息是两个不同的问题。我遇到过文件已被索引和可搜索,但因为代理不知道要查找它们而从未被访问的情况。植入标记,跨会话测试,跨模型切换测试。如果代理找不到你昨天存储的内容,存储就无关紧要。

7. 交接协议是模型切换的解决方案。

OpenClaw 代理在切换模型时会丢失所有上下文。新模型从全新的上下文窗口开始——它只能看到自动加载的文件。如果没有交接协议在切换前将当前状态转储到每日日志中,新模型就不知道发生了什么。这连续几周都是我最大的痛点。

8. 定期运行 /context detail。

这个命令精确显示什么在消耗你的 tokens。你忘记安装的技能、在你不知不觉中增长的文件、你从不使用的工具。我发现了 20 个未使用的技能,每个会话烧掉 3000 tokens。那是在每条消息上 3000 tokens 的开销,用于我从未碰过的功能。

9. 混合搜索优于纯语义搜索。

BM25(关键词)+ 向量(含义)+ 重新排序比仅用向量效果显著更好。客户名称、具体数字、精确短语——语义搜索会遗漏这些。关键词搜索能抓住它们。两者都用。

10. 压缩不是敌人。未写入的上下文才是。

我花了几天对抗压缩,然后意识到解决方案更简单:确保任何重要的东西在压缩运行之前被写入文件。内存刷新自动处理这一点。如果在磁盘上,它就能在压缩中幸存。如果只在对话中,它就处于危险中。

我当前的设置

作为参考,以下是我的工作区现在的样子:

workspace/

├── AGENTS.md (启动序列 + 写入纪律 + 交接协议)

├── SOUL.md (个性和行为)

├── IDENTITY.md (名称、角色)

├── USER.md (所有者信息)

├── TOOLS.md (工具使用指南)

├── HEARTBEAT.md (自主签到行为)

├── MEMORY.md (精心策划的长期记忆,约 90 行)

├── PROTOCOL_COST_EFFICIENCY.md

├── learnings/

│ └── LEARNINGS.md (从错误中总结的规则)

├── memory/ (每日日志:YYYY-MM-DD.md)

├── docs/ (从 MEMORY.md 移出的参考文档)

│ ├── tweetsmash-arch.md

│ ├── knowledge-transfer.md

│ ├── infrastructure.md

│ └── group-chat-rules.md

└── skills/ (32 个技能,从 51 个降下来)

系统提示:8,529 tokens。会话 tokens:14,627,占 200,000 token 上下文窗口的 7.3%。代理启动,读取所需内容,写入所学内容,在模型切换前交接上下文。

花了 5 天才达到这个状态。大部分时间是在放弃“更多文件等于更好记忆”的假设。事实并非如此。纪律才是关键。我的实验仍在继续。

我正在和联合创始人一起构建 TweetSmash 和 LinkedMash——社交媒体书签工具。我在 X 上分享关于在生产环境中运行 OpenClaw 代理的经验:@code_rams

二次创作

使用 YouMind 创作爆款文章

收集素材、拆解爆点、生成视觉资产、撰写内容,并在一个 AI 工作空间里完成分发。

了解 YouMind
写给创作者

把你的 Markdown 变成干净的 𝕏 文章

图片上传、表格、代码块,往 𝕏 上手动重排太痛苦。YouMind 把整篇 Markdown 一键转成干净、可直接发布的 𝕏 文章草稿。

试试 Markdown 转 𝕏

更多可拆解样本

近期爆款文章

探索更多爆款文章