长期记忆

长期记忆,指的是跨会话、可被 memory_search / memory_get 工具检索的那部分“记忆”。

长期记忆的正文保存在工作区里的 Markdown 文件中:工作区根目录的 MEMORY.mdmemory.md,以及 memory/ 目录下的 **/*.md。这些是普通文本文件,不是存在 MySQL 或其他关系型数据库里。

检索与索引存在哪?

  • 为了能做语义搜索和全文检索,OpenClaw 会为这些文件建索引,索引存在 SQLite 里(默认路径类似 ~/.openclaw/memory/<agentId>.sqlite,按 agent 隔离)。库里主要有:已索引文件列表(path、hash、mtime)、文本块(chunks)及向量(embedding)、以及可选的 FTS5 / sqlite-vec 用于全文与向量检索。也就是说:用 SQLite 做“记忆”的索引和检索,不用 SQLite 存记忆的原文;原文在 Markdown 文件里。

  • 可选后端 qmd

若配置了 memory.backend: "qmd",会使用外部命令 qmd 及其自建索引(例如 $XDG_CACHE_HOME/qmd/index.sqlite),同样不是 MySQL。

「无限记忆」的组成


  • 会话记忆:当前会话从创建到现在的所有用户消息与助手回复,保存在会话转录文件(sessionFile)中,由 Pi 的 SessionManager 管理,是“多轮对话上下文”的真正载体。

  • 长期记忆:MEMORY.md 与 memory/*.md,通过 memory 工具读写与检索,与具体某次会话解耦。

  • 会话记忆 + 长期记忆 共同支撑“之前说过的话 / 做过的事”在后续轮次仍可用;当上下文窗口不足时,通过压缩(Compaction) 将部分会话历史摘要化,而不是简单丢弃,从而在模型侧仍保留“完整性”的语义。

  • 会话内:旧轮次不会硬删,而是被越来越“粗”的摘要替换(旧的几百条压成一条 summary),所以语义上还是被带着走。

  • 会话间:通过 Memory 系统(MEMORY.md + memory/.md + 搜索)把长期决策、事实等写入“记忆文件”,后面可以跨会话检索再拼回上下文。

会话转录文件与“当前轮”的关系


要点:

  • 会话转录文件里已经包含“上一轮(及更早)用户说了什么、助手回复了什么”。

  • 本轮只负责生成当前这一条用户消息(commandBody):可以是纯文字、纯媒体说明(如 [User sent media without caption] + [media attached: ...])、或文字+媒体。

  • 模型在调用时看到的是 【会话文件中已有历史】+【本轮新 user 消息】,因此“用户上一轮说的要求”自然落在历史里,“本轮只发文件”不会丢失意图。

多轮对话下请求上下文的完整性


  • 同一会话sessionKey 确定,对应唯一的 sessionIdsessionFile

  • 每一轮请求都会:

    • 读取该 sessionFile(即“到上一轮为止”的完整历史),

    • 本轮的 prompt(commandBody)作为一条新的 user 消息追加到会话,

    • 再将会话整体交给模型。

  • 因此请求上下文的完整性由“同一会话 = 同一 sessionFile = 同一份历史”保证;不会出现“只带当前一句、不带前文”的情况。

会话转录的持久化与恢复

  • 每个会话的 sessionIdsessionFile 路径由 resolveSessionFilePath(sessionId, sessionEntry, options) 等逻辑解析,并可能持久化在 SessionEntry 中。

  • 会话转录文件一般是 JSONL:首行为 session header,后续每行一条消息(user/assistant/system/tool 等)。Pi 的 SessionManager 负责读取、追加、以及在必要时参与压缩(见下节)。

  • 因此“无限记忆”在会话维度的实现就是:同一会话永远写同一个 sessionFile,历史只增不改(压缩时由 Pi/OpenClaw 重写或摘要),从而保证多轮请求上下文的完整性。

长期记忆(MEMORY)与会话记忆的配合

  • 会话记忆:只来自当前会话的 sessionFile,随会话存在,多轮对话的“之前说了什么”都在这里。

  • 长期记忆:MEMORY.md 等由 memory 工具读写和检索,可跨会话;模型在需要时调用 memory_search / memory_get,把检索到的片段加入自己的推理。

  • 两者配合:同一轮请求中,模型既能看到会话历史(含“上一轮你说要总结下一个文件”),又能按需拉取长期记忆,从而在“多轮 + 先说话后发文件”的场景下,既保证请求上下文的完整性,又可以利用更早的持久化知识。

流程要点摘要

阶段 动作 与“记住上下文”的关系
解析会话 按 sessionKey 找到/创建 SessionEntry,确定 sessionFile 保证同一会话始终用同一文件
加载历史 读会话文件 JSONL,得到 messages 多轮“记忆”的来源
Memory Flush 若 token 接近阈值,先跑一轮记忆写入 memory/*.md 压缩前把重要信息持久化,避免丢在压缩里
limitHistoryTurns 只保留最近 N 轮 user 对话 先硬裁剪,再送模型,减少 token
组装上下文 系统提示 + Skills + 裁剪/压缩后的历史 + 当前消息 实际发给模型的“当前上下文”
发送请求 runEmbeddedAttempt → Provider 若 SDK 内部发现超长会触发 in-attempt compaction
溢出处理 识别 overflow → 工具结果截断 / 显式 compaction → 重试 窗口过长时的补救,保证能继续用同一会话
保存 将本轮 assistant/tool 消息追加到会话文件 下一轮“记住”的本轮内容
Logo

小龙虾开发者社区是 CSDN 旗下专注 OpenClaw 生态的官方阵地,聚焦技能开发、插件实践与部署教程,为开发者提供可直接落地的方案、工具与交流平台,助力高效构建与落地 AI 应用

更多推荐