五大开源Agent记忆系统横评:Mem0、Letta、Zep、Cognee实测对比

发布时间:2026/10/31 4:52:58
五大开源Agent记忆系统横评:Mem0、Letta、Zep、Cognee实测对比

今年我给自己的一个硬性目标,就是把市面上叫得出名字的开源 Agent 记忆系统全部拉下来,跑一遍真实业务场景。起因很直接:我做的几个 Agent 项目,单轮对话能力都不差,但一遇到跨天、跨会话的连续任务就露怯,用户两小时前说的偏好,换个 session 就忘得干干净净。这类问题不是调 prompt 能解决的,必须有专门的记忆层。

所谓"记忆系统",说白了就是一套让 Agent 在对话之外,还能持续保存、检索、更新"它知道的事情"的基础设施。现在开源社区里挂着"记忆"名头的项目不少,从 Mem0、Letta 到 Zep、Cognee,各家技术路线差得非常大,有走向量库的,有走知识图谱的,有把 LLM 当操作系统来管理的。但它们解决的问题是同一个:怎么让 Agent 既不超出上下文窗口限制,又能把该记住的东西记住。

这篇文章是我个人实测的完整记录,不是从 README 里抄参数,而是用一个统一的测试脚本,在相同的场景集上跑出来的结果对比。如果你正准备给自己的 Agent 引入记忆能力,或者在几个开源方案之间犹豫,这篇文章可以帮你省掉大量试错时间。我会从架构差异、检索能力、更新策略、工程成熟度几个维度分别拆,最后给出我的选型建议和踩坑清单。

1. 为什么 Agent 需要一套"记忆系统"

1.1 没有记忆的 Agent 是什么体验

很多人觉得 Agent 已经有了上下文窗口,为什么还需要单独的记忆系统?我的理解是:上下文窗口只是"短期工作台",不是"长期存储"。

窗口大小就是模型一次能看到的 token 上限。哪怕你用的是几十万 token 的模型,对话一长,或者任务跨了多个会话,早期信息照样会被截断或稀释。更关键的是,用户不会每次都把背景信息重复一遍,他们默认你应该记得上次聊了什么。

我遇到过一个真实案例:一个客服 Agent,用户前一天投诉了订单延迟,第二天再来问"我的包裹怎么样了",Agent 完全不知道之前的投诉背景,重新问了一堆已经回答过的问题。用户当时的原话是:"你们系统是不是有健忘症?"这就是没有记忆系统的典型症状——每次对话都是第一次见面。

1.2 记忆问题到底难在哪

记忆系统的设计远比"存一段话到数据库里"复杂,拆开看有四个核心难点:

第一,写入什么。对话里哪些信息值得记?用户的姓名、公司、偏好、承诺过的事情显然值得记,但寒暄、追问过程中的中间状态不该记。区分"事实性信息"和"临时上下文",本身就需要模型参与判断。

第二,存在哪里。这是一个存储选型问题。存在关系型数据库?向量数据库?图数据库?还是直接存原始文本?不同方案决定了后续检索的上限。

第三,怎么检索。用户提了一个新问题,系统怎么知道该调取哪段历史信息?关键词匹配显然不够,语义相关性是一个层面,时间相关性、实体关联性又是另一个层面。

第四,什么时候忘。记忆不是越全越好。信息会过期,用户的偏好会变,存了一堆过时信息反而会污染后续决策。怎么更新、怎么覆盖、怎么衰减,这些都是记忆系统的"清理逻辑"。

我见过不少团队,一开始觉得记忆功能好做,"不就是把聊天记录存下来吗",结果做深了才发现,真正的工程难点全在检索和更新上。这也是为什么现在独立的开源记忆项目越来越多——大家都意识到这不是顺手能做的事。

2. 参评项目全景

2.1 我实测的五个开源方案

这次对比我从知名度、社区活跃度、技术路线代表性三个角度,选了五个项目:

