OpenClaw 记忆系统 -- 记忆预加载

【摘要】 本篇继续 OpenClaw 记忆系统分析系列,介绍了 OpenClaw 记忆系统的预加载过程。

1. 记忆系统启动流程

记忆初始化过程分为两个主要阶段:系统启动时的记忆后端初始化和会话启动时的记忆上下文构建。

  • 系统启动阶段主要初始化QMD类型的记忆后端,为后续的记忆操作做准备;
  • 会话启动阶段则根据配置加载最近几天的记忆文件,构建启动上下文,为大模型提供必要的上下文信息。

2. 系统启动阶段 (server-startup-memory.ts)

2.1. 系统启动阶段流程图

系统启动阶段






Gateway启动
startGatewayMemoryBackend
listAgentIds
遍历每个agentId
resolveMemorySearchConfig
配置存在?
跳过该agent
resolveActiveMemoryBackendConfig
是QMD后端?
getActiveMemorySearchManager
初始化记忆搜索管理器
成功?
记录初始化成功
记录错误警告

2.2. 主要过程

  1. 遍历Agent:系统启动时遍历所有配置的agent
  2. 配置检查:检查每个agent的记忆搜索配置是否启用
  3. 后端类型:只初始化QMD(Quantized Memory Database)类型的记忆后端
  4. 管理器初始化:为每个符合条件的agent初始化记忆搜索管理器
  5. 错误处理:记录初始化失败的情况

2.3. 系统启动触发

  • 触发时机:Gateway 服务启动时
  • 配置检查:检查每个 agent 的记忆搜索配置是否启用
  • 后端类型:只初始化 QMD 类型的记忆后端

2.4. 系统启动阶段参数

  • agents.defaults.memorySearch.enabled - 是否启用记忆搜索
  • agents.defaults.memorySearch.backend - 记忆后端类型(必须为"qmd")
  • agents.defaults.memorySearch.qmd - QMD后端配置

2.5. 读取的信息

  • 配置文件中的记忆搜索配置 (resolveMemorySearchConfig)
  • 记忆后端配置 (resolveActiveMemoryBackendConfig)
  • 初始化 QMD 类型的记忆后端
  • 不直接读取具体记忆文件,而是初始化记忆搜索管理器

2.6. 输入/输出

  • 系统启动时的记忆后端初始化

    • src/gateway/server-startup-memory.ts#L8-L35 - startGatewayMemoryBackend
  • 系统启动输入

    • 配置对象 OpenClawConfig
    • 代理ID agentId
  • 系统启动输出

    • 记忆搜索管理器 MemorySearchManager
    • 错误信息(如果有)

2.7. 主要代码和函数

函数名 文件路径 作用
startGatewayMemoryBackend src/gateway/server-startup-memory.ts#L9-L35 系统启动时初始化记忆后端
listAgentIds src/agents/agent-scope.js 列出所有agent ID
resolveMemorySearchConfig src/agents/memory-search.js 解析记忆搜索配置
resolveActiveMemoryBackendConfig src/plugins/memory-runtime.js 解析活跃记忆后端配置
getActiveMemorySearchManager src/plugins/memory-runtime.js 获取记忆搜索管理器

3. 会话启动阶段 (startup-context.ts)

3.1. 会话启动阶段流程图

会话启动阶段


新会话/会话重置
shouldApplyStartupContext
启用启动上下文?
跳过记忆预热
buildSessionStartupContextPrelude
resolveUserTimezone
resolveStartupContextLimits
buildStartupMemoryDateStamps
生成日期窗口
listStartupMemoryPathsByDate
扫描memory目录
按日期分组文件
读取记忆文件
readStartupMemoryFile
openBoundaryFile
readFromFd
closeFd
trimStartupMemoryContent
formatStartupMemoryBlock
fitStartupMemoryBlock
构建启动上下文
返回记忆预加载内容

3.2. 主要过程

  1. 配置检查:检查是否启用启动上下文,以及是否应用到当前操作
  2. 参数解析:解析用户时区和启动上下文限制参数
  3. 日期窗口:生成需要加载的记忆日期范围,考虑本地时区和UTC的差异
  4. 文件扫描:扫描memory目录,按日期分组文件,包括主要文件和slugged文件
  5. 文件读取:读取每个文件的内容,应用单个文件大小限制
  6. 内容处理:修剪和格式化记忆内容,确保符合字符限制
  7. 上下文构建:构建启动上下文字符串,应用总字符数限制
  8. 结果返回:返回构建好的启动上下文,或null(如果没有加载到记忆)

