ai-memory架构拆解:跨Agent记忆层如何解决多智能体记忆共享难题
从去年年底开始,我一直在折腾多 Agent 协作的项目,最让我头疼的不是模型选型,也不是工具调用,而是“记忆”。每个 Agent 各聊各的,用户上午跟售前 Agent 说过需求,下午换到售后 Agent 就全忘了;更别说让多个 Agent 共享同一个用户的长期偏好。那段时间我几乎把 LangChain 的 Memory、LangGraph 的 checkpointer、向量库存对话记录都试了一遍,总感觉差一口气。直到我刷到 ai-memory 这个项目,7.9K Stars,定位是“跨 Agent 记忆层”,一下就把我之前零碎拼凑的方案给统一了。
它解决的其实是很具体的问题:给 Agent 一个可以插拔的长期记忆模块,不仅支持单个 Agent 记住用户,还能按 user_id 和 agent_id 做双维度隔离与共享,让不同 Agent 之间可以访问同一份用户记忆。如果你正在做客服机器人、多角色助手、或者任何“多个 Agent 协作服务同一批用户”的系统,这篇关于 ai-memory 的拆解应该能帮你少走不少弯路。我会从架构逻辑、核心 API、落地接入、实测表现几个方面展开,直接给到能复现的参考。
1. 为什么多 Agent 协作容易栽在“记忆”上
1.1 单体记忆和共享记忆的根本差异
先聊个都不陌生的问题:单体记忆指的是“一个 Agent 自己记住自己的对话历史”,最常见的就是 LangChain 里的 ConversationBufferMemory、ConversationSummaryMemory 这种东西。它们把聊天记录往 context window 里塞,或者压缩成摘要再塞进去。这在单 Agent、单用户、单会话的场景下是够用的,但一旦系统里存在多个 Agent,问题就来了。
我举个真实场景:我的项目里有一个导购 Agent、一个售后 Agent、一个物流查询 Agent。用户跟导购 Agent 聊了半小时,选了一款戴尔笔记本,还提到自己是学生,预算五千以内。然后用户关掉页面,第二天打开来咨询物流,接话的是物流 Agent。物流 Agent 的 memory 是空的,它不知道用户昨天聊过什么,更不知道用户是学生、预算有限。这时候用户如果问“我昨天看的那台电脑发货了吗”,物流 Agent 只能很尴尬地说“抱歉,我这边没有相关记录”。
这就是单体记忆的缺陷:记忆被绑定在单个 Agent 实例上,Agent 与 Agent 之间没有记忆的共享通道。ai-memory 的做法是把记忆从 Agent 里抽出来,做成一个独立层,任何 Agent 都能通过统一的接口去读写这段记忆,记忆的所有权归“用户 + 记忆层”,而不是归某个具体 Agent。
1.2 从 Chat Memory 到 Memory Layer 的演进
这个演进路线其实很清晰。第一代是 Session Memory,以会话为单位,会话结束记忆就没了;第二代是 Chat History 持久化,把对话历史存到数据库,但检索靠翻记录,效率低;第三代是 Vector Memory,用向量库存对话片段,按语义相似度召回,LangChain 的 VectorStoreRetrieverMemory 就是这类;第四代是 ai-memory 这种 Memory Layer,把记忆的写入、抽取、存储、检索、共享做成一个完整的中台,Agent 不需要关心底层是向量库还是关系库,只需要调用 save 和 search。
这里有个很关键的思路转变:前几代方案都在纠结“怎么存”,而 Memory Layer 更关心“怎么让记忆流动起来”。用户的一句话可能同时涉及用户的身份信息、商品偏好、时间约束、情绪状态,这些不同类型的记忆应该按不同的维度被组织,而不是简单堆在一条聊天记录里。ai-memory 的 dual-memory(双记忆)设计正是冲着这个去的:既能按 user_id 存用户长期画像,又能按 agent_id 存 Agent 自己的经验积累。
1.3 ai-memory 到底解决的是哪几个痛点
我把实际使用中感受到的痛点归纳成四类:
- 跨 Agent 记忆不可见:上面那个例子已经说明了,多个 Agent 服务同一用户时,记忆被割裂。
- 记忆与业务数据混杂:很多项目把记忆直接塞进业务数据库,表和表之间耦合严重,后续想换向量库或者加个记忆清洗逻辑,动一发而牵全身。
- 记忆没有生命周期管理:记住的东西越来越多,但哪些该长期保留、哪些该过期清理,没有统一策略。
- 记忆写入过于机械:直接把原始文本扔进存储,没有做结构化抽取,检索时召回的是一堆噪音。
ai-memory 针对这些痛点,提供了一个独立部署的 memory server / memory library,抽象出 save、search、reset 三个核心能力,并且在内部自动化抽取、清洗、排序记忆项。这不只是一个工具库,更是一种架构模式:把记忆从 Agent 的“附加功能”升级为“基础设施”。
2. ai-memory 的核心机制:从 save 到 search 的链路
2.1 整体架构先看一眼
ai-memory 的架构可以用一句话概括:它像一个中间件,夹在 LLM Agent 和存储后端之间。Agent 产生一段交互内容,通过 save 接口丢给记忆层,记忆层内部做抽取、格式化、写入;当 Agent 需要回想相关信息时,通过 search 接口提交 query 和过滤条件,记忆层返回排序后的记忆列表。
从部署形态上看,它既可以直接在 Python 进程里作为库来用,也可以跑成独立服务。我实际测试时是在 FastAPI 项目里直接 import,非常轻量,没有强制引入一堆重依赖。存储后端默认走的 SQLite,但通过配置可以挂到向量库。这种“默认轻量、可选重型”的设计,对中小型项目非常友好。
2.2 save 接口:记录 user 和 agent 双维度记忆
我最开始看文档时以为 save 就是简单存一条对话记录,实际测下来发现它做的事情远不止这些。save 的核心入参包括 user_id、agent_id、prompt(用户输入)以及可选的 metadata。调用之后,ai-memory 会把 prompt 里的关键信息自动抽取成一条结构化的记忆项(memory item),并打上 user_id 和 agent_id 两个维度的标签。
这里我贴一个实际跑通的调用示例,用的是我当时测试时的版本,具体命名以仓库 README 为准:
from ai_memory import Memory memory = Memory() memory.save( user_id="user_123", agent_id="agent_sales", prompt="我是一名学生,预算五千左右,想找一台适合编程和游戏的笔记本", metadata={"source": "web_chat", "session_id": "sess_001"} )执行完这条 save 之后,记忆层内部会生成一个记忆项,大致包含记忆内容、user_id、agent_id、时间戳、metadata 这些字段。更重要的是,它可能会把“学生”、“预算五千”、“编程和游戏”这些实体或偏好单独抽取出来,方便后续精准召回。我没有去深挖它的抽取 prompt 模板,但从结果来看,抽取后的记忆比原始文本更适合向量化检索和精确过滤。
2.3 search 接口:按 user、agent、metadata 检索
search 是记忆层真正发挥作用的地方。我常用的检索方式有三类:
- 按 user_id 全局搜:
memory.search(user_id="user_123", query="笔记本偏好"),不管哪个 Agent 问,都能拿到这个用户的历史画像。 - 按 agent_id 限定范围:
memory.search(user_id="user_123", agent_id="agent_sales", query="..."),只搜某个 Agent 与用户的交互记忆。 - 不传 query 纯拉取:
memory.search(user_id="user_123", agent_id="agent_sales"),把该 Agent 与该用户的所有记忆按时间倒序列出来。
我实际测试中发现,search 返回的结果不是简单的原始记录,而是经过相关性排序的记忆项列表。每个记忆项还有类似“最后访问时间”之类的信号,这为后续做“多久没提到的记忆降权”留了空间。在多 Agent 场景里,我最常用的是“先按 user_id 全量搜,拿回候选后再在业务层做过滤”的策略,因为跨 Agent 共享记忆本身就是这个项目最核心的卖点。
2.4 我理解的内部存储机制
官方文档没有把存储 schema 铺得很细,但根据我扒源码和使用时的观察,简单说一下我的理解:核心表结构大概围绕 memory items 展开,每条记忆项关联 user_id 和 agent_id,附带内容、类型、时间戳、metadata 等字段。内容字段会做向量化索引,生成 embedding 存入向量索引;同时原始文本也存在关系库里,方便结构化查询和人工审计。
提示:如果你打算把这个项目用到生产环境,建议先在小流量下跑一跑,确认 SQLite 的并发表现是否符合预期。我自己的体会是,单机并发不高时完全没问题,但如果 QPS 上来了,优先考虑把存储后端切换到专业的向量数据库。
3. 跨 Agent 记忆共享的边界设计
3.1 双维度隔离与共享模型
很多人第一次看到 user_id 和 agent_id 同时存在时会困惑:到底哪个维度是隔离的,哪个维度是共享的?我的理解是,ai-memory 这个项目在这两个维度上很灵活,但如果你要把它用好,需要明确自己的“记忆共享矩阵”。
我整理了一个四象限模型,大家可以直接套用:
| 维度组合 | 场景 | 典型用法 |
|---|---|---|
| 同 user,同 agent | 单 Agent 持续服务一个用户 | 搜历史偏好 |
| 同 user,不同 agent | 多 Agent 协作服务同一用户 | 跨 Agent 用户画像共享 |
| 不同 user,同 agent | Agent 跨用户积累经验 | 沉淀 Agent 自己的知识库 |
| 不同 user,不同 agent | 全局记忆 | 系统级常识共享 |
实际项目里最常用的是第二行:同一个用户,多个 Agent 都能读到他的记忆。比如我在客服系统里,售前 Agent 记下来的用户偏好,售后 Agent 要能查得到,这就是“同 user、不同 agent”的场景。ai-memory 的实现方式是用 user_id 作为共享的主键,用 agent_id 作为过滤的次键,search 时只要不限制 agent_id,就能跨 Agent 共享。
3.2 user_id 与 agent_id 怎么配才合理
这个坑我踩过,值得专门写一段。一开始我把 agent_id 当成可选的,只在 save 时随便传了个名字,search 的时候又忘了传,结果召回结果里有大量别的 Agent 产生的记忆。后来我把每个 Agent 的 agent_id 规范化成“模块/角色”的形式,比如agent_sales、agent_aftersale、agent_logistics,并且在所有 save 和 search 调用里都显式传入。
另外,user_id 我建议用业务系统自己的用户主键,而不是每次会话随机生成的 ID。如果每次登录生成的 session_id 都不一样,那跨会话的记忆就串不起来了。记住:user_id 是记忆共享的锚点,session_id 应该放进 metadata,而不是当 user_id 用。
3.3 实战场景:三个 Agent 协作的客服机器人
拿我最近在做的客服系统举例,完整跑一遍 ai-memory 的协作链路:
from ai_memory import Memory memory = Memory() # 用户在售前 Agent 这里咨询笔记本 memory.save( user_id="user_123", agent_id="agent_sales", prompt="我是一名学生,预算五千左右,想找一台适合编程和游戏的笔记本", ) # 第二天用户找售后 Agent 查物流,售后 Agent 先拉一下用户画像 memories = memory.search( user_id="user_123", query="用户购买偏好", ) # 售后 Agent 看到用户是学生、预算五千、买的笔记本,于是能给出更贴切的回答这个例子看起来简单,但里面藏着一个架构决策:售后 Agent 和售前 Agent 共享的是“用户记忆”,不是“对话历史”。ai-memory 的价值就在于,它让售后 Agent 不需要完整翻看昨天的聊天记录,只需要拿到结构化、可检索的用户偏好,这比原样塞聊天记录高效得多,也更节省 token。
4. 动手把 ai-memory 接进你的项目
4.1 安装与快速启动
安装非常简单,一行命令搞定:
pip install ai-memory这里的包名和项目名一致,装完之后在 Python 里直接 import 就能用。不需要额外配置环境变量,默认配置下就已经是开箱即用的状态。如果你想查看已经存储的记忆内容,项目还提供了一个简易的界面入口。我当时是直接在终端跑ai-memory命令或者通过 Python 方式启动,具体以最新版 README 为准,主要目的就是可视化地审查记忆条目,方便调试。
提示:如果你是在公司内网或者离线环境部署,记得提前把依赖包下载好。这个项目的依赖不算重,但涉及到 LLM 调用时,你需要配好对应的 API Key 环境变量。
4.2 用一段完整代码跑通记忆存取
为了让大家少踩我踩过的坑,我直接给一段可以跑的完整流程,包括初始化、保存、检索、删除/重置:
from ai_memory import Memory # 初始化,默认本地存储 memory = Memory() # 1. 保存记忆 memory.save( user_id="user_001", agent_id="agent_research", prompt="我正在研究开源项目,重点关注 agent memory 方向的方案", metadata={"project": "daily_open_source"} ) # 2. 检索记忆 results = memory.search( user_id="user_001", query="我最近关注什么方向" ) print(results) # 3. 清理该用户记忆(测试环境用) memory.reset(user_id="user_001", agent_id="agent_research")这里需要注意几点:
- 第一次运行时会初始化本地数据库,无需手动建表。
- search 的 query 参数是可选的,但如果你希望做语义检索,建议还是传入一个能表达意图的问题。
- reset 操作是删库级别的,生产环境一定要谨慎,最好通过权限控制或者人工审核来使用。
4.3 把 ai-memory 接到 LangChain 风格的 Agent 上
很多做 Agent 开发的朋友都是 LangChain/LangGraph 的用户,那 ai-memory 怎么跟这些框架协同?我个人的做法是不用 LangChain 自带的 Memory 类,而是直接在 Agent 的工具列表里注册一个“记忆工具”,把 ai-memory 的 save 和 search 包装成两个工具函数,让 LLM 在需要时自己调用。
基本思路如下:
from langchain.agents import Tool from ai_memory import Memory memory = Memory() def save_memory(prompt: str) -> str: memory.save(user_id="user_001", agent_id="agent_main", prompt=prompt) return "saved" def search_memory(query: str) -> str: results = memory.search(user_id="user_001", agent_id="agent_main", query=query) return str(results) tools = [ Tool(name="save_memory", func=save_memory, description="保存用户重要信息到记忆"), Tool(name="search_memory", func=search_memory, description="检索用户历史记忆"), ]这样做的好处是记忆行为由 LLM 自主决定——它会在觉得重要的时候 save,会在需要回想的时候 search,你不需要在每次对话前手动塞历史记录。缺点也明显,就是行为有一定随机性,需要你在 prompt 里明确告诉它什么信息值得保存。这个取舍我觉得很值得:用一点不确定性换来极大的灵活性。
4.4 持久化配置与 LLM 的接入
ai-memory 本质上需要一个 LLM 来辅助做记忆项的抽取和排序,所以你需要把 LLM 的 API Key 配好。默认情况下它会读取环境变量里的 Key,如果你用的是自建模型或者改为走本地小模型,需要在初始化时传入对应的 llm 配置参数。
关于持久化,我强烈建议在一开始就规划好存储目录或数据库连接串。默认的本地模式适合开发和演示,但生产环境里如果多台机器同时跑 Agent,就得把记忆层指向一个共享存储,否则 A 机器写的记忆 B 机器读不到,跨 Agent 共享就名存实亡了。
5. 实测体验、注意事项与方案对比
5.1 我在测试中观察到的明显收益
项目 Star 数 7.9K 不是没道理的,我实际跑完一圈之后,最直观的收益有三个。
第一,接入成本极低。从我 clone 项目到跑通第一个记忆存取,只花了几分钟,没有繁琐的配置。这让我很快就把注意力放在业务逻辑上,而不是折腾基础设施。
第二,跨 Agent 共享的语义很清晰。user_id + agent_id 双维度组合,简单但不简陋。跟直接拼一个 Redis 存聊天记录相比,ai-memory 多了抽取和排序的逻辑,检索质量高了一个档次。
第三,记忆项统一结构化。save 进去的是原始文本,取出来的是经过组织和排序的记忆项。这一点在给 Agent 做 prompt 拼接时非常关键。我之前用 LangChain 的记忆时,经常要把原始对话记录做截断和摘要,而 ai-memory 的检索结果可以直接作为 context 拼接进 prompt。
5.2 容易踩的几个坑
再分享几个我实际踩过、或者预判很多人会踩的坑:
- 别把敏感数据无差别写进记忆。ai-memory 会抽取 prompt 里的内容,如果你在对话里让用户提供了密码、身份证之类的敏感信息,这些内容会进入记忆库。虽然它在存储和传输上都做了不少安全考量,但数据安全的第一道关永远是业务侧。建议在调用 save 前做一次脱敏过滤。
- user_id 不一致导致记忆串不起来。这个前面提过,如果你在 A 场景用 user_uuid,在 B 场景用 user_phone,AI 再强也匹配不了。最好统一用一个稳定的业务主键。
- search 的 query 不能太宽泛。比如搜“用户信息”这种,召回结果往往不够精准。把 query 写成更具体的问题,比如“用户对笔记本的预算要求是多少”,效果会好很多。这个跟提示词工程一个道理,越是具体的问题,记忆召回质量越高。
- 生产环境单机内存模式慎用。如果你想多实例部署 Agent 服务,需要把记忆存储切到共享存储,否则不同实例之间的记忆是隔离的,这会导致同一个用户在不同机器上被对待成“两个用户”。
5.3 和 Mem0、LangMem 等方案的简单对照
研究过程中我也粗略对比了当前比较主流的几个记忆层方案,包括 Mem0、LangMem 以及 ai-memory。由于它们都在快速迭代,这里只说我在使用层面感受到的差异,不是盖棺定论:
| 方案 | 核心思路 | 适用场景 | 上手难度 |
|---|---|---|---|
| ai-memory | 双维度 user + agent,轻量可插拔 | 多 Agent 共享用户记忆,中小项目 | 低 |
| Mem0 | 面向 Agent 的长期记忆,平台属性更强 | 希望托管记忆服务,接受外部依赖 | 中 |
| LangMem | 跟 LangGraph 强绑定,主要是给 LangChain 生态用 | 深度使用 LangChain 技术栈的项目 | 中 |
我的主观结论:如果项目是轻量自建,希望快速落地、不被框架锁死,ai-memory 是性价比最高的;如果你的技术栈已经是 LangChain 全家桶,LangMem 的集成可能更顺;如果希望用现成的托管服务、少操心运维,Mem0 这类平台值得了解。但核心架构思路其实都一样:把记忆独立出来,而 ai-memory 恰恰把这个思路做到了最轻、最直白。
5.4 我的选型建议
最后说点个人的选型判断。如果你的系统满足下面任一条件,ai-memory 非常值得一试:
- 你有多个 Agent 在服务同一批用户,且用户画像要互通。
- 你不想被某个 Agent 框架绑定,希望记忆层可以独立替换。
- 你不想投入太多精力在记忆系统建设上,但又不满足于简单的聊天记录回填。
- 你想在现有 LLM 应用里快速加一个“记忆增强”能力,看看效果再决定要不要加大投入。
反过来,如果你的项目只是单 Agent 单会话,或者你已经有成熟稳定的记忆系统,那完全没必要为了用而用。工具是为场景服务的,不是用来堆砌的。
6. 基于 ai-memory 的扩展思路与工程化考虑
6.1 把记忆层做成公司内部的基础服务
我在实际项目里感受到一个趋势:记忆层不应该只服务某个 Agent,而应该作为 AI 应用内的基础服务存在。ai-memory 完全可以承担这个角色。你可以把它封装成一个内部 API 服务,统一管理 user_id 体系、统一做权限控制、统一审计记忆内容。
这种“记忆中台”的架构思路,在多部门都有 AI 产品时特别有价值。比如客服部门、营销部门、用户增长部门各自跑着一套 Agent,但面对的是同一批用户。如果每个部门单独建一套记忆库,用户画像就再次被割裂。而 ai-memory 这种可以独立部署、支持双维度检索的特性,天然适合做公司内部的“记忆总线”。
6.2 与强化学习中 reward 信号的配合
这个点比较进阶,但我在调研时留意到 ai-memory 生态里有朋友讨论过将记忆层与强化学习的 reward 机制结合。具体来说,Agent 的一次决策如果被标记为“成功”或“失败”,这个反馈可以转换成记忆项,存入记忆层。后续 Agent 在相似场景中就多了一个参考信号。
AI Agent 领域的项目一直在强调 agent 记忆和外部记忆,ai-memory 的 dual-memory 设计给了这种扩展一个很自然的载体:用户维度的记忆告诉 Agent“这个用户是谁”,Agent 维度的记忆告诉 Agent“这种情况下怎么做更好”。两者叠加,就形成了越来越贴近真实业务的决策辅助。
6.3 和 a-memguard 这类安全工具的联动思考
热词里有朋友在关注 a-memguard,这是一个面向 LLM Agent 记忆的主动防御框架,正好和 ai-memory 形成互补。ai-memory 负责让记忆“存得进、找得到”,a-memguard 负责保障记忆写入和读取过程中的数据安全。我在实际架构里也做了类似的分层:基础记忆层用开源库快速搭建,安全性通过外层的过滤和审计机制来补。
记住一个原则:任何从对话里抽取用户信息并长期存储的机制,都需要伴随严格的用户授权与敏感信息治理。不管项目本身有没有自带安全能力,业务侧必须有一个“记忆内容审批流”,尤其是涉及 C 端用户数据时,这个不能省。
6.4 如果你打算为 ai-memory 做二次开发
最后给想写代码贡献的同仁一些参考方向。我看源码时首先关注的几个点:抽取 prompt 模板的优化空间很大,default 模板比较通用,如果你的业务领域很垂直,自定义抽取模板能显著改善记忆质量;排序算法也有迭代空间,目前更多取决于向量检索的相关性,如果结合记忆新鲜度衰减、记忆重要性权重等信号,效果会更贴近真实业务需求。
这些方向改造成本都不小,但一旦做好了,很容易在社区里沉淀下来。毕竟 7.9K Stars 的项目,能被记住的一定不只是“能用”,而是“好用且不断进化”。
就我自己的实践感受来说,ai-memory 是我目前看到的把“跨 Agent 记忆层”这个理念落地得最轻巧的方案。它没有堆砌复杂概念,也没有强制你接受某种重型架构,而是用两个 ID 加两个核心方法,就把多 Agent 记忆共享的核心问题讲清楚了。如果你正在被 Agent 记忆问题困扰,不妨先拿它把原型跑通,再根据自己的业务场景慢慢打磨。