☰
AI Agent外挂记忆:用mem0构建跨会话长期记忆系统
2026/10/12 3:05:15 网站建设 项目流程

做开发这一年多,最让我头疼的不是模型能力不够,而是模型"记性太差"。上一轮刚跟用户聊完,下一轮它就忘了用户叫什么、偏好什么、甚至刚才说过什么。最开始我靠往系统提示词里堆上下文硬扛,结果token账单越来越离谱,效果还越来越飘。直到我把一个外部记忆系统挂到Agent上,才算是把这块短板真正补上了。

这篇我想聊聊这个"外挂记忆"的具体实现。我用的方案是mem0,它不是一个简单的向量库,也不只是一个缓存,而是一套完整的记忆管理机制。它能判断什么值得记、什么该丢、什么时候该想起来。如果你正在开发AI Agent,尤其是对话类的、需要跨会话理解用户的产品,这篇文章应该能帮你少走不少弯路。我会从原理、实操、踩坑三个层面展开,顺便给出一些我实测下来的数据和建议。

1. AI Agent的"失忆",不是加长上下文能解决的

1.1 上下文窗口更像便利贴,不是记忆

很多人一开始会给Agent拼命加系统提示词、把历史聊天记录全部塞进上下文窗口。这本质上是在把上下文窗口当成"纸笔",告诉AI:你的记忆都在便利贴里,自己翻吧。

但便利贴是有极限的。上下文窗口再长,也有长度上限;即便没有触顶,Token越长,单次请求的响应延迟和费用也跟着涨。我在开发一个客服型Agent的时候,用户聊到第20轮,光是历史消息就已经占了一万多Token,每次请求都在消耗大量算力,而且调用的效果并没有变好——因为真正关键的偏好、承诺、结论,被淹没在大量寒暄和口水话里。

便利贴还有一个致命问题:Agent自己并不知道哪张便利贴重要。它把所有对话都当成同等权重的内容,导致检索关键信息的能力反而变差。

1.2 外部存储也不是救命稻草

还有一波人会尝试自己搞"外挂记忆":把用户对话存进Redis、MySQL或者向量数据库。这个方向是对的,但只做存储远远不够。

我第一版就是往向量库里塞向量,然后每次对话前取TopK条塞进上下文。结果怎么样?用户说"把上次那个方案发我",Agent完全找不到"上次那个方案"是哪条记录。为什么?因为原始对话里那句话是"你觉得我们网站加载慢的问题怎么解决好一些",语义和"那个方案"并不直接匹配。向量相似度检索根本拉不回这种跨表述关联。

这就是记忆和存档的本质区别。存档解决的是"内容别丢",记忆要解决的是"需要的时候能想起来"。而"能想起来"背后需要一套筛选、提炼、关联、检索的完整机制。

1.3 真正可用的记忆需要解决三件事

我把这段时间的需求拆了一下,发现一个可用的Agent记忆系统至少要满足三个条件:

  • 该记的记下:用户的身份信息、明确偏好、任务约束、稳定的结论,这些必须进长期记忆。
  • 该忘的忘掉:一时的话题、偶然的寒暄、临时状态,不能一股脑全存,否则记忆库全是噪声。
  • 关键时想得起:记忆不是全量回放,而是根据当前对话的需求,精准唤起相关的记忆片段。

这三件事,恰好就是mem0在设计上花力气的地方。

2. mem0的工作方式:它不是数据库,是一套记忆机制

2.1 "哪个该记"由记忆决策器说了算

我第一次看mem0的架构时,印象最深的一点是:它不是一个单纯的存储组件,它内部有一个记忆决策的过程。

打个比方:普通向量库像一个仓库管理员,你搬什么进来它都堆着,你问它什么东西它按编号找。而mem0的做法是,请了一个"面试官",先把对话内容过滤一遍,只把真正有价值的陈述提炼出来存进去。

这个面试官本质上是一个大模型调用,具体来说:系统会把新的对话片段交给大模型,让模型判断——这里面是否有值得长期保留的稳定信息?如果有,提取成精炼的条目,而不是原文照搬。

我一开始不理解为什么要多这一步,后来试过才发现,这一步非常关键。比如用户随口一句"今天下雨了,出门记得带伞",如果要存,理想记忆是"用户在雨天会提醒自己带伞"吗?不是。这句话是临时状态,不值得存。但如果用户说"我习惯用快捷键操作",这就是一条稳定的行为偏好,值得存。没有决策器,系统会一视同仁地存,存多了检索质量自然崩。

