MemOS 深度拆解:记忆为什么需要容器、调度器和来源过滤?
从容器、调度与来源过滤拆解多种记忆的组织方式,重点讨论任务状态,以及如何避免把模型的话写成用户偏好。
博客本文目录
Memory Agent 深度拆解 · 第 7 / 8 篇。查看系列目录。
用户说了一句话,系统立即回答;与此同时,后台提取偏好、更新长期记忆、整理一次任务经验。下个会话开始前,这些工作还可能没做完。
当记忆走到这个规模,问题就从“调用哪个向量库”变成了“谁处理什么、按什么顺序、在哪个范围内、什么时候算完成”。
MemOS 的设计适合沿这条线理解。它用可组合记忆单元承载不同后端,再由读取和调度模块组织生命周期。
本文针对 2026 年 9 月 22 日读取的 Python 核心,提交为 a7367d07e55d。官方本地插件、云服务与不同部署配置需分别核验,本文没有执行部署测试。
1. MemCube 首先是一个组合与装载单元
把 MemCube 理解成“另一张记忆表”,会错过它的主要作用。
当前 GeneralMemCube 根据配置通过 MemoryFactory 创建不同记忆后端,包含 text_mem、act_mem、para_mem,以及偏好相关的 pref_mem。后端设为 uninitialized 时,对应组件可以为空。源码:GeneralMemCube
因此,一个 Cube 更像一份“记忆能力与配置的组合”:这个应用用哪些记忆表示,各自由什么实现负责,怎样装载和导出。
统一外壳帮助上层组织操作,但并不要求所有后端具备相同内部结构,也不代表每次部署都会启用全部能力。
理解这点,才能避免把论文里的完整分类,直接画成实际产品中全部运行的模块。
2. 文本、激活和参数记忆,不是三个同义词
文本记忆比较容易理解:可持久化、检索或组织的内容。激活与参数记忆涉及模型运行状态或参数相关的表示,使用条件不同。官方 MemCube 文档
如果你使用一个只暴露聊天 API 的闭源模型服务,就不能仅凭框架提供 act_mem、para_mem 接口,推导出自己能够访问服务端 KV cache 或在线修改模型权重。
这是一道接入边界:抽象告诉你框架准备怎样容纳某类能力,具体后端决定你实际上能做什么。
我会先列清楚本次部署的后端与能力,再谈系统架构。否则“记忆 OS”容易成为一张看起来完整、实际只启动了其中一部分的图。
3. load/dump 体现了记忆可迁移的愿望
GeneralMemCube 的 load 会检查配置 schema,再按选择加载后端;dump 也按记忆类型导出,并拒绝向已有内容的目录直接倾倒数据。源码:装载与导出
这里同时处理内容和解释内容所需的配置。仅拷贝一堆向量,而没有 embedding 维度、后端类型、schema 与主体映射,未必能在另一套环境中正确恢复。
不过,“有 dump 方法”与“跨存储一致快照”仍需区分。若后端在导出期间继续更新,怎样定义一个完整版本,需要结合实际后端实现与运行方式验证。
这会直接影响备份和迁移:你的目标应是恢复一套能正确检索的记忆状态,而不仅是得到一份文件压缩包。
4. MemScheduler 把记忆操作变成任务
调度器通过消息与处理器组织工作。消息携带任务类型、用户、Cube、任务 ID 等信息,再由对应模块处理检索、更新、读入或整理。官方调度器文档
在 submit_messages() 中,当前实现会补充 trace、时间和任务状态信息,检查禁用的 handler,并依据优先级分成即时路径与排队路径。源码:调度队列操作
这说明“异步记忆”不是所有操作都一律扔进同一个队列。有些工作需要优先调度,有些可以等待。
即时任务还按用户与 Cube 分组,再按 label 分派到 handler。这种分组有助于组织批量工作和作用域,但应用仍要在入口建立可信身份,不能仅靠消息上的一个 user_id 完成鉴权。
5. 为什么一条记忆需要 trace 和 task ID?
设想用户刚纠正了偏好,下一轮却仍看到旧答案。
没有任务标识时,你只能猜:是不是模型没理解?有了链路信息,可以依次检查消息是否提交、任务是否排队、哪个 handler 执行、更新了哪个 Cube,以及查询读到了什么。
调度源码记录 enqueue、dequeue 等监控事件,计算排队等待,并接入状态跟踪。源码:任务提交与观测
“接口返回很快”因此可能只是前台交接很快。用户真正关心的另一项时间,是从说出新信息,到下一次查询能用到它之间的间隔。
我会把接收时间、处理完成时间、查询可见时间分开记录。对实时产品,这比把所有延迟混成一个平均数更容易定位问题。
6. 最值得看的小模块:偏好来源过滤
一个记忆系统最危险的错误之一,是把它自己的回答当成用户偏好。
例如助手说“你可能喜欢短途徒步”,用户还没确认。下一轮系统从完整对话中提取出“用户喜欢徒步”,再把它注入上下文。几轮之后,这个猜测看起来就像一条反复出现的事实。
MemOS 的 source_filter.py 为偏好提取提供明确策略:允许 user 角色,排除 assistant、system、tool,并识别若干检索上下文、历史记忆和运行包装形式。源码:偏好来源过滤
注意,这里说的是该偏好过滤策略,不能据此宣称所有记忆路径都只允许用户消息。工具结果可以是任务事实的重要证据,只是不应不加区分地成为用户个人偏好。
这项设计把“来源是否适合此类记忆”放到了提取之前。模型仍负责理解内容,程序先限制它能看见哪些材料。
7. 为什么还要识别已经注入的旧记忆?
许多应用会把查询结果拼进模型输入,然后把完整输入再次传给记忆提取器。
如果不区分原始用户输入与注入内容,系统就可能反复记住自己的历史总结。它不只增加重复,还会让旧信息看上去刚刚被用户重申。
来源过滤中的上下文边界规则,正是在试图切断这种循环。规则方式有可读、易测试的好处,也受包装格式覆盖范围限制:应用换了注入模板,应检查过滤是否仍然生效。
我的建议是尽量在数据结构里保留 role、source 和原始消息 ID,再用文本过滤处理兼容情况。别让一段拼好的长字符串承担所有来源语义。
8. 多模块系统,需要怎样的验收?
先固定一个实际配置:使用哪些后端、哪种队列、启用哪些 handler。只有这样,讨论才落在一个可以复现的系统上。
接着构造三类输入:用户明确表达的偏好,助手未经确认的猜测,以及工具返回的任务结果。检查它们分别进入什么类型的记忆,是否保留来源。
再测试任务重试、进程重启、同一用户连续更正、不同用户并发写入。核对最终状态,也核对中间任务是否可追踪。
导出恢复则单独验收:恢复后查询能否找到原来的记录,作用域是否保持,使用的模型与索引配置是否一致。
这些是根据代码提出的验证方案,本文没有运行结果,不将其写成项目已经通过的承诺。
9. MemOS 的价值在哪里?
如果你的应用已经不止一种记忆,需要在用户、项目、Agent 与后台处理之间协调生命周期,MemOS 提供了比较系统的参考。
代价是组件与配置变多。一个只需保存少量事实的应用,可能没有必要同时引入全部调度与管理抽象。
我最看重的两个细节,一个很大:让不同记忆能力可以被组合与调度;一个很小:在提取偏好之前,先核对谁说了这句话。
长期记忆的可靠性,往往就藏在这些大架构与小边界的连接处。
系列阅读
上一篇:Cognee 深度拆解。
下一篇:Supermemory 深度拆解。