项目开发语言存储后端核心思路开源协议
Mem0Python向量库+图数据库双通道记忆,支持事实抽取与冲突检测Apache-2.0
Letta(原 MemGPT)Python关系库+向量库把 LLM 上下文当作"内存",用系统管理外存Apache-2.0
ZepPython / GoNeo4j 图数据库时序知识图谱,强调关系与时间维度Apache-2.0
CogneePython组合存储(图+向量+关系)从文本到知识图谱的 ECL 管道,偏推理链记忆Apache-2.0
LangChain MemoryPython可插拔(默认内存)框架内的记忆模块,适合轻量场景MIT

LangChain Memory 严格说不是一个独立的记忆系统,它是框架内置的一组记忆抽象。我把它放进来当"对照组",因为很多人的第一个记忆方案就是它,正好可以看看它和专用记忆系统的差距在哪里。

2.2 这几个项目的定位差异

五个项目表面都在做"记忆",实际上解决的场景不同:

Mem0 的定位是"记忆即服务",它提供一串 API,你往里面塞对话文本,它负责提取、存储、检索。它不关心你的 Agent 怎么调度,只把记忆层做好。优点是上手快,对已有 Agent 改动小,适合想快速给应用加记忆能力的团队。

Letta 走的是另一条路。它把记忆当成 Agent 本身的核心组件,引入了"虚拟上下文管理"的概念——LLM 看到的是一个被压缩过的上下文,完整历史放在外部存储里,由 Agent 自主决定什么时候把哪段记忆加载回上下文。这个设计很接近"操作系统换页"的模型,适合需要长期自主运行的 Agent。

Zep 的核心亮点在时态知识图谱。每条记忆不只是文本,而是被解析成"实体-关系-属性"的图结构,并且带上时间戳。比如"张三在 1 月 15 日说他不喜欢喝咖啡",在 Zep 里会变成张三这个节点上带时间属性的一条事实。这种结构在处理"谁在什么时候说了什么、后来变了没有"这类问题上非常有优势。

Cognee 更像一个面向知识工程的记忆系统,它强调把非结构化文本转化成可供推理的结构化知识。如果团队对知识图谱和语义网络比较熟,Cognee 会很顺手,它适合需要严格推理链条的场景。

LangChain Memory 提供的是一组标准化的记忆接口,包括会话缓冲、对话摘要、实体记忆等。优点是和 LangChain 生态无缝集成,缺点也很明显:它默认把整段历史存下来或者做摘要,没有真正意义上的实体级、事实级管理能力,上下文一长,检索精度和存储效率都会出问题。

3. 核心维度横向测评

3.1 记忆写入机制对比

记忆写入是第一个分水岭。我测试时重点关注两件事:项目是"被动接收"对话文本,还是"主动提炼"结构化记忆。

Mem0 采用的是双通道方案。两个纯函数调用分别处理不同性质的信息:

from mem0 import Memory m = Memory.from_config(config) # 基于配置初始化,默认连向量库和图库 # 显式写入:由 Agent 决策哪些信息值得记 m.add("用户当前使用的是企业版套餐", user_id="u_001") # 隐式写入:从对话历史里自动提炼要点 m.add( "用户表示周五下午一般不安排会议,喜欢邮件沟通,对延迟很敏感。", user_id="u_001", metadata={"source": "chat_20250115"} )

实测下来,Mem0 对隐式写入的文本会做一次"事实抽取",把一句话拆成多条独立记忆保存,并且自带去重逻辑。重复输入相似内容时,它不会在库里堆垃圾。

Letta 的做法完全不同,它的记忆更新由 Agent 自己控制。Letta 的记忆结构里预设了若干"记忆块",Agent 通过工具调用来修改这些块的内容。相当于把记忆的增删改查权限直接交给了大模型本身:

