跳转到主要内容
Agent 记忆系统

Agent 记忆系统学习笔记(一):从 Mem0 看懂记忆与召回链路

AI 辅助写的

用 Mem0 作为第一个样本,系统理解 Agent Memory 的写入、存储、实体链接、多信号召回、排序和上下文注入链路。

写在前面:这不是 Mem0 产品介绍,而是记忆系统入门

这个系列我想解决一个问题:AI Agent 的记忆和召回到底是怎么设计的?

如果只看表层,很多系统都在说自己有 memory:有的接一个向量库,有的保留聊天历史,有的做 GraphRAG,有的让 Agent 自己调用工具搜索记忆。但这些方案背后的关键问题其实是同一组:

什么内容值得被记住?
它被存到哪里?
未来怎么找到它?
找到以后怎么排序?
什么时候应该忘掉、降权或保留历史?
最后怎么把记忆交给模型使用?

这一篇先从 Mem0 开始。原因很简单:Mem0 是一个比较典型的工程化 Agent Memory 案例,它把长期记忆拆成了写入、存储、实体链接、多信号召回、时间推理和排序等模块。学完它之后,再看 Zep、Letta、LangGraph、Cognee,会更容易建立统一的分析框架。

我对这篇笔记的定位是:不是教你怎么接入 Mem0,而是用 Mem0 学会拆解一个记忆系统。


一、先建立心智模型:记忆不是聊天记录

很多人第一次理解 Agent Memory,会把它等同于“保存历史聊天”。但这只是最低级的记忆。

聊天记录是原始材料,记忆是被提炼后的可复用事实。

比如用户说:

我不太喜欢惊悚片,最近更想看科幻电影。

原始聊天记录只是这句话本身。但一个记忆系统真正应该沉淀的是:

用户不喜欢惊悚片。
用户偏好科幻电影。

以后用户问“今晚看什么”,Agent 不需要用户重复偏好,而是能主动召回这两条记忆。这才是长期记忆的价值:让每一次交互都能沉淀成未来可用的上下文。

所以,记忆系统不是一个日志系统。日志系统记录“发生过什么”;记忆系统要判断“未来什么会有用”。


二、Mem0 的整体位置和写入链路

Mem0 在 Agent 架构中的位置

Mem0 可以理解成应用和大模型之间的一层长期记忆基础设施。

Mem0 在 Agent 架构中的位置
Mem0 不是替代 LLM,而是在 Agent 和模型之间提供可搜索、可更新的长期上下文。
用户输入
应用 / Agent 编排层
判断任务、组织 prompt、调用工具和模型
回答前
Mem0.search
按用户、会话和任务范围召回相关 memories
把 memories 放进上下文
LLM 生成回答
回答后
Mem0.add
从本轮对话中抽取新事实、偏好和状态
写入长期记忆
未来对话可再次召回
一次对话通常包含两条路径:回答前 search 记忆,回答后 add 新记忆。

它有两个最核心的动作:

add    :把新的对话或事实写入记忆系统
search :在未来根据 query 召回相关记忆

这两个 API 看起来简单,但背后分别对应一条完整链路。


记忆写入链路:从对话到可召回事实

先看写入。

Mem0 不是简单把整段对话塞进数据库,而是要先做一层“蒸馏”:从对话中抽取值得保留的事实。

Mem0 写入链路:从对话到可召回事实
写入不是保存聊天记录,而是把原始对话蒸馏成未来可复用的 memory。
01
新对话 / 新消息
用户和助手刚刚产生的新交互
02
查找相关旧记忆
给抽取过程提供去重和上下文线索
03
LLM 抽取新事实
偏好、计划、决策、状态、反馈
04
生成 memory 对象
memory text + metadata + scope
05
embedding 向量化
为之后的语义检索建立索引
06
hash 去重 / 批量写入
减少完全重复的 memory
07
实体抽取与链接
把人、地点、项目、概念连接到 memory

举个例子:

用户:我下个月要去东京,我比较喜欢住在涩谷附近,也不吃贝类。
助手:好的,我会记住你的旅行偏好。

比较理想的 memory extraction 结果是:

用户下个月计划去东京。
用户偏好住在涩谷附近。
用户不吃贝类。

这一步是 Agent Memory 和普通 RAG 的核心区别之一。

