mem0 dream 技能全解:AI 编码代理记忆库的重复合并、矛盾裁决与过期清理机制
本文围绕 mem0 插件中的 dream 技能展开,完整讲解这条“记忆整理流水线”的六个串行步骤、自动模式(--auto)的并发保护与提醒回写机制,并结合仓库中的配置解析脚本与周边技能源码,说明每一项合并、冲突与清理规则背后的实现依据。读完本文,你将掌握如何针对 AI 编码代理(Claude Code / Codex / Cursor 等)的持久记忆执行去重、矛盾仲裁与按保留策略淘汰,以及如何以交互式与非交互式两种方式落地这套整理流程。
概述:dream 是什么,为什么需要它
mem0 插件为 AI 编码代理提供跨会话的语义记忆:代理在会话中沉淀架构决策、工具配置、bug 修复经验等条目,后续会话通过搜索召回。但记忆只增不减会带来三个典型问题:近重复条目(同一事实换了种说法存了两遍)、矛盾条目(同一主题上断言相反的事实)、过期条目(早已失效的会话状态与压缩摘要)。
dream 技能就是针对这三个问题的记忆整理(consolidation)通道。根据 dream 技能定义,它的行为边界非常明确:
- 拉取当前项目的全部记忆;
- 识别近重复对、标记矛盾、按保留策略(retention policy)挑出过期条目;
- 所有变更先以 diff 形式展示,经用户确认后才实际修改;
- 支持
--auto非交互模式,可挂到周期性任务中。
一个硬性约束值得注意:技能文档开头特别强调六个步骤必须严格按 1 → 2 → 3 → 4 → 5 → 6 顺序串行执行,不允许并行或跳步,因为每一步都依赖上一步的结果(例如保留策略在步骤 1 解析、步骤 3 才使用)。
步骤 1:加载保留策略
整理规则的第一步是确定“哪些类型的记忆可以按年龄淘汰”。技能要求运行插件自带的解析脚本:
python3 "<PLUGIN_ROOT>/scripts/parse_mem0_config.py" "<cwd>"
其中 PLUGIN_ROOT 取当前平台对应的变量(${CLAUDE_PLUGIN_ROOT}、${CODEX_PLUGIN_ROOT} 或 ${CURSOR_PLUGIN_ROOT})。脚本输出一个 JSON 字典,形如 category → days | null。
该行为的实现证据在 配置解析脚本 中。脚本从项目根目录读取可选的 mem0.md 配置文件,定位其中的 ## Retention 小节(正则 ^##\s+Retention[^\n]*\n(.*?)(?=^##\s|\Z),大小写不敏感),逐行解析:
<category>: <N>d(如session_state: 90d)→ 保留 N 天,解析为整数天数;<category>: forever→ 永不修剪,解析为null;- 以
#开头的行视为注释跳过,格式错误的行被静默跳过; - 若
mem0.md不存在或没有## Retention小节,load_retention_policies()直接返回空字典。
因此当脚本失败或返回 {} 时,dream 技能回退到以下内置默认值:
metadata.type |
默认保留期 |
|---|---|
session_state |
90 天 |
compact_summary |
90 天 |
| 其他所有类型 | 不修剪 |
解析出的策略会在步骤 3 的清理(prune)判定中使用。值得注意的是,mem0.md 是纳入版本控制、团队共享的配置文件——同目录下的 policy 技能 负责读写其中的 ## Instructions(提取策略)等小节,而 dream 只消费其中的 ## Retention 部分,职责分离清晰。
步骤 2:拉取项目的全部记忆
进入分析前,必须先拿到当前用户、当前项目的完整记忆集合,调用 MCP 工具 get_memories:
get_memories(
filters={"AND": [{"user_id": "<active_user_id>"}, {"app_id": "<active_project_id>"}]},
page_size=200,
)
要点:
- 过滤条件用
AND组合user_id与app_id,app_id即当前项目 ID(顶层字段,不是 metadata 内的); page_size=200分批拉取,若响应提示还有更多页,必须翻页直到取完,在收集齐完整列表之前不得进入下一步——否则会漏掉后面的重复对与过期条目;- 若查询结果为 0 条,打印固定文案并直接终止:
No memories found for project <project_id>. Nothing to consolidate.
这里体现了一个防御性设计:整理流程的第一步就是“空集短路”,避免对空库执行无意义的分析与确认交互。
步骤 3:内存中分析,找出三类问题
这一步的关键纪律是 work entirely in-memory; do not modify anything yet——只分析、只分组、只记录候选,任何写入动作都推迟到步骤 5。所有记忆先按 metadata.type 分组(字段缺失时归入 "unknown" 组),随后在每组内做三项识别:
3a 近重复对(合并候选)
两条记忆构成近重复,当且仅当同时满足以下三条启发式规则:
- 相似度:估计的余弦相似度 > 0.9。由于 agent 侧拿不到真实向量,技能给出了可操作的代理指标——显著名词/关键词重叠度 > 60% 即视为相似度 > 0.9;
- 类型一致:两条记忆的
metadata.type相同; - 均未固定:两条记忆的
metadata.pinned都不为true(被 pin 的记忆是用户显式保留的,不参与自动合并)。
典型例子是 “Use PostgreSQL for auth” 与 “Auth DB is PostgreSQL”——同一事实、不同措辞。对每一对符合条件的记忆,需要先起草一个合并版本,要求比任一原始版本更完整、更具体,而不是简单拼接。
这条 60% 名词重叠的阈值并非孤例:health 技能的深度模式(/mem0:health --deep)在只读质量扫描中识别潜在重复时,使用了完全相同的判据(同一 metadata.type 组内共享名词/关键词 > 60%)。可以推断,整个插件有意把“重复”的代理指标统一成这一个阈值,让 health --deep 的扫描结果与 dream 的合并决策保持一致——前者负责“只报告”,后者负责“动手修”。
3b 矛盾(contradictions)
两条记忆矛盾,当且仅当它们就同一主题断言相反的事实,例如 “Deploy to ECS” 与 “Deploy to Vercel”。识别时同时判断可能的胜者(likely winner):时间更新、置信度更高的那条倾向胜出。但技能此时只把两条记忆的 ID 与内容记录下来,留给用户在步骤 5 逐对裁决——矛盾的最终判定权在人类,不在自动流程。
3c 清理候选(prune)
一条记忆成为清理候选,只要满足任一条件:
- 超龄:其
metadata.type存在保留策略(步骤 1 解析或默认值),且记忆年龄超过配置天数(拿created_at与当天比较); - 低置信度且无独特信息:置信度低于 0.3,并且内容不包含属于本项目的独特信息(没有文件路径、标识符或领域专有名词)。
第二条规则值得展开:低置信度本身不足以删除,只有“既不可靠又对本项目没有专属价值”的条目才进清理名单。这个“双弱”判据避免了误删那种置信度低但包含独特文件路径/约定、日后仍可能被检索命中的边缘条目。
还有一条贯穿 3a 与 3c 的绝对规则:metadata.pinned == true 的记忆无论多旧、置信度多低,一律跳过。
步骤 4:打印 diff 报告
分析完成后、动任何写操作之前,必须以固定格式向终端打印结构化 diff:
## dream — consolidation report
Merges (<N>):
[mem0:<id1>] + [mem0:<id2>] → "<merged content, 100 chars>"
Conflicts (<N>):
[mem0:<idA>] vs [mem0:<idB>] — "<topic>" [A/B/skip]
Prune (<N>):
[mem0:<id>] — <type>, <age>d old
Proposed: <N> merges, <N> prunes, <N> conflicts. Apply? [Y/n]
格式上有两条细节规则:
- 某一类数量为 0 时,整个小节直接省略,不打印空列表;
- 三类提案总数为 0 时,打印固定文案并终止,不做任何确认交互:
Dream complete. No duplicate, contradictory, or stale memories found.
这个“干净即退出”的分支意味着,对一个健康的记忆库运行 dream 的成本只是一次全量拉取与一轮分析,而不会产生无意义的确认提示。
步骤 5:等待用户输入并应用变更
5a 逐对裁决矛盾
报告中的每个 CONFLICT 对,等待用户输入 A、B 或 skip(大小写不敏感);空输入视为 skip。所有裁决记录完毕后,才进入最终确认。这保证了矛盾处理是“先收集完、后统一执行”,不会出现改了一半被取消的中间状态。
5b 最终确认
全部矛盾裁决完成后提示:
Apply? [Y/n]
- 输入
n或no(不区分大小写)→ 打印Cancelled. No changes made.并终止,此前收集的所有裁决一并作废; - 输入
Y、yes或直接回车(空输入) → 按以下顺序应用全部变更。
应用顺序固定为 Merges → Contradictions(已裁决)→ Prunes,其中各操作的底层调用是:
合并(每个已批准的合并对)
delete_memory(<id1>)delete_memory(<id2>)add_memory写入合并版本,参数约束非常具体:text="<merged content>"user_id=<active_user_id>app_id=<active_project_id>—— 放在顶层参数,而不是 metadata 里;metadata={"type": "<原始类型>", "branch": "<当前分支>", "confidence": <两条原始记忆中较高的分数>, "source": "mem0-dream"}infer=False
infer=False 的含义是直接把合并后的文本作为记忆存储,不再经过 Mem0 的事实抽取/推理管线——dream 已经完成了语义层面的“抽取”,再走一遍推断反而可能引入偏差。source: "mem0-dream" 则为这条记忆打了来源标记,方便日后区分“代理自然沉淀”与“整理器合成”的条目;confidence 取两条原始记忆中的较高值,语义是“合并版本的可信度不应低于其任一来源”。
矛盾(用户裁决为 A 或 B 的)
只删除落败者:delete_memory(memory_id=<loser_id>)。用户选择 skip 的矛盾对原样保留,不做任何改动。
清理
对每个清理候选直接 delete_memory(<memory_id>)。
步骤 6:打印执行摘要
全部变更落地后,打印单行汇总:
Dream complete — merged: <N>, pruned: <N>, conflicts resolved: <N>, skipped: <N>
四个计数分别对应:成功合并的对数、删除的过期/低价值条目数、用户裁决解决的矛盾数、被跳过(skip)的矛盾数,构成一次整理运行的完整可审计记录。
自动模式:--auto
/mem0:dream --auto 面向无人值守场景(如定时任务),非交互运行,但保留人类判断的边界:
- Merges:自动应用(两条兼容、无矛盾,无需人工);
- Prunes:自动应用(基于年龄/置信度的机械规则,无歧义);
- Contradictions:一律跳过——矛盾裁决被明确划定为必须人类参与的决策。
并发保护(concurrency guard)
自动模式在开始任何工作前先检查锁文件 /tmp/mem0_dream_auto.lock:
- 锁文件存在且创建时间距今不足 10 分钟 → 打印
[mem0-dream --auto] Another run in progress — skipping.并终止,防止两个实例并发对同一记忆库做合并/删除; - 否则创建锁文件(写入当前时间戳),并且在所有退出路径上删除它——这一点与 10 分钟的过期窗口互为兜底:即使进程崩溃没来得及删锁,最多 10 分钟后锁自然失效。
自动模式的执行流程
- 按正常流程执行步骤 1–3(加载策略、拉全量记忆、分析);
- 静默应用合并与清理——不打印 diff、不发起任何确认;
- 打印紧凑摘要:
[mem0-dream --auto] project=<id> merged=<N> pruned=<N> conflicts_skipped=<N>
- 若检测到矛盾但被跳过,执行提醒回写(reminder),且先做去重检查:
- 先搜索是否已存在同类提醒:
search_memories(query="mem0-dream contradictions manual review", filters={"AND": [{"user_id": "..."}, {"app_id": "..."}, {"metadata": {"source": "mem0-dream-auto"}}]}, top_k=1); - 若已有结果且相似度 > 0.9,说明提醒已存在,跳过写入;
- 否则写入提醒记忆:
- 先搜索是否已存在同类提醒:
add_memory(
text="mem0-dream detected <N> contradiction(s) requiring manual review. Run /mem0:dream to resolve them interactively.",
user_id="<active_user_id>",
app_id="<active_project_id>",
metadata={"type": "task_learning", "source": "mem0-dream-auto", "branch": "<active_branch>"},
infer=False,
)
这个设计的用意是:自动模式“看见了但不管”的矛盾不能就此消失,而是转化为一条可被后续会话检索到的高优先级待办,把机器无权做的决定显式移交给人。去重检查(相似度 > 0.9 即不重复写入)保证了无论自动任务跑多少轮,提醒只有一条。提醒使用的 task_learning 类型来自插件的编码场景分类体系——见 分类初始化脚本,它将 Mem0 默认的消费向类别替换为 17 个面向编码的类别,其中 task_learnings 的定义是“特定任务上被验证成功的策略与做法”,提醒消息恰好落在这一语义域内。
协作技能:dream 在记忆生命周期中的位置
dream 并非孤立的命令,它与同插件的两个技能构成“发现—处理—兜底”的关系:
- /mem0:forget:对指定记忆的定点删除(搜索或按 ID 定位 + 逐条确认 + 删除)。dream 是“批量整理”,forget 是“外科手术”,两者互补;
- /mem0:health --deep:只做质量扫描、不应用任何变更的“体检”模式。其深度检查项与 dream 的分析维度一一对应——重复对(60% 名词重叠)、过期条目(
session_state/compact_summary超 90 天、置信度 < 0.3 且超 30 天)、矛盾、无类型孤立项——并在发现任何非零计数时提示Run /mem0:dream to fix.。从源码结构看,推荐的使用姿势是:先health --deep低成本确认记忆库是否脏,再决定是否付出一次完整 dream 交互流程。
插件整体架构上,插件描述 声明其为基于 Mem0 Platform MCP 服务的跨会话记忆插件(当前版本 0.1.7,16 个斜杠命令 + 生命周期钩子),MCP 接入配置见 mcp_config.json:连接 https://mcp.mem0.ai/mcp/ 并以 Authorization: Token ${MEM0_API_KEY} 鉴权。dream 所调用的 get_memories、search_memories、add_memory、delete_memory 均通过该 MCP 通道执行,因此使用前提是本机已配置有效的 MEM0_API_KEY 且 MCP 连接可用——这一点也可以先用 health 技能的四项连接性检查预先验证。
小结
mem0 的 dream 技能把“记忆库维护”拆解成了一条可审计、可中止、人机分工明确的流水线:
| 环节 | 决策方 | 规则 |
|---|---|---|
| 保留策略 | 项目配置 | mem0.md 的 ## Retention 小节,缺失时回退默认(session_state/compact_summary 90 天,其余不修剪) |
| 重复识别 | 自动 | 同类型 + 名词重叠 > 60% + 双方未 pinned |
| 矛盾识别 | 自动发现,人类裁决 | 更新且置信度更高者为建议胜者,A/B/skip 逐对裁决 |
| 清理 | 自动 | 超龄,或置信度 < 0.3 且无项目独特信息;pinned 一律豁免 |
| 变更执行 | 人类确认(交互)/ 规则驱动(--auto) | 合并 = 删二写一(infer=False、source: mem0-dream);矛盾删败者;清理直删 |
| 无人值守兜底 | 自动 | 10 分钟锁文件防并发;矛盾以 mem0-dream-auto 提醒记忆回写(相似度去重) |
核心设计哲学可以概括为两点:其一,所有破坏性操作都必须先 diff 后确认(交互模式)或限定在“无歧义”的子集内(自动模式);其二,机器负责机械规则,人类保留矛盾裁决权,且机器放弃裁决时留下的痕迹(提醒记忆)能被下一次会话检索到。相关实现与文档均可在仓库中查证:dream 技能定义、保留策略解析脚本、health 深度检查、forget 定点删除。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0623
Hy4-previewHy4 preview 是由腾讯混元团队研发的新一代混合专家(MoE)旗舰模型。模型总参数量 770B,每个 token 激活 49B,主干共包含78层,第一层采用标准 FFN,其余 77 层均为 MoE 结构,每层包含 256 个路由专家与 1 个共享专家,每个 token 激活 top-8 路由专家及共享专家。主干之外原生内置 1 层 MTP(总参数量 10B,激活 0.7B)以支持投机解码。Python00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
GLM-5.3-FlashGLM-5.3-Flash (320B-A18B),是GLM-5系列的首个原生多模态模型。320B总参数,能力超过GLM-5.2Jinja00
Spark-X2.5-4BSpark-X2.5-4B 旨在让强大的 AI 更实用、更高效、更易获得。在广泛日常任务中表现强劲,涵盖对话、写作、翻译、推理、编码、工具调用以及智能体工作流,并在同等规模的开源模型中取得领先成绩。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00