乐于分享
好东西不私藏

给 AI 装上记忆:Mem0 源码级拆解

给 AI 装上记忆:Mem0 源码级拆解

每次对话都从零开始的 AI,不是真正的助手。这篇文章拆解 Mem0 如何用一层”记忆中间件”解决 LLM 的失忆症——从架构设计到核心算法,从源码实现到生产选型。


一个反直觉的事实

主流 LLM 的上下文窗口已经长到 128K 甚至 1M token。按理说,”记忆”应该不再是问题——把所有历史对话塞进 Context Window 不就行了?

但事实是:更长的上下文窗口不但没有解决记忆问题,反而让问题暴露得更加彻底。

三个层面:

  1. 成本问题。把过去 30 天的对话记录全塞进去,每次请求消耗 50K+ token 的 input。粗略估算:按 GPT-4o 的定价($2.5/M input),日活 1 万用户、每人 3 次交互,光 input 就烧 $3750/天——还没算 output。实际情况更糟,因为同一用户的多轮交互中上下文会累积,后面几轮的 token 消耗远高于第一轮。

  2. 性能问题。上下文越长,模型的注意力越分散。早期研究(Liu et al., 2023)表明,当有用信息处于长上下文的中间位置时,模型的召回率会显著下降——这就是著名的 “Lost in the Middle” 问题。虽然 2025-2026 年的新模型已经大幅缓解了这个现象,但核心矛盾仍在:Context Window 越大,信噪比越低。把 30 天的对话全塞进去,真正相关的可能只有几百 token。

  3. 根本性问题。LLM 是无状态的。每次 API 调用都是一次独立事件——模型处理完请求就”失忆”了。Context Window 只是一个临时的”工作台”,不是永久存储。真正的记忆需要的是:跨会话持久化 + 智能检索 + 自动去重更新

这正是 Mem0 要解决的问题。


Mem0 是什么

Mem0(读作 “mem-zero”)是一个开源的 AI 记忆层——它不是一个向量数据库,也不是一个 RAG 框架,而是夹在你的应用和 LLM 之间的一层”记忆中间件”。

顺便说一下它和 RAG 的区别:RAG 是”检索预先准备好的文档来增强生成”,Mem0 是”从实时产生的对话中自动提取事实来增强记忆”。RAG 的知识源是静态的,Mem0 的知识源是动态的——每次对话都可能产生新的记忆。

用一句话概括它的核心设计思想:

把非结构化的对话流,自动蒸馏为结构化的事实片段,存进多级存储,按需精准召回。

GitHub 上 54K+ Stars,300+ 个发版,Y Combinator 孵化——这些数字说明它不是玩具项目。但比数字更值得关注的是它的架构选择。我们来拆。


架构全景:三层架构

Mem0 的架构是一个干净的三层结构:

┌─────────────────────────────────────────────┐
│              Client Layer                    │
│  Python SDK · TypeScript SDK · REST API · CLI│
├─────────────────────────────────────────────┤
│           Core Memory System                 │
│  Memory 类 · 事实提取 · 去重 · 动作决策       │
│  Factory Pattern → LLM / Embedder / Store    │
├─────────────────────────────────────────────┤
│           Storage Backends                   │
│  Vector Store · Graph DB · SQLite (History)  │
└─────────────────────────────────────────────┘

第一层:Client Layer

提供多种接入方式。自托管用 Memory 类,云平台用 MemoryClient,还有 CLI 工具可以在终端直接操作记忆:

npm install -g @mem0/cli
mem0 add "偏好暗色模式和 Vim 键位" --user-id alice
mem0 search "Alice 的偏好是什么?" --user-id alice

第二层:Core Memory System

这是 Mem0 的大脑。核心是 Memory 类(mem0/memory/main.py),它通过 工厂模式 动态组装组件:

# 工厂模式:一个 config 搞定所有组件
memory = Memory.from_config({
"llm": {"provider""openai""config": {"model""gpt-4o-mini"}},
"embedder": {"provider""openai""config": {"model""text-embedding-3-small"}},
"vector_store": {"provider""qdrant""config": {"host""localhost""port"6333}},
})

