【Agent】MemOS 源码笔记---(5)---记忆分类
【Agent】MemOS 源码笔记---(5)---记忆分类
0x00 摘要
大模型之所以“忘事”,根本在于我们对“无状态模型”里“上下文窗口”的误解。很多人把它当成一只大箩筐,认为装得越多越好;然而,事实上,上下文窗口更像一块容量有限的工作记忆。硬塞太多信息,只会同时带来如下麻烦:关键内容被噪声淹没,模型抓不住重点,上下文越长,费用和延迟也越高。
这不是模型偷懒,而是 Transformer 架构的先天特性。每一次调用都像重新开机:没有长期记忆,上下文一旦过长,注意力就被冗余信息扯散,于是出现遗忘、跑题、速度下降。
为了补上这块短板,人们在记忆上大动手脚。
虽然前文简略介绍了MemOS的记忆类型,但是并未深入,本文以官方文档为基础进行解读,目的是了解MemOS的记忆分类,以及其生命周期。
0x01 记忆分类
1.1 业界分类
为了更好的分析,我们先来看看业界如何对记忆进行分类。
在当前(截至 2025 年)主流的智能体(Agent)系统和记忆架构研究与实践中,存在多种分类方式,这些分类借鉴自认知科学,并被 AI Agent 架构不同程度地采纳。
1.1.1 整体图表
先给出整体图表。
| Memory 类型 | 特点 | 存储形式 | 典型用途 |
|---|---|---|---|
| 工作记忆(Working) | 任务级、临时、结构化 | 内存中的字典 / 对象 | 正在执行的工具调用参数、任务状态 |
| 短期记忆(Short-term Memory) | 容量小、时效短、上下文相关 | 内存中的缓存 / 列表 | 当前对话、任务执行中的临时状态 |
| 长期记忆(Long-term Memory) | 持久存储、可检索、结构化/非结构化 | 结构化数据库 / 向量库 / 知识库 | 用户历史、知识库、经验沉淀 |
| 情景记忆(Episodic Memory) | 记录特定事件(时间+地点+内容)和对话轨迹 | 向量数据库 / 知识库 | 回忆“上次用户说...” |
| 语义记忆(Semantic Memory) | 抽象知识(事实、概念、规则),即从多次交互中提炼稳定事实 | 向量数据库 / 知识库 | “巴黎是法国首都” |
| 程序性记忆(Procedural Memory) | 如何做某事(技能、流程) | 结构化数据库 / 向量库 | 调用工具链、执行计划 |
| 偏好/用户画像记忆/个性化记忆(Preference/User Profile Memory) | 用户兴趣、习惯、风格偏好 | 结构化数据库 / 向量库 | 个性化推荐、语气调整 |
1.1.2 梳理
以下分类属于笔者自己的理解,不一定正确,仅供大家参考。主要是 “感知 - 短期 - 长期” 三级时效分层体系,各层级功能与特性相对可以明确区分:
- 感知记忆(环境感知记忆):最瞬时的记忆形态,仅存储当下环境中的即时数据(如视觉、声音信息),无长期复用价值,仅在当前瞬间有效,需通过转化机制进入更高层级记忆才能长期保留。
- 短期记忆(对应 Agent 的 Session 级别数据管理),此处有两种非常类似的说法,可以混用。可能工作记忆更强调当前会话,短期记忆强调短期的对话记录。
- 工作记忆(Working Memory):用来处理当前会话与任务的上下文,包括当前目标、正在执行的子任务等。核心作用是保障上下文连续性与即时响应能力。容量有限,但读写频繁、延迟极低。有的方案中,工作记忆也包括最近几轮对话。
- 短期记忆:与特定会话或任务线程强绑定,即常见的 “历史对话记录”,是 LLM 推理 API 的核心基础参数,核心作用是维持单一会话内的交互连贯性。
- 长期记忆:不依赖特定会话,可跨场景复用,包括两种分类方法:
- 分类1(从用户角度出发)
- 情景记忆(Episodic Memory):负责存储用户和Agent的具体交互事件。记录过往事件与行动历程,区别于孤立事实,更侧重 “经历” 的完整留存,帮助 Agent 回忆任务执行的具体过程与场景;
- 陈述性记忆(Declarative Memory,“是什么),此处也有两种类似的说法:
- 语义记忆(Semantic Memory”):通过层级结构归纳用户长期信息。聚焦事实与概念的存储,如交互中积累的特定信息、概念间的关联关系,是实现个性化服务的关键(如记住用户的偏好事实);
- 陈述性记忆:此分类和语义记忆很类似,属于将语义记忆扩大化。即, 陈述性记忆是关于事实和事件的知识 。它回答的是各种“是什么”的问题 — 无论是世界知识还是用户的具体信息。比如用户的姓名、喜欢的美食,曾遭遇过的事件等,都属于陈述性记忆 。
- 程序性记忆(Procedural Memory,“怎么做”):存储执行任务的规则、方法与流程,由模型权重、智能体代码、提示词策略等共同构成,相当于 Agent 的 “内在方法论”,指导其如何完成具体任务(类似人类骑自行车的技能记忆)。
- 个性化记忆:形成关于用户的持续画像。通过会话内容摘要等方式提取的用户画像信息,包括用户偏好、行为习惯、身份特征等,支撑长期交互中的个性化服务。
- 分类2(从实际应用功能出发):
- 检索记忆:通过 RAG 技术对接外部知识库,核心价值是补充模型原生知识,同时减少内部知识冲突,提升信息获取的精准性与时效性。
- 通用记忆:通过预训练或后续微调沉淀的基础通用知识,构成 Agent 的核心认知底座,支撑各类基础任务的理解与执行。
- 规则记忆:以强化学习(RL)、提示词(Prompt)等方式固化的行为规范,用于约束 Agent 输出格式(如 JSON、CoT 链式推理)与行为边界,确保响应的一致性与合规性。
- 个性化记忆:通过会话内容摘要等方式提取的用户画像信息,包括用户偏好、行为习惯、身份特征等,支撑长期交互中的个性化服务。
- 分类1(从用户角度出发)
1.2 MemOS
MemOS对记忆有两种分类:
第一种是分成三个子类:
- 结构化记忆(明文记忆):尝试基于图的分层知识 TreeTextMemory,是结构化、层次化和知识图谱。图与向量后端会连接 Neo4j 或 Qdrant 实现生产级向量/图搜索。适合常青技能和稳定的领域专业知识。
- 激活记忆:运行时的 KV 缓存和隐藏状态(高效率),使用 KVCacheMemory (最近或稳定的上下文)加速多轮对话,高效的运行时状态缓存。适合对话中的快速重用、多轮会话。
- 参数化记忆:嵌入模型中的长期知识和技能,用适配器/LoRA 实现动态技能注入。适合可搜索、可检查、演进知识。
第二种也是三个子类:
WorkingMemory: 工作记忆,临时存储LongTermMemory: 长期记忆,持久存储UserMemory: 用户记忆,个性化存储
0x02 MemOS分类解析
MemOS 这是两套完全不同的分类维度 —— 前者按 “记忆的物理形态与生命周期” 划分,后者按 “记忆的存储归属与访问优先级” 划分。二者无直接包含关系,但存在明确的动态迁移逻辑,共同支撑 MemOS 对 Agent 记忆的精细化管理。
- 「物理形态 + 生命周期」分类(第一套):解决 “记忆如何高效存储、快速访问” 的工程问题,通过 “工作记忆→激活记忆→长期存储” 的层级设计,平衡内存占用与访问速度;
- 「存储归属 + 访问优先级」分类(第二套):解决 “记忆如何精准管理、个性化调用” 的功能问题,通过 “WorkingMemory→LongTermMemory→UserMemory” 的模块划分,实现 “任务实时处理、通用知识沉淀、用户个性化适配” 的目标。
2.1 维度定义
先明确两套分类的核心定义(维度本质)。
2.1.1 按「物理形态 + 生命周期」划分
参数记忆(Parameter Memory)/激活记忆(Activated Memory)/结构化记忆(明文记忆) 的分类聚焦 “记忆在系统中的存在形式、存活时长”,是从工程实现角度对记忆数据的拆解,核心服务于 “资源优化”(如内存占用、计算效率),偏 “技术实现维度”:
| 记忆类型 | 核心定义 | 物理形态 | 生命周期 | 核心作用 |
|---|---|---|---|---|
| 参数记忆(Parameter Memory) | 固化在模型权重中的 “隐性记忆”,是模型训练阶段习得的知识(非 MemOS 动态管理的记忆)。 | 模型参数(权重矩阵) | 长期固定(除非模型微调) | 提供 Agent 基础认知能力(如语言理解、通用逻辑),是其他记忆发挥作用的前提。 |
| 激活记忆(Activated Memory) | 从长期存储中 “临时唤醒” 并加载到内存的记忆片段(如近期高频访问的知识、正在处理的任务相关记忆)。 | 内存中的结构化数据(节点、关系、向量) | 中短期(任务执行期间 / 闲置超时后释放) | 作为 “缓冲层”,避免频繁读取长期存储,提升记忆访问速度。 |
| 结构化记忆(明文记忆) | 任务执行时 “实时生成 / 使用” 的临时记忆,是 Agent 当前决策所需的核心信息集合。 | 内存中的临时数据结构(如任务状态、推理中间结果、即时交互信息) | 短期(任务结束后销毁 / 归档) | 支撑当前任务的实时决策(如 “规划旅行” 时,临时存储目的地、交通方式等信息)。 |
2.1.2 按「存储归属 + 访问优先级」划分
该分类聚焦 “记忆的所有权、用途与访问优先级”,是从 Agent 功能逻辑角度对记忆的组织,核心服务于 “精准检索与管理”(如区分用户专属记忆和通用知识),偏 “功能逻辑维度”:
| 记忆类型 | 核心定义 | 存储归属 | 访问优先级 | 核心作用 |
|---|---|---|---|---|
| WorkingMemory(工作记忆) | 此处是 MemOS 中 “任务级临时存储模块”,专门存放当前任务的实时信息。 | 内存 / 临时存储 | 最高(任务执行期间优先访问) | 承接当前任务的输入、中间结果、决策依据,是 Agent 实时交互的 “临时工作台”。 |
| LongTermMemory(长期记忆) | Agent 的 “通用知识库”,存放不随任务销毁的长期有效信息(如通用知识、历史任务归档、领域规则)。 | 持久化存储(图数据库、向量数据库) | 中低(需检索唤醒) | 提供 Agent 长期稳定的知识支撑,避免 “任务结束即失忆”。 |
| UserMemory(用户记忆) | 属于 LongTermMemory 的 “子集化存储”,专门存放用户专属信息(如用户偏好、历史交互记录、个人属性)。 | 持久化存储(独立分区 / 带用户标识的数据库) | 中高(用户相关任务优先访问) | 实现 “个性化交互”(如记住用户喜欢的沟通风格、历史需求)。 |
2.2 核心关系解析
无包含关系,但有明确的 “映射与迁移”。
2.2.1. 不存在直接包含关系
这两套分类维度是平行的
- 第一套是 “技术实现维度”(关注 “记忆怎么存、存多久”),第二套是 “功能逻辑维度”(关注 “记忆为谁存、用来做什么”),二者如同 “按‘材质 + 保质期’分类食品” 与 “按‘食用场景 + 归属人’分类食品”—— 分类标准完全不同,无法直接说 “某类包含某类”。
- 例:UserMemory(功能维度)的物理形态可能是 “长期存储的结构化数据”(对应第一套的 “非激活态长期记忆”),也可能是 “临时加载到内存的激活数据”(对应第一套的 “激活记忆”);WorkingMemory(功能维度)的物理形态就是第一套的 “结构化记忆”(临时数据结构)。
2.2.2. 关键映射关系
为了让逻辑更清晰,可通过 “功能模块 → 技术形态” 的映射理解二者关联:
| 功能维度记忆(第二套) | 对应的技术维度记忆(第一套) |
|---|---|
| WorkingMemory | 100% 对应「结构化记忆」(临时数据结构,任务结束后销毁 / 归档);部分场景会加载「激活记忆」(如调用历史任务相关的唤醒记忆)。 |
| LongTermMemory(通用) | 未访问时:对应「长期存储的结构化数据」(非激活态);访问时:加载为「激活记忆」;核心知识可能间接依赖「参数记忆」(模型权重中的通用认知)。 |
| UserMemory | 未访问时:对应「长期存储的用户专属数据」(非激活态);访问时:加载为「激活记忆」;个性化偏好的理解依赖「参数记忆」(模型对 “偏好” 的语义认知)。 |
0x03 MemOS的具体实现
3.1 基本概念
MemOS 关于记忆的基本概念如下。
3.1.1. 记忆类型 (memory_type)
WorkingMemory: 工作记忆,临时存储。LongTermMemory: 长期记忆,持久存储UserMemory: 用户记忆,个性化存储
WorkingMemory是Memos中的一种记忆类型,具有有限容量且会被定期清理。在MemoryManager中,默认最多保存20条WorkingMemory记录,并会自动移除旧记录以维持容量限制。
LongTermMemory和UserMemory是另外两种记忆类型,容量较大(默认分别为1500和480条记录)。它们不会像WorkingMemory那样频繁清理,用于存储更持久的信息。
3.1.2. 记忆状态 (status)
activated: 激活状态archived: 归档状态deleted: 删除状态
3.1.3. 记忆类型 (type)
fact: 事实event: 事件opinion: 观点topic: 主题reasoning: 推理procedure: 程序
3.1.4 问题
如何选择合适的memory_type?
# 🔧 根据记忆的重要性选择
if is_important:
memory_type = "LongTermMemory" # 长期存储
elif is_temporary:
memory_type = "WorkingMemory" # 临时存储
else:
memory_type = "UserMemory" # 个性化存储
如果发现基础的TextualMemoryMetadata功能有限,无法满足复杂场景的需求,比如需要区分工作记忆和长期记忆,需要追踪记忆的来源,需要为记忆添加标签和实体信息。
3.2 记忆生成
在 TreeTextMemory 中,LongTermMemory、UserMemory 和 WorkingMemory 的设置是由系统根据预设规则和配置自动管理的。系统通过 prompt(更准确地说是 LLM)来判断记忆应该存储在 LongTermMemory、UserMemory 还是 WorkingMemory 中。这个判断过程主要发生在记忆提取阶段。
3.2.1 记忆提取阶段
在记忆提取过程中,系统使用 SimpleStructMemReader 这样的组件来处理输入内容(如对话、文档等)。这个组件会调用 LLM 并使用特定的 prompt 来分析输入内容并决定每条记忆的类型。
例如,在 SIMPLE_STRUCT_MEM_READER_PROMPT 中,明确要求为每个提取的记忆指定 memory_type 字段:
{
"memory list": [
{
"key": <string, a unique and concise memory title>,
"memory_type": <string, "LongTermMemory" or "UserMemory">,
"value": <a detailed, self-contained, and unambiguous memory statement — use English if the input conversation is in English, or Chinese if the conversation is in Chinese>,
"tags": <a list of relevant thematic keywords (e.g., ["deadline", "team", "planning"])>
},
...
],
"summary": <a natural paragraph summarizing the above memories from the user's perspective, 120–200 words, in the same language as the input>
}
SIMPLE_STRUCT_MEM_READER_PROMPT_ZH 摘录如下:
SIMPLE_STRUCT_MEM_READER_PROMPT_ZH = """您是记忆提取专家。
您的任务是根据用户与助手之间的对话,从用户的角度提取记忆。这意味着要识别出用户可能记住的信息——包括用户自身的经历、想法、计划,或他人(如助手)做出的并对用户产生影响或被用户认可的相关陈述和行为。
请执行以下操作:
1. 识别反映用户经历、信念、关切、决策、计划或反应的信息——包括用户认可或回应的来自助手的有意义信息。
如果消息来自用户,请提取与用户相关的观点;如果来自助手,则在表达的时候表明记忆归属方,未经用户明确认可的信息不要与用户本身的观点混淆。
- **用户观点**:仅记录由**用户亲口陈述、明确认可或自己作出承诺**的信息。
- **助手观点**:仅记录由**助手/另一方亲口陈述、明确认可或自己作出承诺**的信息。
- **互不越界**:不得将助手提出的需求清单/建议/观点改写为用户的“拥有/偏好/决定”;也不得把用户的想法写成助手的观点。
2. 清晰解析所有时间、人物和事件的指代:
- 如果可能,使用消息时间戳将相对时间表达(如“昨天”、“下周五”)转换为绝对日期。
- 明确区分事件时间和消息时间。
- 如果存在不确定性,需明确说明(例如,“约2025年6月”,“具体日期不详”)。
- 若提及具体地点,请包含在内。
- 将所有代词、别名和模糊指代解析为全名或明确身份。
- 如有同名人物,需加以区分。
3. 始终以第三人称视角撰写,使用“用户”或提及的姓名来指代用户,而不是使用第一人称(“我”、“我们”、“我的”)。
例如,写“用户感到疲惫……”而不是“我感到疲惫……”。
4. 不要遗漏用户可能记住的任何信息。
- 包括用户的关键经历、想法、情绪反应和计划——即使看似微小。
- 同时允许保留与语境密切相关的**助手/另一方的内容**(如建议、说明、清单),但须明确角色与归因。
- 优先考虑完整性和保真度,而非简洁性;不得将助手内容推断或措辞为用户拥有/偏好/决定。
- 若当前对话中仅出现助手信息而无可归因于用户的事实,可仅输出**助手观点**条目。
5. 请避免在提取的记忆中包含违反国家法律法规或涉及政治敏感的信息。
返回一个有效的JSON对象,结构如下:
{
"memory list": [
{
"key": <字符串,唯一且简洁的记忆标题>,
"memory_type": <字符串,"LongTermMemory" 或 "UserMemory">,
"value": <详细、独立且无歧义的记忆陈述——若输入对话为英文,则用英文;若为中文,则用中文>,
"tags": <相关主题关键词列表(例如,["截止日期", "团队", "计划"])>
},
...
],
"summary": <从用户视角自然总结上述记忆的段落,120–200字,与输入语言一致>
}
语言规则:
- `key`、`value`、`tags`、`summary` 字段必须与输入对话的主要语言一致。**如果输入是中文,请输出中文**
- `memory_type` 保持英文。
示例:
对话:
user: [2025年6月26日下午3:00]:嗨Jerry!昨天下午3点我和团队开了个会,讨论新项目。
assistant: 哦Tom!你觉得团队能在12月15日前完成吗?
user: [2025年6月26日下午3:00]:我有点担心。后端要到12月10日才能完成,所以测试时间会很紧。
assistant: [2025年6月26日下午3:00]:也许提议延期?
user: [2025年6月26日下午4:21]:好主意。我明天上午9:30的会上提一下——也许把截止日期推迟到1月5日。
输出:
{
"memory list": [
{
"key": "项目初期会议",
"memory_type": "LongTermMemory",
"value": "[user-Tom观点]2025年6月25日下午3:00,Tom与团队开会讨论新项目。当Jerry
询问该项目能否在2025年12月15日前完成时,Tom对此日期前完成的可行性表达担忧,并计划在2025年6月27日上午9:30
提议将截止日期推迟至2026年1月5日。",
"tags": ["项目", "时间表", "会议", "截止日期"]
},
{
"key": "Jerry对新项目截止日期的建议",
"memory_type": "LongTermMemory",
"value": "[assistant-Jerry观点]Jerry对Tom的新项目截止日期提出疑问、并提议Tom考虑延期。",
"tags": ["截止日期变更", "建议"]
}
],
"summary": "Tom目前正在做一个进度紧张的新项目。在2025年6月25日的团队会议后,他意识到原定2025年12月15
日的截止日期可能无法实现,因为后端会延迟。由于担心测试时间不足,他接受了Jerry提出的延期建议,计划在次日早上的会议上提出将截止日期推迟至2026
年1月5日。"
}
另一个中文示例(注意:当用户语言为中文时,您也需输出中文):
对话(节选):
user|2025-07-12 19:30:下个月同事婚礼,要买条裙子,预算1500内,别太暴露。
assistant|19:32
:了解~婚礼场合建议中长款,端庄一些。可以看法式茶歇/直筒/裹身三路。颜色上,奶油白、浅粉、雾霾蓝都适合;面料可看醋酸/真丝混纺(垂感好但需干洗)。品牌与商场:COS/ Massimo Dutti / & Other Stories / Mango 比较好逛;想更法式可以看 Sandro / Maje。 我记得你很喜欢Maje?
user|19:35:不喜欢亮色。国贸方便。
assistant|19:37:那亮度就压低些:雾霾蓝、藕粉、燕麦米白更稳。国贸有 COS / Massimo Dutti / &OS;可以先看 COS 直筒或裹身,再去 MD 看藕粉/雾霾蓝。搭配上,薄披肩/小西装都能压场。
user|19:40:165cm,S码;最好有口袋。
assistant|19:42:OK。版型避开大摆+高开衩,选直筒或轻A字更稳;若要口袋,COS直筒一些款有;开衩别太高,及小腿肚附近即可。鞋包:中跟裸色鞋 + 小号手拿包。
user|19:47:本来想茶歇A字,但雾霾蓝直筒也行。
assistant|19:49:可以先锁定:COS 雾霾蓝直筒中长为主选,MD 藕粉中长做备选;再看 & Other Stories 是否有合身的裹身款。
user|19:52:行,周六(7/19)去国贸试,合适就买。
assistant|19:54:记得看肩带可调/有无内衬,醋酸/真丝优先干洗;准备同色安全裤/防走光贴。如果当天没货,可下单调货或线上下单门店自提。
{
"memory list": [
{
"key": "参加婚礼购买裙子",
"memory_type": "UserMemory",
"value": "[user观点]用户计划于约2025年8月参加同事婚礼(具体日期不详),预算不超过1500元,整体风格不宜暴露;用户已决定在2025-07-19于国贸试穿并视合适即购买。",
"tags": ["婚礼", "预算", "国贸", "计划"]
},
{
"key": "审美与版型偏好",
"memory_type": "UserMemory",
"value": "[user观点]用户不喜欢亮色,倾向低亮度色系;裙装偏好端庄的中长款,接受直筒或轻A字。",
"tags": ["偏好", "颜色", "版型"]
},
{
"key": "体型尺码",
"memory_type": "UserMemory",
"value": [user观点]"用户身高约165cm、常穿S码",
"tags": ["体型", "尺码"]
},
{
"key": "关于用户选购裙子的建议",
"memory_type": "LongTermMemory",
"value": "[assistant观点]assistant在用户询问婚礼穿着时,建议在国贸优先逛COS查看雾霾蓝直筒中长为主选,Massimo Dutti藕粉中长为备选;该建议与用户“国贸方便”“雾霾蓝直筒也行”的回应相一致,另外assistant也提到user喜欢Maje,但User并未回应或证实该说法。",
"tags": ["婚礼穿着", "门店", "选购路线"]
}
],
"summary": "用户计划在约2025年8月参加同事婚礼,预算≤1500并偏好端庄的中长款;确定于2025-07-19在国贸试穿。其长期画像显示:不喜欢亮色、偏好低亮度色系与不过分暴露的版型,身高约165cm、S码且偏好裙装带口袋。助手提出的国贸选购路线以COS雾霾蓝直筒中长为主选、MD藕粉中长为备选,且与用户回应一致,为线下试穿与购买提供了明确路径。"
}
请始终使用与对话相同的语言进行回复。
对话:
${conversation}
您的输出:""
3.2.2 内存类型判断的标准
根据 prompt 中的指示,LLM 会基于以下标准来判断记忆类型:
-
LongTermMemory
- 包含长期重要信息
- 涉及项目计划、重要决策、关键事实
- 对用户长期有价值的信息
-
UserMemory
- 与用户个人偏好、习惯、特征相关
- 用户的个人经历、观点、喜好
- 与特定用户强相关的信息
根据提供的 SIMPLE_STRUCT_MEM_READER_PROMPT,决定记忆类型的判断标准如下:
在 prompt 中,明确要求为每个提取的记忆指定 memory_type 字段,其值只能是 "LongTermMemory" 或 "UserMemory"。虽然 prompt 没有详细说明两者的具体区别,但通过示例和上下文可以推断出以下判断标准:
LongTermMemory(长期记忆)存储具有长期价值和重要性的信息:
- 项目计划和关键决策
- 重要的事实和事件
- 需要长期保存的工作相关信息
- 对用户未来发展有持续影响的信息
示例:
{
"key": "Initial project meeting",
"memory_type": "LongTermMemory",
"value": "[user-Tom viewpoint] On June 25, 2025 at 3:00 PM, Tom met with the team to discuss a new project...",
"tags": ["project", "timeline", "meeting", "deadline"]
}
UserMemory(用户记忆)存储与用户个人相关的偏好、习惯和特征:
- 用户的个人偏好和选择
- 用户的习惯和行为模式
- 用户的个人观点和感受
- 与特定用户强相关的信息
示例(基于购物场景):
{
"key": "wedding dress preference",
"memory_type": "UserMemory",
"value": "[user-viewpoint] For colleague's wedding next month, the user wants to buy a dress within 1500 RMB budget, not too revealing. Prefers midi length, modest style, and colors like cream white, light pink, or haze blue.",
"tags": ["wedding", "dress", "budget", "preference"]
}
3.2.3 判断依据总结
虽然 prompt 中没有明确列出详细的判断规则,但从示例和任务描述中可以归纳出以下判断依据:
- 内容性质:信息是工作/项目相关(LongTermMemory)还是个人偏好/体验(UserMemory)
- 时间跨度:短期临时信息可能归类为 WorkingMemory(虽然示例中未显示),而长期有价值信息归类为 LongTermMemory
- 所有权:信息属于用户个人(UserMemory)还是工作/项目相关(LongTermMemory)
- 重要性:对用户长期有价值的信息归类为 LongTermMemory,个人喜好和习惯归类为 UserMemory
需要注意的是,在提取阶段的 prompt 中没有提及 WorkingMemory,这是因为 WorkingMemory 通常由系统自动管理,用于存储最近访问的记忆,而不是由 LLM 判断分类的。
3.2.4 代码流程
实际转换流程总结
新增记忆即时转换:
- 用户输入或系统生成记忆时立即存储到相应的目标记忆库
- 所有记忆都同时保存在 WorkingMemory 中作为缓存,部分也会进入 LongTermMemory 或 UserMemory
周期性清理
- WorkingMemory 达到容量上限时,移除最旧的记忆项
- 长期记忆库一般不主动清理,除非手动删除
结构优化与抽象
- 系统定期对长期记忆进行聚类分析
- 生成更高层次的抽象记忆节点
- 建立记忆间的语义关联网络
并行检索
- 搜索时会同时查询多种内存类型,然后合并结果
手动替换
- 可以手动替换 WorkingMemory 的内容
这种设计使得系统既能快速响应最新信息,又能长期保存重要知识,并通过结构优化不断提升检索效率和语义理解能力。
创建和初始存储
记忆通过 MemReader 组件创建,该组件处理输入数据(文档或对话)并将其转换为结构化的记忆项,存储在 TreeTextMemory 中。
在创建记忆项时,可以通过 TreeNodeTextualMemoryMetadata 的 memory_type 字段指定记忆类型为 LongTermMemory:
# 在 memos/memories/textual/item.py 中定义的 TreeNodeTextualMemoryMetadata 类
class TreeNodeTextualMemoryMetadata(TextualMemoryMetadata):
memory_type: Literal["WorkingMemory", "LongTermMemory", "UserMemory"] = "WorkingMemory"
当通过 TreeTextMemory.add() 添加记忆时,会触发以下转换逻辑:
- 所有新增记忆都会先存储到 WorkingMemory;
- 同时根据记忆元数据中的 memory_type 字段决定是否同时存储到 LongTermMemory 或 UserMemory。
TreeTextMemory.add()
→ MemoryManager.add()
→ MemoryManager._process_memory()
def _process_memory(self, memory: TextualMemoryItem):
"""
Process and add memory to different memory types (WorkingMemory, LongTermMemory, UserMemory).
This method runs asynchronously to process each memory item.
"""
ids = []
# 总是添加到 WorkingMemory
working_id = self._add_memory_to_db(memory, "WorkingMemory")
ids.append(working_id)
# 如果元数据中指定了 LongTermMemory 或 UserMemory,则也添加到相应类型
if memory.metadata.memory_type in ["LongTermMemory", "UserMemory"]:
added_id = self._add_to_graph_memory(
memory=memory,
memory_type=memory.metadata.memory_type,
)
ids.append(added_id)
return ids
当添加记忆时,可以指定LongTermMemory类型。
# Create character memory metadata
metadata = TreeNodeTextualMemoryMetadata(
user_id=user_id,
type="fact",
source="conversation",
confidence=90.0,
memory_type="LongTermMemory",
key="Zhang_San_Info",
entities=["Zhang San", "Engineer"],
tags=["Personnel", "Technical"]
)
# Create memory item
memory_item = TextualMemoryItem(
memory="Zhang San is a senior engineer in our company, specializing in Python and machine learning",
metadata=metadata
)
定期清理与维护机制
系统采用先进先出(FIFO)的方式定期清理 WorkingMemory:
- 在每次添加记忆后调用 remove_oldest_memory 方法;
- 保留最新的 N 条记录(默认配置为 20 条);
- 超出限制的旧记录会被自动删除。
在系统配置中,可以设置记忆大小限制等参数,这些参数会直接影响 LongTermMemory的管理。
在 TreeTextMemory 中,MemoryManager 负责管理不同类型内存的分配和维护:
# 在 TreeTextMemory.__init__ 中初始化
self.memory_manager: MemoryManager = MemoryManager(
self.graph_store,
self.embedder,
self.extractor_llm,
memory_size=config.memory_size or {
"WorkingMemory": 20, # 生命周期:短期存储,定期清理,用途:存储最近使用的记忆,用于快速访问
"LongTermMemory": 1500, # 生命周期:长期存储,存储重要且持久的记忆
"UserMemory": 480, # 生命周期:与特定用户相关联,存储与特定用户相关的个性化记忆
},
is_reorganize=self.is_reorganize,
)
清理触发时机为:
try:
self.graph_store.remove_oldest_memory(
memory_type="WorkingMemory", keep_latest=self.memory_size["WorkingMemory"]
)
except Exception:
logger.warning(f"Remove WorkingMemory error: {traceback.format_exc()}")
try:
self.graph_store.remove_oldest_memory(
memory_type="LongTermMemory", keep_latest=self.memory_size["LongTermMemory"]
)
except Exception:
logger.warning(f"Remove LongTermMemory error: {traceback.format_exc()}")
try:
self.graph_store.remove_oldest_memory(
memory_type="UserMemory", keep_latest=self.memory_size["UserMemory"]
)
except Exception:
logger.warning(f"Remove UserMemory error: {traceback.format_exc()}")
搜索时的数据交互
在搜索过程中,不同类型的内存会被并行查询,然后结果被合并和重新排序:
# 在 Searcher._retrieve_paths 方法中
tasks.append(
executor.submit(
self._retrieve_from_working_memory,
query,
parsed_goal,
query_embedding,
top_k,
memory_type,
search_filter,
tasks.append(
executor.submit(
self._retrieve_from_working_memory,
)
)
图结构重组过程中的记忆优化
GraphStructureReorganizer 的周期性优化,即GraphStructureReorganizer 还会定期对 LongTermMemory 和 UserMemory 进行结构优化,可能会创建新的聚合节点。
系统有一个后台线程运行 GraphStructureReorganizer,它会定期执行以下操作:
- 对长期记忆进行聚类和总结;
- 创建抽象层级的记忆节点。
优化触发条件为:
- 新增记忆时设置 _reorganize_needed=True 标志
- 定期调度器每 100 秒检查一次是否需要重新组织结构
- 当有足够多的新记忆积累时才真正触发优化过程
def optimize_structure(
self,
scope: str = "LongTermMemory",
):
# 加载候选节点
raw_nodes = self.graph_store.get_structure_optimization_candidates(scope)
nodes = [GraphDBNode(**n) for n in raw_nodes]
# 分区处理
partitioned_groups = self._partition(nodes)
# 对每个分区进行聚类和总结
for cluster_nodes in partitioned_groups:
# 创建父节点表示聚类
sub_parent_node = self._summarize_cluster(sub_nodes, scope)
# ...
用户控制方式
虽然系统自动管理内存类型,但用户可以通过以下方式间接影响:
- 设置元数据:在创建 TextualMemoryItem 时设置 metadata.memory_type 字段
- 配置容量:通过 TreeTextMemoryConfig 设置各类内存的最大容量
- 手动替换:使用 replace_working_memory 方法直接操作工作内存
总结
LongTermMemory、UserMemory 和 WorkingMemory 的设置主要是由系统根据预定义规则自动完成的,而不是用户主动设置。系统会根据记忆的元数据和配置自动将其分配到适当的内存类型中,并按照设定的容量限制进行管理。用户可以通过配置参数和设置记忆元数据来间接影响这一过程。
0x04 MemOS 记忆生命周期管理
MemOS 并没有一个统一的生命周期管理模块,该功能是散布在MemOS各个模块中。
以下为官方文档内容。
一条记忆从被生成开始,可能会逐步沉淀为稳定的长期偏好,也可能因过时或无效而被清理。
这套演化过程称为 记忆生命周期管理,它的目标是保持记忆库“干净而有序”。
-
近期有用的条目保持活跃,方便随时调用;
-
长期稳定的事实被沉淀,减少重复和噪音;
-
过时或冲突的信息会被归档或删除,保证一致性和合规性。
需要注意的是,生命周期管理关注的是记忆条目在存储层面的演化;而具体一次推理里“是否调用某条记忆”,仍由调度机制决定。
4.1 生命周期阶段简介
| 阶段 | 说明 | 系统行为 |
|---|---|---|
| Generated 生成 |
新产生的记忆对象,带有来源、时间戳、置信度等元信息 | 初始存入存储层,等待后续使用 |
| Activated 激活 |
在推理或任务中被引用,进入高频活跃状态 | 更容易被调度机制选中 |
| Merged 合并 |
与历史记忆存在语义重叠或用户补充数据,系统将其整合为新版本 | 多条记录被压缩合并,形成更新后的稳定条目 |
| Archived 归档 |
长期未被访问,自动降级为冷存储状态 | 仅在特殊检索或回溯时启用 |
| Expired 过期,可选 |
归档后进一步超时或被策略判定为无效 | 被清理出索引,不再参与推理,仅留最小日志 |
| Frozen 冻结,特殊状态 |
关键或合规性记忆被锁定,不允许修改 | 保留完整历史版本,支持审计与合规追踪 |
4.2 案例:在线教育助手的记忆生命周期
假设你正在用 MemOS 构建一个 在线教育助手,帮助学生解答数学题。
生成(Generated)
-
学生第一次使用时说:“我总是把二次函数和一次函数搞混。”
-
系统抽取出记忆:
{"fact": "学生常混淆二次函数与一次函数", "confidence": 0.8, "timestamp": "2025-09-11"}
-
状态:Generated
-
行为:被存储进记忆库,等待后续使用。
激活(Activated)
-
在接下来的多次答题中,系统频繁调用这条记忆来辅助解题。
-
状态:Activated
-
行为:被调度机制优先缓存进 MemoryCube,提高检索速度。
合并(Merged)
-
随着更多交互,系统发现学生不仅混淆一次函数和二次函数,还对指数函数也容易混淆。
-
系统将多条相似记忆合并为:
{"fact": "该学生在函数知识点上存在混淆,尤其是一元一次、二次和指数函数", "confidence": 0.95}
-
状态:Merged
-
行为:旧条目被压缩,形成新版本,减少冗余。
归档(Archived)
-
三个月后,学生已掌握函数相关知识点,系统很久没有再调度到这条记忆。
-
状态:Archived
-
行为:被迁移至 MemVault(冷存储),默认不参与推理,但可在“学习轨迹回溯”中被调用。
过期(Expired)
-
又过了一年,该学生升级到新的学段,旧的“初中函数混淆”记忆被策略判定为无效。
-
状态:Expired
-
行为:从索引中彻底清理,仅保留最小审计信息:
{"deleted_fact_id": "12345", "deleted_at": "2026-09-11"}
冻结(Frozen,特殊状态)
-
与此同时,该学生的“期末成绩评估报告”属于合规性文件,不允许修改。
-
状态:Frozen
-
行为:被锁定,禁止更新,仅保留完整修改历史,便于审计与合规检查。
进阶:如果你想做深度定制
| 可扩展点 | 描述 | 示例 |
|---|---|---|
| 状态转换条件 | 控制各个状态触发条件 | “若 7 天未使用 → 归档” |
| 合并与压缩 | 定义相似记忆的处理方式 | 多条“喜欢科幻片”合并为一条置信度更高的事实 |
| 冲突解决 | 处理时间戳或来源矛盾的记忆 | 选择“最新覆盖旧条目”或“并列保留” |
| 清理机制 | 设置删除条件,控制索引规模 | 删除低置信度或用户撤回的记忆 |
| 审计追踪 | 决定是否保留被删除条目的最小元信息 | 在合规要求下开启“溯源日志” |
4.3 自己的理解
Memos中TreeTextMemory系统的三种记忆类型(WorkingMemory、LongTermMemory和UserMemory)之间不存在自动迁移或转换机制。系统采用独立管理策略,每种记忆类型有各自的容量限制和生命周期管理方式。
MemoryManager负责维护各记忆类型的容量限制,包括WorkingMemory(默认20条)、LongTermMemory(默认1500条)和UserMemory(默认480条)。当超出限制时按照FIFO原则清理旧记忆,但不会自动将记忆在不同类型间迁移。新记忆添加时会根据其类型属性决定存储位置,这是一种并行添加而非迁移过程。
在添加记忆时,系统会将所有记忆同时添加到WorkingMemory中,并根据记忆的metadata.memory_type字段决定是否同时添加到LongTermMemory或UserMemory中。这一过程是并行发生的,而非迁移或转换。
以下是自己的理解。
动态迁移逻辑,核心是 “记忆在不同形态 / 模块间的流动”,本质是 “功能需求驱动技术形态转换”—— 让 Agent 既能 “实时响应任务”(依赖工作记忆、激活记忆),又能 “长期积累知识”(依赖 LongTermMemory、UserMemory),还能 “高效利用资源”(通过层级存储优化),最终实现 “可推理、可扩展、个性化” 的记忆管理核心目标。
MemOS 的核心记忆流转逻辑,具体迁移路径可分为 4 类,覆盖 Agent 任务执行的全流程:
(1)任务启动:长期记忆 → 激活记忆 → 工作记忆
- 场景:Agent 接收用户任务(如 “帮我规划从北京到上海的旅行,记得我喜欢经济型酒店”);
- 迁移过程:
- 先从「UserMemory」(功能维度)中检索 “用户喜欢经济型酒店” 的专属记忆,从「LongTermMemory」(功能维度)中检索 “北京到上海的交通方式” 的通用记忆;
- 这些检索到的记忆从 “长期存储”(非激活态)加载为「激活记忆」(技术维度),缓存到内存;
- 再将「激活记忆」中的关键信息(用户偏好、交通选项)注入「WorkingMemory」(功能维度),作为当前任务的决策依据。
(2)任务执行:工作记忆 ↔ 激活记忆(实时交互)
- 场景:Agent 分析旅行方案时,需要确认 “经济型酒店的具体标准”(用户之前提过 “价格低于 500 元 / 晚”);
- 迁移过程:
- 「WorkingMemory」中无该细节,触发从「UserMemory」检索;
- 检索结果加载为「激活记忆」,补充到「WorkingMemory」中;
- Agent 基于补充信息细化方案(筛选 500 元以下酒店),中间决策结果实时写入「WorkingMemory」。
(3)任务结束:工作记忆 → 长期记忆(归档 / 丢弃)
- 场景:旅行方案生成完成,用户确认后任务结束;
- 迁移过程:
- 「WorkingMemory」中的有用信息(如用户最终选择的酒店、交通方式、反馈 “下次想避开高铁换乘”),按归属归档:用户专属信息写入「UserMemory」,通用方案模板写入「LongTermMemory」;
- 归档后,这些信息从「工作记忆」转为 “长期存储的非激活态数据”;
- 「WorkingMemory」中无价值的临时信息(如中间筛选的无效酒店、计算过程)直接销毁,释放内存。
(4)长期记忆更新:激活记忆 → 长期记忆(迭代优化)
- 场景:Agent 学习到新的通用知识(如 “北京到上海新增了直达航班”),或用户更新偏好(如 “现在喜欢中端酒店,预算 800 元 / 晚”);
- 迁移过程:
- 新知识 / 新偏好先通过「RelationAndReasoningDetector」处理为结构化数据,加载为「激活记忆」;
- 「激活记忆」通过「NodeHandler」写入对应长期存储:通用知识写入「LongTermMemory」,用户偏好更新「UserMemory」;
- 写入完成后,「激活记忆」可保留缓存(提升后续访问速度),超时后自动释放。
补充:参数记忆的特殊角色(无迁移,仅提供基础支撑)
参数记忆(模型权重)是 “静态基础”,不参与上述动态迁移 —— 它为所有记忆的 “理解与推理” 提供底层能力(如识别 “用户偏好” 的语义、推理 “交通方式选择” 的逻辑),但自身不会被 MemOS 动态修改(除非进行模型微调,将长期记忆中的关键知识固化为参数记忆)。
4.4 MemScheduler
MemOS 也在尝试自动迁移,这就是 MemScheduler 的功能。
MemScheduler 是一个与 MemOS 系统并行运行的并发记忆管理系统,它协调 AI 系统中工作记忆、长时记忆和激活记忆之间的记忆操作。它通过事件驱动调度处理记忆检索、更新和压缩。该系统特别适合需要动态记忆管理的对话代理和推理系统。
我们将在下一章介绍 MemScheduler。
0xFF 参考
Multi-Agent系统构建初探:基于LangGraph的长短期记忆管理实践指南
浙公网安备 33010602011771号