传统 RAG 往往默认资料已经存在,重点在检索;Agent Memory 需要先判断什么内容值得被写成记忆。


ADD-only:为什么 Mem0 不急着覆盖旧记忆?

Mem0 新版算法里一个重要取舍是 ADD-only extraction。也就是写入阶段主要做新增,而不是让 LLM 在每次写入时决定 ADD、UPDATE、DELETE。

这件事一开始看起来有点反直觉:如果只新增,记忆不是会越积越多吗?

会。但这是有意为之。

因为很多事实不是互相冲突,而是随时间演化。

2025 年:用户住在纽约。
2026 年:用户搬到了旧金山。

如果系统把“用户住在纽约”直接更新成“用户住在旧金山”,那它就丢掉了历史。以后用户问:

我搬家之前住在哪里?

系统可能就答不上来。

所以 Mem0 的思路是:

写入时尽量保留事实
召回时再判断当前问题需要哪条事实

这个设计很关键。它把复杂度从写入阶段转移到了召回阶段。

写入阶段少做破坏性判断,可以降低误删、误合并、误覆盖的风险;召回阶段再根据语义、实体、时间和新旧程度决定哪条记忆更应该出现。

这也是我认为 Mem0 最值得学习的地方之一:长期记忆不应该只保存“当前状态”,还应该保存“状态如何变化”。


三、Mem0 的存储与 Graph Memory

Mem0 的存储:向量库只是其中一层

很多人会把记忆系统想象成一个向量数据库。但 Mem0 的结构不止这一层。

从官方文档和评估说明看,它至少可以拆成三类存储:

Mem0 的存储分层
向量库只是其中一层;长期记忆还需要实体索引和历史事件记录。
Vector Store
存 memory 文本、embedding、metadata、时间戳;主要服务语义检索。
Entity Store / Graph Memory
存实体、实体 embedding、实体和 memory 的连接;主要服务实体相关召回增强。
SQL / History Store
存写入事件、历史记录、滚动上下文;主要服务审计、去重和系统管理。

Vector Store 负责“意思像不像”。Entity Store 负责“是不是和同一个人、地点、项目、概念有关”。History Store 则更偏系统内部的事件记录和上下文管理。

这个分层说明一件事:一个好的记忆系统不能只靠 embedding。

Embedding 适合语义相似,但它对专有名词、时间、实体关系、精确关键词并不总是稳定。记忆系统需要更多索引结构共同工作。


Graph Memory:Mem0 的图更像“实体增强检索”

Mem0 现在的 Graph Memory 是内置的,不再要求使用 Neo4j、Memgraph、Kuzu 这类外部图数据库。

它的基本逻辑是:

Graph Memory:实体如何把记忆连接起来
Mem0 的图更像实体增强检索:实体连接 memory,并在召回时影响排序。
写入时:从 memory 抽取实体
Memory A
我和 Alice 做 Q1 路线图
抽取实体
Alice
Q1 路线图
Memory B
Alice 负责产品策略
抽取实体
Alice
召回时:实体连接相关 memories
Alice
Memory A
Memory B
Q1 路线图
Memory A
Memory C
这里的图不是完整知识图谱,而是把“同一实体相关的 memory”聚合起来,作为召回排序的 boost 信号。

之后用户问:

Alice 现在和什么项目有关?

系统就不只看语义相似,也会看哪些 memory 和 Alice 这个实体连接。相关 memory 会获得排序加权。

但要注意:Mem0 的 Graph Memory 不是完整知识图谱。它不会严格记录:

Alice -- 管理 --> Bob
Alice -- 就职于 --> Acme

它更像:

Alice 这个实体连接了哪些 memories?
哪些 memories 共同提到了 Alice?

所以我会把 Mem0 的图理解成 entity-aware retrieval,也就是实体增强召回,而不是强 schema 的图推理系统。

这个判断很重要。因为如果你只是想让 Agent 更容易召回和某个人、项目、公司相关的历史,Mem0 的图已经很有用;但如果你要做复杂关系推理、路径查询、关系约束,那就需要看 Zep/Graphiti 或传统图数据库方案。


四、Mem0 的召回链路

召回链路总览:Mem0 怎么“想起来”?

记忆系统最难的不是存,而是召回。

