ReMe vs Mem0 源码对比:两种 AI 记忆管理方案的架构差异
导读:ReMe 和 Mem0 是当前开源社区中两个代表性的 AI 记忆管理框架。ReMe 由 AgentScope 团队开发,聚焦于 Agent 的上下文管理和文件化工作记忆;Mem0(“mem-zero”)由 Y Combinator S24 孵化,定位为 AI 应用的"记忆层",主打用户画像和个性化交互。本文从源码层面对比两者的架构设计,帮助开发者理解它们的定位差异,以便在自己的 Agent 应用中做出合适的技术选型。
一、定位与设计哲学
在深入源码之前,先明确两者的定位差异——这是理解后续所有架构差异的根源。
| 维度 | ReMe | Mem0 |
|---|---|---|
| 一句话定位 | Agent 的上下文管理 + 工作记忆框架 | AI 应用的个性化记忆层 |
| 核心问题 | “对话太长,上下文溢出了怎么办?” | “如何记住用户的偏好和事实?” |
| 记忆来源 | 对话流中自动提取(压缩副产品) | 开发者显式调用 memory.add() |
| 记忆粒度 | 文件级(Markdown 文档) | 事实级(一条条独立的 fact) |
| 架构风格 | 框架型(继承、Hook、可选子系统) | 服务型(API 调用、托管平台) |
| 开源协议 | Apache 2.0 | Apache 2.0 |
| 背景 | AgentScope 团队 | Y Combinator S24 |
ReMe 的哲学:记忆是上下文管理的副产品——对话太长需要压缩,压缩产生的摘要顺便持久化为记忆。记忆的生命周期与对话的生命周期紧密耦合。
Mem0 的哲学:记忆是独立于对话的一等公民——每次交互后主动提取事实,存入独立的记忆库,下次交互前检索出来注入上下文。记忆的生命周期独立于任何具体对话。
二、记忆的写入流程
Mem0:Extract → Search → Decide → Store
Mem0 的记忆写入是一个两阶段 LLM 调用的流程:
# 开发者显式调用 memory.add(messages, user_id="user_123")内部流程:
第一次 LLM 调用:事实提取 输入:对话消息 输出:{"facts": ["Name is John", "Is a Software engineer"]} ↓ 对每个 fact 做向量检索,找到相关的已有记忆 ↓ 第二次 LLM 调用:记忆决策 输入:新 facts + 已有记忆 输出:对每条记忆执行 ADD / UPDATE / DELETE / NONE ↓ 执行操作:写入向量数据库 + 记录变更历史到 SQLite 核心源码(Memory._add_to_vector_store()):
# 第一阶段:LLM 提取事实 system_prompt, user_prompt = get_fact_retrieval_messages(parsed_messages) response = self.llm.generate_response( messages=[{"role":"system","content": system_prompt},{"role":"user","content": user_prompt},], response_format={"type":"json_object"},) new_retrieved_facts = json.loads(response)["facts"]# 对每个新 fact,检索已有记忆for new_mem in new_retrieved_facts: messages_embeddings = self.embedding_model.embed(new_mem,"add") existing_memories = self.vector_store.search( query=new_mem, vectors=messages_embeddings, limit=5, filters=search_filters,)# 第二阶段:LLM 决定 ADD/UPDATE/DELETE/NONE function_calling_prompt = get_update_memory_messages( retrieved_old_memory, new_retrieved_facts ) response = self.llm.generate_response( messages=[{"role":"user","content": function_calling_prompt}], response_format={"type":"json_object"},)# 解析 response,执行 ADD/UPDATE/DELETE 操作ReMe:Compress → Summarize → Write File
ReMe 的记忆写入是上下文压缩的副产品:
上下文 token 超限 ↓ FbCompactor:压缩上下文(生成摘要替代原始消息) ↓ ↓ _compressed_summary(滚动更新) FbSummarizer:异步持久化 ↓ LLM 按 prompt 指令写入 memory/YYYY-MM-DD.md ↓ FileWatcher 检测变化 → 更新向量索引 核心特点:
- 记忆写入是被动触发的(token 超限时)
- 写入目标是 Markdown 文件(非结构化)
- 向量索引由 FileWatcher 异步更新
关键差异
| 维度 | Mem0 | ReMe |
|---|---|---|
| 触发方式 | 开发者显式调用 memory.add() | 上下文溢出时自动触发 |
| LLM 调用次数 | 2 次(提取 + 决策) | 1 次(压缩/持久化共用) |
| 写入目标 | 向量数据库(结构化 payload) | Markdown 文件 → FileWatcher → 向量索引 |
| 记忆格式 | 独立的 fact 字符串 | 按日期组织的文档段落 |
| 去重策略 | LLM 判断 ADD/UPDATE/DELETE | 依赖 FbSummarizer prompt 中的"智能合并"指令 |
三、记忆的存储结构
Mem0:向量数据库 + SQLite 变更历史
Mem0 的每条记忆存储为向量数据库中的一条记录:
# 向量数据库中的一条记忆{"id":"uuid-xxx","vector":[0.1,0.2,...],# Embedding 向量"payload":{"data":"Name is John",# 记忆内容(一条 fact)"user_id":"user_123",# 所属用户"agent_id":None,# 或所属 Agent"hash":"abc123",# 内容哈希(用于去重)"created_at":"2025-02-12T...","updated_at":"2025-02-12T...",}}同时在 SQLite 中维护变更历史:
CREATETABLE history ( id TEXTPRIMARYKEY, memory_id TEXT,-- 关联到向量数据库的 ID old_memory TEXT,-- 修改前的内容 new_memory TEXT,-- 修改后的内容 event TEXT,-- ADD / UPDATE / DELETE created_at DATETIME, updated_at DATETIME, is_deleted INTEGER, actor_id TEXT,-- 来源标识 role TEXT);这意味着 Mem0 可以追踪每条记忆的完整变更历史——什么时候加的、改过几次、每次改了什么。
ReMe:Markdown 文件 + 向量索引
ReMe 的记忆存储在纯 Markdown 文件中:
working_dir/ MEMORY.md ← 长期记忆(用户/Agent 手动维护) memory/ 2025-02-12.md ← 每日日志(自动 + 手动) 2025-02-13.md 向量索引由 FileWatcher 自动维护——文件一改,自动切 chunk、embedding、写入向量数据库。
关键差异
| 维度 | Mem0 | ReMe |
|---|---|---|
| 存储介质 | 向量数据库(Qdrant/Chroma/Pinecone 等 25+ 种) | Markdown 文件 + 可配置向量存储 |
| 记忆单元 | 一条 fact = 向量数据库一条记录 | 一个文件 = 多个 chunk = 多条向量记录 |
| 变更追踪 | SQLite 完整变更历史 | 无(文件被覆盖就丢失旧版本) |
| 人可读性 | 需要通过 API 查看 | 直接打开 Markdown 文件 |
| 可编辑性 | 需通过 memory.update() API | 直接编辑文件,FileWatcher 自动同步 |
四、记忆的检索方式
Mem0:向量检索 + 可选 Reranker + 知识图谱
results = memory.search(query="项目语言", user_id="user_123", limit=5)内部流程:
查询 → Embedding → 向量数据库检索(带 metadata 过滤) ↓ 可选:Reranker 重排序 ↓ 可选:知识图谱实体检索(Neo4j/Kuzu) ↓ 合并返回结果 Mem0 的检索特点:
- 支持
user_id、agent_id、run_id三维度的 metadata 过滤 - 支持 Reranker(Cohere、Jina 等)对结果重排序
- 支持 知识图谱(Neo4j、Kuzu、Memgraph)做实体关系检索
- 支持丰富的过滤操作符(
eq、ne、in、gt、contains、AND/OR/NOT)
ReMe:向量 + BM25 混合检索
results = memory_search(query="项目语言", max_results=5, min_score=0.1)内部流程:
查询 → 向量语义搜索(权重 0.7) → BM25 全文检索(权重 0.3) ↓ 按 chunk 去重 + 加权融合 + 排序截断 ↓ 返回 top-N 结果 ReMe 的检索特点:
- 向量 + BM25 混合检索是核心差异——BM25 对精确 token 命中效果极好(如函数名、错误码)
- 无 Reranker,但通过加权融合实现类似效果
- 无知识图谱,纯文本检索
关键差异
| 维度 | Mem0 | ReMe |
|---|---|---|
| 检索方式 | 纯向量 + 可选 Reranker | 向量 + BM25 混合 |
| 知识图谱 | 支持(Neo4j/Kuzu/Memgraph) | 不支持 |
| 过滤能力 | 丰富(多操作符、逻辑组合) | 基础(按文件路径/来源) |
| 精确匹配 | 依赖向量语义相似度 | BM25 擅长精确 token 匹配 |
| 多用户隔离 | 原生支持(user_id/agent_id/run_id) | 通过文件目录隔离 |
五、记忆的去重与更新
Mem0:LLM 驱动的四操作决策
Mem0 的去重是其架构中最精巧的部分。每次 add() 时:
- LLM 提取新 facts
- 对每个 fact 做向量检索,找到相关的已有记忆
- 将新 facts + 已有记忆一起发给 LLM,让 LLM 判断每条应该 ADD / UPDATE / DELETE / NONE
已有记忆:["I really like cheese pizza", "User likes to play cricket"] 新 facts:["Loves chicken pizza", "Loves to play cricket with friends"] ↓ LLM 决策 结果: "cheese pizza" → UPDATE 为 "Loves cheese and chicken pizza" "play cricket" → UPDATE 为 "Loves to play cricket with friends" 这种方式的优势是语义级去重——LLM 能理解"cheese pizza"和"chicken pizza"应该合并而非新增。
ReMe:Prompt 指令驱动的文件合并
ReMe 的 FbSummarizer 通过 prompt 指令实现去重:
工作流程: 1. 先 read memory/YYYY-MM-DD.md 2. 智能合并新信息与现有内容: - 避免重复已记录的信息 - 在相关时丰富现有条目的新细节 - 在适用时保持时间顺序 3. 写入更新后的内容 去重的质量完全依赖 LLM 对 prompt 的遵循程度,没有 Mem0 那样的结构化检索 + 决策流程。
ReMe(ReMe 类):Draft-Retrieve-Deduplicate
ReMe 的 ReMe 类(CoPaw 未使用的长期记忆子系统)有更精细的去重机制:
- Draft:LLM 生成候选记忆
- Retrieve:在向量数据库中检索相似记忆
- Deduplicate:LLM 判断是否重复,决定合并或丢弃
这与 Mem0 的流程非常相似,但 ReMe 的 ReMeFb 子系统(更常用)没有这套机制。
六、记忆的层级与分类
Mem0:三维度记忆空间
Mem0 通过 user_id、agent_id、run_id 三个维度组织记忆:
# 用户级记忆(跨 session 持久) memory.add("I prefer Python", user_id="user_123")# Agent 级记忆(Agent 自身的学习) memory.add(messages, agent_id="agent_456")# 运行级记忆(单次 run 内有效) memory.add("Current task is data cleaning", run_id="run_789")# Procedural 记忆(Agent 的行为模式) memory.add(messages, agent_id="agent_456", memory_type="procedural_memory")此外,Mem0 支持知识图谱存储实体关系:
User --[likes]--> Python User --[works_at]--> Google Python --[is_a]--> Programming Language ReMe:两套独立子系统
ReMe 项目 | |-- ReMe 类(向量化长期记忆) | |-- PersonalSummarizer 个人记忆 | |-- ProceduralSummarizer 程序性记忆 | |-- ToolSummarizer 工具记忆 | |-- ReMeFb 类(文件化工作记忆) |-- MEMORY.md 长期事实 |-- memory/*.md 每日日志 ReMe 的 ReMe 类支持四种记忆类型(personal / procedural / tool / task),由 DelegateTask 自动路由。但实践中更常用的 ReMeFb 类不区分类型,统一按文件组织。
七、上下文管理能力
这是两者最根本的差异所在。
Mem0:不管理上下文
Mem0 不参与上下文窗口的管理。它只负责"记住"和"想起",至于上下文 token 超限的问题需要开发者自行处理:
# Mem0 的典型用法——开发者自己管理上下文defchat_with_memories(message, user_id):# 1. 检索记忆 relevant_memories = memory.search(query=message, user_id=user_id, limit=3)# 2. 手动注入上下文 system_prompt =f"User Memories:\n{memories_str}"# 3. 调用 LLM(上下文管理完全由开发者负责) response = openai_client.chat.completions.create(...)# 4. 保存新记忆 memory.add(messages, user_id=user_id)ReMe:上下文管理是核心
ReMe 的核心能力就是上下文管理——自动检测 token 超限、自动压缩、自动持久化:
每次 LLM 推理前(pre_reasoning Hook) ↓ FbContextChecker 检测 token 是否超限 ↓ 超限 FbCompactor 压缩上下文 ↓ 同时 FbSummarizer 异步写入 memory/*.md 关键差异
| 维度 | Mem0 | ReMe |
|---|---|---|
| 上下文压缩 | ❌ 不支持 | ✅ 核心能力 |
| 自动触发 | ❌ 需手动调用 add/search | ✅ Hook 自动触发 |
| 与 Agent 耦合度 | 低(独立服务) | 高(继承/Hook 集成) |
八、LLM 与 Embedding 管理
Mem0:自管理所有模型
Mem0 内置了完整的 LLM 和 Embedding 管理:
- LLM:OpenAI、Anthropic、Gemini、DeepSeek、Groq、Ollama、vLLM 等 18 种
- Embedding:OpenAI、Azure、Gemini、HuggingFace、Ollama、FastEmbed 等 14 种
- Reranker:Cohere、Jina 等
config = MemoryConfig( llm=LlmConfig(provider="openai", config={"model":"gpt-4o-mini"}), embedder=EmbedderConfig(provider="openai"), vector_store=VectorStoreConfig(provider="qdrant"),) memory = Memory(config=config)ReMe:支持外部 LLM 委托
ReMe 同样内置 LLM 管理,但其架构允许外部委托——如 CoPaw 通过 return_prompt=True 绕过 ReMe 的 LLM,只使用其 Embedding。这种灵活性是 Mem0 不具备的。
九、向量存储生态
| 后端 | Mem0 | ReMe |
|---|---|---|
| Qdrant | ✅ | ✅ |
| ChromaDB | ✅ | ✅ |
| Elasticsearch | ✅ | ✅ |
| FAISS | ✅ | ❌ |
| Pinecone | ✅ | ❌ |
| Milvus | ✅ | ❌ |
| pgvector | ✅ | ❌ |
| MongoDB Atlas | ✅ | ❌ |
| Redis | ✅ | ❌ |
| Weaviate | ✅ | ❌ |
| Supabase | ✅ | ❌ |
| SQLite(本地) | ❌ | ✅ |
| JSONL(本地) | ❌ | ✅ |
Mem0 在向量存储生态上占据明显优势(25+ 种后端),这与其"服务化"定位一致——适合部署在各种云环境。ReMe 的后端较少但包含轻量级本地选项(JSONL、SQLite),更适合桌面/边缘场景。
十、集成方式与侵入性
Mem0:零侵入的 API 调用
from mem0 import Memory memory = Memory()# 完全解耦——在任何框架中都能用 memory.add("User prefers dark mode", user_id="user_123") results = memory.search("UI preferences", user_id="user_123")Mem0 与应用完全解耦,通过 API 调用即可集成,不需要修改现有的 Agent 架构。
ReMe:深度集成的框架模式
from reme import ReMeFb classMemoryManager(ReMeFb):# 继承 ReMeFb 获得全部能力def__init__(self,...):super().__init__( llm_api_key="",# 可选:绕过 ReMe 的 LLM embedding_api_key=key,# 委托 Embedding 给 ReMe...)# 通过 Hook 集成 agent.register_hook("pre_reasoning", MemoryCompactionHook(...))ReMe 的集成需要继承和 Hook 注入,侵入性更强但功能更深入。
十一、适用场景对比
| 场景 | 推荐方案 | 原因 |
|---|---|---|
| 多用户 SaaS 产品 | Mem0 | 原生多用户隔离,丰富的云存储后端 |
| 单用户 AI 助理 | ReMe (ReMeFb) | 自动上下文管理,文件化记忆透明可控 |
| 客服/销售 Agent | Mem0 | 用户画像积累,跨 session 个性化 |
| 开发者 Copilot | ReMe (ReMeFb) | 长对话压缩是刚需,代码记忆需要 BM25 精确匹配 |
| 需要知识图谱 | Mem0 | 原生 Neo4j/Kuzu 支持 |
| 桌面/边缘部署 | ReMe | JSONL/SQLite 本地存储,无需云服务 |
| 已有 Agent 框架 | Mem0 | API 调用零侵入,不改架构 |
| 从零搭建 Agent | ReMe | 框架级集成更深入,上下文管理自动化 |
十二、总结
ReMe 和 Mem0 解决的是 AI 记忆管理的不同侧面:
上下文管理 用户画像 (对话压缩) (事实提取) ↑ ↑ | | ReMe Mem0 | | ↓ ↓ 文件化工作记忆 结构化向量记忆 (Markdown + FileWatcher) (向量数据库 + 变更历史) - ReMe 更像一个操作系统级的内存管理器——自动检测、自动压缩、自动持久化,深度嵌入 Agent 的运行时
- Mem0 更像一个独立的记忆数据库服务——提供 CRUD API,让任何应用都能快速接入记忆能力
两者并非互斥。一个理想的 Agent 系统完全可以同时使用 ReMe 管理上下文(防止 token 溢出),用 Mem0 管理用户画像(跨 session 个性化)——它们工作在记忆管理的不同层级,天然互补。
相关链接:
- ReMe GitHub:https://github.com/agentscope-ai/ReMe
- Mem0 GitHub:https://github.com/mem0ai/mem0
- Mem0 官网说明:https://mem0.ai/research