你先别骂模型“失忆”,它的 Context 本来就不是 Long-term Memory。
你正在做企业知识库 Agent 的验收。前五轮它表现很好,能准确引用项目上线日期、负责人和审批规范。第六轮你随口问:刚才提到的那条紧急变更审批规则,后来被安全团队驳回了吗? Agent 停了一会儿,回答说:我之前的对话里没有这条信息。你翻回第三轮,发现它明明引用过。项目同学第一反应是模型失忆了,然后开始考虑:上下文窗口不够?要不要换更长窗口的模型?要不要直接把 RAG 接上?要不要用 MCP 把一堆工具串起来?
这些方向都贴着“Agent Memory”的边,但又都没打在要害上。
做企业级 Agent 的人,迟早会在某个深夜面对同一个问题:为什么模型看起来什么都懂,却记不住自己说过的话?真正的答案不是模型能力不行,而是很多团队把 Context、RAG、MCP 当成了记忆本身。它们可以成为记忆的载体或通道,但不是记忆系统。企业级 Agent Memory 真正要解决的,是给信息建立分层的生命周期:哪些是当轮对话的临时状态,哪些要跨会话保留,哪些必须经过校验、授权和审计之后才能写入长期存储。
这篇文章想和你认真拆一遍:Context 和 Long-term Memory 到底差在哪,RAG 在记忆里承担什么角色,MCP 为什么不能缺位,以及真正落到生产环境时,最容易在哪个环节翻车。
1. 当 Agent 突然失忆,先别急着骂模型
1.1 一个让人血压升高的真实场景
先还原一个我在团队里复盘过的案例。
团队做了一个面向销售团队的客户助手,希望它能在多轮对话里记住客户的行业、预算区间、决策链和上一轮沟通结论。Demo 阶段效果不错,因为演示时问题比较连续,模型窗口能装下整段对话。到了真实试用,新的会话一开始,Agent 就不认识客户了。销售同事说“还是之前那个客户”,Agent 反问“请问您指的是哪个客户”。更麻烦的是,如果某轮对话内容太长,还会直接抛类似this model's maximum context length is 1048576 tokens之类的报错,或者提示context overflow。
很多团队的第一反应是:换一个上下文窗口更大的模型。这能缓解“单次塞不下”的问题,但治标不治本。
因为窗口再大,也有尽头;而且把大量历史消息堆进窗口,并不会让模型更“懂”你,只会让它从更多内容里找答案,找错的风险反而更高。
1.2 多数团队把“记住”理解窄了
“记住”这个词在企业场景里其实包含三种完全不同的能力:
- 记住“这轮对话刚才说了什么”:这是会话内的连续性,由 Context 管理。
- 记住“这个用户、这个项目在之前几个月里的偏好和决策”:这是跨会话的长期记忆,必须由存储系统管理。
- 记住“Agent 有哪些工具、哪些数据源、哪些红线规则”:这是系统能力和权限边界的记忆,通常由配置、知识库和协议层管理。
如果只用 Context 去承担这三种任务,结果必然顾此失彼。你会在投入大量 token 之后发现:用户偏好没记住,工具权限写不进去,历史决策又和最新规则互相打架。
一个合格的 Agent Memory 架构,不是让模型“记得更多”,而是让不同类型的记忆各归其位。想做到这一点,得先把 Context 和 Long-term Memory 的区别彻底掰开。
2. 把概念拆开:Context 是草稿纸,Long-term Memory 才是档案室
2.1 Context 解决的是“这一轮任务”,不是“跨会话记忆”
Context,通俗说就是模型在生成回答时“手里能看到的全部内容”。它通常包括系统提示词、用户输入、历史消息、工具返回结果。模型每次生成回答,都会把这些内容重新读取一遍。也就是说,Context 是易失性的,它在当前请求结束后就不存在了。
可以把它理解成一张草稿纸。草稿纸上的内容,只在当前这道题里有效。你换一张草稿纸,上一张上的过程、草稿、备注就都不在了。模型不会因为你在上一轮输入过某些内容,就在下一轮自动知道这些内容;它必须每一轮都看到。
很多人误以为“ChatGPT 记得我之前说过的话”,其实是产品层把历史消息重新放进了下一次调用的 Context 里。这不是模型自带的能力,而是工程上的“拼接”。如果拼接逻辑断了、超长了、或者没有把关键历史放进去,Agent 就会显得失忆。
所以,Context 的正确使用方式是:只放当前任务真正需要的内容。它不应该承担“所有历史都保存”的职责,否则系统会变得越来越慢、越来越贵、也越来越容易出错。
2.2 上下文窗口再大,也替代不了长期记忆
上下文窗口在快速变大,从几万 token 到百万 token 都有。这会让人产生一种错觉:既然窗口这么大,是不是把所有历史都丢进去就行了?不用额外做长期记忆?
你至少会遇到三个问题。
第一是成本。每轮调用都要处理窗口里的所有 token,历史越长,费用和延迟增长得越明显。把几十万 token 的聊天记录反复塞给模型,换来的是缓慢的响应和快速拉高的账单。
第二是噪声。窗口越大,和当前问题无关的内容也越多。模型需要从大量历史里找到少数关键信息,注意力会被稀释。你会发现它开始关注一些不重要的细节,甚至忽略用户最新给出的约束。
第三是不可维护。记忆不是越多越好,它需要更新。旧的客户表述、过期审批规则、已经被推翻的决策,如果永远留在窗口里,模型就永远分不清版本。长窗口可以避免“放不下”,但不能解决“哪些该放、哪些该扔”的问题。
这也是为什么社区里会出现大量关于 context overflow、上下文过长的讨论。模型给出了一个物理上限,但工程上真正要守住的,是“有效上下文”的上限,而不是“全部历史”的上限。
结论很朴素:Context 解决的是单次任务的临场感,Long-term Memory 解决的才是跨时间和跨会话的记忆连续性。两者是上下游关系,不是替代关系。
3. 企业级 Agent Memory 的分层架构:别把所有信息塞进一个篮子
3.1 四层记忆模型,先建一张地图
我在实践里倾向把 Agent Memory 分成四层。这四层各自有生命周期、存储介质和读写方式,不能混着用。
| 层级 | 名称 | 生命周期 | 常见存储 | 典型内容 | 读写方式 |
|---|---|---|---|---|---|
| L0 | 瞬时上下文 | 当前请求内 | 模型窗口 | 系统提示词、当前用户输入、工具结果 | 每次调用重新组装 |
| L1 | 会话工作记忆 | 单个会话内 | Redis、内存、Memcached | 会话状态、最近关键消息、临时变量 | API 参数传递或状态服务读取 |
| L2 | 长期事实记忆 | 跨会话,按月或年 | 向量库、结构化数据库、对象存储 | 用户偏好、项目事实、历史决策、知识文档 | RAG 检索 + 结构化字段查询 |
| L3 | 能力与规则记忆 | 长期,随系统更新 | 配置文件、知识库、MCP 工具定义 | 工具能力、审批规则、安全边界、行为偏好 | 启动加载 / 动态发现 |
L0 和 L1 解决的是“当前任务不丢上下文”。它们应该尽量轻量,只保留当前步骤需要的信息。
L2 才是很多人挂在嘴边的 Long-term Memory。它的价值在于:会话结束后,Agent 依然能回答“这位客户上个月提过什么需求”“这个项目为什么选择当前技术方案”。这些内容适合放进知识库或结构化记忆表,而不是堆在对话记录里润色。
L3 解决的是“Agent 知道它能做什么、不能做什么”。工具清单、调用权限、数据访问范围、输出红线,这些属于系统级规则,最好以配置形式存在,由 MCP 这类协议层做统一暴露。
3.2 为什么“全塞进上下文”在企业场景里走不通
我们曾经在内部做过一次简单对比。同样是解决“客户在下一个会话里提到‘还是按上次说的办’”,用两种方案实现:
方案 A 是每次对话都把该客户最近三个月的历史消息全部拼进 Context。效果看起来不错,但每轮调用都需要处理大量历史文本,延迟和成本都高;而且历史消息里充满寒暄、临时讨论和未定事项,模型经常分不清哪一条是最终结论。
方案 B 是在对话过程中,把已经确认的客户偏好和决策点提取出来,写入 L2 长期记忆表;下一轮开始前,只检索最近使用过的、和当前问题相关的记忆片段,再拼进 L0 Context。效果更稳定,因为模型看到的是加工过的结论,而不是原始流水账。
企业级场景和 Demo 最大的区别,正在于此:你不能假设模型每次都面对一个干干净净的环境。真实生产里有多租户隔离、有权限控制、有数据过期、有审计需求。如果所有记忆都堆在对话历史和上下文里,你会发现“记不住”只是表面症状,真正的病根是没有任何一层存储系统在帮你管理信息。
四层模型的本质,是把记忆从“模型的一种不可控行为”变成“系统的一种可管理资源”。
4. 用 RAG 把长期记忆变成可检索、可回写、可更新的系统
4.1 长期记忆不能只做只读知识库,要设计写入链路
很多人一谈 RAG,想到的就是“把文档切片、向量化、做相似度检索”。这个理解本身没错,但如果把 RAG 用在 Agent Memory 里,只做只读是不够的。
原因很简单:知识库是静态的,记忆是动态的。你的项目文档可能三个月更新一次,但一次对话里用户反馈的偏好、一个临时决策、一条最新审批状态,可能几分钟后就要被后续会话引用。如果你不做写入链路,这些信息永远只活在当轮 Context 里,会话一结束就消失。
我给长期记忆设计了这样一条最小写入链路:
- 从对话、工具执行结果或业务事件中提取候选记忆。
- 用规则判断或让模型判断:这条信息是否值得持久化?它是不是一个稳定事实?是否得到了用户确认?是否涉及不该写入的敏感内容?
- 清洗记忆:补全主体、时间、来源,把口语化内容改写成便于检索的陈述句。
- 权限校验:当前用户是否有权限写入这条记忆?数据是否属于当前租户?
- 写入存储:文本向量化后进向量库,结构化字段进数据库,原始来源留一份引用地址。
- 维护元数据:写入时间、来源消息 ID、重要程度、过期时间。
这里最容易被忽略的是第二步。很多团队把“写入”做成“全量记录”,把用户随口说的一句“可能用 A 方案也行”也当成长期事实写进去。结果下次 Agent 就会把猜测当结论。判断力是长期记忆质量的核心,不能省。
4.2 读取链路:query 改写、双路召回、重排
有了长期记忆,读取时也不能简单做一次 top-k 向量检索就完事。
真实对话里,用户很少会用规范语言提问。他们可能会说“上次聊的那个方案后来怎么定了”“还有印象吗”。如果直接把这句话拿去向量检索,召回效果通常很差。所以先要做 query 改写,把含指代、省略的问题改写成独立可检索的语句。
然后在召回阶段,我会建议做双路召回:
- 一路走向量库,用语义相似度找到相关片段。
- 一路走结构化查询,用用户 ID、租户 ID、日期、状态、类型等字段做条件过滤。
两路结果合并后还要重排。重排阶段可以消除两个问题:一是排在前面但跟当前问题关系不大的片段;二是新旧版本记忆互相矛盾时,需要按时间戳、来源权威性来裁决。
整个过程很像人回忆一件事:你不是把人生所有片段都翻一遍,而是先确定“大概哪段时间、和谁、发生在哪个项目”,再去翻对应记录。RAG 做长期记忆读取,本质上就是这个过程的外化。
4.3 一个简化的记忆读写流程示例
下面是一个偏伪代码的示例,用于理解主流程。真实落地时,需要根据你的数据库和框架做适配。
# 记忆写入链路(伪代码) def persist_memory(message, user_id, tenant_id): candidate = extract_memory_candidate(message) if not should_persist(candidate): # 临时信息、未确认的猜测、敏感内容,不写入 return None cleaned = clean_memory(candidate) if not check_permission(user_id, tenant_id, cleaned): return None embedding = embed_text(cleaned["content"]) vector_db.insert( vector=embedding, metadata={ "tenant_id": tenant_id, "user_id": user_id, "source_message": message["message_id"], "timestamp": message["timestamp"], "expired_at": cleaned.get("expired_at", None) } )# 记忆读取链路(伪代码) def recall_memory(query, user_id, tenant_id): rewritten = rewrite_query(query) # 指代消解、补全 vector_hits = vector_db.search( embed(rewritten), filters={"tenant_id": tenant_id, "user_id": user_id}, top_k=20 ) structured_hits = sql_db.query( "SELECT * FROM memory " "WHERE tenant_id=? AND user_id=? AND expired_at IS NULL", tenant_id, user_id ) fused = merge_and_rerank(vector_hits, structured_hits) return build_memory_block(fused)这段流程看起来代码量不大,但真正上线之后,你会发现难点全在should_persist和merge_and_rerank这两个函数里。前者决定了长期记忆会不会被垃圾信息污染,后者决定了模型能不能拿到真正有用的记忆。
5. MCP 不是记忆本身,而是“受控接口”
5.1 MCP 在记忆架构里的三个关键价值
MCP 是一个让模型和外部工具、数据源之间进行标准化交互的协议。对记忆系统来说,它像是一套统一接口:Agent 不需要关心底层是向量库、MySQL、REST API 还是内部文档系统,只需要调用标准化的工具。
在 Agent Memory 架构里,MCP 的关键价值有三点。
第一,统一记忆读写入口。可以用一个 MCP server 暴露memory.search、memory.save、memory.delete这类工具。Agent 只知道“我有能力读取和写入记忆”,不需要知道具体存储细节。这对模型是减负,对系统是解耦。
第二,权限和审计前置。当记忆读写变成工具调用时,你就可以在工具层做统一鉴权。谁有权限查询某个租户的长期记忆?谁有权限写入一条用户偏好?每次查询是否留下日志?这些问题不再散落在业务代码里,而是在 MCP 层集中处理。
第三,工具能力可扩展。你想让 Agent 额外读取 CRM、工单系统或数据库里的信息,不需要修改主对话流程,只需要新增或调整 MCP server。这种扩展方式对长期维护比较友好。
5.2 别为了 MCP 而 MCP:适用边界要清楚
MCP 这段时间非常热,但越热越要冷静。
它不是银弹。如果你只是本地内存里保存会话状态,完全没必要引入 MCP 和网络请求;如果记忆存储在同一个服务内部,直接函数调用可能更高效。为了“架构先进”而把内部函数调用强行改成 MCP,带来的网络延迟和运维复杂度是实实在在的。
我建议这样判断:当记忆读写需要跨服务、跨团队、或者需要严格控制权限和审计时,才适合用 MCP 暴露成外部工具。它更适合在企业内部充当“记忆和外部数据系统的受控网关”,而不是所有场景的标配。
另外,MCP 是接口规范,不是存储。接上 MCP server 不代表 Agent 就有了长期记忆。记忆本身还存储在向量库、数据库和文件系统里。MCP 只是让模型能稳定、安全地操作这些存储。
6. 真正企业级的难点:记忆如何更新、遗忘和合规
6.1 只增不删的记忆系统,用半年就会退化
长期记忆和数据库一样,不能只做 insert,不做 update 和 delete。原因有两个:
一是检索精度会下降。当你存了一万条历史记忆,模型检索时很难每次都精准命中当前最相关的一条,旧信息会持续制造噪声。
二是信息冲突。用户一个月前说“偏好用 A 供应商”,上周改成了“换到 B 供应商”。如果系统没有更新机制,模型可能把两个偏好都呈现给用户,甚至引用过期的 A 方案。
解决思路是版本化和状态标记,而不是物理覆盖。
当新记忆和旧记忆冲突时,把旧记忆标记为superseded,并保留指向新记忆的来源链接。这样检索时不会把过期内容当成当前事实,但审计时依然能看到完整变更历史。
你还可以给记忆设计一个重要性评分。高频命中的记忆权重更高,长时间未命中的记忆定期降权。降到冷阈值以下后,可以归档到冷存储,减少在线检索的干扰。这个机制听起来很吸引人,但在企业落地时要注意:不是所有记忆都适合自动淘汰。如果一条记忆涉及合同、合规或安全事项,即使长期没被命中,也不能轻易清除。必须靠记忆分级来处理。
一个更稳妥的分级方式是:业务型记忆按热度和重要度做衰减,合规型记忆走独立保留期,到期由人工或任务确认后再处理。
6.2 隐私、隔离和可解释性,比“记得全”更重要
在企业场景里,长期记忆是资产,也是风险。
你可以在记忆里存放用户偏好,但最好不要把用户明文密码、银行卡号、敏感身份信息写进长期记忆。这不仅是技术判断,更是数据合规的基本要求。如果确实需要记录,必须加密存储、限制访问权限、并且记录访问日志。
多租户场景下,记忆隔离尤其重要。租户 A 的记忆不应该被租户 B 的 Agent 检索到。隔离可以分两种程度:简单做法是在元数据里加tenant_id过滤,更稳妥的做法是按租户独立索引或独立数据库。过滤方式实现快,但容易出现“忘记过滤”之类的低级错误;独立实例更安全,但成本更高。你可以先按数据敏感程度选。
最后是可解释性。每一条长期记忆最好都带上来源、时间戳、写入方。这样当模型基于某条记忆回答时,系统能说清楚“它为什么知道”。否则 Agent 一旦一本正经地给出错误结论,团队连追溯的入口都没有,这在企业环境里几乎不可接受。
7. 从 Demo 到生产:落地路径、排查链路与适用边界
7.1 四步落地路径,不要贪多
如果你现在正处于“想给 Agent 加上记忆”的起步阶段,我建议不要一上来就做完整平台。更稳的顺序是先跑通单点,再延伸到整张链路。
第一步:把单会话内的状态管理做好。先保证 Agent 在同一个会话内不会丢失“刚刚聊过什么”。这一步如果做不好,后面所有记忆增强都是沙子上的塔。
第二步:引入只读 RAG,把项目文档、公司手册、历史问题记录变成可检索知识。这个阶段先不做写回,只验证“模型能不能在里面找到需要的信息”。
第三步:增加记忆写入链路。等只读 RAG 验证通过后,再支持把对话中确认过的用户偏好、决策、结论沉淀到长期记忆。
第四步:接入 MCP 或类似的工具协议层,对记忆读写做权限、日志和审计。这是企业落地的关键一步,也是和单纯个人开发者的最大区别。
每一步都要小规模验证,不要一次性全部铺开。
7.2 “失忆”问题按这个顺序排查
如果 Agent 在生产环境出现“明明之前知道,现在却忘了”,或者“引用了一条过期信息”,我一般按这个顺序排查:
- 先看现象:是当前会话内丢上下文,还是跨会话完全失忆?两者的排查方向完全不同。
- 再看 Context 拼接:模型真正收到了哪些内容?系统提示词是否把工作记忆放进去?历史消息是否被截断?有没有把长期记忆注入?
- 再看检索链路:query 改写是否合理?向量检索有没有把租户、用户 ID 作为过滤条件?重排有没有把正确结果刷掉?
- 再看写入链路:候选记忆是否被错误地过滤掉?有没有写入成功?写入时元数据是否完整?重要性和过期时间是否正确?
- 再看权限和日志:是否因为权限校验失败,导致没有返回记忆?还是因为某条记忆来源不可信,被系统的审计逻辑过滤了?
这个顺序遵循一个基本原则:先确定问题是出在“输入没进去”“内存没找到”还是“权限没放行”。不要一上来就改 prompt、换模型。
7.3 哪些场景暂时不需要这套复杂架构
不是所有 Agent 都需要完整长期记忆,这个结论要说得足够直白。
如果是简单的单轮问答工具、一次性文档摘要、或者内部工具调用场景,用户不太会在意“你还记不记得上一个问题”,那 Context 加少量结构化存储就够了。强行引入 L2 长期记忆和 MCP 网关,只会增加系统复杂度和排查难题。
需要这套架构的信号一般有三个:
- 用户会在不同会话里提起同一个客户、项目或需求。
- Agent 需要在回答时引用历史决策或用户偏好。
- 团队有审计、权限和数据合规方面的强制要求。
如果你遇到的是这三个问题,那大概率需要的不是一个更长的 Context,而是一套真正有写入、有检索、有更新、有遗忘的长期记忆系统。
回到开头那个验收场景。当你再次遇到 Agent“失忆”,先别急着换模型。先打开调用日志,看看它这一轮到底拿到的是哪些内容。很多时候你会发现,它不是没有能力记住,而是你的系统根本没有把记忆送到它面前。
企业级 Agent Memory 的落点,从来不是把上下文窗口撑大,而是围绕 Context 建立一套分层、可控、可追溯的长期记忆体系。Context 决定这次任务能走多远,RAG 决定 Agent 能查到多准,MCP 决定外部能力和权限能不能被统一管理。把这三者组合起来,不贪大、不堆料,先从最小链路跑通,再一层层补上权限和更新策略,才是一条真正能长期走下去的路。