OpenClaw Memory Architecture

MEMORY.md 太长怎么办?

OpenClaw 长期记忆文件的处理机制、截断策略、压缩与自动化维护全解析

🧠 问题是什么

MEMORY.md 的角色

MEMORY.md 是 OpenClaw Agent 的长期记忆文件,存储持久性事实、用户偏好、重要决策和教训。每次新会话(私聊)启动时,它会被自动加载注入到模型上下文中,让 Agent "记住" 之前的一切。

⚠️
核心矛盾:MEMORY.md 每次会话都要加载,太长 = 吃掉上下文窗口 = 可用对话空间变少 = 模型变笨。但记太少 = 重要信息丢失 = Agent 变傻。如何平衡?

两个关键限制

限制项默认值说明
bootstrapMaxChars20,000 字符单个文件注入上下文的最大字符数
bootstrapTotalMaxChars150,000 字符所有工作区文件注入的总字符上限

约 20,000 字符 ≈ 5,000 tokens,意味着 MEMORY.md 默认最多能注入约 5000 tokens 的内容。超过的部分会被截断(而非报错)。

💡
好消息:这两个限制是可配置的!你可以调大它们——但代价是占用更多上下文窗口,留给对话的空间更少。这是一场零和博弈。
✂️ 截断机制详解

截断时发生了什么?

💾 磁盘文件:完整保留,不会修改
🧩 上下文注入:超出部分被截断
🔔 系统信号:标记为需要优化

关键点:磁盘上的 MEMORY.md 不会被修改,只是在注入到模型上下文时,超出的部分会被静默截断。Agent 只能看到截断后的内容——后面的记忆对它来说「不存在」。

截断的视觉化示意

# MEMORY.md(磁盘上实际内容)
用户喜欢深色主题 ✅ Agent 能看到
偏好的编程语言:Python ✅ Agent 能看到
重要决策:部署必须确认后执行 ✅ Agent 能看到
...
旧的项目笔记(2025年3月) ✅ Agent 能看到
已过期的偏好设置 ✅ Agent 能看到
历史教训记录 ✅ Agent 能看到
更多详细记录 ✅ Agent 能看到
---
========== 截断线(bootstrapMaxChars = 20000)==========
以下内容被截断,Agent 看不到 ⛔
早期调研笔记...
过时的临时决策...
2年前的项目日志...
🚨
问题:截断是从文件末尾开始的。如果 MEMORY.md 头部是旧内容、尾部是新内容,那么最新写入的重要记忆可能恰好被截断掉!这就是为什么记忆的组织顺序很重要。
🎮 交互演示:拖动滑块体验截断
MEMORY.md 注入模拟器
MEMORY.md 实际大小 20,000 字符 (刚好满)
磁盘文件: 20,000 字符
注入上下文: 20,000 字符
截断: 0 字符
📄 MEMORY.md 正常

拖动滑块增大 MEMORY.md 大小,观察截断如何发生。红色区域 = Agent 看不到的内容。

🏗️ 三层记忆架构

OpenClaw 用三层架构来管理记忆,每一层有不同的生命周期、加载策略和管理方式。理解这个架构是解决 MEMORY.md 膨胀问题的基础。

第一层:上下文层 (Context)

📍 当前对话的实时上下文(模型的工作记忆)

📍 跟进承诺(Commitments)— 短期跟进事项

📍 模型未保存到磁盘的「隐藏状态」

⚡ 生命周期:当前会话。会话结束后,如果没有保存到文件,就永久丢失。

⬇️ 压缩 (Compaction) + 记忆刷新 (Memory Flush)
第二层:压缩层 (Compaction)

📍 对话过长时自动触发压缩,生成摘要

📍 压缩前自动运行静默轮次,提醒 Agent 保存重要信息到文件

📍 Memory Flush 默认启用,可用本地模型(如 ollama/qwen3:8b)

⚡ 生命周期:中间缓冲层,防止压缩导致上下文丢失的「安全网」。

⬇️ 提炼 (Distillation) + Dreaming 提升
第三层:记忆文件层 (Memory Files)

📄 MEMORY.md — 长期记忆,每次私聊会话启动时加载

📄 memory/YYYY-MM-DD.md — 每日笔记,自动加载今天 + 昨天

📄 DREAMS.md — 梦境摘要,供人工审阅(可选)

