资讯动态

给AI助手加上长期记忆:用Mem0实现跨会话用户记忆的完整指南

发布时间:2026/10/14 4:44:42 来源:尧图企业网站定制
最近我在给一个内部用的智能助手加长期记忆试了一圈方案之后把重心放在了 Mem0 上。它做的事情说简单也简单给 AI 加上长期记忆让同一个用户在不同的会话里被持续识别记住偏好、背景和约定而不是每一次对话都像第一次见面。说复杂也复杂因为“记忆”这两个字背后牵扯到抽取、存储、检索、更新、遗忘一整条链路任何一个环节没想清楚最终的体验都会非常割裂。这篇文章把我从理解到落地整个过程里最关键的判断、实现步骤和踩坑记录都写出来。如果你是做 Agent、智能客服、个人助手的开发者或者正在纠结“为什么我的机器人总是不记得用户说过的话”这篇内容应该能帮你省掉不少弯路。1. 为什么“助手总是记不住你”是个系统设计问题很多人面对“AI记不住事情”的第一反应是加大上下文窗口。今天的一些大模型确实可以一次塞进几十万字但把用户过去一个月说过的所有话全部拼到提示词里效果并不会变好反而会带来两个问题一是成本暴涨每轮请求的 token 开销不可避免二是噪声变大模型在大量历史细节里反而找不到当前最有用的信息。另一个常见误解是“做一次 RAG 就够了”。RAG 解决的核心问题是知识检索比如把文档切块存进向量库用户提问时把相关片段捞出来。但它的工作对象是外部文档几乎不关心用户是谁、上次聊了什么、做过什么决定。长期记忆要解决的则是“这个人”的问题是用户画像、偏好、历史约定这类跨会话的稳定信息。这两件事可以配合使用但互相替代不了。1.1 会话上下文、RAG 和长期记忆是三件不同的事我这里把容易混淆的三类能力放在一起对比方便你判断手里那个项目到底缺的是哪一块能力类型数据来源生命周期典型问题会话上下文当前会话内的消息会话结束即失效换个会话就失忆RAG 知识库文档、FAQ、资料库按文档版本更新不知道用户是谁长期记忆从对话中抽取的用户事实与偏好跨会话持久保存可更新可删除需要一整套管理机制你可以把会话上下文想成一次饭局上的交谈说了就过RAG 是旁边的书架随手翻资料长期记忆则是一张不断维护的客户档案卡。很多产品把三件事混成一件事结果就是档案卡没人写、书架放到了餐桌正中间体验可想而知。1.2 真正该被写下来的不是聊天记录而是事实我早期做记忆功能时犯过一个很典型的错误把用户的原始聊天记录直接入库需要时按相似度捞几段。这样做表面上“有记忆”实际上模型在回复时仍然要从大段文本里自己找线索而且用户一句开玩笑的话、一个临时性安排都会变成长期记忆反复出现。正确的姿态是先让模型把对话“压缩”成结构化事实。比如用户说“我一般在晚上八点以后有空家里还有个上小学的女儿”这不应该被存成一句原文而应该被提炼成类似“用户晚间空闲时间20点之后”“用户家庭成员一个上小学的女儿”这样的独立条目。后者才可以被匹配、被更新、被删除前者只能被含糊地“想起”。这也是 Mem0 这类方案的核心思路它不追求把整个对话史背下来而是追求把“值得长期记住的事实”管理好。2. 记忆系统的四个关键动作抽取、存储、召回、遗忘我拆解 Mem0 的设计时把它的工作流归纳成四个动作抽取、存储、召回、遗忘。这四个动作并不是先后执行一次就结束而是一个不断循环的闭环。下面逐个说。2.1 抽取让模型从对话里提炼“可长期复用的事实”而不是原文复述抽取是记忆系统里最微妙的一步。它决定了一条对话里哪些信息值得被写进档案哪些应该忽略。具体操作上可以把最近几轮用户消息和助手回复一起交给一个大模型让它输出结构化记忆条目并且让每条记忆带一个“操作类型”ADD这是一条全新的用户事实需要新增。UPDATE这条事实之前已经记住过但内容需要修正。DELETE用户明确表示某条信息失效或不想被记住。NOOP本轮对话没有值得长期记忆的信息。举个例子。用户说“我现在搬到杭州了”而记忆库里已经有一条“用户所在城市上海”那这次抽取就不应该新增一条“用户所在城市杭州”而应该输出一条 UPDATE把旧条目改掉。这个细节非常关键否则记忆库会出现大量互相矛盾的事实检索时哪条都可能被捞出来。抽取时的判断标准我建议至少看三条第一信息是否足够具体第二它是否会影响未来某个对话的决策第三它是不是一个长期状态而不是临时情绪。满足其中两条才值得入库。泛泛的闲谈、一次性任务指令都不应该进入长期记忆。2.2 存储记忆条目不是字符串而是带生命周期和元数据的数据结构把抽取出来的事实存到哪里、怎么存直接决定了后续召回和更新的复杂度。我的经验是不要只把它当成一个字符串放进向量数据库就完事每条记忆应该带这些元数据用户标识这条记忆属于谁这是多用户隔离的基础。内容描述记忆的正文通常是提炼后的简短陈述。重要度评分用来衡量它对未来对话的价值。创建时间与最后确认时间支撑时间衰减和遗忘策略。来源片段记忆是从哪段对话里提炼的方便回过头核对。状态标记正常、临时、待确认、已失效。向量索引在召回时做相似度匹配而普通的数据表则负责精准过滤、更新和批量清理。两者结合才是完整形态。我见过只靠向量库存储的方案结果做删除时旧记忆的向量记录难清理索引和业务数据经常对不上。记忆条目必须设计成“业务实体 索引”的双层结构而不是一条裸文本。2.3 召回把记忆“按需翻出来”而不是一股脑塞给模型召回阶段要回答的问题是在用户发出当前这条消息时他过去积累的哪些记忆最值得被放进提示词。最简单的做法是把当前消息向量化然后去向量库里找相似度最高的若干条记忆。但在实际使用中这个“若干条”非常讲究。拉得太多提示词会被大量与当前任务无关的背景信息淹没拉得太少又可能导致关键记忆缺席。我的做法是给召回加三道闸门第一层过滤必须携带相同的用户标识先过滤再排序。第二层排序把“语义相似度”“信息新鲜度”“重要度评分”加权成一个综合分。第三层限制设置硬性上限例如最多带 5 条记忆进入提示词。还有一个容易被忽略的细节召回出来的记忆应该作为独立的提示词段落给模型并明确告诉模型“以下是关于该用户的长期记忆可以用于辅助回答但不要直接转述”这样才能避免模型把记忆当作用户当前说的话来处理。2.4 遗忘和更新长期记忆系统里最容易被偷工减料的一环更新和遗忘做不好记忆系统会从一个助手变成一个“固执的旧档案管理员”。它坚持用户的旧信息哪怕用户已经在最近一次对话里明确改了日期、改了地点、改了偏好。更新其实不难理解当抽取模型输出 UPDATE 时系统应该去定位原有条目并替换。难点在于如何判断“新信息”和“老信息”是在描述同一件事。只靠文本完全相同显然不够。我的做法是检查记忆的类型字段和主题字段如果类型相同、主题相近再让抽取模型判断是否针对同一件事并给出新旧值。这样比单纯用文本距离判断可靠得多。遗忘策略我分了两个层次。一是被动遗忘用户说“把……忘掉”“以后别提……了”“我不再喜欢……了”系统识别到 DELETE 意图后删除。二是主动清理长时间没有被召回、一直没有被二次确认的临时记忆定期进入“待清理”队列多个记忆互相矛盾时保留最近确认的一条其余标记失效。删除记忆这一步技术上一定要做到“业务记录删除”和“向量索引删除”同步。只删主表不删索引是后面各种诡异问题的根源。3. 本地跑通一个 Mem0 最小闭环选型、实现、验证理论说得再多不如实际动手跑一遍。下面是我搭建最小闭环的完整过程不涉及高可用、分布式这些东西但足够验证记忆的基本能力。3.1 选型先做小闭环别一上来就追生产级架构我见过不少团队一上来就规划微服务、独立的记忆集群、大规模向量索引折腾一个月还没让 AI 真正记住一个人的名字。我的建议先在一个小而完整的架构里跑通效果。选型上我坚持三条原则第一向量存储先用单机可运行的方案数据本地落盘不依赖外部服务方便调试第二大模型接口采用可替换的封装既能接订阅接口也能切换到本地开源模型这样不会在测试阶段被供应商绑定第三记忆管理和模型调用写在同一个进程里先不拆服务等确定记忆抽取质量合格后再做拆分。具体到向量库我用的是一款支持本地化部署的开源嵌入式方案数据保存在一个本地文件里查询速度对个人项目完全够用关键是犯错时可以直接清库重来。生产环境以后要换别的方案只要入库、召回、删除三个接口不变就行。3.2 最小实现思路对话前召回对话后抽取最小闭环的逻辑可以用下面这段伪代码表达def chat(user_id, user_message): # 1. 取该用户已有的长期记忆按当前消息检索 memories memory_retrieve(user_id, user_message, top_k5) # 2. 拼装提示词把记忆作为独立段落注入 prompt build_prompt(user_message, memories) # 3. 让大模型生成回复 reply llm_chat(prompt) # 4. 对话完成后把近期消息交给抽取模块 extracted memory_extract(user_message, reply) # 5. 将新抽取的记忆写入存储执行新增/更新/删除 memory_persist(user_id, extracted) return reply这套流程的执行顺序我特意调整过先召回、后抽取。召回发生在生成回答之前保证回答能用到记忆抽取发生在回答生成之后保证抽到的信息包含完整的一轮交互而不是只看到一个碎片。不要为了省事把抽取放在回答之前因为用户可能在连续几轮对话里才把完整信息说出来最后一句加密的细节往往藏着真正有价值的事实。配置方面我习惯把“是否开启记忆功能”做成开关先只在少数测试账号打开观察一段时间再全面放量。这样即使抽取逻辑有 bug也不会立刻影响所有用户。3.3 验证三件事跨会话记住、事实修正、主动遗忘闭环搭起来之后我给自己写了三个测试用例每一件都对应记忆系统的一个核心承诺。第一个测试是跨会话记住。第一个会话里我对助手说“我平时晚上九点以后才有空喜欢用 Python 写脚本”然后结束会话。隔一段时间在完全新的会话里只问一句“你觉得我什么时候适合约一次深度工作讨论”。如果它能在回答里默认考虑晚上九点以后说明召回和注入链路通了。第二个测试是事实修正。我在新会话里说“我现在换工作了时间是早九晚六晚上反而没空了”。然后重新提问适合讨论的时间。系统应该输出 UPDATE替换掉旧记忆而不是同时保留两个冲突版本。第三个测试是主动遗忘。我明确要求“把我关于工作时间的记忆全部删掉”随后在新会话里询问相关安排。如果回答里不再出现任何相关时间偏好说明删除链路是干净的。这三个测试看着简单但能把系统里最薄弱的“更新”和“删除”堵住。市面上很多记忆方案能演示“记住”但撑不过这三个测试。4. 实测记录四个我踩过的坑和完整排查思路下面这些坑都是我实际踩过的。每一个我都会先讲现象再讲我当时的排查链路最后给结论。这样你在遇到类似问题时可以按同样的思路定位。4.1 记忆抽取系统“太爱记”什么都往本子上写现象是用户只是随口说了句“今天天气真差”系统就为此记住了一条类似“用户对天气不满意”的长期记忆。更离谱的版本是用户提了一嘴“这个界面颜色太亮了”系统记录“用户喜欢暗色界面”完全是无中生有。排查过程是这样的我先打开了抽取日志逐条看了被输出的记忆内容和原始对话。结果发现抽取模型几乎把所有带情绪和评价的句子都当成“用户偏好”因为输出提示词里给了“偏好”“倾向”“评价”这样的宽泛引导而模型的默认行为会倾向于过度提取。解决方案有三个。第一收紧抽取指令明确要求只抽取“会影响未来对话决策的长期事实”并且给出反例比如“用户对作品的具体评论不要存储除非他明确表示某种品味偏好”。第二给每条提取出的记忆加一个置信度字段低于门槛的标记为临时记忆不参与后续召回。第三增加“复核”机制如果同一类事实被用户重复或主动补充确认过才升级为稳定记忆。4.2 召回 TopK 越多效果越差上下文被记忆噪声淹没我一直以为召回 10 条记忆肯定比召回 3 条强结果实测完全相反。当我一次给模型注入 10 条记忆时模型反而会花大量笔墨在无关的旧信息上甚至编造出记忆中并不存在的细节。我用了一个很笨但很有效的排查办法把每次召回的 10 条记忆和当前用户问题摆在一起人工判断这 10 条里有几条真的对回答有贡献。结果发现平均只有 3 条左右是有用的其余都是早期随手记下的低价值信息。原因在于相似度检索天然会把“看起来像”但“不需要”的内容捞出来。修复时我做了两处改动。一是把综合排序公式调整为“相似度分数”加“重要度分数”加“时间衰减系数”并观察权重对效果的影响二是硬性限制记忆条数默认 5 条以内宁缺毋滥。另外我在提示词里加强了边界说明“给出的长期记忆是背景参考请优先响应用户最新指令不要逐条解释记忆”。4.3 多账号混用一个记忆库A 的偏好出现在 B 的回答里这是我迭代过程中最严重的隐私事故。我的本地测试一开始只用了一个测试账号后来为了测试多用户直接复用了同一个内存数据库。结果发现A 用户在多轮对话里留下的“我喜欢简洁风格”这样的记忆竟然在 B 用户的会话里被召回并影响了回答。排查链路非常清晰我在召回函数里加了一行日志打印了召回的每条记忆所属的用户标识发现背后原因就是召回时只用了向量相似度没有做用户标识过滤。修改方式也很简单向量检索前先用元数据过滤把用户标识限定住再进行相似度匹配。这里要强调顺序不能反不能先按相似度召回再过滤否则即使最终结果看起来对了检索过程仍然可能把别人的记忆带回来一旦后期混入其他逻辑风险就会复现。还有一个容易被忽略的点记忆更新时要判断新记忆和旧记忆是否属于同一个用户。抽取模型如果同时处理多个用户的对话数据必须按用户拆分后分别抽取避免跨用户“参考”。4.4 用户让我删除记忆删了一个星期又回来了这是最诡异的一个问题。用户说“把关于我项目的记忆删掉”系统当时执行了删除业务库和列表里也都确认没有这条记忆了。但下一次会话时这条旧记忆又出现了仿佛从没删除过。我一开始怀疑是删除接口没刷新缓存翻了一遍代码没有发现问题。最后查到一个原因向量索引里的记录没有被删除。业务表和向量索引是不同的存储体系我只删了业务表索引里那一段向量还安安静静躺着。等到召回的向量检索阶段相似度一匹配又把这段“已删除”的记忆捞出来了。第二个隐藏原因是抽取阶段的反噬用户说“把关于我项目的记忆删掉”这句话本身包含“项目”这个主题词。我当时的抽取模块会把这句话当作一条新信息重新提炼成“用户提到项目希望删除项目记忆”或者更糟——“用户正在做项目”然后又写回库。这就像你努力清理桌面吸尘器又把你扫掉的垃圾吹了回来。针对第一个原因我做了删除同步删除业务数据时必须在同一个事务里把向量索引的记录也删掉。针对第二个原因我在抽取阶段加了“抑制指令”当用户消息中包含明确的删除/遗忘意图时这一整段消息不参与正向记忆抽取只执行删除操作。这两个问题修掉之后删除才算真正生效。5. 把长期记忆真正用进 Agent我对接入方案的几条总结文章最后部分聊一聊当我决定把长期记忆真正接入自己的 Agent 时沉淀下来的几条实践原则。5.1 触发时机不要在每一轮对话里都跑记忆抽取记忆抽取需要调用大模型有 token 成本也有延迟。最开始我天真地对每一轮对话都做抽取结果是每一轮都慢几百毫秒而且大量抽取结果都是 NOOP白白浪费算力。后来我把触发策略改成三种。第一种是“关键节点触发”在用户明确完成某个任务、离开对话、或者确认一次安排时才执行抽取。第二种是“轮次窗口触发”每攒够 5 到 8 轮对话做一次批量抽取把这几轮里值得记住的事实合并提炼。第三种是“异常语义触发”当检测到用户改口、取消、更换偏好时立即做一次更新操作。这三种方式组合使用后抽取次数减少了大概七成记忆库的质量反而更高了。5.2 质量优先给记忆加“实习期”让重要信息转正记忆不是一次性写入就永远可信。我给重要度不够高的新记忆增加了一个状态叫“临时候选”它默认不参与召回。如果用户在后面的对话里再次提到同一类信息或者用更明确的语气重复确认系统就把这条记忆升级为“正式记忆”。这个过程相当于“实习转正”。这个设计非常实用。它避免了模型因为一次随口闲聊就记住某个用户偏好也让真正重要的信息经过多次验证后稳定沉淀下来。代价是系统需要具备“合并同类事实”的能力但这一点在抽取阶段顺带解决远比清除大量噪声记忆要轻松。5.3 记忆可见性与脱敏长期记忆必须让用户能查看、能一键清空功能做出来之后我还做了一个原始但极其必要的页面展示“这个 AI 记住了关于你的哪些东西”。用户可以看到记忆库里的列表也可以一键清空所有记忆。这个功能的意义不仅仅是体验问题更重要的是降低使用风险。很多隐私问题都藏在看不见的地方。如果用户不知道系统记住了什么他可能在不经意间透露了不想被记录的信息而且毫无察觉。我在接入时给自己定了一条底线敏感信息默认不进入长期记忆身份证号、手机号、家庭住址这类信息在抽取阶段就要被拦截。对普通信息则提供回收站和导出功能做到“用户能查看、能删除、能知道自己被记住了什么”。这也是我在整个项目中觉得最值得坚持的一件事。记忆功能越是强大越需要给用户一个“遗忘的按钮”否则它就会从助手变成监控。我最后的体会是长期记忆这类功能的难点从来不在“把话存下来”而在于把信息变成对后续对话有价值的资产并且随时可以修正和删除。Mem0 给了我一个很好的框架起点但真正让一个 AI“看起来有记性”还是需要针对自己的场景反复调抽取、校验召回让记忆体系和对话流程磨合出一条稳定路径。希望我的这些经验和坑能让你在自己的项目里少走几步弯路。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