这里的设计哲学很明确:关注点分离。LLM、Embedding 模型、向量数据库——每个环节都可以独立替换。支持 18+ LLM 提供商、11+ Embedding 提供商、24+ 向量数据库。你可以用 Ollama 跑本地模型 + Qdrant 做存储,完全不依赖外部 API。

第三层:Storage Backends

Mem0 不只用一种存储——它用三种

存储类型
作用
默认实现
Vector Store
存储事实的语义向量,用于相似度检索
Qdrant(本地磁盘模式)
Graph Store
存储实体和关系(如 用户 -- 喜欢 --> Python),做关系推理
Neo4j / FalkorDB(可选,需单独配置)
SQLite
存储记忆的元数据、原始文本、变更历史
SQLiteManager

为什么需要三种?因为不同类型的”记忆”适合不同的存储和检索方式:

  • “用户喜欢深色模式” → 语义向量,适合模糊匹配

  • “用户 Alice 在公司 X 工作” → 知识图谱,适合关系推理

  • “这条记忆在 3 天前从’素食主义者’更新为’纯素主义者’” → 关系型存储,适合审计追溯


核心算法:单轮提取 + 智能决策

这是 Mem0 最值得拆解的部分。2026 年 4 月发布的新记忆算法(官方称 New Memory Algorithm,本文简称 v3)做了一个关键改变:事实提取从多轮 LLM 调用简化为单轮 ADD-only 提取,再配合一轮独立的动作决策——官方称相比上一版算法,Token 效率提升约 3-4 倍(对比基线是 Mem0 自己的 v2 算法,而非全量上下文方案),同时准确率大幅提升。

记忆处理的完整流水线

当你调用 memory.add(messages, user_id="alice") 时,背后发生了什么?