⚡ 生命周期:持久化存储。MEMORY.md 是核心,但也最容易膨胀。

设计哲学:不是所有信息都该进 MEMORY.md。每日笔记承载详细内容,MEMORY.md 只保留提炼后的精华。就像写书一样——草稿可以很长,但最终出版的是精炼的版本。
🌙 Dreaming:梦境系统

什么是 Dreaming?

Dreaming(梦境)是 OpenClaw 的可选后台整合流程,专门设计用来保持 MEMORY.md 的高信噪比。它从短期记忆中筛选出真正值得长期保留的内容,防止 MEMORY.md 被低价值信息填满。

默认:关闭(需手动启用)
启用后自动管理 cron 任务

梦境提升的三重门槛

候选记忆必须同时通过以下三个门槛才能被提升到 MEMORY.md:

门槛含义作用
分数门槛 (Score Threshold)记忆的质量评分必须达标过滤低质量噪音
召回频率 (Recall Frequency)被重复访问的次数足够多只保留真正有用的记忆
查询多样性 (Query Diversity)从不同角度/场景被检索过避免只对单一场景有用的记忆占位

梦境处理流水线

📋 每日笔记
memory/*.md
🔍 短期阶段
评分筛选
📊 暂存存储
.dreams/
🎯 深度阶段
三重门槛
📝 DREAMS.md
人工审阅
✅ MEMORY.md
最终提升
🔒
安全机制:MEMORY.md 只通过深度提升写入。即使回填产生的候选也不直接写入 MEMORY.md,而是暂存到短期存储中,必须经过完整的深度提升流程。这保证了 MEMORY.md 写入的严格管控。

两条审查通道

通道数据来源作用
实时梦境 (Live Dreaming)memory/.dreams/ 短期梦境存储常规深度阶段用它来决定哪些内容晋升
有依据回填 (Grounded Backfill)历史 memory/YYYY-MM-DD.md重播旧笔记,重新评估哪些值得持久化

回填 CLI:

openclaw memory rem-backfill --path ./memory --stage-short-term
openclaw memory rem-backfill --rollback    # 回滚(不影响常规日记)
💓 Heartbeat:心跳自动化

Heartbeat 做什么?

Heartbeat 是 OpenClaw 的定期自动化机制,让 Agent 可以定期主动执行任务——无需用户手动触发。在记忆管理场景中,Heartbeat 可以:

  • 定期从近 N 天的每日笔记中提炼重要信息 → 写入 MEMORY.md
  • 定期清理 MEMORY.md 中过时的决策和偏好
  • 定期检查并汇报记忆文件的健康状态

配置示例

{
  "cron": {
    "jobs": [
      {
        "name": "记忆整理心跳",
        "schedule": { "kind": "every", "everyMs": 1800000 },
        "payload": {
          "kind": "systemEvent",
          "text": "Read HEARTBEAT.md. Follow it. If nothing needs attention, reply HEARTBEAT_OK."
        },
        "sessionTarget": "main"
      }
    ]
  }
}

HEARTBEAT.md 中定义具体任务清单,Agent 每次心跳读取并执行。无任务时返回 HEARTBEAT_OK,不打扰用户。

1️⃣ Heartbeat 触发

cron 定时器到期,向 Agent 发送系统事件

⬇️

2️⃣ Agent 读取 HEARTBEAT.md

检查任务清单,判断是否有需要处理的事项

⬇️

3️⃣ 执行记忆整理

从近期日志提炼 → 更新 MEMORY.md → 清理过时条目 → 检查文件大小

⬇️

4️⃣ 返回结果或 HEARTBEAT_OK

有任务则汇报执行结果,无任务则静默返回

🔍 检索机制与时间衰减

Vector + BM25 混合检索

OpenClaw 使用混合检索来从记忆文件中召回相关内容:

Vector 70%:语义匹配,理解含义
BM25 30%:关键词匹配,精准命中

为什么需要混合?纯向量检索擅长「Mac主机」匹配「运行gateway的机器」,但不擅长匹配 commit hash 或配置项名。纯 BM25 精准但语义理解差。两者互补。

{
  "memorySearch": {
    "query": {
      "hybrid": {
        "enabled": true,
        "vectorWeight": 0.7,
        "textWeight": 0.3,
        "candidateMultiplier": 4,
        "mmr": { "enabled": true, "lambda": 0.7 }
      }
    }
  }
}

MMR(Maximal Marginal Relevance)开启去重,避免返回多条高度相似的记忆。

时间衰减机制(Temporal Decay)

让近期记忆权重更高,旧记忆自动淡化。但 MEMORY.md 是永久文件,不受时间衰减影响——这是它的特权。

"temporalDecay": {
  "enabled": true,
  "halfLifeDays": 30   // 半衰期 30 天
}

衰减公式:decayedScore = score × e^(-λ × ageInDays),其中 λ = ln(2) / halfLifeDays

时间衰减效果可视化(半衰期 30 天)

📌 注意:MEMORY.md 和非日期格式文件(如 memory/projects.md)为永久文件,不受时间衰减影响,得分始终为 100%

衰减数据表

记忆年龄得分保留比例说明
当天100%最新记忆,权重最高
7 天前~84%上周的记忆,影响轻微
30 天前50%恰好到半衰期
90 天前12.5%3个月前的记忆大幅衰减
180 天前~1.6%半年前的记忆几乎不可见
📝 最佳实践

MEMORY.md 应该写什么、不写什么

  • 用户偏好:语言习惯、工作方式、沟通风格
  • 策略性决策:「部署前必须确认」「所有分支从 main 创建」
  • 历史教训:「2026-02-13 未确认导致配置错误上线」
  • 长期项目状态:核心项目的关键进展和待办
  • 持久性偏好:编辑器设置、框架偏好、部署方式
  • 敏感凭据 → 存到 ~/.openclaw/credentials/
  • 大段原始日志 → 只写总结
  • 临时计算结果 → 写入当日笔记即可
  • 超过2个月无参考价值 → 归档或删除
  • 可以语义检索到的内容 → 写入日志文件,通过 memory_search 访问

MEMORY.md 太长的应对策略(优先级排序)

🔴 策略1:压缩内容(最优先)

将详细材料移回 memory/*.md,只在 MEMORY.md 保留精炼摘要。比如「2025年Q1服务器迁移记录(3000字)」→「2025年Q1完成服务器迁移至AWS,注意:需先备份数据库」

⬇️

🟡 策略2:拆分主题文件

将不同主题拆到独立文件(如 memory/projects.md、memory/deploy-rules.md),避免单文件超限。这些文件通过 memory_search 语义检索访问。

⬇️

🔵 策略3:启用 Dreaming

开启梦境系统,让 AI 自动评分、筛选值得保留的记忆,自动清理低价值内容。

⬇️

🟢 策略4:配置 Heartbeat 定期维护

设置周期性心跳任务,自动从日志提炼精华到 MEMORY.md、清理过时条目。

⬇️

⚪ 策略5:调大 bootstrapMaxChars(最后手段)

如果确实需要更多上下文,可以调大限制。但代价是占用更多对话空间。配置:agents.defaults.bootstrapMaxChars

🩺 诊断与监控命令

常用诊断命令

命令作用关注点
/context list查看所有注入文件的大小和状态看是否有 TRUNCATED 标记
/context detail详细查看 skills、tools、文件的 token 开销找出吃 token 最多的文件
/status当前会话 token 使用情况是否接近上下文上限
openclaw doctor整体健康检查文件大小与注入大小对比
memory_search("关键词")测试检索效果验证记忆是否被正确索引

截断输出示例

TOOLS.md: TRUNCATED | raw 54,210 chars (~13,553 tok) | injected 20,962 chars (~5,241 tok)
MEMORY.md: OK         | raw 18,400 chars (~4,600 tok)  | injected 18,400 chars (~4,600 tok)
SOUL.md:    OK         | raw   1,200 chars (~300 tok)  | injected   1,200 chars (~300 tok)

看到 TRUNCATED 就说明该文件超限了,需要优化。

🎯 一句话总结

MEMORY.md 太长 → 超出 bootstrapMaxChars → 注入时被截断 → Agent 看不到后面的内容。 解决方案:压缩内容 → 拆分主题文件 → 启用 Dreaming 自动筛选 → 配置 Heartbeat 定期维护 → 最后才考虑调大限制。 核心理念:MEMORY.md 是精炼的「知识库」,不是大杂烩的「日记本」。