3.3. 会话启动触发

  • 触发时机:新会话创建或会话重置时
  • 配置检查agents.defaults.startupContext.enabled 不为 false
  • 应用条件agents.defaults.startupContext.applyOn 包含当前操作类型("new" 或 "reset")

3.4. 会话启动阶段参数

typescript 复制代码
// src/auto-reply/reply/startup-context.ts
startupContext: {
  enabled: boolean;           // 是否启用启动上下文
  applyOn: string[];          // 应用到哪些操作("new", "reset")
  dailyMemoryDays: number;    // 加载最近几天的记忆,默认2天
  maxFileBytes: number;       // 单个文件最大字节数,默认16384
  maxFileChars: number;       // 单个文件最大字符数,默认1200
  maxTotalChars: number;      // 总字符数限制,默认2800
}
  • agents.defaults.startupContext.enabled - 是否启用启动上下文
  • agents.defaults.startupContext.applyOn - 应用场景("new"或"reset")
  • agents.defaults.startupContext.dailyMemoryDays - 加载最近几天的记忆(1-14天,默认2天)
  • agents.defaults.startupContext.maxFileBytes - 单个文件最大字节数(默认16384,最大64KB)
  • agents.defaults.startupContext.maxFileChars - 单个文件最大字符数(默认1200,最大10000)
  • agents.defaults.startupContext.maxTotalChars - 总字符数限制(默认2800,最大50000)
  • agents.defaults.userTimezone - 用户时区设置

3.5. 读取的信息

  • 每日记忆文件:memory/YYYY-MM-DD.md

  • 每日slugged文件:memory/YYYY-MM-DD-*.md(最多4个/天)

  • 注意:MEMORY.mdSOUL.mdUSER.md 由其他模块单独处理

  • 读取的数据库信息

    • 此阶段不直接读取SQLite数据库
    • 数据库读取在后续的记忆搜索和同步过程中进行

3.6. 输入/输出

  • 会话启动时的记忆上下文构建

    • src/auto-reply/reply/startup-context.ts#L309-L386 - buildSessionStartupContextPrelude
  • 会话启动输入

    • 工作区目录 workspaceDir
    • 配置对象 OpenClawConfig
    • 当前时间 nowMs(可选)
  • 会话启动输出

    • 启动上下文字符串 stringnull

3.7. 主要代码和函数

函数名 文件路径 作用
shouldApplyStartupContext src/auto-reply/reply/startup-context.ts#L17-L30 判断是否应用启动上下文
buildSessionStartupContextPrelude src/auto-reply/reply/startup-context.ts#L309-L386 构建会话启动上下文
resolveUserTimezone src/agents/date-time.js 解析用户时区
resolveStartupContextLimits src/auto-reply/reply/startup-context.ts#L32-L64 解析启动上下文限制
buildStartupMemoryDateStamps src/auto-reply/reply/startup-context.ts#L91-L111 构建记忆日期窗口
listStartupMemoryPathsByDate src/auto-reply/reply/startup-context.ts#L224-L307 列出按日期分组的记忆路径
readStartupMemoryFile src/auto-reply/reply/startup-context.ts#L202-L222 读取记忆文件内容
trimStartupMemoryContent src/auto-reply/reply/startup-context.ts#L113-L119 修剪记忆内容到字符限制
formatStartupMemoryBlock src/auto-reply/reply/startup-context.ts#L133-L142 格式化记忆块
fitStartupMemoryBlock src/auto-reply/reply/startup-context.ts#L144-L174 适配记忆块到字符限制

4. 读取记忆的限制条件

4.1. 文件数量限制

  • 时间范围 :最近 dailyMemoryDays 天(默认2天)
  • 文件数量:每天最多5个文件(1个主要文件 + 4个slugged文件)
  • 总量限制
    • 单个文件:最多64KB或10000字符
    • 总内容:最多50000字符

4.2. 文件大小限制

  • 单个文件最大字节数:maxFileBytes(默认16384,最大64KB)
  • 单个文件最大字符数:maxFileChars(默认1200,最大10000)
  • 总字符数限制:maxTotalChars(默认2800,最大50000)