真正的记忆不是录音机,而是编辑——只保留有长期价值的信息。

既然提到了架构,我把实际用到的几个核心组成部分列在这里:

组成部分作用
记忆决策器判断当前对话哪些信息值得进入长期记忆
长期记忆库存提炼后的记忆条目,底层用向量库做相似度检索
记忆更新器发现新信息与旧记忆冲突、相关时,自动合并、更新
检索器根据当前对话上下文,从记忆库中捞取最相关的记忆片段
图关系层提取实体和实体之间的关系,支持多跳关联记忆

2.2 短时记忆与长时记忆的通道分离

在接线实际使用时,我体会到mem0管理记忆也有类似人脑的短时和长时之分。

短时记忆,负责当前会话内的上下文;长时记忆,负责跨会话、跨轮次的稳定信息。mem0在我理解里的设计,是让你把短时上下文继续放在Agent的对话历史里,把长时记忆交给它来管理。这样两边职责清楚,不挤占上下文窗口。

更让我觉得它做得"像人"的一点,是记忆的写入不只是新增一条,还会根据新信息和旧记忆的关系去做更新和删除。我测试过一个场景:

用户第一次说"我比较喜欢简洁的界面",它存入一条记忆。隔天用户说"其实复杂一点的设置项我也能接受,之前的说法不太准确"。这种情况如果只做新增,记忆库里就会出现两条互相矛盾的记忆。而mem0会基于新的陈述去修改原记忆,或者删掉旧陈述再新增。这种动态更新能力,恰恰是普通向量库给不了的。

2.3 和RAG的区别,一句话讲透

很多人会问:Agent带记忆,是不是做个RAG就够了?我自己也纠结过这个问题。

我的理解是:RAG是给Agent提供外部知识的,回答的是"事实依据在哪里";mem0提供的是"这个用户是谁""我们之前达成了什么结论""他有哪些偏好"。一个是查资料,一个是记人。你可以让Agent兼职查资料,但你不能指望它靠RAG记住用户上次选了哪个套餐。

从产品体验上说,RAG缺失顶多是"回答不够准确",记忆缺失则是"用户每次都要重新自我介绍、重新交代背景"。后者对留存和体验的伤害,远比前者严重。

3. 把mem0挂到Agent上的完整实操

3.1 环境准备:记忆服务不是黑盒,先给它配一个大模型

开始之前,需要明确一件事:mem0既然需要一个"记忆决策器",那么你就得给它准备好一个大模型API或者本地模型接口。

我这边用的是兼容主流大模型接口的本地服务,这样所有请求都跑在自己环境里,记忆提取和检索的隐私性更好。你也可以直接用各种大模型API,关键是让mem0能拿到一个可用的接口地址和密钥。

然后安装mem0的Python包,初始化记忆客户端:

from mem0 import Memory m = Memory.from_config({ "llm": { "provider": "openai_compatible", "config": { "model": "your-model-name", "api_key": "your-api-key", "base_url": "http://localhost:11434/v1" } }, "embedder": { "provider": "openai_compatible", "config": { "model": "your-embedding-model", "api_key": "your-api-key", "base_url": "http://localhost:11434/v1" } } })

如果你用的是各类云厂商的大模型API,把base_url和api_key换成对应的值就行,其他逻辑同理。

参数说明:llm是指挥记忆的"编辑大脑";embedder是负责把记忆转成向量的编码器。两个可以不同模型,实测下来,决策器用能力强的模型效果更好,编码器用轻量模型就够。

3.2 最小可跑的外挂代码:让聊天Agent突然有记性

我先把一个最简单的"无状态"聊天Agent做出来,然后给它挂上记忆。

先看一段核心代码,这是每一次用户发言后,Agent要做的三件事:

def chat_with_memory(user_message, user_id="alice"): # 1. 先把当前用户的长时记忆捞出来 memories = m.search(query=user_message, user_id=user_id, limit=8) # 2. 把记忆拼进系统提示词,让Agent带上"记忆上下文" memory_context = "\n".join(f"- {item['memory']}" for item in memories) response = call_llm( system_prompt=f"你是客服助手。如果关于用户有以下记忆,请结合记忆做出回应:\n{memory_context}", user_message=user_message ) # 3. 对话结束前,把有价值的消息写入记忆库 m.add(user_message, user_id=user_id) return response

