OpenClaw Dreaming 深度解析:light / REM / deep 三睡眠阶段的后台记忆固化机制
【免费下载链接】openclawThe AI that really does things. Any OS. Any Platform. The lobster way. 🦞项目地址: https://gitcode.com/GitHub_Trending/cl/openclaw
Dreaming 是 OpenClaw 内置于memory-core插件的后台记忆固化(memory consolidation)系统:它按 light → REM → deep 三个阶段周期性地把短期记忆中“信号足够强”的片段评分、排序,最终只把真正值得保留的内容写入长期记忆MEMORY.md,同时用一份人类可读的 Dream Diary(DREAMS.md)让整个过程可解释、可审查。读完本文,你将理解 Dreaming 的写入边界与阶段职责、deep 阶段的加权评分模型与阈值门、整合改写(consolidation)的安全约束、Dream Diary 的生成与回退语义,以及如何通过配置、斜杠命令和 CLI 调度并干预整个流程——包括历史会话的 grounded backfill 与可回滚的 staging。
Dreaming 是什么,以及它写什么
Dreaming 的官方定义(见 docs/concepts/dreaming.md):在后台把强短期信号移入持久记忆,同时保持过程可解释、可审查。它默认开启;如需关闭,设置:
{ "plugins": { "entries": { "memory-core": { "config": { "dreaming": { "enabled": false } } } } } }一次 dreaming sweep 会产生三类产物,写入边界非常明确:
- 机器状态:存放在 SQLite 支撑的插件状态中(recall store、phase signals、ingestion checkpoints、locks)。配置参考文档 docs/reference/memory-config.md 进一步指出,Dreaming 的机器状态写入
memory/.dreams/目录。 - 改写前镜像(rewrite preimages):在每一次被接受的
MEMORY.md改写之前,先存入 SQLite 插件状态,保证可审查、可追溯。 - 人类可读输出:
DREAMS.md(或已存在的dreams.md)中的叙事性 Diary 条目,以及可选的阶段报告文件memory/dreaming/<phase>/YYYY-MM-DD.md。
几条关键不变量值得注意:
- 长期提升(promotion)只写
MEMORY.md,其他文件不参与持久记忆的变更; - Deep 报告只按“拒绝类别”计数来解释为何某些候选未被提升,不复制被拒绝的片段或来源标识,且这些计数只覆盖到达 promotion 的候选,不描述在排序阶段被排除的条目;
- 如果一个候选在最终 apply 检查时发生变化,报告中保留的是“通用变更原因”,而不是推测的因果;
- 一次“空扫”(empty sweep)只在插件状态中记录完成,不创建任何 memory/dreaming 文件,因此不会替全新工作区完成首次运行设置;已存在的每日笔记仍可能收到受管的 phase-block 更新;
- 每个新提升的条目都携带从候选派生的行尾召回元数据:最多三个概念标签(形如
<!-- trigger: phrase one, phrase two -->)和一个 1 到 10 的有界<!-- importance: N -->值;整合(consolidation)会逐字节保留已有注释条目,除非显式合并或替代(supersede)它们。
阶段模型:light → REM → deep
每次 sweep 依次运行三个协作阶段。它们是内部实现阶段,不是用户可单独配置的模式:
| 阶段 | 目的 | 持久化写入 |
|---|---|---|
| Light | 对近期短期素材去重、排序并暂存(stage)候选行 | 否 |
| REM | 基于近期短期痕迹生成主题与反思摘要 | 否 |
| Deep | 评分并提升(promote)持久候选 | 是(MEMORY.md) |
各阶段的具体行为:
- Light 阶段:读取近期短期召回状态、每日 memory 文件,以及可用的、已脱敏(redacted)的会话转录;对信号去重并 stage 候选行;当存储配置包含 inline 输出时写入受管的
## Light Sleep块;为后续 deep 排序记录强化(reinforcement)信号;从不写MEMORY.md。 - REM 阶段:从近期短期痕迹构建主题与反思摘要;在启用 inline 输出时写入受管的
## REM Sleep块;记录 deep 排序会使用的 REM 强化信号;从不写MEMORY.md。 - Deep 阶段:
- 用加权评分加阈值门排序候选(
minScore、minRecallCount、minUniqueQueries必须全部通过); - 写入前从实时每日文件重新水化(rehydrate)片段,过时/已删除的片段会被跳过;
- 通过门槛的 owner 候选和 agent 派生候选会交给一次无工具(tool-free)补全,由模型对照当前
MEMORY.md决定追加、合并与替代; - 用经过验证的来源证据组合出新的
MEMORY.md,保留无关条目,且候选来源引用需满足既有条目的丢失上限与 bootstrap 预算; - 当模型不可用或改写未通过校验时,回退到先前的 append-only promotion 路径;
- 把
## Deep Sleep摘要写入DREAMS.md,可选写入memory/dreaming/deep/YYYY-MM-DD.md。
- 用加权评分加阈值门排序候选(
源码视角:一次 sweep 的真实执行链
extensions/memory-core/src/dreaming.ts 中的runShortTermDreamingPromotionIfTriggered展示了完整调用链:对每个解析出的工作区,依次执行(1)runDreamingSweepPhases跑三个阶段;(2)repairShortTermPromotionArtifacts先修复召回工件(重写 recall store、清理无效/悬空/溢出条目、移除陈旧 promotion 锁);(3)rankShortTermPromotionCandidates用limit、minScore、minRecallCount、minUniqueQueries、recencyHalfLifeDays、maxAgeDays等参数排序候选;(4)applyShortTermPromotions应用提升,携带maxPromotedSnippetTokens与maxPriorEntryLossFraction两个安全参数;(5)writeDeepDreamingReport写 deep 报告;(6)当有候选或有应用时触发runDreamNarrative生成 Diary 叙事,若 subagent 运行时不可用则appendFallbackNarrativeEntry写入本地回退条目。
被拒绝的候选按类别聚合计数后写入报告行(如- Not promoted: N candidate(s) (category: n, ...)),与文档所述“deep 报告只输出拒绝类别计数”一致。最后的汇总日志会把workspaces / candidates / applied / failed / degraded / narrativesPending一并打出;当所有工作区都失败或出现降级叙事时,日志级别升级为 warn——源码注释直言这是为了防止“坏掉的流水线看起来和正常时一模一样”。
调度与 Cron 对账
Dreaming 的调度完全由插件自管理:memory-core自动维护一个完整 sweep 的 cron 任务,并在主运行时工作区与已配置的 agent 工作区之间去重,避免 subagent 工作区扇出把主 agent 的DREAMS.md和记忆状态排除在外。
从 dreaming.ts 的buildManagedDreamingCronJob可以确认任务形态:sessionTarget: "isolated"(隔离会话中执行)、wakeMode: "now"、payload 为携带 dreaming 系统事件文本的agentTurn(带lightContext),并且delivery.mode: "none"——源码注释说明“Dreaming 是一次维护性扫描,不是面向用户的通告任务”。任务以声明键memory-core:memory-dreaming-promotion登记,描述中直接内嵌当前阈值(limit、minScore、minRecallCount、minUniqueQueries、recencyHalfLifeDays、maxAgeDays),便于排查。
对账逻辑(reconcileShortTermDreamingCronJob,dreaming.ts)做了几件工程上很有价值的事:
- 禁用时清理:
enabled: false会删除所有受管 dreaming cron 任务,并迁移掉旧版按 phase 拆分的 legacy cron 任务(legacy light/REM 任务),同时通过removeStaleJobFamily清除声明键之前的陈旧行——源码注释解释:留一个旧副本会导致新旧两个 sweep 重复运行; - 重复修剪:按创建时间排序后,删除声明键任务之外的重复受管任务;
- 漂移修补:对名称、描述、启用状态、cron 表达式/时区、sessionTarget、payload、delivery 逐项对比并打最小 patch,无漂移则 noop;
- 运行时持续对账:服务启动时执行一次 startup 对账,之后每 60 秒(
RUNTIME_CRON_RECONCILE_INTERVAL_MS)运行期对账一次,以跟随配置热变更。
触发侧,before_agent_reply钩子(dreaming.ts,eligibleTriggers: ["heartbeat", "cron"])只在heartbeat或cron触发且消息包含 dreaming 系统事件令牌时接管本轮,随后runShortTermDreamingPromotionIfTriggered通过resolveMemoryDreamingWorkspaces解析出全部待扫工作区并逐区执行。若配置了limit: 0则整体跳过。
此外,Dreaming 补全与其他插件补全共享后台工作预算(background work budget,见 docs/concepts/queue.md):总量最多三次运行,其中最多三次可供memory-core使用;sweep 协调器在等待阶段工作时不占用补全槽位;系统繁忙度把这些运行合并显示在background行。
多 agent 舰队需要一个 ambient system owner 来拥有该 cron 任务。若日志报Agent-less cron job has no resolvable owner,为某个已有 agent 指定所有权即可,例如该 agent 叫ops时:
openclaw config set agents.defaults.systemAgent.agentId ops这只选定执行所有者,不会改变任何 agent 的工作区,也不会把 sweep 限制到该 agent 的记忆里。单 agent 安装会自动解析出所有者。
默认值:
| 设置 | 默认 |
|---|---|
dreaming.frequency | 0 3 * * * |
dreaming.model | 默认模型 |
会话转录摄取与两个运营控制开关
Dreaming 可以把已脱敏的会话转录摄取进 dreaming 语料,但只有交互式会话有资格;cron、heartbeat、subagent 与未知来源的会话被排除在持久候选摄取之外。个人与敏感内容在摄取前脱敏,且运行时标记的“已召回上下文”会被移除——这样召回过的片段不会作为新记忆被再次学习。
两个运营控制可以把会话排除在自动摄取之外,且各自记录原因(详见 docs/concepts/memory-provenance.md 与 docs/cli/memory.md):
- memory admission policy:按保留的 hook-source、channel 或 chat-type 元数据做匹配;
openclaw memory forget:把选定的会话 ID 记为forgotten,影响后续扫描。
注意:策略变更不会删除已有候选,也不能阻止直接文件写入。手动会话回填(session backfill)在 preview、REM 和 apply 三种模式下都同时应用这两道控制,并在 stage 候选时保留源会话出处。
Deep 排序信号
Deep 排序使用六个加权基础信号外加阶段强化。权重常量直接定义在 extensions/memory-core/src/short-term-promotion-utils.ts 的DEFAULT_PROMOTION_WEIGHTS中,与文档完全一致:
| 信号 | 权重 | 说明 |
|---|---|---|
| Relevance(相关性) | 0.30 | 该条目的平均检索质量 |
| Frequency(频率) | 0.24 | 该条目累积的短期信号数量 |
| Query diversity(查询多样性) | 0.15 | 使该条目浮现的不同交互式召回查询数 |
| Recency(新近度) | 0.15 | 时间衰减的新鲜度得分 |
| Consolidation(整合度) | 0.10 | 跨多天重复出现的强度 |
| Conceptual richness(概念丰富度) | 0.06 | 来自片段/路径的概念标签密度 |
light 与 REM 阶段记录在 SQLite 插件状态中的命中,会为候选追加一个小幅的、带新近度衰减的 boost。候选最终能否进入 deep 应用,仍由确定性门槛决定:minScore、minRecallCount、minUniqueQueries三者必须全部通过(managed cron 任务的描述字符串里就内嵌着这些当前生效值,见 dreaming.ts)。
整合(Consolidation)安全
确定性评分、召回次数与查询多样性阈值是候选门槛,consolidation 只在这些门槛通过之后运行。其安全设计层层设防:
- 结构性污点门:在构建 consolidation 提示词之前,
memory-core会直接移除索引溯源为untrusted或system的候选——这是结构性剔除,不是分数惩罚。合格候选会携带其来源、会话类型、观测时间、可选的替代键(supersession key)以及每日笔记来源引用。 - 模型只出决策,不出文本:模型返回操作决策(add / merge / supersede),而不是整段替换记忆文本;memory writer 用每个候选有界且有据的条目把决策应用到现有文件上。
- 被接受的改写必须满足:
- 保留既有条目的比例不低于
phases.deep.maxPriorEntryLossFraction(默认 0.25,超过则拒绝该改写); - 包含每个被提升候选的
Source: path#Lx-Ly引用; - 满足
MEMORY.md的 bootstrap 安全文件预算; - 解析为预期的结构化响应。
- 保留既有条目的比例不低于
- 可审查性:文件变更之前,旧版
MEMORY.md存入 SQLite 插件状态;DREAMS.md记录 added / merged / superseded 计数与简短的 diff 风格亮点——这让每次改写都可审查,同时不会把 Dream Diary 变成 promotion 的来源。
文档同时说明其研究背景:后台整合借鉴了 sleep-time compute 的思路(arXiv:2504.13171),溯源与反思边界沿用了 Generative Agents 研究中关于持久记忆的框架。对应的测试覆盖在 extensions/memory-core/src/dreaming-consolidation.test.ts 等用例中。
Dream Diary 与 grounded backfill
Dreaming 在DREAMS.md中维护一份叙事性Dream Diary:每个阶段积累到足够素材后,memory-core运行一次无工具后台补全并追加简短的 Diary 条目,使用工作区 agent 的默认模型,除非配置了dreaming.model。若配置的模型不可用,Diary 运行会用该 agent 的默认模型重试一次;信任(trust)或白名单失败不重试。Diary 与 consolidation 补全都使用全新上下文,不保留会话、不投递聊天回复;生成失败或为空时写入本地回退条目并报告降级结果,保证模型输出缺失时留下可见痕迹。
Diary 供人类在 Dreams UI 中阅读,不是promotion 来源。Diary/报告产物被排除在短期提升之外,只有有据(grounded)的记忆片段才有资格进入
MEMORY.md。
此外还有一条 grounded 历史回填通道,用于审查与恢复工作:
| 命令 | 作用 |
|---|---|
openclaw memory rem-harness --path <path> --grounded | 预览基于历史YYYY-MM-DD.md笔记的 grounded Diary 输出 |
openclaw memory rem-backfill --path <path> | 向DREAMS.md写入可逆的 grounded Diary 条目 |
openclaw memory rem-backfill --path <path> --stage-short-term | 把 grounded 持久候选 stage 进 deep 阶段使用的同一短期证据库 |
openclaw memory rem-backfill --rollback/--rollback-short-term | 移除上述 backfill 工件,不触碰普通 Diary 条目与实时短期召回 |
openclaw memory session-backfill --agent <id> | 预览该 agent 保留会话历史中的可信候选,从最旧未处理的一天开始 |
openclaw memory session-backfill --agent <id> --apply | 经正常短期库 stage 候选并写入可逆 Diary 块,不改MEMORY.md或USER.md |
openclaw memory session-backfill --agent <id> --rem | 按天写确定性 grounded 预览进DREAMS.md,不 stage 候选、不调用模型 |
openclaw memory session-backfill --agent <id> --rollback | 清除共享的 grounded backfill 候选与 Diary 块(含rem-backfill产生的工件) |
实现层面的边界(源自文档并可在cli-rem.runtime.ts、rem-harness.ts等源文件中查证):
- session backfill 使用规范的保留转录身份(包括跨轮转保留的会话),消息按配置的 dreaming 时区分桶,并与实时摄取共享消息哈希追踪与信号上限;
--apply会在一条命令内把有界批次抽干到完成;--rollback会移除生成工件以及这些批次拥有的哈希与游标进度,从而允许同一批候选再次被 stage;- 通过
--archive-files提供的外部文件被保守处理:其内嵌的所有权字段由调用方控制,因此保持 untrusted;没有经过认证的溯源契约,它们无法进入短期 staging; - 工具输出、web 内容与非 owner 的发言同样被排除在规范会话路径之外。
Control UI 在 agent 的 Memory 页签(Agents 页面)暴露同样的 Diary backfill/reset 流程,让你可以在 dream scene 中检查结果、再决定 grounded 候选是否值得提升;一条独立的 grounded Scene 通道会标明哪些 stage 的短期条目来自历史回放、哪些已提升条目由 grounded 主导,并允许只清除 grounded-only 的 stage 条目而不触碰实时短期状态。
配置参考与默认值
所有设置位于plugins.entries.memory-core.config.dreaming下(不是memory.search下)。用户可调项(见 docs/reference/memory-config.md):
| 键 | 类型 | 默认 | 说明 |
|---|---|---|---|
enabled | boolean | true | 启用/禁用整个 dreaming sweep |
frequency | string | 0 3 * * * | 完整 dreaming sweep 的 cron 节奏 |
timezone | string | 系统时区 | sweep 与消息分桶使用的时区 |
model | string | 默认模型 | Dream Diary 补全的模型覆盖;若同时设置 subagentallowedModels白名单,请写规范provider/model值 |
phases.deep.maxPromotedSnippetTokens | number | 160 | 每个被提升进MEMORY.md的短期召回片段保留的估算 token 上限;排序溯源仍然可见 |
phases.deep.maxPriorEntryLossFraction | number | 0.25 | 若一次整合改写删除了超过该比例的既有条目,则拒绝 |
自定义 sweep 节奏的完整示例:
{ "plugins": { "entries": { "memory-core": { "config": { "dreaming": { "enabled": true, "timezone": "America/Los_Angeles", "frequency": "0 */6 * * *" } } } } } }警告:
dreaming.model要求先设置plugins.entries.memory-core.subagent.allowModelOverride: true;若要限制可选模型,再配合plugins.entries.memory-core.subagent.allowedModels。自动重试只覆盖“模型不可用”类错误;信任或白名单失败会产出回退 Diary 痕迹与降级结果,而不会静默换模型。配置参考中的完整示例:{ plugins: { entries: { "memory-core": { subagent: { allowModelOverride: true, allowedModels: ["anthropic/claude-sonnet-4-6"], }, config: { dreaming: { enabled: true, frequency: "0 3 * * *", model: "anthropic/claude-sonnet-4-6", }, }, }, }, }, }
需要强调的是:大多数 phase 策略、阈值与存储行为属于内部实现细节,并非用户配置面;完整的键列表见 docs/reference/memory-config.md。
斜杠命令与 CLI 工作流
聊天渠道内的斜杠命令:
/dreaming status /dreaming on /dreaming off /dreaming help权限语义:/dreaming on与/dreaming off要求渠道调用者具备 owner 身份,或 Gateway 客户端具备operator.admin;/dreaming status与/dreaming help为只读。
CLI 侧(命令归属与更多参数见 docs/cli/memory.md):
提升预览 / 应用
openclaw memory promote openclaw memory promote --apply openclaw memory promote --limit 5 openclaw memory status --deep手动memory promote默认使用 deep 阶段阈值,除非用 CLI 标志覆盖。
解释某个候选为何提升/不提升
openclaw memory promote-explain "router vlan" openclaw memory promote-explain "router vlan" --jsonREM harness 预览(不写任何内容地预览 REM 反思、候选事实与 deep 提升输出)
openclaw memory rem-harness openclaw memory rem-harness --jsonDreams UI
启用后,Gateway 的Dreams页签展示:
- 当前 dreaming 启用状态;
- 阶段级状态与受管 sweep 的存在性;
- short-term、grounded、signal 与“今日已提升”计数;
- 下一次计划运行时间;
- 一条独立的 grounded Scene 通道,展示 stage 中的历史回放条目;
- 一个可展开的 Dream Diary 阅读器,背后是
doctor.memory.dreamDiary。
当捆绑的 memory-wiki 插件启用时,Diary 视图旁还会多出两个子页签:
- Imported Insights:外部历史导入(例如
openclaw wiki chatgpt import)浮现的聚类洞见,供其在“毕业”进持久记忆之前审查; - Memory Wiki:记忆系统可检索与推理的编译后 wiki——综合页、实体页、概念页(以及携带主张、未决问题或矛盾的来源页与报告页),附逐页计数、全库分布与内联页面预览。
memory-wiki关闭时,这两个子页签只显示启用提示。
小结与延伸阅读
Dreaming 的设计可以浓缩为三句话:写入边界最小化(机器状态进 SQLite、叙事进DREAMS.md、只有 deep 阶段能碰MEMORY.md)、提升全程有门(确定性阈值门 → 结构性污点门 → 模型只出决策 → 改写四重校验 + 前镜像存档)、产物永远可审查且可回滚(Diary 计数与 diff 亮点、backfill 工件全部支持 rollback)。实现集中在 extensions/memory-core,核心源码文件包括 dreaming.ts(调度与 sweep 主流程)、short-term-promotion-utils.ts(评分权重与工具函数)、dreaming-phases.ts、dreaming-consolidation.ts 与 dreaming-narrative.ts,并有 dreaming.test.ts、dreaming-phases.test.ts 等成体系的测试覆盖。
延伸阅读(均为本仓库文档):
- Memory 概念
- Memory 架构
- Memory CLI
- Memory 配置参考
- Memory 搜索
- 队列与后台工作预算
- memory-wiki 插件
【免费下载链接】openclawThe AI that really does things. Any OS. Any Platform. The lobster way. 🦞项目地址: https://gitcode.com/GitHub_Trending/cl/openclaw
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考