本文内容主要讲解了OpenClaw和Claude Code的memory机制,并针对他们的异同展开了探讨


1 OpenClaw的memory

OpenClaw 是开源 Agent 框架,其memory机制主要想法是**“文件即状态,搜索即召回”**

1.1 两层记忆

OpenClaw 的记忆系统主要分为两层:

  • 长期记忆 — MEMORY.md:存放用户偏好、关键决策、固定规则等需要长期记住的信息。文件默认不存在,需要用户手动创建。每次对话启动时自动注入上下文,Agent 在对话中主动往里写,人也可以直接编辑。
  • 工作记忆 — memory/YYYY-MM-DD.md:每天一个独立文件,记录当天的会话摘要、运行笔记、临时观察。它们是 append-only 的——每天自动创建新文件,旧内容不修改。每次会话启动时,系统加载今日和昨日的日志文件。

当这些记忆被保存后,会在后台自动进行向量化索引。

1.2 如何召回

除去上面自动注入的记忆,Agent会通过如下两个工具召回其他记忆:

  • memory_search:混合搜索(BM25 30% + 向量70%)搜索之前索引在SQLite 里的向量。向量语义(70% 权重)负责"意思差不多"的内容,BM25(30% 权重)负责精准匹配 ID、代码符号、错误信息等。自动注入的只是近期内容,碰上三天前的日志或 MEMORY.md 里某条特定信息,靠这个工具找。
  • memory_get:直接读取指定记忆文件或行范围。

1.3 上下文压缩

长对话不可避免地逼近上下文窗口上限。当这发生时,系统必须压缩上下文,但压缩会丢失细节。OpenClaw 的解决方案是Memory Flush:即在压缩执行之前,触发一个动作让模型把当前关键上下文紧急写入文件,触发阈值 = contextWindow - reserveTokensFloor(默认20K) - softThresholdTokens(默认4K)。以 200K 模型为例,200K - 20K - 4K = 176K token 时触发。

另外,在触发压缩的过程中,旧消息被摘要并保留最近 20K tokens 的原始对话。


2 Claude Code的memory机制

2.1 存储内容

Claude Code 的记忆系统实现跨会话持久化,让模型在下次对话中"记得"用户是谁、偏好什么、项目在干什么。存储的内容主要分为下面四类记忆:

  • user(用户画像):用户的角色、技术背景、知识水平、工作目标。
  • feedback(行为反馈):用户对 Agent 工作方式的确认和纠正。
  • project(项目动态):当前的工作目标、截止日期、上下文。
  • reference(外部索引):外部系统的位置信息,如 bug 在哪个 Linear 项目等。

2.2 存储类型

和OpenClaw一样都是用文件存储memory内容。

  • 索引层MEMORY.md 是一个目录文件,每行一条引用指向一个具体的记忆文件。每次对话启动时自动加载进上下文,上限 200 行 / 25KB,超 200 行后硬性截断,只加载前 200 行。
  • 文件层:每个记忆存为一个独立 .md 文件,文件开头有一段 YAML 格式的元信息(namedescriptiontype),按语义分类(user/feedback/project/reference)。文件内容不进上下文,只在需要时由模型 Read 按需加载。

2.3 召回机制

MEMORY.md 索引默认只加载到system上下文,但具体该召回哪些记忆文件是用廉价快捷的Sonnet 模型判断

具体流程如下:

  1. scanMemoryFiles 直接扫 memory 目录下所有 .md 文件(上限 200 个,按修改时间最新优先),每个文件只读前 30 行,提取元数据而先不加载正文。注意它不走 MEMORY.md 索引而是直接读磁盘。
  2. 把用户当前 query + 记忆文件清单发给 Sonnet
  3. Sonnet 返回最多 5 个最相关的文件名,不相关就返回空列表
  4. 选中的文件完整内容按需加在注入对话上下文

Sonnet 侧查询不是在主模型需要时才触发的,而是在用户提交消息后立刻就开始了,和主模型的 API 调用并行执行。等主模型的响应回来时,记忆选择早就完成了。整个记忆召回过程几乎不增加任何额外延迟。

2.4 上下文压缩

Claude Code的上下文压缩更是复杂,按顺序分别是五级压缩:

  • Tool Result Budget:它的逻辑很简单,如果单个工具的结果超过约 50KB,就把完整内容写到磁盘上,在消息里只留一个 2KB 的预览摘要。除了单个工具的限制,还有一个消息级的总量控制,同一条消息里所有工具结果的总大小不能超过 200KB。如果超了,系统会挑出最大的那几个结果存磁盘,直到总量降到限制以内。
  • History Snip:裁剪旧消息。当消息历史过长时,直接切除早期的轮次。对于那些确实已经完全过时的消息来说,这是代价最低的做法,因为它不需要额外调用大模型来生成摘要,零 API 开销。
  • Microcompact :主要是清除旧工具调用结果。不是所有工具都会被清,只有 COMPACTABLE_TOOLS(Read、Bash、Grep、Glob、WebSearch、WebFetch、Edit、Write)的结果才会被清理。可以被裁剪的,都是「可重新获取」的工具,Read 的结果可以再读一次,Bash 的输出可以再执行一次,搜索结果可以再搜一次。但 AgentTool(子 Agent 的输出)类似的工具的结果永远不会被裁剪,因为子 Agent 的推理过程是不可重复的,砍掉就真的丢了。
  • Context Collapse:这步最重要的是读时投影。前面三层都是「写时压缩」,直接修改消息列表,把内容替换掉或删掉。但Context Collapse 不修改原始消息,它只在调用 API 的那一刻,动态计算一个「压缩视图」给模型看。
  • Autocompact :完整压缩。当前四步仍不够时触发,Claude Code 用一个公式计算触发阈值,即从有效窗口内减去13K的缓冲作为触发阈值。以 200K Token 的模型为例:有效窗口大约 180K(预留 20K 给输出),减去 13K 缓冲区,当上下文达到 167K Token 时触发。具体步骤是首先调用大模型生成摘要,然后用摘要替换旧消息,最后Post-Compact Restoration(压缩后恢复),即系统会从文件状态缓存中找出最近访问过的文件,按最后访问时间排序,挑选最多 5 个、总共不超过 50K Token 的文件内容重新注入,同时恢复不超过 25K Token,活跃的 Skill,如果有进行中的 Plan 也会恢复 Plan 文件。

3 总结与感想

我们从上文发现,无论是openclaw还是claude code,都是固定的长期记忆+不固定的短期记忆+滚动压缩context的这样的行为模式,而且他们对于长期记忆的存储方式都十分简单,相比我们之前读过的论文Mem0[1]的记忆管理模式更为简洁。

另外值得注意的一点是,目前工业级的agent memory似乎更加倾向于markdown文件而非数据库去存储对应的记忆,这或许说明了一个朴素的道理:在工程落地中,部署的简易性和可维护性往往比算法复杂度更重要。当一篇 Markdown 文件就能胜任的事,引入一套向量数据库和检索管线反而增加了故障点和维护负担。

或许对于memory来说,当下的最优解不是"存得更精巧",而是"存得刚好够用"。大道至简,简单的记忆提升可以依赖工程上的改进,而更多的提升还需依赖基座模型的能力。


  1. Chhikara P, Khant D, Aryan S, et al. Mem0: Building production-ready ai agents with scalable long-term memory[J]. arXiv preprint arXiv:2504.19413, 2025. ↩︎