用户对话
  → ① 消息解析        parse_messages()        归一化为字符串
  → ② LLM 事实提取    llm.generate_response()  提取结构化事实(ADD-only
  → ③ 相似度搜索      vector_store.search()    找到已有相似记忆
  → ④ 动作决策        llm.generate_response()  判断 ADD/UPDATE/DELETE/NONE
  → ⑤ 存储更新        写入 Vector Store + SQLite 审计记录

让我们逐步拆解。

Step 1: 事实提取(Fact Extraction)

输入一段对话:

用户: 我叫 Alex,最近从北京搬到了上海,在做量化交易相关的工作。
助手: 欢迎来到上海!量化交易是个很有意思的领域。

Mem0 用 LLM 从中提取结构化事实:

{
"facts":[
"用户名字是 Alex",
"用户最近从北京搬到了上海",
"用户从事量化交易相关工作"
]
}

v3 算法的关键改变:提取阶段只做 ADD,不做 UPDATE/DELETE。提取阶段只管“蒸馏事实”,不管“和已有记忆冲突了怎么办”——这个复杂逻辑交给后面的动作决策阶段。

为什么这样更好?旧算法在提取阶段就尝试判断 ADD/UPDATE/DELETE,导致提取和决策逻辑耦合。LLM 在一次调用中同时完成事实提取和冲突解决,容易出错(尤其是当已有记忆列表很长时)。拆成两步后,每步的 Prompt 更聚焦,LLM 的输出质量更高。这是典型的关注点分离在 Prompt Engineering 中的体现。

不过这个设计也带来一个开放问题:存储膨胀。提取阶段只做 ADD,意味着记忆会持续累积。虽然后续的动作决策阶段会通过 UPDATE 和 DELETE 清理过时信息,但它依赖于“新事实与旧记忆被相似度搜索命中”这个前提。如果一条旧记忆从未被新事实命中,它就会永远留在那里。生产环境中可能需要配合定期的记忆审计或 TTL 策略来控制增长——这一点我们在后面“遗忘曲线”部分会再展开。

另一个细节:Mem0 区分了用户记忆和 Agent 记忆。如果设置了 agent_id,系统会使用不同的提取 Prompt——Agent 确认的操作(“我已经帮你订了周五的会议室”)也会被记录为一等事实。

Step 2: 相似度搜索(Similarity Search)

提取出事实后,Mem0 把每条事实嵌入为向量,然后在向量数据库中搜索已有的相似记忆。

这一步是为了找到可能需要更新或去重的记忆。比如:

  • 新事实:“用户住在上海”

  • 已有记忆:“用户住在北京”

  • 相似度:0.92 → 可能是同一事实的更新版本

v3 算法引入了多信号检索——不只用语义相似度,而是三路并行:

  1. 语义检索(Semantic):基于向量余弦相似度

  2. 关键词检索(BM25):传统文本匹配,擅长捕捉专有名词

  3. 实体链接(Entity Linking):提取实体并跨记忆做链接

三路结果融合排序。这解决了纯语义检索的一个经典问题:比如用户说“帮我查一下 iPhone 15 的订单”,语义检索可能返回“用户对苹果产品感兴趣”(太泛),但 BM25 能精确命中包含“iPhone 15”的历史记忆。又比如在量化交易场景中搜索“MACD 指标”,BM25 能直接命中,而语义检索可能只返回“用户关注技术分析”。

要启用完整的混合检索,安装时需要带上 NLP 支持:

pip install mem0ai[nlp]
python -m spacy download en_core_web_sm

Step 3: 动作决策(Action Determination)

这是最精巧的部分。Mem0 把新提取的事实和检索到的已有记忆一起交给 LLM,让它决定每条事实该执行什么动作:

动作
含义
示例
ADD
全新的事实,直接写入
“用户养了一只猫叫 Muffin”
UPDATE
已有记忆需要更新
“用户住在北京” → “用户住在上海”
DELETE
已有记忆不再有效
“用户是素食主义者”(用户说”我不再吃素了”)
NONE
已有记忆仍然有效,无需操作
“用户名字是 Alex”(已存在完全相同的记忆)

这里有一个巧妙的工程细节:UUID 映射策略。真实的记忆 ID 是类似 f47ac10b-58cc-4372-a567-0e02b2c3d479 这样的 UUID,如果直接传给 LLM,容易出现幻觉(模型可能编造不存在的 UUID)。Mem0 的做法是把 UUID 映射成简单的整数(“0”、“1”、“2”),传给 LLM 做判断,拿到结果后再映射回真实 UUID。

这背后是一个更普遍的工程经验:不要让 LLM 处理它不擅长的事情。UUID 是结构化标识符,LLM 擅长语义理解,不擅长精确字符串匹配。用简单整数替代复杂 ID 是“扬长避短”的经典做法——这个思路在其他需要 LLM 处理结构化数据的场景中同样适用。

# 简化后的逻辑(mem0/memory/main.py)
uuid_mapping = {}
for idx, memory inenumerate(existing_memories):
    uuid_mapping[str(idx)] = memory.id# "0" -> "f47ac10b-..."

# LLM 返回: {"action": "UPDATE", "id": "0", "new_text": "用户住在上海"}
# 映射回: {"action": "UPDATE", "id": "f47ac10b-...", "new_text": "用户住在上海"}

Step 4: 执行动作

根据 LLM 的决策,执行对应的存储操作:

  • ADD:生成新向量,写入 Vector Store,在 SQLite 记录创建事件

  • UPDATE:用新文本重新生成向量,替换 Vector Store 中的旧记录,在 SQLite 记录更新事件(保留旧值用于审计)

  • DELETE:从 Vector Store 删除向量,在 SQLite 标记为已删除

  • NONE:更新 updated_at 时间戳(表示这条记忆仍然活跃)

每一步都在 SQLite 中留下审计记录——你可以追溯任何一条记忆的完整变更历史。


基准测试:数字与现实

v3 算法在三个公开基准上的表现:

基准
v3 得分
vs 上一版本
说明
LoCoMo
91.6
+20 pts
长对话记忆理解
LongMemEval
93.4
+26 pts
长期记忆评估(其中助手记忆召回 +53.6)
BEAM (1M)
64.1
百万 token 级生产规模评估

Mem0 团队开源了完整的评估框架(memory-benchmarks[1]),任何人都可以复现。

特别值得注意的是 LongMemEval 上助手记忆召回 +53.6 分的提升。这得益于 v3 算法将 Agent 生成的事实提升为”一等公民”——当 Agent 说”我已经帮你设置了每周三提醒”,这个信息也会被存入记忆,下次用户问”我设了什么提醒”时可以准确召回。

一个重要的 caveat:这些基准主要基于英文场景。在非英文环境、高噪声对话、或极端长上下文场景下,混合检索的召回质量、Graph Store 的维护成本、以及事实提取的准确率都可能有波动。把这些数字当作“上限”而非“保证”更稳妥。


10 分钟上手

说了这么多架构,来看看实际用起来有多简单:

from openai import OpenAI
from mem0 import Memory

openai_client = OpenAI()
memory = Memory()

defchat_with_memory(message: str, user_id: str = "default_user") -> str:
# 1. 检索相关记忆
    relevant = memory.search(query=message, filters={"user_id": user_id}, top_k=3)
    memories_str = "\n".join(f"- {m['memory']}"for m in relevant["results"])

# 2. 构造带记忆的 Prompt
    system_prompt = f"你是一个有记忆的 AI 助手。以下是关于用户的已知信息:\n{memories_str}"
    messages = [
        {"role""system""content": system_prompt},
        {"role""user""content": message}
    ]

# 3. 正常调用 LLM
    response = openai_client.chat.completions.create(
        model="gpt-4o-mini", messages=messages
    )
    assistant_reply = response.choices[0].message.content

# 4. 自动提取并存储新记忆
    messages.append({"role""assistant""content": assistant_reply})
    memory.add(messages, user_id=user_id)

return assistant_reply

就这么简单。memory.add() 会自动完成事实提取、去重、冲突解决。memory.search() 会做混合检索返回最相关的记忆。

实际成本估算:每次 add() 调用背后有 2 次 LLM 调用(事实提取 + 动作决策),加上 Embedding 调用。以 GPT-4o-mini 为例,一轮典型对话(5-10 条消息)的 add() 大约消耗 2000-4000 token input + 500-1000 token output,成本约 $0.001-0.003。如果用更大的模型(如 GPT-4o)做提取,成本会高 5-10 倍。search() 相对便宜,主要是 Embedding 调用的成本。选择什么模型做记忆提取,是成本和质量之间的权衡——默认的 gpt-4o-mini 对大多数场景够用。

你的代码几乎不需要改动——在已有的 LLM 调用前加一步 search,调用后加一步 add。这就是”记忆中间件”的设计优势。


多级记忆隔离

Mem0 的记忆不是一个大杂烩——它按四个维度做隔离:

# 用户级:每个用户有独立的记忆空间
memory.add("我喜欢暗色模式", user_id="alice")
memory.add("我喜欢浅色模式", user_id="bob")

# Agent 级:不同 Agent 可以有不同的"人设记忆"
memory.add("我是一个专注量化交易的助手", agent_id="quant_bot")

# 会话级:单次会话内的临时上下文
memory.add("用户正在调试一个 Python 脚本", run_id="session_123")

# 应用级:跨用户的全局知识
memory.add("公司的报销政策是...", app_id="hr_assistant")

这种隔离确保了:Alice 的偏好不会泄漏给 Bob,量化助手的人设不会污染客服助手,单次 debug 会话的上下文不会被长期保留。


横向对比:Mem0 vs Letta vs Zep

2026 年的 AI 记忆层赛道有三个主要选手,它们的设计哲学截然不同:

维度
Mem0
Letta (MemGPT)
Zep
定位
可插拔记忆服务层
有状态 Agent 运行时
时序知识图谱记忆层
类比
给车加一个外挂记忆仪
造一辆有记忆的车
给车加一个带时间线的记忆仪
集成成本
最低(几行代码)
最高(需要重构 Agent 架构)
中等
记忆模型
Vector + Graph + Relational
三层:核心/回忆/归档
时序知识图谱
核心优势
通用性强、生态最大
Agent 自管理记忆、长期连贯性
时序推理、审计追溯
适用场景
通用个性化、快速集成
长期自主 Agent
企业级时序推理

怎么选?

如果你已经有一个 Agent 框架(LangChain / LlamaIndex / CrewAI),想快速加上记忆能力 → Mem0。几行代码接入,不需要改架构。

如果你在从零构建一个需要长期运行的自主 Agent → Letta。它的 “LLM OS” 理念——Agent 像操作系统一样主动管理自己的记忆——适合需要 Agent 在数周或数月内保持连贯身份的场景。代价是要买入它的整个运行时。

如果你的应用需要”这个信息是什么时候变化的”这种时序推理 → Zep。它的 Graphiti 引擎用双时序模型(事件发生时间 vs 记录时间)追踪信息演变,在审计和合规场景下特别有用。

我的判断:大多数场景选 Mem0 不会错。它是三者中集成成本最低、社区最大、灵活性最高的方案。等你的需求复杂到 Mem0 满足不了的时候,你自然会知道该换什么。


生产部署:三种模式

Mem0 提供三种部署方式,适应不同阶段:

1. 库模式:本地开发和测试

pip install mem0ai

数据默认存在本地磁盘(Qdrant 嵌入式模式 + SQLite)。零运维,开箱即用。

2. 自托管模式:数据主权

cd server && make bootstrap
# 一条命令启动整个栈,创建管理员,签发 API Key
# 访问 http://localhost:3000 管理面板

Docker Compose 一键部署,数据完全在你的服务器上。适合对数据主权有要求的企业场景。v1.0 之后默认开启认证——生产环境必须设置 ADMIN_API_KEY

3. 云平台模式:零运维

注册 app.mem0.ai[2],获取 API Key,接入 SDK。Sub-50ms 检索延迟,自带 Dashboard 管理记忆和分析。

from mem0 import MemoryClient
client = MemoryClient(api_key="your-api-key")
client.add("用户喜欢暗色模式", user_id="alice")

选择建议:试水用库模式,团队开发用自托管,生产上量用云平台


超越”记住偏好”:一些值得思考的方向

Mem0 目前解决的核心问题是”记住用户说了什么”。但 AI 记忆的疆域远不止于此:

1. Agent 记忆 ≠ 用户记忆

v3 算法已经迈出了关键一步——Agent 确认的操作也被记录为事实。但更深层的问题是:Agent 能否从自己的错误中学习?

想象一个编程助手,它昨天帮你调试时走了弯路——先试了方案 A 失败了,最终用方案 B 解决了。如果这个”方案 A 不适用于这类问题”的经验能被记住,下次遇到类似问题就能直接跳过方案 A。

这需要的不只是”事实存储”,而是经验蒸馏——从具体的操作序列中提炼出可复用的策略。目前 Mem0 的 custom_fact_extraction_prompt 配置提供了定制化的入口,但这个方向还有很大的探索空间。

2. 记忆的遗忘曲线

人类的记忆有遗忘机制——不重要的信息会自然衰减。AI 记忆目前是”完美记忆”——一旦存入就永远存在。但在生产环境中,一个两年前的用户偏好可能已经过时了。

Mem0 的 updated_at 时间戳和变更历史为实现”记忆衰减”提供了基础设施,但目前还没有内置的衰减策略。这可能是一个有意义的扩展方向。

3. 记忆的可解释性

当你的 AI 助手说”根据我的了解,你偏好使用 Python 而不是 Java”——用户可能会问:“你是怎么知道的?”

Mem0 的 SQLite 历史记录可以回答这个问题:这条记忆来自于 2026-04-15 的一次对话,原文是”帮我用 Python 重写这个 Java 脚本,我更喜欢 Python 的语法”。这种可追溯性在企业场景中尤其重要。


写在最后

回到开头的问题:更长的 Context Window 能解决 AI 的记忆问题吗?

答案很清楚:不能。Context Window 是工作记忆(Working Memory),Mem0 提供的是长期记忆(Long-term Memory)。就像你不会把整个图书馆搬到办公桌上——你需要的是一个聪明的图书管理员,知道什么时候该把哪本书放到你桌上。

Mem0 的设计选择给了我们几个启发:

  1. “记忆中间件”是对的抽象层级。不要在 Agent 逻辑里硬编码记忆管理,把它拆出来作为独立的关注点。

  2. 用 LLM 管理记忆,而不只是存储记忆。Mem0 的核心竞争力不是向量数据库(那东西谁都有),而是 LLM 驱动的事实提取、去重和冲突解决。

  3. 多信号检索比纯语义检索靠谱得多。语义 + BM25 + 实体链接三路融合,是 v3 算法准确率大幅提升的关键。

如果你正在构建需要”记住用户”的 AI 应用,Mem0 值得认真看一看。


相关资源

  • 项目地址:github.com/mem0ai/mem0[3]

  • 论文:Mem0: Building Production-Ready AI Agents with Scalable Long-Term Memory[4](arXiv 2504.19413)

  • 文档:docs.mem0.ai[5]

  • 评估框架:github.com/mem0ai/memory-benchmarks[1]