from letta import create_client client = create_client() # 连接 Letta server agent = client.create_agent( name="demo_agent", memory_blocks=[ {"label": "human", "value": "Unknown"}, {"label": "persona", "value": "我是一个耐心细致的助手"} ] ) # 对话过程中,模型自行决定是否更新记忆块 response = agent.send_message("我叫李昂,是一名后端工程师。") # Letta 会在内部调用 memory_replace 之类的工具,更新 human 块

这个设计的优势是记忆状态永远是最精炼的——模型每次只会修改真正变化的字段,不会把整段对话都倒进去。但代价是记忆的"好与坏"完全取决于模型的判断能力,模型判断错了,记忆就脏了。

Zep 的写入是异步且自动化的。只要在对话流里注册了 Webhook 或回调,Zep 会持续从消息流里抽取实体、关系、事实进图数据库。写入过程是流水线化的,不同 NLP 任务各自独立执行:

from zep_cloud import ZepClient client = ZepClient(api_key="your_key") # 告知 Zep 有一条新消息到达,它会自动完成抽取、建图、时序更新 client.add_message( graph_search_depth=3, session_id="session_test", role="user", content="我下周二去上海出差,需要订一间带书桌的酒店" )

Cognee 的写入是批处理式的,它把原始文档切成块,逐块走 ECL 管道(Extract-Cognize-Load,即抽取、认知建模、装载),最终沉淀成知识图谱节点。适合事后归档,不适合需要实时记忆的对话场景。

LangChain Memory 的写入最简单粗暴,就是把对话存进列表或者做一轮摘要总结。回到代码层面看,它没有真正的实体管理概念:

from langchain.memory import ConversationSummaryMemory memory = ConversationSummaryMemory.from_messages(llm=llm) # 需要传 LLM 实例 memory.chat_memory.add_user_message("我叫李昂") memory.chat_memory.add_ai_message("你好李昂!") # 本质上只是把文本追加进列表,不识别任何实体

3.2 检索方式的取舍

写入决定记忆怎么进库,检索决定记忆怎么出来。这五位选手的检索策略差异非常明显。

Mem0 默认配置下做的是"语义加实体混合检索"。查询先做向量化,从向量库取 Top-K 候选;同时把查询里的实体抽出来,在知识图谱里定位相关节点和相邻事实。两部分结果合并排序后返回:

results = m.search( query="用户对会议时间有什么偏好?", user_id="u_001", limit=5 ) # results 按综合相关性排序,既有向量相似,也有图谱关联

我实测时故意问了一个和原文用词完全不同的问题:存入的是"周五下午一般不安排会议",查询用的是"这周哪天不方便开会"。Mem0 返回了正确的记忆片段,说明向量语义本身起到了作用。但如果查询里包含明确实体,比如"张三喜欢什么饮料",图通道的精确匹配往往比向量通道更准。

Zep 的检索具备天然的图遍历能力。它支持"子图搜索",给定一个起始实体和搜索深度,它会沿着关系边把相关记忆全部拉出来:

search_result = client.search( session_ids=["session_test"], query="出差时的酒店要求", search_type="graph" # 图搜索模式 )

这项检索能力在涉及多人、多组织、多事件交错的问题上有碾压性优势。比如"张三上次见李四是在哪家餐厅,当时聊了什么",普通向量库很难把"张三见李四"这个关系精确关联起来,图数据库却可以沿着实体边直接找到答案。

Cognee 的检索同样走图结构,但它的路径更重。整个查询会经过一系列管道化处理,先识别查询里的实体,再在图谱里做子图匹配。精度高,但延迟也高。我测试时单次检索在百毫秒到秒级浮动,这还是本地单机环境。

Letta 的检索不是一个显式 API,而是内建于 Agent 的"注意力管理"。系统在每次对话前决定把哪些记忆块内容注入上下文:

# Letta Agent 响应时会自动决定加载哪些 memory block response = agent.send_message("你还记得我叫什么吗?")

这个机制的好处是检索不需要开发者设计查询逻辑,模型自己判断;坏处是记忆块的规模一旦变大,Agent 的调度决策变多,token 消耗相应上涨。我实测下来,Letta 是五个项目里单轮查询 token 消耗偏高的。

LangChain Memory 的检索就简单了:要么把全部历史拼进上下文,要么只取摘要。没有过滤、没有相关性排序。在会话很短的时候能用,一旦对话历史超过几千 token,这种"全量塞入"的检索方式会迅速吃满上下文窗口。

3.3 存储层设计与扩展性

存储层决定了记忆系统能撑多大、检索能有多快。

Mem0 是有状态存储,支持多种后端切换。默认配置用向量库做语义索引、图数据库做实体关系。我测试时用 Qdrant + Neo4j 的组合,单机环境下 10 万条记忆记录检索在数百毫秒级。不过 Mem0 的代码里,向量库和图库的同步是应用层做的,数据量大之后,两库的强一致性维护需要自己考虑。

Zep 的存储设计是它最看重的一部分。它深度绑定 Neo4j,利用图数据库原生的时间属性管理时态数据。每条关系边上可以挂时间区间,查询时天然支持"某时间点之后发生了什么"这类问题。这种时态能力在其他项目里基本没有。

Cognee 的设计更重一点。它不是单库存储,而是分级存储:原始文本放对象存储,向量放向量库,图谱节点放图数据库,三者通过一个中间层做关联。好处是抗单点故障能力更强,适合企业级知识库场景;坏处是部署复杂度直线上升,单机玩不转。

Letta 在后端存储上相对务实。它用 Postgres 存结构化数据(包括记忆块和状态),向量部分依赖 PG 扩展或者其他向量库。对于大多数中小规模项目,这套组合足够稳。它的亮点在于"状态管理",所有记忆块都能追溯版本、来源和更新时间,这在调试 Agent 行为时极其有用。

3.4 遗忘与更新策略

遗忘是记忆系统最容易被忽略、实则是及格线的能力。我拿了一个经典场景做测试:用户先说喜欢喝美式,两周后说现在只喝燕麦拿铁。正确行为是旧记忆被覆盖而不是并存。

Mem0 对更新做了显式接口和隐式冲突检测。调用 add 传入新事实后,它会先检索已有相同实体的记忆,按时间戳和置信度决定是新增、覆盖还是保留。实测中,当我输入"用户目前只喝燕麦拿铁"后,再搜索"用户喜欢什么咖啡",返回的是新记忆,旧的"喜欢美式"不再出现在 Top 结果里,表现符合预期。

Zep 的时效策略靠时间戳保证新事实胜出。图数据库中同一条关系如果存在多条时间版本,查询时默认只返回最新时间片内的信息。这套机制的优点是不做物理删除,历史状态仍在库中,想做"用户行为变化分析"有据可查。

Letta 的更新是模型驱动的记忆块覆盖。模型会在合适时机调用记忆替换工具,过程是黑盒的,调试时需要通过日志查看模型修改的完整轨迹。实测中模型能够准确执行"替换记忆块"指令,但偶尔会把一些陈述性内容误当成事实存进记忆块,需要人工过滤。

Cognee 在更新上最弱,它本质上是知识图谱构建工具,对"单条事实变更"没有特别设计。要修改一条旧结论,通常需要重新跑一遍包含新文档的数据管道,整体周期长。

LangChain Memory 几乎没有遗忘和更新能力,历史记录只增不减。

3.5 综合表现评分

我根据几个维度的实测结果,给这五个项目打了一个主观分:

维度Mem0LettaZepCogneeLangChain Memory
上手难度(5分制,分数越高越省事)53325
检索精度(长对话场景)43541
记忆更新能力44520
中文支持44434
部署成本43325
适合场景广度54432

需要说明:LangChain Memory 分数低不是因为它"差",而是因为它本来就不承担深度记忆职责,如果只做 Demo 或者轻量会话回忆,它足够用。

4. 实操过程与核心环节实现

4.1 测试环境与方法

统一测试环境说明一下,方便你自己复现时对齐:

  • 操作系统 Ubuntu 22.04,Python 3.10,Docker 用于跑中间件(Qdrant、Neo4j、Postgres)
  • 模型统一用 GPT-4o 和本地部署的 Qwen2.5-7B 各跑一遍,看模型依赖度
  • 每个项目用相同场景集:身份偏好记忆、叙事连续性、时间敏感事件、记忆更正

测试逻辑不复杂,就是模拟一个用户连续多条消息,间隔一段时间后再来提问,看系统能否给出正确的历史关联信息。下面是场景一个脚本化的完整过程。

4.2 场景实测:跨会话身份与偏好记忆

场景设计为:第一次会话告诉 Agent 自己的名字和偏好,第二次会话直接用代词提问,看能不能回忆起来。这类场景是所有 Agent 产品的基础能力。

Mem0 的表现最直接,写入和检索各一个 API,Debug 很透明:

from mem0 import Memory m = Memory.from_config() # 会话1:写入用户信息 m.add("用户叫林夏,是产品经理,偏好简洁风格", user_id="u_10086", metadata={"conv": 1}) # 模拟漫长中间对话,隔了半天 # 会话2:检索用户身份 results = m.search("他是做什么工作的?", user_id="u_10086") print(results)

返回结果里能清晰看到"林夏、产品经理、偏好简洁"这几条独立记忆。中文分词和实体识别对这种短句场景没有出问题,命中相当准。

Letta 的跨会话记忆依赖 Agent 自己的记忆块管理。首次对话时模型会把"林夏、产品经理"这类信息写入记忆块,第二次会话时模型调用读取工具把相关块注入上下文。全程不需要开发者定义检索逻辑,适合"对话驱动型"产品;但如果你需要精确控制"什么该记什么不该记",它的自由度反而是一种负担。

Zep 在身份记忆上表现也不错,不过它的抽取结果是埋在图里的,返回的形式是"实体+属性",适合程序化消费,直接给 LLM 用反而需要再做一层组装。

4.3 场景实测:多人叙事记忆

这个场景模拟客服场景,一个会话里连续多个话题穿插,后期提问时要能定位到特定的一件事。

消息序号内容
1我的订单 20250113 延迟了,客服让我等 3 天
2同时我另一个充电器订单已经到货了
3我周五要出远门,必须在周四前收到
4(查询)我的充电器订单状态

在这个场景里,Mem0 的向量检索能召回订单相关的语义记忆,但如果提问变成"我之前提到的出行日期是哪天",它针对日期类信息的召回就不太稳定,偶尔会因为语义偏差漏掉关键实体。

Zep 在这个场景几乎是无敌的。订单、充电器、出行日期三个实体在图里天然分开,每条边带着"谁提到的、什么时候提到的"属性,查询"用户的出行计划"能直接沿着用户节点把相关事实全部拉出来。这种在复杂关系场景下的精确性,是图结构对比纯向量方案的降维打击。

Cognee 在这个场景的表现在我预期之上。它构建出来的知识图谱能支持比较复杂的多跳查询,比如"所有涉及订单延期的消息中,用户表达过哪些时间约束"。不过响应时间偏长,需要接受它的处理周期。

4.4 场景实测:记忆更正

把遗忘和更新单独拎出来测试,是我这次评测里收获最大的一环。前面说过"喜欢美式咖啡,后来改成燕麦拿铁",五个项目中只有 Zep 和 Mem0 做对了。

Zep 的时序图谱里,新旧两条记录同时存在但时间权重不同,检索时返回最新状态。它的记忆更新不需要额外调用 API,只要把新消息投喂进去,解析管道自己会完成版本切换。这在实际应用里非常省心。

Mem0 需要你保证新事实的表述足够清晰。我测试时输入"用户目前只喝燕麦拿铁",它能正确建立覆盖关系;但输入"用户觉得燕麦拿铁也不错"这种模糊语气,它就只新增了一条关联记忆,不触发旧记忆的覆盖。所以用 Mem0 时,开发者在写入侧要给模型明确的"新旧冲突处理指令"。

Letta 的更新完全靠模型自己。模型在对话中接受到新信息后,会调用更新工具改写记忆块。我跑了三轮测试,模型每次都成功做了覆盖,但有一轮额外保留了一条冗余信息,增加了少许 token 消耗。整体可控,但在生产环境需要对模型行为设置更严格的槽位和约束。

4.5 场景实测:中文检索与语义边界

中文场景是国产 Agent 团队最关心的问题之一。我补充测试了几个容易出问题的点:

  • 口语化表达:"周五下午一般不安排会议" vs 查询"哪天开会不太合适"
  • 上下文省略:"这个功能我们团队内部先放着,不用对外说" 之后查询"客户能不能看到这个功能"
  • 中英混合术语:"用户提到需要 SLA 保障,但周末不接告警"

Mem0 在中文上的表现取决于底层 Embedding 模型。换成 text2vec 或者 bge-m3 之后,整体召回率在 85% 以上,日常场景够用。Zep 的抽取管道对中文实体识别依赖 Spacy 和自定义 NLP 组件,默认配置对中文的支持需要额外加载模型。Cognee 的中文支持相对弱一些,它在处理中文专名和长难句时偶尔会把关系边抽得比较稀碎。

5. 场景化选型建议

5.1 不同团队怎么选

我根据项目定位、团队规模和业务场景把选型逻辑整理成了表格:

如果你的场景是推荐方案核心原因
个人开发者快速 MVP、DemoMem0上手快、API 清爽、不绑架 Agent 框架
客服系统、用户画像类产品Zep时序图谱天然适配用户行为追踪和关系梳理
长期自主运行的 Agent(无人值守)Letta自主记忆编辑机制更像一个"活体"长期运行单元
企业知识库、合规审计强需求Cognee处理管道完整、知识链路可追溯,适合重交付
简单会话总结、低并发内测LangChain Memory + 向量库架构简单,不做过度设计,快速跑通

5.2 集成成本和注意事项

选型不只是看功能,还得看团队规模。Mem0 的部署依赖不大,一个向量库一个图库就能跑,适合三个人以内的小团队。Zep 自带服务端,如果你需要自托管就要多运维一个 Go 服务和一个 Neo4j 实例,这部分成本需要提前算进去。Letta 的服务端支持 Docker Compose,Postgres 和向量库都是熟面孔,卡点主要在理解它的记忆管理哲学,团队需要有人能把 Agent 调度逻辑捋顺。

我的一个经验是:别盯着"哪个最强"做决定,要看"哪个最容易在你的架构里活下来"。记忆系统不是一个独立产品,它要跟你的 Agent 框架深度融合。Mem0 之所以成为很多团队的首选,不是因为它各方面分数最高,而是因为它的接入成本低、方案通用,后续想换也不至于伤筋动骨。

6. 常见问题与排查技巧实录

6.1 记忆污染:检索出来的东西不相关

这是所有记忆系统最常见的故障。症状是问 A 的时候带出了一堆 B、C、D 的旧记忆,导致 Agent 回答张冠李戴。

排查路径三件套:第一步,检查向量检索的召回阈值,把相似度阈值调高一些,宁可漏掉也别乱带;第二步,检查图路径检索的搜索深度,Mem0、Zep 都支持配置图遍历层数,默认深度过深会捞出一大堆间接关联的节点;第三步,检查是否缺少"时间过滤条件",很多场景只需要最近 7 天的记忆,Zep 支持精确时间窗口查询,Mem0 需要在元数据里手动维护时间戳再过滤。

调参建议:先严格召回,再逐步放宽。对话类场景中,召回精度比召回率重要得多,一条错误记忆对用户体验的伤害远超十条正确记忆带来的增益。

6.2 明明存了信息,检索时却找不到

这个问题的隐蔽性很高,通常不是程序 bug,而是写入和检索的"表述口径不一致"。

比如存的是"用户联系方式的邮箱是 a@b.com",查的时候问"怎么联系用户",向量检索找不到精确取值,图检索又没有把 Email 属性建好索引,结果就漏了。解决思路有两个:写入侧要给关键实体打统一标签,比如 "user.contact.email",检索侧按标签精确过滤;或者养成双向检索的习惯——既做语义检索,也做实体检索,再把结果合并。

6.3 并发写入时数据错乱

记忆系统的数据有一个特点:同一个用户的信息会频繁更新。多线程或多服务同时写入时,很容易出现"最后一次写入覆盖了更早的新数据"的问题。Zep 因为使用图数据库,并发冲突概率相对较低;Mem0 则需要关注应用层的写锁。

我遇到过一个真实事故:两个服务同时为同一用户写偏好,一个写"喜欢邮件沟通",另一个写"偶尔用 Slack",因为没有版本控制,后写入的覆盖了先写入的,最终用户偏好只剩一条。解决方案是引入"更新时间戳核对",写入前先取当前记忆的最新时间,只有新数据的时间戳更晚才允许覆盖。部分项目支持条件更新,也可以在应用层自行实现。

6.4 记忆系统有没有"评测集"

很多人问过我这个问题。目前开源社区没有一个公认的 Agent 记忆评测基准,各家 README 里贴的指标基本都是自定义测试集的结果,可比性有限。

我的做法是自建一个"记忆回归测试集",包含 5 大类场景:身份信息、偏好变更、多人叙事、时间敏感事件、模糊查询。每次改动代码后跑一遍,用正确率、召回率、错误调用率三个指标做回归对比。这个测试集规模不大,但能覆盖 80% 的常见故障。民间也有一些 Agent 评测框架开始支持记忆专项,但成熟度还不高,建议自建为主。

6.5 部署与运维上的避坑

最后再说几个运维层面的坑。如果你在生产环境引入开源记忆系统,至少要注意这四点:

第一,中间件版本锁定。Qdrant、Neo4j、Postgres 各自的大版本升级经常引起客户端驱动不兼容,锁定版本是省事省心的第一步。第二,向量库的索引参数要按数据规模设置,默认配置在万级数据上没问题,到百万级数据时 recall 会急剧下降,需要在写入前做好分片规划。第三,图数据库的 schema 设计要提前定,图谱数据的 schema 变更比关系库难得多,一旦跑起来再改结构会非常痛苦。第四,考虑数据隔离。多租户场景下,每条记忆记录至少带上 user_id / tenant_id 标记,Mem0 原生支持这个字段,Zep 需要在 metadata 里自行管理。

我在实际项目中踩过的另一个细节是:中文语义检索的 Embedding 和英文用的是不同模型,切换模型后向量索引需要重建,否则新旧向量分布不一致,召回结果会出现"越查越错"的现象。换模型一定记得重建索引。

最后分享一个体会。记忆系统的选型,本质上是在"控制力"和"自动化"之间做权衡。Zep 的自动化程度很高,图结构帮你把记忆整理得井井有条,但对开发者的图谱建模能力有要求;Letta 把记忆的决策权交给模型,灵活但不可控;Mem0 走中间路线,值得大多数团队作为起步选择。真正上线之后你会发现,记忆能力不是一个"装上就能用"的功能,持续的数据治理、检索调参、脏数据清理才是日常工作。这个领域的开源生态还在快速演进,现在把基础架构选对,后面更换成本就低很多。