最近一直在折腾 Agent 项目的记忆模块,发现团队内部对"记忆"的理解居然能差出十万八千里。有人觉得把聊天记录存数据库就算记忆,有人坚持必须上向量库,还有人张口闭口"长短期记忆网络"。正好这段时间密集对比了阿里、腾讯、字节这三家对外公开的 Agent 记忆方案,踩了不少坑,也摸清了一些门道,写出来给同样在做 Agent 开发的朋友做个参考。
先说结论:这三家的方案没有绝对的好坏,核心区别在记忆的建模粒度和召回策略上。阿里的方案偏"结构化业务记忆",腾讯的偏"轻量会话记忆",字节的则铁了心走"语义向量记忆"路线。下面逐个拆开聊。
1. 为什么 Agent 的记忆成为核心问题
1.1 记忆在 Agent 架构中的位置
一个真正能用的 Agent,底层逻辑其实就四件事:感知、规划、行动、记忆。前三件事各家做得都差不多,模型能力决定上限,工具调用决定下限,真正的差距全在记忆上。没有记忆的 Agent 是个"金鱼脑子",上一轮对话刚结束,下一轮它就忘了你叫什么、刚才让它处理到哪一步、文档里哪个字段是关键。
我实测过最典型的场景:让 Agent 连续处理一份合同,先让它提取关键条款,再让它对比模板差异,最后让它生成修订意见。如果每一步都当作全新对话,前两步的结果它全不记得,第三步的输出基本就是重新读一遍文档,既浪费 Token 又容易出错。加了记忆模块之后,中间结果直接复用,整个流程的响应速度能提升 30% 以上,输出质量也更稳定。
从架构上看,记忆模块夹在 LLM 和业务逻辑中间,扮演的是"状态层"的角色。它决定了 Agent 能不能在多轮、多任务、跨会话的场景下保持一致性。这也是为什么各家大厂宁可牺牲一点响应速度,也要把记忆模块做重。
1.2 三层记忆结构:短期、长期、工作记忆
行业内比较统一的划分方式是三层结构,这也是热词里"双网络记忆模型"的底层逻辑来源:
- 短期记忆(Short-term Memory):本质上就是 LLM 的上下文窗口(Context Window),模型能在本次请求内看到的所有内容都算短期记忆。特点是快、但容量有限,而且请求一结束就没了。
- 长期记忆(Long-term Memory):持久化存储的各类知识、用户偏好、历史事实,放在向量数据库、图数据库或普通数据库里。特点是容量大、可跨会话复用,但需要做召回(Retrieval)才能进入上下文。
- 工作记忆(Working Memory):当前任务执行过程中的临时状态,比如已经执行到子任务第几步、某个中间变量的值、步骤间的依赖关系。工作记忆通常在 Agent 的编排层(Orchestration Layer)维护,任务结束可以丢弃,也可以沉淀到长期记忆。
这三层对应到具体实现上,就是三类存储:上下文窗口管短期,向量库/键值库管长期,执行器状态机管工作记忆。任何一家的方案,本质上都是在给这三层做不同的编排和调度策略。
2. 三套方案的整体设计与设计思路
2.1 阿里:业务链路驱动的结构化沉淀
阿里这套方案给我最大的感受是重业务。它的记忆模块不是单纯做"聊天记录归档",而是把记忆拆成业务实体、业务关系、业务状态三个维度。比如客服场景,实体是用户、订单、商品;关系是"用户 A 下单了订单 B,订单 B 包含商品 C";状态是"订单 B 当前在退款流程中"。
这套设计的聪明之处在于,它把记忆从"自然语言片段"提升到了"结构化业务数据"的层面。Agent 在跑业务的时候,记忆不仅仅是给它提供参考背景,而是直接参与决策逻辑。比如用户说"上次那个订单怎么样了",Agent 不用全文检索历史对话,而是直接查结构化状态,几毫秒就能拿到结果,且回答准确率极高。
实现上,阿里偏向用一套轻量的业务记忆框架,结合规则引擎做实体抽取和关系维护。记忆的写入不是靠模型每次对话完自动总结,而是靠业务动作触发——用户下单写一条、退款状态变更更新一条、工单关闭归档一条。这样一来,记忆的时效性和准确性都有保障,不会出现"模型总结出一堆废话存进去"的问题。
2.2 腾讯:以会话为中心的轻量键值记忆
腾讯的思路走的是另一个极端——轻、快、好接入。它的记忆模块核心是一个带 TTL(生存时间)的键值存储,外加一个会话级的临时存储区。键就是会话 ID 或用户 ID,值可以是字符串、JSON、甚至嵌套对象,读取的时候按 key 直接取,压根不做向量召回。
这套方案对于"轻量个性化"场景非常友好。比如你让 Agent 记住"用户所在城市是杭州"、"用户偏好简洁风格"、"用户上次登录时间是昨天",直接 set 进去就完事。读取的时候按需取出来塞进 Prompt,简单直接,几乎没有额外延迟。
但它的短板也很明显:不擅长处理模糊的、语义化的记忆。用户说"我记得上次有个文件里面提到过预算的事",如果当时没把"预算"这个关键词显式写进键值里,这套方案基本召回不出来。腾讯内部对这套记忆的定位也是"辅助上下文",而不是"核心决策依据",适合绝大多数轻量交互场景,但不适合重度知识密集型任务。
2.3 字节:向量化语义记忆的坚定路线
字节的方案是三家里最"潮"的,核心就是一切皆向量。对话记录、用户偏好、任务约束、外部文档,全部切块、Embedding、进向量库。召回的时候用余弦相似度或者点积相似度,找出语义最接近的 top-k 片段,拼进上下文。
这套方案的优势在"召回能力"上确实是碾压级的。用户用口语化的方式提需求,哪怕表达方式和当初写入时的文本完全不一样,语义向量也能兜住。比如用户当初存的是"我比较喜欢偏暖色调的设计",后面问"UI 风格能不能柔和一点",向量召回能把这两条关联起来。这在腾讯的键值方案里就很难做到。
字节的注意力花了很多在记忆的写入侧上。它会对原始文本做清洗、去噪、话题聚类,聚完类的话题才作为一条记忆写入向量库,每条记忆还附带置信度分数和时间戳。这个设计直接呼应了热词里的"记忆=score+时间半衰期"思路——记忆不是永不过期的,分数会随时间衰减,旧记忆会被逐渐降权,避免长期运行之后记忆库被陈年旧事污染。
3. 核心机制逐项拆解:写入、召回、更新、遗忘
3.1 记忆的写入策略:谁来决定"这值得记"
三家方案在写入策略上的差异,直接影响记忆库的数据质量。阿里的方案靠业务事件驱动,写入的是高度结构化的数据;字节的方案靠模型驱动,对话结束后异步做一轮总结、聚类、Embedding;腾讯的方案最简单,开发者自己决定什么时候 set。
我的建议是混合策略最靠谱。用阿里那种"业务事件驱动"的方式保证核心状态准确,叠加字节那种"异步总结"的方式捕获非结构化的用户偏好,最后用腾讯的键值存储放高频访问的临时配置。三个写入通道各自负责一类记忆,互不干扰。
实操里,异步总结有一个必须注意的点:一定要做去重和合并。我把同一段对话跑了两遍,第一遍和第三遍的总结结果有 60% 的内容是重复的,如果直接都写进记忆库,召回的时候会返回大量冗余片段,白白吃掉上下文窗口。
3.2 召回策略:向量相似度之外的事
召回是整个记忆链路里最影响体验的一环。很多人以为向量召回 top-k 就完事了,实际上纯向量召回在真实业务里表现并不好。我跑过一组对比实验,纯向量召回在"用户明确提到某个实体词"的场景下,准确率反而比关键词召回低——因为向量把实体名的语义信息稀释了。
现在业内普遍的做法是混合召回:关键词(BM25)召回一路,向量相似度召回一路,两路结果用 RRF(Reciprocal Rank Fusion)做分数融合,取融合后的 top-k。三家里面字节其实最接近这个思路,它虽然主打向量,但也内置了轻量的关键词索引做补充。
召回还有一个细节是带时间衰减的重排。召回结果不能只看相似度,排序的时候要乘一个时间衰减因子。一条三个月前的记忆和一条昨天的记忆,哪怕向量相似度一样,在排序上也要拉开差距。具体做法我参照热词里的思路,给每条记忆维护一个 score,召回到候选集后按 `score * (0.5 ^ (age / half_life))` 重排,half_life 设成 7 天左右,实测效果比较稳。
3.3 上下文管理:Token 的硬约束
记忆召回结果的拼接方式直接决定 Token 消耗和模型理解质量。这里有个非常反直觉的结论:召回结果不是越多越好,拼接位置也不是越靠前越好。
我最初的做法是把召回的记忆全部一股脑塞进 System Prompt,结果模型经常把历史记忆当成交代任务来执行,或者被不相关的记忆带偏。后来改成这套策略:系统提示词只保留角色设定和硬性规则,记忆内容单独放在一个"已知信息"的 sections 里,并且每条记忆用`[记忆时间: 2025-03-12] 记忆内容...` 这种格式加时间戳前缀,效果立刻好了很多。
各家其实都在做类似的事,核心逻辑就是把"记忆"和"指令"在 Prompt 层面拆开。阿里做的更细,它会把记忆按业务维度分桶,只把当前场景关联的实体和状态拼接进 Prompt,其他的一概不塞。这个"场景过滤"思路非常值得抄,能省一半的 Token。
3.4 记忆的持久化与迁移:跨账号、跨设备的灵魂拷问
热词里那条"workbuddy 换账号如何获得原来账号的记忆"非常真实。记忆的持久化看起来简单——存库就行——但一旦涉及账号切换、设备迁移,问题就全冒出来了。核心难点在于记忆的序列化格式和身份映射。
我在实际项目里定的规范是:记忆库底层全部按 `user_id + namespace` 分片存储,导出的时候打包成 JSON Lines 格式,每条记录带版本号、时间戳、记忆类型。换账号的时候,如果新旧账号在系统里有绑定关系(比如手机号绑定),直接触发一次记忆迁移任务;如果没有绑定,就只能靠用户手动导入导出文件。参考 yicat 那类记忆库文件的做法,导出文件命名统一带上用户标识和版本,避免迁移的时候覆盖错账户。
我踩过的坑是:字节那套向量化记忆导出的时候,向量数据本身是几百维的浮点数组,文件极大,而且换了 Embedding 模型之后向量全废。后来我们迁移的时候干脆只导出原始文本和元数据,到新环境重新 Embedding。这个"重新向量化"的过程要多花几分钟,但胜在干净可靠。
4. 选型建议与实战经验
4.1 不同业务场景下的选型参考
说到底,选哪家的思路,取决于你的 Agent 到底是干什么用的。我把常见场景和推荐方案列了个表,方便直接套:
| 业务场景 | 推荐思路 | 原因 |
|---|---|---|
| 客服/工单 Agent | 阿里式结构化业务记忆 | 需要精准的实体状态追踪,不能靠模糊语义 |
| 个人助理/轻交互 | 腾讯式键值记忆 | 记忆内容简单,需要低延迟高并发 |
| 知识问答/内容生成 | 字节式向量记忆 | 查询方式多变,语义召回能力强 |
| 多步骤任务编排 | 阿里式结构化 + 工作记忆 | 任务中间状态必须显式管理,不能靠上下文硬扛 |
| 长期陪伴型 Agent | 字节式向量 + 时间衰减 | 需要跨长期会话保持一致性,且要防记忆污染 |
这张表后面是血泪教训换来的。最开始我做客服 Agent 的时候一股脑上了纯向量记忆,结果用户说"我上次那个订单"——向量召回把"上次"和"订单"这俩词分别匹配到了不同的历史对话,压根没关联起来,回答直接翻车。后来才明白,业务状态类的问题,结构化方案才是正解。
4.2 我在实际落地中踩过的坑
坑一:记忆写入风暴。有段时间给 Agent 接了流式对话,每轮对话结束都触发一次异步记忆总结,结果高峰期并发一上来,总结任务堆积,数据库写入负载直接飙红。后来加了两个限制:一是做了写入去抖(短期内相同内容的记忆不重复写),二是把总结任务改成批量处理,攒够 N 条对话才触发一次总结任务。
坑二:记忆召回噪音。向量召回有个天然问题,相似度最高不代表相关。我遇到过用户问"推荐一部电影",结果召回回来一堆"这部电影很好看"之类的影评——语义上确实像,但根本不是记忆,是垃圾。后来加了实体校验环节,召回结果先做 NER 抽取,抽取出来的实体和当前问题实体有重叠才保留,噪音立刻降了一半。
关于"ai agent 怎么扛并发"这个热词,我的理解是记忆模块的并发瓶颈几乎都在写入侧和召回侧。写入侧用队列削峰,召回侧用缓存——高频访问的记忆片段(比如用户 id → 用户偏好)直接放 Redis,命中率能到 80%,向量库的 QPS 压力能降一个量级。
5. 常见故障与排查技巧速查
| 故障现象 | 排查思路 | 解决方案 |
|---|---|---|
| Agent 总是忘记刚说过的内容 | 检查是否启用了持久化记忆,短期上下文是否被截断 | 确认写入链路正常,调大上下文管理中的关键记忆优先级 |
| 召回的记忆和当前问题完全无关 | 检查向量模型和查询预处理,看是否做了实体对齐 | 加混合召回,加实体过滤,必要时替换 Embedding 模型 |
| 记忆库无限膨胀,Token 消耗飙升 | 检查去重和遗忘策略是否生效 | 加时间半衰期衰减,设置记忆条数上限,定期清理低分记忆 |
| 切换账号后记忆全部丢失 | 检查身份映射和内存/持久化边界 | 统一 user_id 分片,手动导入导出 JSON Lines 格式记忆文件 |
| 多轮对话后模型越聊越糊涂 | 检查 Prompt 中记忆和指令是否混在一起 | 记忆单独成 section,加时间戳,约束模型只把记忆当背景信息 |
排查工具方面,我现在最依赖的还是"日志三件套":写入日志、召回日志、Prompt 日志。每次对话都记录最终拼进去的召回片段,出了问题能直接回放,看是哪条记忆把模型带偏了。
注意:不要一上来就怀疑模型能力。在我接手的项目里,70% 的记忆类问题出在写入侧——不是没记,而是记了不该记的、或者记了没去重。
还有个小技巧:给记忆模块做一套可视化的管理后台。看起来重,但排查问题非常管用——直接把当前用户的所有记忆列出来,啥问题一目了然。我们内部叫它"记忆检查员",每次 Agent 表现异常,先打开后台看它脑子里装的什么,基本就定位了八成的问题。
6. 最后分享一点个人体会
做了这么久的 Agent 记忆方案,我最大的感触是记忆架构没有银弹,只有取舍。跑业务链路重的场景,你就得放弃纯向量的浪漫,老老实实做结构化状态管理;做泛知识类的场景,就得接受召回噪音,用重排和过滤去补救。
如果非要说有什么放之四海皆准的经验,那就是:记忆方案设计的第一件事,永远不是选数据库,而是定义"你的 Agent 到底要记住什么、忘掉什么"。这个定义想清楚了,后面的一切——选型、写库、召回、衰减——都是顺理成章的事。定义没想清楚,哪怕把阿里、腾讯、字节的方案整套搬过来,照样跑不出效果。