因为长期记忆会越来越多,里面会有旧信息、相似信息、冲突信息、不同 session 的信息、不同用户的信息。真正的问题是:当前这一刻,哪几条记忆最应该进入上下文?

Mem0 的召回链路可以这样理解:

Mem0 召回链路:从 query 到 top memories
召回不是单次向量搜索,而是 scope、候选检索、多信号加权和最终排序的组合。
用户当前 query
Scope Filter
user_id / agent_id / app_id / run_id
Query 预处理
embedding / keyword / entity / time
进入多信号召回与排序
语义向量检索
找意思接近的 memories
BM25 关键词
强化专有名词、项目名、日期等精确命中
实体匹配
强化和 query 中实体相连的 memories
时间推理
处理 now、last week、as of 等时间表达
Memory Decay
近期常用记忆增强,长期不用记忆轻微降权
Rerank
对候选结果做更精细的二次排序
score fusion + threshold + top_k
返回 top memories
LLM 上下文
当前输入 + 召回记忆 + 系统指令

这条链路里,每一步都在减少错误召回的概率。


第一步:先确定搜索边界,而不是全局乱搜

记忆召回首先要解决隔离问题。

如果一个系统里有多个用户、多个 Agent、多个应用、多个 session,搜索时不能直接全局检索。否则很容易出现“串记忆”。

Mem0 用这些字段来划分记忆空间:

字段作用例子
user_id某个用户的长期记忆用户偏好、历史行为
agent_id某个 Agent 的记忆旅行助手、客服助手、学习助手
app_id某个应用或租户白标应用、不同产品线
run_id某次任务或会话一张客服工单、一次旅行规划

所以一个典型 search 应该像这样:

client.search(
    query="用户有什么饮食禁忌?",
    filters={"user_id": "alice"}
)

这一层不是锦上添花,而是安全底线。

我建议以后拆所有 memory 系统时,都先问:

它的记忆隔离模型是什么?
按用户隔离,还是按会话隔离?
多 Agent 共享记忆时怎么防止串上下文?

没有 scope 的记忆系统,很难进入生产。


第二步:语义检索,解决“意思相近”

语义检索是最基础的一层。

query 会被转成 embedding,然后和 memory embedding 做相似度匹配。

适合的问题是:

用户喜欢什么类型的电影?
用户对旅行有什么偏好?
之前这个项目有哪些背景?
用户对远程办公怎么看?

这类问题不一定有精确关键词,但语义上可以匹配。

不过,语义检索不是万能的。它常见的问题是:

专有名词可能召回不稳
订单号、会议名、项目名可能被弱化
时间问题容易混淆
实体关系不够清晰
相似但不相关的内容可能被召回

所以 Mem0 后面又叠了关键词、实体和时间信号。


第三步:BM25,解决“精确词命中”

有些查询不是语义问题,而是关键词问题。

比如:

Q1 roadmap
Alice
invoice-38291
San Francisco
March 10

这些词对用户来说非常关键,但在向量空间里不一定有足够稳定的表达。BM25 的价值就是让这些关键词能影响排序。

所以 Mem0 的召回不是只看:

这条 memory 和 query 意思像不像?

还要看:

这条 memory 有没有命中 query 里的关键字?

不过 Mem0 文档里有一个细节值得记住:在 OSS v3 的说明中,BM25 更像是 boost signal,不一定是独立扩展候选池。也就是说,它主要提高相关候选的排序,而不是完全替代向量召回。

这说明 Mem0 的多信号召回更像:

先通过语义找到候选
再用关键词和实体信号调整排序

第四步:实体匹配,解决“和谁有关”

实体匹配是 Mem0 召回链路中最值得关注的一层。

用户问:

Alice 相关的项目有哪些?

系统会从 query 中识别实体:

Alice

然后去 Entity Store 中找 Alice,找到和 Alice 连接的 memories,并给它们加权。

流程大概是:

实体匹配如何影响召回排序
当 query 中出现 Alice、Acme、Q1 路线图这类实体时,Mem0 会用实体连接给相关 memories 加权。
query
Alice 相关项目有哪些?
实体
Alice
Entity Store
Alice 连接的 memories
排序加权
Memory A、Memory B 排名上升