4.3. 安全限制

  • 文件路径必须在工作区内(openBoundaryFile 检查)
  • 记忆内容标记为"不受信任",防止执行其中的指令

4.4. 重要的常量和默认值

常量 描述
STARTUP_MEMORY_FILE_MAX_BYTES 16384 单个文件最大字节数默认值
STARTUP_MEMORY_FILE_MAX_CHARS 1200 单个文件最大字符数默认值
STARTUP_MEMORY_TOTAL_MAX_CHARS 2800 总字符数限制默认值
STARTUP_MEMORY_DAILY_DAYS 2 加载最近几天的记忆默认值
STARTUP_MEMORY_FILE_MAX_BYTES_CAP 64*1024 单个文件最大字节数上限
STARTUP_MEMORY_FILE_MAX_CHARS_CAP 10000 单个文件最大字符数上限
STARTUP_MEMORY_TOTAL_MAX_CHARS_CAP 50000 总字符数限制上限
STARTUP_MEMORY_DAILY_DAYS_CAP 14 加载最近几天的记忆上限
STARTUP_MEMORY_MAX_SLUGGED_FILES_PER_DAY 4 每天最多加载的slugged文件数

5. 记忆内存存储格式

5.0.1. 中间存储格式

  • 数组形式:Array<{ relativePath: string; content: string }>
  • 每个元素包含文件路径和内容

5.0.2. 最终存储格式

  • 最终格式:格式化的文本区块,合并为单个字符串
  • 字符串形式,包含:
    • 头部说明(启动上下文信息)

    • 格式化的记忆区块(每个文件一个区块)

    • 每个区块格式:

      [Untrusted daily memory: {relativePath}]
      BEGIN_QUOTED_NOTES
      ```text
      {content}
      ```
      END_QUOTED_NOTES

6. 系统配置

6.1. 记忆搜索配置

typescript 复制代码
// src/agents/memory-search.ts
sync: {
  onSessionStart: boolean;  // 会话开始时是否同步
  onSearch: boolean;        // 搜索时是否同步
  watch: boolean;           // 是否监视文件变化
  watchDebounceMs: number;  // 监视防抖时间
  intervalMinutes: number;  // 同步间隔
  sessions: {
    deltaBytes: number;         // 会话增量字节数阈值
    deltaMessages: number;      // 会话增量消息数阈值
    postCompactionForce: boolean; // 压缩后是否强制同步
  };
}

7. 总结

记忆预热是 OpenClaw 记忆系统的重要组成部分,通过以下步骤确保系统启动和会话开始时记忆的有效加载:

  1. 系统启动:初始化 QMD 类型的记忆后端,确保记忆搜索管理器就绪
  2. 会话启动:根据配置加载最近几天的记忆文件,构建启动上下文
  3. 数量控制:通过多种配置参数控制读取的文件数量和大小
  4. 内存管理:优化内存使用,确保启动上下文在合理大小范围内

这种设计既保证了记忆的有效加载,又控制了系统资源的使用,为大模型提供了必要的上下文信息,同时避免了过度加载导致的性能问题。

相关推荐
葫芦和十三4 小时前
图解 MongoDB 21|选举与 failover:Primary 是怎么选出来的
后端·mongodb·agent
考虑考虑5 小时前
Mybatis实现批量插入
java·后端·mybatis
咖啡八杯6 小时前
GoF设计模式——中介者模式
java·后端·spring·设计模式
带刺的坐椅7 小时前
从 Claude Code 隐私争议,看 SolonCode 的设计选择
ai·llm·agent·claudecode·soloncode·codingplan
青石路10 小时前
记一次多JDK版本问题的排查,一坑套一坑,差点没爬上来
java
后端小肥肠11 小时前
小红书虚拟商品怎么做?我先用 Skill 跑通了壁纸品类
人工智能·aigc·agent
先吃饱再说11 小时前
判断回文字符串,从一行代码到双指针优化
算法
Java陈序员12 小时前
企业级!一个基于 Java 开发的开源 AI 应用开发平台!
spring boot·agent·mcp
Chen6667812 小时前
我让一个Agent Team长时间自治运行后,发现问题不在“怎么组队”
agent