跨Agent记忆层:把记忆从上下文窗口解放出来
发布时间:2026/11/2 13:14:02 锦皓数字建站

做 Agent 开发大半年我最大的感受是模型能力已经不是瓶颈记忆才是。单跑一个 Demo 很容易给个 prompt 就能完成任务但一旦到了多 Agent 协作的场景比如一个负责规划的主 Agent 带着几个执行 Agent 干活你就会发现每个 Agent 都在失忆。它在子任务里查到的用户偏好、刚确认过的约束条件、上一轮对话里敲定的方案换个 Agent 就全不记得了。上下文窗口再大也只是当前这次会话的临时草稿纸进程一停、会话一切换纸就被风吹走了。所以当我看到 ai-memory 这个项目时第一反应是终于有人把跨 Agent 记忆层当成一个独立的基础设施来做了。它在 GitHub 上有 7.9K Stars核心思路一句话就能说清楚——把记忆从单个 Agent 的上下文里抽出来放到一个所有 Agent 都能读写的一层服务上。这篇文章我会从需求、架构、实操、生命周期、并发、安全到选型把它掰开揉碎讲清楚。如果你也在做多 Agent 系统或者准备在项目里引入长期记忆能力这篇应该能帮你省不少试错时间。1. Agent记不住事问题不在模型而在架构1.1 上下文窗口只是临时草稿纸很多人一开始会觉得记忆不够就加大上下文窗口。比如把模型从 8K 换到 128K、200K甚至加一层自动摘要把历史对话压短听起来都能解决问题。但实际上窗口再大解决的只是当前这次会话内能不能装下更多历史而不是Agent 能不能长期记住东西。这里有个关键区别上下文窗口是模型每次请求时临时拼装出来的输入。它有两个硬伤。第一token 是成本也是延迟。把几万 token 的历史都塞进每次请求响应时间会肉眼可见地变慢账单也会很难看。第二它是无状态的。会话一结束、进程一重启、请求一超时这些内容就没了。哪怕你把它存到 Redis 里下次还是得重新全量塞回窗口本质上还是在做临时拼装。更麻烦的是上下文窗口里的信息没有结构。模型读到 200K 的聊天记录要靠注意力机制自己去找哪些是用户偏好的咖啡口味哪些是已经放弃的技术方案。对小模型来说这种大海捞针式的检索既不稳定也没法解释。所以我的结论一直很明确上下文窗口是桌上的便签纸适合当前这轮对话临时用不适合当长期记忆的载体。真正的记忆层要解决的是Agent 重启之后怎么自动把有用的东西找回来。这个视角一变问题就从换更大窗口变成了怎么建一个档案室。1.2 记忆绑定进程是单Agent方案最大的坑市面上的单 Agent 记忆方案不少。LangChain 有 ConversationBufferMemoryLlamaIndex 有 ChatMemoryBuffer还有一些框架直接帮你把历史消息存到 Redis 里。这类方案的特点是把记忆绑定在一个 conversation_id 或者 session_id 上跟着某个 Agent 实例走。单 Agent 场景下够用到了多 Agent 协作就露馅了。我举个实际例子一个招聘助手系统里主 Agent 负责理解候选人要求子 Agent A 负责查简历库子 Agent B 负责整理面试题。候选人在对话早期说过我优先考虑远程岗位这个信息被主 Agent 记住了。但主 Agent 把检索任务派给 A 时A 的上下文里并没有这条偏好于是 A 返回了全是坐班岗位的结果。主 Agent 只能再补一句你是不是没看候选人偏好再做一轮二次检索。这种问题不是靠把所有东西都塞进每个 Agent 的上下文能解决的因为你永远不知道哪个子 Agent 需要哪条记忆。真正需要的是所有 Agent 共享一个逻辑上的记忆空间谁需要谁去查而不是每个人都拷贝一份完整聊天记录。记忆一旦绑定进程就天然无法跨 Agent 复用这是架构层面的问题不是调参能解决的。1.3 跨Agent记忆要解决的四件事把跨 Agent 记忆拆开看其实是四个问题写入、读取、共享、生命周期。写入解决的是一条值得记住的信息用什么格式落到哪里。不是所有对话内容都值得写得有个判断和抽象的过程。读取解决的是给定当前任务怎么把最相关的记忆捞出来而不是把整个历史倒给模型。共享解决的是在多个 Agent、多个会话之间这套记忆空间怎么做到逻辑统一。生命周期解决的是记忆什么时候过期、什么时候合并、什么时候删除。这四个问题看似简单但实际上每一个都会在真实场景里炸出很多细节。ai-memory 这类项目能拿到 7.9K Stars正是因为它把这些问题作为第一公民来设计而不是像普通框架那样顺手做一个挂在会话上的缓存。后面几章我会顺着这四个问题展开你会发现每一个都在生产环境里有对应的坑。2. ai-memory把记忆层抽出来一个档案室而不是随身的便利贴2.1 核心抽象记忆空间、记忆条目与来源追溯以 ai-memory 这类记忆层项目的通用设计来看通常会有三层抽象。最外层是 Memory Space记忆空间相当于一个档案室每个用户、每个项目或者每个团队可以拥有一个独立空间中间是 Memory Item记忆条目是单条可检索的信息单元最底层是 Metadata元数据描述这条记忆的来源、时间、类型和重要程度。这个抽象有一个很大的好处记忆不再只是一串文本而是一条带血缘关系的记录。比如用户偏好远程办公这条记忆它的来源是某个时间点用户在对话中的原话类型是 user_preference重要程度是 0.9。多 Agent 共享时后写的 Agent 能通过来源字段判断这条信息是用户亲口说的还是某个子 Agent 推断出来的从而决定信任权重。相比之下很多自研方案只是把聊天记录原样存进数据库。那样虽然也能查但等 Agent 数量上去之后你会发现问题没有元数据的记忆就像没有分类的杂物间什么都找得到等于什么都找不到。你可能会问直接全文搜索不行吗行但全文搜索解决不了哪条记忆更可信这条记忆是不是过时了这类问题而这些恰恰是 Agent 做出合理决策的关键。2.2 写接口Agent主动归档而不是被动缓存ai-memory 这类项目在写路径上有一个共同点鼓励 Agent 主动调用归档接口而不是由框架自动把每一轮对话都存起来。自动缓存看似省事副作用却很大。第一无关信息太多检索噪声大第二敏感信息会被无差别归档第三记忆之间互相矛盾时根本没有机会让 Agent 做一次该不该写的判断。实操中我会在每个子任务结束时加一个是否值得记忆的判断步骤。例如让执行 Agent 在返回结果时额外返回一个 memory_candidates 字段里面是结构化候选记忆再由主 Agent 决定真正写哪些。这套先候选、后确认的流程能显著提升记忆层的质量。下面是我在项目里用的示意写法# 示意代码API命名以你拉到的项目实际版本为准 memory_client.create_item( space_idcandidate-42, content候选人对远程岗位的需求优先级最高, item_typeuser_preference, source_agentinterviewer-agent, trust_score0.9, tags[remote, job_pref], )这看起来多了一步但换来的是写入记忆的准确率大幅提升而且每条记忆都能追溯到是哪个 Agent 在哪个环节写的。这对后面的调试和审计都特别重要。记住一个原则宁可少写几条也不要写一堆噪声进去噪声比空白更危险因为它会让检索结果的置信度整体下降。2.3 读接口检索要给模型刚刚好的材料读取路径是记忆层最容易做砸的地方。如果直接把最近 N 条返回给模型那跟把聊天记录塞回上下文没有区别。好的做法是走查询重写 → 候选召回 → 重排序 → 精简拼接这条链路。查询重写是指根据当前 Agent 的任务生成几个检索 query。比如主 Agent 要派任务给简历筛选 Agent检索层会自动把用户最近强调的求职偏好翻译成几个向量查询。候选召回用向量相似度把最相关的几十条捞回来。重排序再结合时间衰减、来源可信度、条目类型把真正重要的排到前面。最后精简拼接只把模型在注入窗口容量内最需要的内容返回。这一步看起来复杂但在真实项目里非常值得。我做过一个对比实验同样一个简历筛选任务直接从对话历史里截取相关段落时模型能命中偏好的概率大约 70%换成经过重排序的检索结果后稳定在 95% 左右。差的这 25 个百分点恰恰是 Agent 在用户眼里聪明和迟钝的分界线。理解读路径的机制比理解写路径更重要因为最终呈现在模型面前的选择题是由检索质量决定的。3. 接入一个最小可用的共享记忆系统3.1 部署与存储选型在动手之前先确定存储后端。ai-memory 这类项目通常依赖两部分主存储和向量索引。主存储可以用 PostgreSQL向量索引可以用支持 HNSW 的扩展也可以用独立的向量数据库。我的建议是先用 PostgreSQL 加向量扩展原因只有一个部署简单备份和事务都在一个地方不需要额外维护一套异构系统。部署方式用 Docker Compose 最顺手一个服务加一个数据库配置文件固定下来之后任何环境都可以一键拉起。需要注意一点如果你在本地开发别把数据库连接池配得太大很多项目默认配置对本地环境来说太激进启动十个连接就能把一台小开发机的资源吃满。我把最小部署要做的事列一下拉取项目镜像确认版本与你的模型兼容配置 PostgreSQL 连接串和向量维度参数设置记忆空间的默认隔离策略启动服务确认健康检查通过用 API 客户端写入一条测试记忆并检索回来这个过程大概半小时能跑通。如果卡在向量索引的维度不一致基本都是 embedding 模型没对齐把两端的维度参数改成一致就行。提示部署时最容易踩的坑是向量维度不匹配。先用一条测试数据走通写入→索引→检索全链路再接入真实 Agent能省掉大量排错时间。3.2 让两个不同框架的Agent共享同一份记忆部署只是开始真正有意思的是让两个不同框架的 Agent 共享同一个记忆空间。比如一边用 LangGraph 写了个客服 Agent另一边用 Spring AI 写了个工单处理 Agent两边本来完全没关系。接入记忆层之后它们变成共用同一个记忆空间的两只手。具体做法不复杂两边只要会调 HTTP API 就行。客服 Agent 在对话结束时把用户反馈的关键信息写入记忆空间工单 Agent 在开始处理前先查询该用户的历史记忆把上下文拉回来。这样即使两套 Agent 用的模型、编排逻辑完全不同它们在用户是谁、用户在意什么这个问题上依然能保持一致。我特别推荐用一个中间适配层来做这件事而不是在业务代码里到处拼 HTTP 调用。适配层对外暴露两个方法remember(user_id, content, meta) 和 recall(user_id, task_desc)。业务 Agent 只需要关心这两个方法至于背后是同步写还是异步写、是向量检索还是全文检索都跟它们无关。这个设计思路也是记忆层产品化的关键否则每个接入方都得理解底层细节推广成本会高很多。3.3 一个能复现效果的验证实验光说概念容易飘分享一个能验证的 demo。场景设定为用户先在客服 Agent 里说我比较忙只有下午三点后有空然后切换到一个预约 Agent问它这周能约什么时间。如果预约 Agent 直接回答早上九点说明记忆没打通如果它能自动建议下午三点后的时段说明记忆层起效了。实验步骤在客服 Agent 中调用 remember写入用户时间偏好用另一个客户端直接调用 recall确认能检索到该偏好启动预约 Agent让它先 recall 再生成答复对比关闭记忆层时的输出这个实验技术上不难但它能一次性验证三件事写入链路是否通、检索是否准、跨 Agent 共享是否生效。我在团队里做内部演示时用的就是这套流程十分钟就能把记忆层有什么用讲清楚。而且当你换框架、换模型之后这个验证实验还能继续复用它测的不是具体某个框架而是记忆层这层基础设施本身的可靠性。4. 记忆不能只进不出生命周期管理的四个阶段4.1 多条记忆冲突时谁说了算跨 Agent 记忆一定会遇到冲突。用户先说了我倾向快速迭代过两天又说这次我们要把稳定性放在第一位。两条信息都进了记忆空间检索的时候模型到底该信哪条ai-memory 这类项目对冲突的处理一般会落到版本机制和信任机制上。每条记忆都带 version 和 created_at后写入的版本原则上可以覆盖先写入的但覆盖不能靠后到优先这种粗暴规则而是要结合来源可信度。用户亲口说的优先级应该高于用户的反馈被 Agent 总结后的描述Agent 单方面推断最低。这个信任层次应该在元数据里显式记录下来而不是靠模型自己猜。我的习惯是在记忆层的写入接口里加一个 conflict_resolution 参数支持 append、overwrite、merge 三种模式。append 适合记录并列信息比如多个备选方案overwrite 适合纠正性信息比如用户明确推翻之前的说法merge 适合把新旧信息融合成一条更完整的描述。提前把这个机制定好比冲突发生了再人工处理高效得多。很多团队是等到线上出现Agent 言行不一才开始补这套机制那时候数据已经脏了。4.2 记忆过期不清理的Agent会精神分裂很多人刚用上记忆层时会兴奋地什么都往里塞后来就发现 Agent 开始精神分裂上个月还认为用户是学生这个月用户已经工作了旧记忆还在被检索出来导致回答前后矛盾。解决思路有三个层次。第一层是时间衰减记忆的检索分数随年龄增长下降太老的记忆除非是长期偏好否则自然沉底。第二层是重要性分级把用户所在城市这种稳定属性设为长期保留把用户本周出差这种临时状态设为低优先级。第三层是定期摘要合并当一类记忆积累到足够多时触发一个 Agent 来把散乱条目合并成一条概括性记忆降低噪声。我踩过的一个坑是只做时间衰减不做摘要合并。结果老记忆是自然沉底了但新记忆又碎又杂反复检索到的是用户说周五下午开会用户说周五下午四点后有空这种细碎片段模型拼不出完整上下文。后来加了每日一次的合并任务让一个专门的 Agent 按主题汇总当天新增记忆整体效果才明显好转。记忆层的质量不是靠堆容量而是靠定期整理。4.3 遗忘要可解释删除要可审计记忆层里的遗忘和数据库里的 DELETE 不太一样。我更倾向于把遗忘设计成标记 归档两级标记表示这条记忆不再参与检索归档表示这条记忆进入只读存储保留完整的原始内容。这样做的好处是当用户问你为什么会记得这个管理员能查得到依据当 Agent 行为异常要复盘也能从归档里找到是哪几条记忆影响了它。删除则是另一个层面的事。用户明确要求删除的记忆必须从所有存储介质里真正删掉包括向量索引和备份副本否则就违背了删除的语义。这一点在自研记忆层时最容易遗漏很多人只在业务库里删了忘了向量库里还留着一份结果用户以为删了实际检索还能捞到。生产环境里的删除流程最好走一个统一的删除服务由它负责清理所有副本而不是让业务代码各自调用。5. 生产环境最容易被问倒的问题并发、延迟与一致性5.1 多个Agent同时写记忆冲突怎么处理社区里大家都在问AI Agent 怎么扛并发落到记忆层上最典型的问题就是多个 Agent 同时写一个用户的记忆空间。比如调度系统同时派了三个子 Agent 去收集信息它们各自返回不同维度的结论然后同时写回。如果没有并发控制轻则丢更新重则把记忆空间写乱。我推荐的做法是单条记忆用乐观锁批量更新用事务。乐观锁的做法是在更新时带上预期的 version数据库比对不通过就重试一次重试还不行就进告警队列。批量更新则要走事务保证一个 Agent 写的一批相关记忆要么全部成功、要么全部失败不能出现用户偏好写了一半另一半丢了的状态。另一个容易被忽略的点是幂等。Agent 因为超时重试同一个写入请求可能被发两次。写入接口必须支持按 request_id 去重否则你会发现记忆空间里出现两条一模一样的记录检索时模型被重复信息干扰。这三板斧做完并发写基本不会出大问题。5.2 检索延迟是感知不到的隐形杀手记忆检索是 Agent 响应链路的一部分。如果一次 recall 要 300ms看起来不算多但多 Agent 编排里一个主任务可能要调用好几次 recall累计下来延迟就上去了。更麻烦的是很多项目在实现检索时会把召回重排拼接全同步串起来一旦向量库出毛刺整个 Agent 的响应都在等它。我的处理原则是把检索拆成快路径和深路径。快路径查热记忆缓存面向同一个用户最近几轮确定性的偏好毫秒级返回深路径走完整向量检索面向开放性的找找有没有相关信息允许几百毫秒。Agent 先拿快路径结果开始生成深路径结果再异步追加能明显降低首字延迟。这套思路在 RAG 里已经很常见记忆层同样适用因为它本质上也是一个检索系统。5.3 缓存与异步写用内层设计扛住并发写路径同样不能全同步。用户每轮对话都触发同步写底层数据库扛得住业务侧也会被写入毛刺拖慢。正确的姿势是同步确认 异步写盘先把记忆写入消息队列确认入队成功就返回后台 worker 再消费并写入存储。对 Agent 来说写入成功的时间从几十毫秒降低到几毫秒而且削峰效果非常明显。缓存方面我要特别提醒记忆层的缓存不要只缓存结果还要缓存检索 query 的重写结果。同一个用户在短时间内发起相似任务query 重写如果每次都跑一次模型会成为隐性开销。把这个结果缓存下来可以显著减少不必要的模型调用。实测下来这一条优化的收益甚至比缓存记忆条目本身还大因为 query 重写往往被忽略但它对每条请求都是固定开销。6. 记忆层引入了新的安全边界必须提前设计6.1 记忆投毒让Agent学坏的最短路径记忆层有一个很少有人一开始就注意到的风险它让外部内容进入 Agent 知识多了条捷径。如果一个子 Agent 在处理网页时把遇到不认识的人名就推荐会员套餐这样的内容写进了记忆空间主 Agent 后续可能老老实实照做。这就是记忆投毒。对付它我目前觉得最实用的三招第一写入白名单。不是所有 Agent 都能往用户空间写记忆只有具备明确 write 权限的 Agent 可以。第二内容校验。写入之前跑一遍敏感规则和指令检测识别那些试图劫持后续行为的文本。第三来源标记。每条记忆都带上 source_agent可疑来源的记忆在重排序时降权。热词里提到的 a-memguard 这类防御框架思路本质也是如此在记忆读写路径上加一道主动防守而不是等出了事故再清理。我不建议做的是因噎废食地禁止 Agent 写入。Agent 之间共享经验本来就是记忆层存在的意义只要来源清晰、权限明确、可降权就能把风险控制在可接受范围。你要是完全禁止写入那记忆层就退化成只读档案库了价值少了一大半。6.2 权限隔离一套记忆层服务多个租户生产环境里一个记忆层往往要服务多个业务方甚至一条数据链路会同时服务多个用户。如果没有隔离用户 A 的记忆被用户 B 的 Agent 捞到那就不只是 Bug而是事故了。至少要设计四层隔离存储层按 space_id 分桶检索层强制带空间过滤条件绝不能允许不带空间条件的全局检索接口层做内容归属校验防止 A 空间传来 B 空间的 ID监控层记录每一次跨空间的访问尝试哪怕被拦截也要留痕。我见过不少项目把空间隔离当成以后再说的优化项结果一上线就出事。记忆层这种基础设施隔离必须在第一天就做对因为它不像业务代码那样可以随时重构一旦线上积累了大量记忆数据迁移和修复成本会非常高。做技术选型时这也是我重点考察一个项目是否成熟的标准之一。6.3 审计追踪每条记忆都能讲清来源最后讲可观测性。记忆层和普通业务服务不一样它直接影响 Agent 的推理依据。当模型回答出人意料时运维人员最需要回答的问题是这条回答是基于哪几条记忆生成的这些记忆是谁在什么时候写的如果这些问题答不上来排查就会退化成猜谜。所以生产部署时我会强制开启两个机制读审计和写审计。写审计记录每条记忆的新增、更新、合并、删除读审计把每次 recall 请求与返回的记忆条目 ID 关联保存。这样即使出了问题也能复盘出完整的因果链。比如用户投诉Agent 怎么老说我想要线下开会审计日志一查很快就能定位是某个环节把偶尔线下写成了偏好线下。没有审计的记忆层就像没有日志的线上服务出事只能靠重启解决。7. 选型建议什么时候该上独立记忆层什么时候别上7.1 主流记忆方案对比写到这里肯定有人想问ai-memory 到底值不值得用和其他方案比怎么样。我把常见的几类方案放到一个表里对比方便你做判断。方案定位跨Agent共享结构化程度部署成本适合场景ai-memory独立记忆层服务独立基础设施强高带元数据与生命周期管理中多Agent协作、跨会话长期记忆、生产级Mem0轻量记忆层库中需要自行设计共享中低快速原型、单Agent记忆增强MemoryScope端到端记忆框架中中高中需要可视化记忆流的研究与调试LangGraph Memory框架内置记忆弱绑定框架生态低低单框架内的对话记忆自研Redis/向量库完全自定义取决于设计取决于设计高开发成本特殊需求、已有基础设施强绑定注意这里的评价角度是我自己在实际项目里的体感不同版本和玩法差异很大。记住一点没有最好的方案只有最匹配的方案。不要看到 7.9K Stars 就无脑上先看自己的场景适不适合。7.2 我的判断维度什么时候该上独立记忆层我一般看三个信号。第一个信号是 Agent 数量。只有一两个 Agent、跑单会话任务用框架内置记忆就够了当 Agent 数量到五个以上或者有编排层和子 Agent 频繁切换就该考虑独立记忆层。第二个信号是跨会话需求。用户今天说的事下周的对话还要参考今天是客服 Agent 收集的信息明天是推荐 Agent 要用。只要存在跨会话、跨 Agent 复用记忆就必须从会话上下文里抽出来。这个信号其实最容易被识别也最容易被拖延。第三个信号是治理需求。需要知道 Agent 为什么记住某件事、需要控制某种记忆的留存周期、需要审计访问记录。治理需求这四个字一旦出现就说明你不能再靠贴片式的会话记忆方案了。反过来如果只是做技术验证、写 Demo用完整方案反而显得重不如先用轻量库把流程跑通再说。技术选型最忌讳杀鸡用牛刀和一步到位项目阶段不同答案就不同。7.3 一点个人的使用心得从开始接触记忆层到现在我最大的感受是记忆层不是一个加上就能变聪明的插件它是一个需要用心设计的子系统。ai-memory 这类项目给了你一个很好的起点但真正让记忆层起效果的是你想清楚了自己的 Agent 要记住什么、怎么证明它记住了、记错了怎么修正。我会建议所有刚接触的人都从那个客服 Agent 写入偏好、预约 Agent 读取偏好的最小实验开始亲手跑通一遍再考虑复杂功能。跑通之后再做三件事设计合理的元数据、加审计、定义过期策略。这三件事做完你的记忆层才勉强算能上生产。至于记忆层未来的方向我比较看好来源可追溯和自动摘要这两块它们决定了记忆层能不能从一个存储成长成一个会自我整理的知识组织。如果你也在做 Agent 基础设施这个方向值得持续关注。
锦
锦皓数字建站
深耕本土企业品牌数字化升级,专注原创端正雅致商务官网,从视觉设计到稳定运维全程保驾护航。