这类能力对长期记忆很重要。因为真实问题经常围绕实体展开:某个人、某家公司、某个项目、某个地点、某个概念。

向量检索能找到语义类似的内容,但实体匹配能帮助系统找到“围绕同一对象分散在不同对话里的记忆”。


第五步:时间推理,解决“什么时候为真”

长期记忆系统一定会遇到时间问题。

用户的偏好会变,住址会变,工作会变,项目状态会变。

以前住在纽约,现在住在旧金山。
以前喜欢咖啡,现在戒咖啡了。
上个月在做 A 项目,现在转到 B 项目。

所以召回时不能只问:

哪条 memory 最像 query?

还要问:

这条 memory 在时间上是否适合当前问题?

Mem0 Platform v3 的 Temporal Reasoning 处理的就是这类问题:

last week
next month
right now
currently
as of March 2025
since when
upcoming

比如:

用户问:我现在住在哪里?

系统应该更偏向:

用户 2026 年搬到了旧金山。

而不是:

用户 2025 年住在纽约。

但如果用户问:

我搬家之前住在哪里?

旧记忆又应该被召回。

这就是为什么 ADD-only 和时间推理要放在一起理解:ADD-only 保留历史,Temporal Reasoning 决定在当前问题下哪段历史更相关。


第六步:Memory Decay,解决旧记忆污染

长期记忆还有一个问题:旧记忆会越来越多。

有些旧记忆仍然重要,比如过敏信息;有些旧记忆只是临时信息,比如上季度的项目名称。如果所有记忆永远平等,旧信息就会污染召回。

Mem0 的 Memory Decay 可以理解成一种搜索时的轻量排序偏置:

刚被召回过的记忆 → 得到轻微增强
长期没被触达的记忆 → 得到轻微降权

注意,它不是删除,也不是硬过滤。

Memory Decay:旧记忆不是删除,而是温和降权
Decay 是搜索时的 soft ranking bias,让最近常用的记忆更容易浮现,但不把旧记忆硬过滤掉。
原始相关性分数
semantic / BM25 / entity 等信号融合后的候选分数
Decay Factor
近期访问增强,长期未触达轻微降权
最终排序
改变相近候选的顺序,但不直接删除候选

这很像人类记忆:我们不是彻底忘掉过去,而是最近频繁使用的信息更容易浮现。

不过 decay 不能太强。因为低频信息不代表不重要,比如医疗过敏、法律约束、安全偏好。一个好的 memory decay 应该是“温和影响排序”,而不是决定生死。


第七步:Criteria Retrieval,让“相关性”变成业务定义

Mem0 还有一个高级能力叫 Criteria Retrieval。它的核心思想是:有些应用里,“相关”不只是语义相似。

比如一个心理健康助手,可能更想优先召回带有情绪信号的记忆;一个学习助手可能更关心“好奇心”和“挫败感”;一个客服 Agent 可能更关心“紧急程度”和“风险”。

也就是说,普通检索问的是:

这条 memory 和 query 有多像?

Criteria Retrieval 问的是:

这条 memory 是否符合我这个应用定义的重要性?

可以把它理解成业务层的 relevance shaping。

这说明记忆召回最后一定会走向业务定制。因为不同 Agent 对“重要记忆”的定义不一样。


第八步:Rerank,解决 top 结果顺序

前面的语义、关键词、实体、时间、衰减都可以产生一个综合分数。但在一些高风险或高体验要求的场景里,还需要 rerank。

Rerank 的作用是把候选结果重新排序,让最应该进入上下文的 memory 排在前面。

适合开启 rerank 的场景:

用户只能看到少量结果
第 1 条结果的质量非常关键
医疗、客服、付费用户体验等高精度场景
复杂 query 需要更强语义判断

不适合无脑开启的原因也很简单:它会增加延迟。

所以 rerank 应该是一种按场景打开的精度增强,而不是默认万能药。


最终:记忆如何进入 LLM 上下文

召回不是终点。召回出来的 memories 最终要进入 LLM 的上下文。

一个常见结构是:

系统指令:
你是一个有长期记忆的助手。以下是和当前用户相关的历史记忆。

用户记忆:
- 用户不喜欢惊悚片。
- 用户偏好科幻电影。
- 用户下个月计划去东京。
- 用户不吃贝类。