这个流程我称为"捞取—拼接—写入"。每一步都很直观,但真正跑起来之后,有几个细节特别重要:

  • 检索要发生在Agent组装提示词之前,而且要把检索到的记忆放在显眼位置,模型才有更高的概率参考到。
  • 写入要发生在判断"这条消息值得记"之后,而不是所有消息都往里加。
  • 用户ID必须带上,这是后续做用户记忆隔离的基础,少了它,所有用户的记忆都会串在一起。

3.3 记忆的读、改、删与重置:不只是add和search

很多人集成到"能跑"就停了,但真实场景下,记忆管理还有几个接口必须掌握。

获取全部记忆:调试和后台管理时很常用,比如要看看某个用户到底记了什么,再加个user_id过滤就好。

all_memories = m.get_all(user_id="alice")

更新和删除:这是处理用户主动纠正的关键。用户说"我不喜欢简洁风格了,改成喜欢详细说明",你不能只往库里塞一条新记忆,旧的还留在那里。正确做法是先搜索到相关旧记忆,再更新或删除:

# 搜索具体记忆条目 search_results = m.search(query="用户界面风格偏好", user_id="alice") # 对每一条需要修正的旧记忆做删除/更新 m.delete(memory_id=target_memory_id, user_id="alice") m.add("用户偏好:详细说明风格的界面说明", user_id="alice")

重置/清空:做测试的时候高频使用。一个用户下线、注销,或者你要换个测试账号,都需要把记忆清掉:

m.reset()

实时清理用户记忆会直接改变Agent的行为,所以生产环境需要配套一个管理后台,让用户能看到"AI记得关于你的事情",并且能手动删除。这不只是功能,也是信任的一部分。

3.4 多用户与多会话隔离:memory_id的正确打开方式

接入真实产品时,一定会有多用户并发的场景。mem0的隔离方式不是给你开很多实例,而是通过层级ID,我这里主要用user_id做隔离。

同样的代码,只要把user_id换成"用户的业务唯一标识",比如用户ID或会话ID,就能做到不同用户的记忆完全隔离。我见过有人图省事,全局共用一个user_id,结果所有人的记忆互相污染,用户A的偏好出现在用户B的对话里。这是上线前排查最费劲的一个低级错误。

这里我的建议是:如果业务是客服场景,用用户账号ID做user_id;如果是匿名咨询场景,可以用浏览器的临时唯一标识,但要考虑过期策略。项目上线前,最好专门写一个测试用例,验证两个不同ID之间的记忆互不可见。

4. 实测避坑:记忆污染、检索失效和成本陷阱

4.1 记忆污染不是技术问题,是取舍问题

功能跑通之后,我遇到的第一场灾难是记忆污染。用户的这句话,被记忆提取器记住,将来检索时会给Agent一些并不合适的"背景信息"。比如用户发了一句"今天网络又卡了,烦死了",这本来是一句吐槽,但决策器可能提取成"用户经常遇到网络卡顿问题,且情绪烦躁"。

这种东西存多了之后,Agent每次看到这个用户,心里先入为主觉得"用户对网速不满意",连用户问"帮我推荐电脑配置"都会被带偏。

我当时的调整方案是三件事:

  • 在给mem0的指令中明确加一条:仅保存任务相关的、用户主动表达的稳定偏好;寒暄、情绪化抱怨、临时状态默认不存。
  • 对用户消息做预处理:先过滤无效文本,再交给记忆系统。
  • 每周检查一次用户的记忆列表,清理明显是误记的条目。

这条经验后来帮我省了非常多线上问题。记忆系统不是无脑记录器,给得太多和完全没有一样糟糕。

4.2 检索失效:向量相似度不是万能的,要加元数据过滤

另一个实战问题是:记忆确实存进去了,但检索时拉不出来。我在某个场景下测试,用户前一天说"我的预算大概1万左右",次日问"推荐一下符合我要求的方案",检索结果却没有把这条记忆召回。

原因其实很老套:向量相似度在两个语义表述差距较大的句子之间效果很差。"1万预算"和"符合我要求的方案"这两句话的向量距离,大概率排在TopK之外。

我最后的处理方式是三层结合:

  • 加元数据过滤:给记忆条目打上用户ID、标签、来源场景标签,检索时先按元数据粗筛,再在粗筛结果里做向量排序。
  • 提高召回数量limit:从默认5提到10,必要时甚至提到20,让排序层有更多候选。
  • 检索时拼接"多路召回":不只是用用户当前这句话去搜,还可以组合用户历史上最常提到的关键词去搜,提高召回率。

我最终用了"元数据过滤 + 提高limit + 多路召回"的搭配,线上检索命中率才算稳定在合理水平。

