Dream 记忆巩固

Dream 是记忆的垃圾回收 + 归档:把近似重复的记忆按向量聚类合并(相似度 ≥ 阈值),把长期没被用到的记忆降权,把既旧又没用的记忆忘掉。它是唯一会删除记忆的自动化流程,所以参数默认值都偏保守。

触发 手动 / 每 30 分钟检查 贪心聚类 按向量相似度 ≥ 0.85 选代表(keeper) 重要度 → 更公共 → 更早 合并 重要度 +0.05 · 访问数累加 · 时间取最新 衰减 / 遗忘 超 30 天未用 → ×0.8;超 180 天且低于 0.15 → 遗忘 写回 LastRunAt 与统计:Merged / Decayed / Forgotten / Remaining / 耗时
顺序固定:先聚类合并、再衰减、最后遗忘;每一步都写回统计,便于判断「这次动了什么」。

触发方式

方式行为
手动POST /api/memories/dream,立即执行并返回统计
后台DreamMemoryService 作为常驻后台服务:启动即检查一次,之后每 30 分钟轮询一次
执行条件Enabled = true 且距上次运行已超过 IntervalHours(默认 24 小时)

配置与默认值

配置项默认约束
Enabledtrue关闭后后台不再执行,手动仍可用
IntervalHours241–720
MergeThreshold0.850.5–0.99
DecayDays301–3650
ForgetDays180必须 ≥ DecayDays
ForgetBelowImportance0.150.01–1
LastRunAt—由执行流程写回;保存配置不会覆盖它(否则每次改配置都会重置周期)

配置键是 DreamConfig。

聚类与合并

  1. 取出全部未删除记忆,按 embedding 相似度做贪心聚类,阈值即 MergeThreshold。
  2. 每个簇选一个代表(keeper),选择顺序:Importance 更高 → 作用域更公共(Global < Project < Session)→ CreatedAt 更早。
  3. 保留代表并更新:Importance += 0.05(上限 1)、AccessCount 累加被吸收记忆的次数、LastAccessedAt 取簇内最新。
  4. 被吸收的记忆被移除(含向量行)。
合并偏好「更公共、更早」的那条:项目级或会话级的重复表述会被吸进全局记忆,这也是为什么合并后要检查一下原文表述是否还准确。

衰减与遗忘

阶段条件动作
衰减距上次访问 > DecayDays 且 Importance > 0.05Importance ×= 0.8,下限 0.05
遗忘距上次访问 > ForgetDays 且 Importance < ForgetBelowImportance软删并移除 embedding

结果与观测

  • 返回统计 DreamResultDto:Merged / Decayed / Forgotten / Remaining / DurationMs / RanAt。
  • 日志:启动 记忆 Dream 巩固服务已启动;自动执行 [Dream] 自动巩固完成:…;手动完成 [Dream] 记忆巩固完成:…;失败 Dream 自动巩固失败 / Dream 记忆巩固失败。
  • 失败不会拖死后台服务:异常在服务层被捕获并记录,仅本次不生效。

实作要点

  • Dream 是不可逆的:没有记忆版本历史,合并与遗忘都直接落库。调低阈值前先确认能接受合并后果。
  • 「记忆莫名变少」通常不是 bug:查 ForgetDays 与 ForgetBelowImportance,以及这些记忆的 LastAccessedAt(长期不召回就会被衰减到阈值以下)。
  • 想保留某条记忆,把 Importance 提到 0.2 以上并偶尔让它被召回,两个信号都能挡住遗忘。
  • 换 embedding 模型后聚类阈值语义会变,建议先手动跑一次看 Merged 数量再让后台自动执行。