当前用户输入:
今晚有什么推荐?

这一步看起来简单,但也有几个问题:

召回多少条?
按什么顺序放?
是否区分事实、偏好、计划和历史事件?
是否告诉模型这些记忆可能过时?
是否允许模型基于记忆主动提问确认?

记忆注入的质量会直接影响回答质量。召回太少,模型缺上下文;召回太多,模型会被噪音干扰。

所以长期记忆的目标不是“召回尽可能多”,而是“召回刚好够用”。


五、用一张总图理解 Mem0

把写入和召回放在一起,Mem0 的整体链路可以画成这样:

Mem0 端到端闭环
长期记忆系统是一个循环:对话产生记忆,记忆影响未来对话,未来对话继续产生新记忆。
输入与生成
用户输入
应用 / Agent
组织任务、调用 Mem0 和 LLM
LLM
当前输入 + 召回记忆 → 回答
Mem0 记忆层
召回链路
scope、semantic、BM25、entity、time、decay、rerank
写入链路
extract、ADD-only、embed、dedupe、entity link
统一排序问题
当前这一刻,哪几条 memory 最应该进入上下文?
存储层
Vector Store
memory + embedding + metadata
Entity Store
实体 + memory 连接
History Store
事件 + 审计 + 上下文

这张图里最重要的是:Mem0 不是单一检索器,而是一条闭环。

对话产生记忆
记忆影响未来对话
未来对话继续产生新记忆

这就是 Agent 长期记忆的基本循环。


六、我对 Mem0 的初步判断

我现在对 Mem0 的理解是:它不是一个“记忆数据库”,而是一个记忆排序系统

它真正解决的是:

在大量、分散、跨时间、跨实体、可能过时的记忆里,
为当前 query 找出最应该进入上下文的几条。

它的优点是工程化程度很高,几乎把生产环境里会遇到的问题都拆成了对应模块:

多用户隔离        → Entity-Scoped Memory
语义召回          → Vector Search
关键词命中        → BM25
实体相关          → Graph Memory / Entity Linking
时间变化          → Temporal Reasoning
旧记忆污染        → Memory Decay
业务重要性        → Criteria Retrieval
高精度排序        → Rerank

它的局限也很清楚:

第一,Graph Memory 更像实体增强检索,不是完整知识图谱。

第二,ADD-only 会让 memory 增长,后续必须依赖排序、衰减和清理策略。

第三,官方 benchmark 很有参考价值,但真正上线前仍然要在自己的业务数据上评估。

第四,隐私、同意、可见性、错误记忆纠正,这些治理问题不是接入 Mem0 就自动解决,应用层仍然要认真设计。

所以我对它的定位是:

Mem0 很适合作为学习 Agent Memory 工程化的第一个样本。它展示了现代长期记忆系统应该有哪些模块,但它不是所有记忆问题的最终答案。


七、以后拆其他记忆系统,可以沿用这套问题

这篇是系列第一篇。后面不管研究 Zep、Letta、LangGraph 还是 Cognee,我都会尽量用同一套问题拆:

1. 它怎么写入记忆?
   原始对话、摘要、事实抽取,还是结构化事件?

2. 它怎么存储记忆?
   向量库、全文索引、图数据库、SQL、对象存储?

3. 它怎么划分记忆边界?
   user、agent、session、app、organization?

4. 它怎么召回?
   向量、BM25、图遍历、实体匹配、时间推理、工具调用?

5. 它怎么排序?
   score fusion、rerank、decay、recency、业务规则?

6. 它怎么处理变化?
   update、delete、ADD-only、时间版本、事实失效?

7. 它怎么把记忆交给模型?
   自动注入、工具调用、上下文块、prompt 模板?

8. 它有什么治理能力?
   可见、可删、可审计、可纠错、权限隔离?

如果用这套框架看 Mem0,可以得到一句总结:

Mem0 的核心是:写入时把对话蒸馏成事实,存储时建立语义和实体索引,召回时融合语义、关键词、实体、时间、衰减和业务信号,再把最相关的记忆注入上下文。

这也是我理解 Agent Memory 的第一块拼图。


参考资料

评论

目录

Agent 记忆系统学习笔记(一):从 Mem0 看懂记忆与召回链路 | Yu的赛博工位