4.3 成本和延迟:每一次记忆写入都在悄悄烧钱

做了一个多月之后回看账单,才意识到mem0真正的开销不是存储,而是那个"记忆决策器":每一次需要写入的记忆片段,都要调用一次大模型去判断和提炼。

这确实不便宜。我当时的用量是每天几万条用户消息,如果每一条都让决策器判断一次,Token消耗量会非常大,而且每个判断还要等大模型返回,接口延迟也上来了。

我的解法不是说少用,而是给记忆来料加一道前置闸门:

  • 太短的无意义消息(小于10个字)直接不参与判断。
  • 高频重复的抱怨、无实质内容的请求,单独做规则过滤。
  • 可以批量合并的上下文,先在业务层聚合,再统一写入。
  • 对延迟敏感的场景,写入操作异步化,不在用户请求链路上同步执行。

这四条下来,成本大概降了两三成,而且整体响应速度也没被拖累。如果从一开始就按这个方法去设计,体验能稳定不少。

4.4 一个记忆中心供多个Agent共享

后来我的业务里有好几个不同的Agent:客服、导购、售后。最初我给每个Agent单独接了一套mem0,结果发现用户在同一次服务里,客服记住了"这个用户上次退过货",导购还在热情地推荐同类商品。体验非常割裂。

调整之后,我把所有Agent共享同一个记忆服务,通过不同的user_id和隔离键区分使用场景。这样,用户的历史偏好、历史交互在多个Agent之间是连续的——客服问到的信息,导购端也能用来做推荐。

共享的前提是:不同Agent之间的记忆安全性。不要让一个完全无关的Agent读取到另一个场景的敏感记忆。我的做法是两个维度配合:一是在写入不同Agent的对话时,在记忆条目上打上Agent类型标记;二是检索时用Agent类型作过滤条件,保证"客服Agent不检索导购Agent的记忆"。

5. 哪些场景真正值得上记忆系统

5.1 还是先算一笔账:记忆系统不是白送的

接入前,我建议大家先用一张表盘算一下自己的场景值不值:

场景类型是否需要长期记忆原因
客服机器人强烈需要用户讨厌反复描述问题,记住上下文直接提升满意度
个人助理/陪聊强烈需要用户偏好是核心体验,忘掉等于不合格
知识库问答弱需要主要是查资料,用户记忆不是核心矛盾
一次性工具Agent不需要用完即走,记忆反而是负担

我的一个判断经验是:如果用户在跟Agent交互时,平均对话轮数超过5轮,后续轮次里只要出现"刚才说的""上次提到"这类词,就必须上长期记忆。如果没有这种情况,那先把RAG和提示词写好更重要。

5.2 不同Agent接入记忆后的实测效果差异

我实际把mem0接入到三个场景做了对照:

**场景一:客服Agent。**接入之前,用户问完一句话后经常要重复"我刚才不是说了吗",人工接管率明显偏高;接入之后,用户在一个流程内重复交代背景的比例降下来了,客服人工转接率稳步下降。最直观的变化是:用户第二句开始,Agent已经知道用户是会员、知道用户上次遇到什么问题、知道用户要的是什么。

**场景二:个人助理Agent。**接入前,用户设置偏好后,Agent第二天就忘得一干二净,导致用户反复重复设定,体验极差;接入后,用户不需要重复设置,而且因为记忆有更新机制,用户改过的偏好能立刻生效。

**场景三:教育辅导Agent。**接入前,用户的学习水平、薄弱点完全要靠用户每次自己描述;接入后,Agent记住了用户当前的学习进度,每次能从上次结束的地方继续讲解,学生的学习连续性有了保障。这也是记忆系统效果最直观的验证。

5.3 我的总体体会

单独看每个能力,mem0好像就是"提取+向量库+检索",但放在Agent里,它带来的体验变化是跳跃式的。一个用户对一个Agent的信任,很大程度来自"AI是不是记得我上次说过什么"。用户不会因为你的Agent知识渊博就喜欢它,但绝对会因为"你居然还记得我喜欢简洁的界面"而更喜欢它。

从实际工程角度看,记忆系统的设计要点其实就是"克制"这个词。克制地选择该存的内容,克制地设计检索策略,克制地分配调用成本。把这三件事做对了,Agent看起来就越聪明。我实测下来的结论是:记忆系统不是"加一个库"那么简单,它是一个AI产品从"demo能用"走到"用户愿意用"的关键一跃。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询