OpenClaw 的记忆系统本质上仍是对现有记忆设计方法与模块的组合。本文尝试对其记忆系统的设计思路与实现机制进行一次简单的梳理。
记忆的存储
OpenClaw 将记忆实体化地存储在工作区中的 Markdown 文件里。其设计哲学是 “文件是真实的记忆来源,模型只‘记得’写入磁盘的内容”。系统默认包含两类文件:
memory/YYYY-MM-DD.md:这是每日流水日志,采用追加写入模式。
MEMORY.md(可选):作为长期记忆的汇总文件。
这种设计的优势非常直接:文件本身可读性强,便于人工查看和编辑;同时可以利用 Git 等工具进行版本控制和备份。任何对记忆内容的修改,无论是 Agent 还是用户,都直接作用于这些文件。
记忆的形成
Agent 通过调用文件写入工具,将新的记忆条目追加到上述 Markdown 文件中。具体触发机制包括:
- 主动指令:当对话中出现“记住这个”等明确指令时,Agent 会识别出重要信息并将其写入相应的记忆文件。
- 自动预刷新:当会话长度接近模型的上下文上限,即将触发压缩时,系统会自动进行一次“预刷新”。它会向模型发送一条默认提示(通常是
“Session nearing compaction. Store durable memories now.”),促使模型将那些具有持久价值的信息保存到 memory/*.md 文件中。
记忆的演化
记忆的演化过程相对简单:
- 追加而非覆盖:新记忆总是以追加的方式写入文件末尾,系统没有内置的自动合并或版本控制机制。每日日志文件 (
YYYY-MM-DD.md) 是纯粹的追加日志,而 MEMORY.md 则通常需要用户或 Agent 手动编辑来整理、归纳长期信息。
- 冲突与遗忘:由于缺乏冲突合并逻辑和专门的重写过程,旧记忆不会被自动覆盖。如果不同时间形成的记忆产生了矛盾,OpenClaw 本身没有自动解决策略,必须依赖人工调整文件内容来纠正。同时,系统目前没有任何自动遗忘机制,这意味着除非手动删除,否则所有记忆条目都会永久保留,这可能导致噪声和冗余的积累。
记忆的检索
为了高效支持检索,OpenClaw 为每个 Agent 维护了一个记忆索引(默认路径为 ~/.openclaw/memory/.sqlite)。该索引会在记忆文件内容发生变化时进行增量更新,确保查询时能访问到最新内容。
检索功能通过两个核心的内建工具(属于“memory”工具组)实现:
memory_search(语义搜索):在已索引的记忆文件中执行搜索。其工作流程是:首先基于向量相似度进行语义匹配,再结合 BM25 算法进行关键字匹配以优化排序。返回的结果包括相关的文本片段、源文件路径、行号范围以及匹配分数等元数据。
memory_get(文件读取):用于精确读取某个记忆文件中指定行范围内的内容,适合在已知具体位置时获取信息。
检索到的记忆片段会作为额外的上下文插入到当前对话中,从而帮助模型更好地回答关于历史决策、长期计划或用户偏好等问题。这种结合向量搜索与关键字检索的方式,是当前 RAG(检索增强生成)架构中的常见实践。
设计局限性
尽管 OpenClaw 的记忆系统提供了一个可落地的基本框架,但它在设计上仍存在一些明显的局限性:
- 缺乏冲突解决机制:系统没有自动处理记忆冲突的逻辑。长时间运行后,智能体可能因为存储了相互矛盾的信息而产生“幻觉”或做出前后不一致的决策。
- 缺少自动化整理与遗忘:随着记忆条目不断累积,文件中的噪声和冗余信息会越来越多。将这些未经筛选的内容喂给模型,可能导致生成的回答案非所问或准确性下降。如何设计智能的遗忘与整合策略,是一个待解决的挑战。
- 记忆条目孤立:目前每条存储的记忆条目之间是平等的、孤立的,系统没有为它们建立逻辑或语义上的关联。检索返回的结果是一个个离散的片段,缺乏上下文联系,这对于需要复杂逻辑推理的场景来说支撑能力有限。
如果你对这类 Agent 架构与实现的细节感兴趣,欢迎在 云栈社区 的 开源实战 板块与更多开发者交流探讨。
|