尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

Memmy:为多Agent系统构建统一记忆层基础设施

Memmy:为多Agent系统构建统一记忆层基础设施 多 Agent 系统在实际项目中越拆越细很快会遇到一个比“工具调用失败”更隐蔽的问题每个 Agent 各记各的上下文片段互相割裂A 会话里确认过的用户偏好B 会话又重新问一遍甚至同一个 Agent 重启之后就把关键业务约束忘干净。MemOS 团队开源的 Memmy瞄准的正是这个痛点用统一记忆层把多个 Agent 的记忆收敛到一起让记忆像数据库一样可写、可查、可共享。这篇文章会从多 Agent 记忆为什么难入手讲清楚 Memmy 的核心设计思路、本地部署方式、关键 API 用法、接入多 Agent 框架时的数据模型设计以及生产环境必须考虑的隔离、权限和过期策略。读完可以在自己的项目中把“记忆”从零散的上下文补丁升级成一个独立基础设施。1. 先理解多 Agent 记忆为什么不能靠改 prompt 解决很多团队刚接触多 Agent 开发时记忆方案很朴素把历史对话塞进 system prompt或者把上一轮输出拼到下一轮输入里。这种做法在 demo 阶段够用一旦 Agent 数量超过三个、任务链变长问题就会集中爆发。1.1 多 Agent 场景下记忆到底指什么Agent 记忆可以从两个维度拆开看。第一个维度是时间范围短期记忆对应当前会话内的上下文比如用户刚提交的需求、上一步工具返回的结果长期记忆对应跨会话的稳定信息比如用户的偏好、项目的约束、历史决策记录。第二个维度是归属主体单个 Agent 自己维护的私有记忆以及多个 Agent 需要共享的公共记忆。把这两个维度交叉就能看到一张矩阵记忆类型时间范围归属典型内容失效风险会话上下文短期单个 Agent当前任务输入、中间结果会话结束即丢失工作记忆短期多个 Agent任务链中的共享结果任务链中断后丢失长期偏好长期单个用户/项目用户习惯、风格偏好缺少持久化组织知识长期多个 Agent业务规则、历史决策难以检索和更新如果只把记忆塞进 prompt本质上是在模拟短期记忆长期记忆和共享记忆完全没有落地。多 Agent 协同的时候A Agent 写入的重要结论无法让 B Agent 感知整个系统就退化成多个独立助手而不是一个协作团队。1.2 prompt 拼接方案的四个典型瓶颈直接在 prompt 中堆历史记录至少会遇到四个问题。第一是上下文窗口压力。一份完整业务历史可能有几万 token塞进 prompt 后留给推理和工具调用的空间被严重压缩Agent 的理解质量会明显下降。第二是信息新鲜度无法保证。如果 Agent 每次启动都重新从日志、数据库或者用户输入里拼记忆那么记忆更新就是一个完全靠开发者手动维护的流程很容易漏。用户昨天变更了偏好今天的 Agent 可能还在用旧信息。第三是检索能力缺失。prompt 里的记忆是线性文本当记忆量变大之后无法回答“这条规则是在哪个项目里定的”“上个月我们为什么选择这个方案”这类精确查询。普通文本只能顺序读取不能按标签、时间、实体关系过滤。第四是权限和隔离没法做。所有内容拼进同一个 promptAgent A 能看到 Agent B 的私有信息业务上不允许的跨域数据访问在 prompt 拼接体系里根本拦不住。1.3 Memmy 的核心思路把记忆当成独立服务Memmy 的出发点是Agent 的记忆不应该藏在大模型上下文里而应该被建模成一个带语义索引的存储层。每个 Agent 通过统一接口写入记忆、查询记忆、订阅记忆变更底层由 Memmy 完成向量化、结构化存储和相关性检索。这个思路和人类记忆系统很像。人类不会在每次对话时把一生经历都读一遍而是根据当前问题从记忆里提取和任务相关的片段。多 Agent 系统也需要这种机制每次运行只加载相关记忆而不是加载全部历史和全部上下文。用这种设计Agent 的 prompt 可以变得很干净只包含当前任务指令和检索到的相关记忆片段。记忆的写入、更新、删除、过期都变成对 Memmy 服务的标准操作而不是散落在各个 Agent 代码里的字符串拼接逻辑。2. 部署 Memmy 之前需要对齐的环境与概念Memmy 作为基础设施型组件部署方式和单体应用不同。在动手之前最好先把环境要求、核心数据模型和部署架构理解到位否则后面接入 Agent 时会反复返工。2.1 本地环境与最低依赖Memmy 本身是一个服务端应用对外提供 HTTP API底层存储负责持久化。结合目前多 Agent 开发常见的部署形态建议按以下环境准备依赖项推荐配置说明操作系统Linux / macOSWindows 也可以但容器部署更方便Docker20.10 以上本地快速启动依赖容器内存8 GB 以上向量索引和并发请求都需要内存存储引擎PostgreSQL / SQLite生产用 PostgreSQL本地实验可用 SQLite向量能力pgvector / 内置向量索引用于语义检索Embedding 模型本地模型或 API 模型需要把文本转成向量需要注意这里给的是通用依赖范围。原始项目文档如果没有明确版本号落地时先执行docker compose pull观察镜像版本再根据自己项目的模型选型决定 Embedding 来源。推荐先跑一个最小容器实例不要一上来就接生产配置。学习阶段只要能确认 API 能起来、写入一条记忆、查询到这条记忆就算环境合格。2.2 记忆单元的结构设计Memmy 处理的基本单位是一条记忆记录。每条记录通常包含以下字段字段作用示例id全局唯一标识mem_8f3a2cagent_id记忆所属 Agentagent_orderuser_id记忆所属用户或项目user_1001content记忆正文用户偏好控制台风格界面metadata结构化标签{project:consolev2,level:preference}timestamp记忆产生时间2025-01-12T10:30:00Zsource记忆来源conversation / manual / system这个结构解决了一个关键问题记忆不只是文本而是带归属、带来源、带业务标签的数据。这样后续做权限过滤、时间过滤、标签过滤时不需要再对纯文本做解析。2.3 理解写入、检索与遗忘三条链路Memmy 提供的核心能力可以归纳成三条链路。写入链路负责把 Agent 产生的记忆持久化。调用方提交记忆内容、归属主体和元数据Memmy 对内容做向量化将原始文本、元数据和向量一并存储。检索链路负责根据当前问题召回相关记忆。调用方提交一个查询文本Memmy 把查询转成向量在向量索引中做相似度搜索同时按照元数据过滤条件缩小范围最后返回排序后的记忆列表。遗忘链路负责控制记忆生命周期。开发者可以设置过期时间也可以主动删除不再需要的记忆记录。这个链路很容易被忽略但长期运行的系统如果只写不退记忆库会迅速膨胀检索质量和存储成本都会恶化。三条链路对应三个基础 APIPOST /memories、GET /memories/search、DELETE /memories/{id}。后面的接入实验会围绕这三个接口展开。3. 用容器启动 Memmy 并跑通基础 API这一节进入实操。目标是本地启动 Memmy 服务写入一条测试记忆再通过检索接口查回这条记忆。所有示例以通用 HTTP API 为例实际路径和请求体格式以项目 README 和接口文档为准。3.1 容器编排示例先创建一个最小化的docker-compose.yml把 Memmy 服务和底层存储一起启动。这里使用 PostgreSQL 和 pgvector 作为示例因为生产场景最常见。version: 3.9 services: memmy: image: memos/memmy:latest container_name: memmy ports: - 8000:8000 environment: MEMORY_STORAGE: postgres DATABASE_URL: postgresql://memmy:memmypostgres:5432/memmy EMBEDDING_PROVIDER: local EMBEDDING_MODEL: bge-small-zh depends_on: - postgres postgres: image: pgvector/pgvector:pg16 container_name: memmy-postgres environment: POSTGRES_USER: memmy POSTGRES_PASSWORD: memmy POSTGRES_DB: memmy ports: - 5432:5432 volumes: - memmy_pgdata:/var/lib/postgresql/data volumes: memmy_pgdata:使用本地 Embedding 模型的好处是请求不依赖外部 API数据不出内网但镜像体积和内存占用会更大。如果使用云端 Embedding API则需要在环境变量中配置 API Key这属于生产环境要考虑的密钥管理问题。启动命令docker compose up -d docker compose ps看到memmy和postgres两个服务都是 healthy 或 running 状态后再检查 API 是否可访问curl http://localhost:8000/health正常响应会返回一段 JSON包含服务状态、版本号和存储引擎信息。这一步能确认服务进程起来了但还不能确认记忆读写链路正常所以还需要做一次基础写入。3.2 写入一条带元数据的记忆假设业务系统里有两个 Agent一个是客服助手一个是订单助手。客服助手发现用户偏好短信通知这个信息需要写入公共记忆供订单助手在发送通知时使用。向 Memmy 写入记忆的请求体可以是{ agent_id: agent_support, user_id: user_1001, content: 用户偏好使用短信接收订单状态通知不偏好邮件通知。, metadata: { project: order_service, memory_type: preference, level: user }, ttl: 2592000 }ttl字段单位是秒这里设置 30 天过期。对于偏好类记忆过期时间要结合实际业务判断如果希望长期有效可以不设置 ttl 或设置更长时间。调用接口curl -X POST http://localhost:8000/memories \ -H Content-Type: application/json \ -d { agent_id: agent_support, user_id: user_1001, content: 用户偏好使用短信接收订单状态通知不偏好邮件通知。, metadata: { project: order_service, memory_type: preference, level: user }, ttl: 2592000 }正常响应会返回记忆记录 id。如果返回 400 或者 422优先检查字段名和类型是否和文档一致尤其是metadata是否只允许扁平结构。3.3 按语义检索相关记忆订单助手在处理发通知请求时需要知道用户的通知偏好。此时检索查询应该是自然语言问题而不是精确 SQLcurl -X GET http://localhost:8000/memories/search?query用户希望如何接收订单通知user_iduser_1001limit5返回结果通常包含记忆正文、相关度分数、元数据和写入时间{ results: [ { id: mem_8f3a2c, content: 用户偏好使用短信接收订单状态通知不偏好邮件通知。, score: 0.93, metadata: { project: order_service, memory_type: preference, level: user }, created_at: 2025-01-12T10:30:00Z } ] }通过user_id做过滤能避免把 A 用户的偏好召回给 B 用户这是多租户场景最基本的隔离手段。相关度分数用于排序但生产环境不能只看分数还要结合元数据里的业务条件做二次过滤。3.4 检查点与常见失败现象实验跑通后用三个检查点确认链路完整检查点操作预期结果服务健康curl /health返回 200 和状态 JSON写入成功POST /memories返回记忆 id检索命中GET /memories/search返回包含该记忆的列表常见失败现象有三种。第一种是写入成功但检索不到通常是因为 Embedding 模型没有正确加载索引需要看服务日志里是否出现向量维度不一致的报错。第二种是检索结果相关度极低先确认查询文本和记忆正文语言是否一致混合语言场景下向量检索效果会明显下降。第三种是user_id过滤不生效一般是传入参数名和后端字段名不一致检查 API 文档确认是user_id还是userId。4. 把 Memmy 接入多 Agent 框架时如何设计数据流多 Agent 框架通常自带上下文传递机制比如任务链中的state对象、消息总线、或者是工具调用上下文。接入 Memmy 之后关键不是新增一个 HTTP 调用而是重新设计记忆的读写时机。4.1 记忆读取插在 Agent 执行链的哪个位置推荐在 Agent 拿到用户输入之后、构造大模型 prompt 之前增加一个记忆检索步骤。伪代码如下def build_prompt_with_memory(user_input, user_id, agent_id): # 1. 从 Memmy 检索和当前输入相关的记忆 memories memmy_client.search( queryuser_input, user_iduser_id, agent_idagent_id, limit8 ) # 2. 将记忆格式化为上下文片段 memory_context format_memories(memories) # 3. 组装 prompt prompt f 以下是和当前任务相关的历史记忆 {memory_context} 当前用户输入 {user_input} 请结合记忆回答用户问题。 return prompt这里的核心原则是记忆检索发生在 prompt 构造之前只加载相关片段不加载全部记忆。这样可以控制 token 长度也能保证 Agent 只基于当前任务相关的信息做决策。4.2 记忆写入要区分稳定信息与临时状态不是所有对话内容都值得写入长期记忆。写多了会让记忆库充满噪声检索质量下降写少了又丢失有价值的信息。推荐按照以下标准判断信息类型是否写入原因用户明确表达的偏好写入跨会话稳定业务规则确认写入后续 Agent 需要遵守任务中间结果视情况写入短链任务可以不写大模型生成的泛化建议不写噪声太多一次性的临时参数不写无复用价值写入动作建议放在 Agent 执行完成并且确认结果成功之后而不是每生成一句话就写一次。批量写入或者定时总结式写入在真实项目中比实时逐条写入更稳定。4.3 用 metadata 控制共享边界Memmy 的一个关键能力是通过元数据控制记忆的可见范围。多 Agent 场景里至少要建立如下几类隔离维度metadata 键作用示例scope记忆层级global/project/userproject项目归属order_serviceagent_id允许读取的 Agentagent_ordermemory_type记忆类型preference/rule/decision检索时把当前 Agent 的上下文条件传进去就能实现类似数据库行级权限的效果。比如订单 Agent 只能检索projectorder_service且scope不包含private的记忆客服 Agent 同理。这样设计之后多个 Agent 共享的是公共记忆私有记忆仍然隔离在各自的命名空间里。相比把所有记忆都暴露给所有 Agent 的方式这种方式更适合业务系统落地。4.4 订阅与事件通知的扩展用法有些场景下Agent 需要感知记忆变化。比如用户修改偏好后正在执行的订单流程需要立刻使用新偏好而不是等下一次检索才生效。Memmy 若提供事件订阅能力可以在记忆写入或更新时触发回调。接入模式类似消息队列memmy_client.subscribe( event_typememory.updated, user_iduser_1001, callbackhandle_memory_updated ) def handle_memory_updated(event): # 更新本地 Agent 缓存或重新执行任务 refresh_context(event.memory_id)这种设计能减少重复轮询适合对时效性要求高的流程。学习阶段可以先不接订阅理解检索和写入两个核心链路即可。5. 生产环境落地 Memmy 必须处理的六个问题从本地跑通到生产可用中间还隔着一段很长的工程距离。下面六类问题是多 Agent 系统接记忆服务时最容易踩坑的地方。5.1 向量检索与业务过滤的顺序默认情况下Memmy 先做向量相似度召回再根据元数据过滤。这种顺序的问题是如果某个用户的历史记忆非常多而相关性排序又优先业务过滤就可能在后面裁掉高相关但权限不符的结果。推荐做法是在建立索引时就设计好分区键把user_id、project_id这类租户字段作为固定过滤条件而不是只放在 metadata 里。这样数据库能先缩小检索范围再在范围内做排序既提升性能也增强隔离。5.2 Embedding 模型选择与维度兼容本地模型和云端模型各有取舍。本地模型的数据私密性好但效果需要自己评估云端模型效果通常更稳定但存在调用成本和网络延迟。重要风险点如果后期更换 Embedding 模型新模型生成的向量维度可能和旧向量不一致。这会导致检索接口报向量维度错误或更隐蔽的相似度失真问题。切换模型前必须做数据迁移或全量重建索引。5.3 记忆过期和归约策略一味增加 ttl 不是好方案。记忆库中大量重复、过期、冲突的记录会让检索召回结果变差。生产环境建议增加三层策略写入时去重先按user_id和metadata.memory_type查一次如果已有相同内容做更新而不是新增。定期归约把多条相似记忆合并成一条总结性记忆。过期清理对超过 ttl 且不再访问的记录用离线任务批量删除或归档。5.4 权限与安全边界Memmy 服务本身如果暴露到内网接口鉴权不能只依赖网络策略。推荐在 Gateway 层增加 token 校验每个 Agent 使用独立 API KeyMemmy 侧根据调用方身份限制可写入和可读取的范围。场景风险建议不加鉴权直接访问任意 Agent 可读写所有记忆至少加 Bearer Token共享同一个 key无法追溯数据来源每个 Agent 独立 key明文存储敏感信息记忆中的个人信息泄露加密存储或脱敏5.5 高可用与降级Memmy 一旦成为 Agent 系统的一部分它的故障会影响整个 Agent 链路。生产环境要考虑降级方案Memmy 不可用时Agent 可以退化为只使用当前 prompt 内的上下文并记录一条告警日志而不是直接抛异常终止流程。try: memories memmy_client.search(...) except MemmyUnavailableError: logger.warning(memmy unavailable, fallback to empty memory) memories []这样的降级逻辑能保证核心业务不被记忆服务拖垮。5.6 记忆一致性与多副本冲突如果 Memmy 多副本部署需要确认写入是强一致还是最终一致。多 Agent 并发写入同一条记忆时要定义冲突策略。最简单的方式是使用更新时间戳后写入覆盖先写入更可靠的方案是增加版本号写入时携带版本版本不匹配则重试或合并。6. 从 Memmy 延伸到多 Agent 记忆体系的四种架构形态Memmy 可以独立使用也可以作为多 Agent 系统记忆层的核心组件。根据项目规模可以把架构分成四种形态。6.1 单体记忆库形态所有 Agent 共用同一个 Memmy 实例通过agent_id和metadata区分归属。适合中小型项目Agent 数量在十个以内业务隔离要求不高。优点是运维简单缺点是一旦一个 Agent 写入大量低质量记忆会影响所有 Agent 的检索效果。6.2 按服务分库形态每个业务域部署独立的 Memmy 实例比如订单域一套、客服域一套。适合业务边界清晰、数据不允许跨域访问的场景。优点是故障隔离好缺点是跨域记忆共享需要另外开发同步机制。6.3 中央库加边缘缓存形态Memmy 作为中央记忆服务每个 Agent 节点本地维护一个高频缓存定期从中央库拉取相关记忆。适合 Agent 分布式部署、对延迟敏感的场景。缓存命中时不走网络大幅降低检索延迟缓存失效时回源查询。6.4 记忆分层形态在 Memmy 之上再做一层记忆管理层把短期记忆、工作记忆、长期记忆分开存储。比如短期记忆用 Redis长期记忆用 Memmy通过上层调度器判断当前任务需要哪一层记忆。这种形态适合复杂的自主 Agent 系统工程成本也最高。下表总结了四种形态的适用场景架构形态适用规模隔离能力运维成本推荐场景单体记忆库小中低快速验证、中小项目按服务分库中高中业务边界清晰中央库加边缘缓存中大中中高延迟敏感分布式部署记忆分层大高高复杂自主 Agent7. 记忆质量治理比写入更难的三个实践接入 Memmy 只是开始。真正让多 Agent 系统表现出“记得住、记得准、忘得掉”的能力需要持续治理记忆质量。7.1 建立记忆审查链路Agent 自动写入的记忆不能直接进入长期库建议经过一层规则过滤或人工抽查。规则过滤可以包括长度阈值、敏感词检测、必填 metadata 校验。对高价值记忆比如业务规则、用户契约可以设置为需要人工确认后才能生效。7.2 记忆冲突检测同一个用户的喜好可能在不同时间发生变化旧记忆和新记忆会冲突。建议在检索返回时带上记忆的timestamp和version上层 Agent 结合时间信息判断该采信哪条。更高级的做法是让 Memmy 提供冲突检测接口当待写入的新记忆和已有记忆语义相近但内容矛盾时返回提示给调用方。7.3 定期评估检索效果维护一组标准测试问题每个问题对应期望召回的记忆片段。每周跑一次检索统计命中率变化。当命中率下降时重点检查是否写入了大量低质量记忆、Embedding 模型是否需要更换、metadata 过滤条件是否过宽或过窄。评估清单示例查询“用户期望怎么接收通知”能否召回“偏好短信通知”这条记忆。只传入user_id时是否返回了其他用户的数据。删除过期记忆后检索结果列表是否明显变干净。新写入的记忆在多长时间后能被检索到。高相关度但权限不符的记忆是否被正确过滤。8. 学习路径与落地顺序建议把 Memmy 引入项目时不要一上来就追求完整记忆体系。下面这条路径适合大多数团队。8.1 第一阶段跑通最小闭环先部署 Memmy写一个测试 Agent调用写入和检索两个接口确认记忆能跨会话存活。这一阶段只验证基础设施不接业务逻辑。8.2 第二阶段接入真实 Agent把 Memmy 接进一个业务 Agent在 prompt 构造前增加记忆检索在 Agent 执行完成后增加记忆写入。重点观察记忆写入后是否影响后续回答质量以及在 prompt 中插入记忆后 token 消耗的变化。8.3 第三阶段建立隔离和权限增加user_id、project_id过滤为每个 Agent 配置独立凭证设计 metadata 规范。这个阶段的目标是让记忆系统具备基本的生产安全性。8.4 第四阶段治理与监控引入记忆过期、归约、冲突检测和效果评估。这一阶段的核心是建立数据治理机制让记忆库在长期运行中保持稳定。阶段核心任务完成标志第一阶段部署与接口验证写入并检索成功第二阶段接入真实 AgentAgent 能使用历史记忆第三阶段隔离与权限多租户数据互不可见第四阶段治理与监控记忆库长期运行质量可控9. 关于 Memmy 的几个常见理解误区最后梳理几个容易误解的点帮助你把概念搞清楚。误区一Memmy 是一个通用数据库。Memmy 的重点是语义检索与记忆生命周期管理不是通用 KV 或关系库。适合存自然语言形态的记忆片段不适合存强结构化业务表。误区二用向量检索就不需要元数据。向量检索解决“语义相似”的问题元数据解决“权限和范围”的问题。真实场景两者缺一不可。误区三记忆越多越好。记忆越多检索噪声越大存储成本越高冲突概率也越高。记忆系统需要设计遗忘和归约这和人类记忆的机制一致。误区四接入 Memmy 就一定要替换现有 prompt。Memmy 是补充而不是替代。短期会话内的临时信息仍然可以放在上下文里Memmy 负责管理需要跨会话、跨 Agent 复用的长期记忆。多 Agent 系统的成熟度很大程度取决于记忆层的成熟度。Memmy 把记忆从“prompt 里的一段文本”升级成“一个可管理的基础设施”思路值得借鉴。实际落地时建议先跑通最小闭环再逐步加入隔离、权限、过期和治理策略让记忆系统在业务复杂度上升的过程中始终可控。
返回列表