多 Agent 系统里,记忆不是共享状态

当多个 Agent 各自保存环境事实时,过期副本会让每个参与者都“记得没错”,却共同做出错误决策。

一个多 Agent 工作环境运行久了,常会出现一种很隐蔽的分叉:每个 Agent 都有自己的长期记忆,里面保存着模型、通道、服务和工具状态。它们写入时都是真的,但环境改变后,只有执行变更的那一个知道新状态。

于是同一时刻可能出现几份互相冲突的“事实”:

  • 一个 Agent 认为某个通道仍然开启;
  • 另一个记得它已经停用;
  • 第三个根据配置残留判断它仍可使用;
  • 实际服务早已走了另一条链路。

这不是简单的记忆质量问题。持续变化的运行状态,本来就不应该由多个独立记忆副本承载。

🧠 记忆回答“我学到了什么”,状态回答“现在是什么”

Agent 的长期记忆适合保存稳定知识:用户偏好、协作规则、踩坑经验、项目背景。它的目标是跨会话延续认知。

环境状态则不同:

  • 当前模型链是什么;
  • 某个通道是否开启;
  • 某项服务是否存活;
  • 某份凭据由谁使用;
  • 某个工具是否已经卸载。

这些事实会频繁变化,并且需要被多个 Agent 同时消费。把它们复制进每份记忆,等于手工维护多个缓存,却没有失效机制。

真正的问题不是“哪份记忆写错了”,而是系统缺少唯一权威来源。

📚 共享账本不能只是另一份文档

最容易想到的修复,是建一份公共 Markdown,要求所有 Agent 开工前阅读。但如果它只能由人手动更新,它很快也会变成新的过期副本。

一个可用的共享事实层至少需要四样东西:

  1. 唯一标识:每条事实有稳定 ID,而不是散落在自然语言段落里。
  2. 登记值与验证条件:既写“应该是什么”,也写“怎样证明它仍然如此”。
  3. 状态分级:已验证、过期待复测、验证失败、人工确认、明确搁置要能区分。
  4. 变更闭环:修改环境后,必须同步登记、重新验证并留下变更记录。

例如,“服务正在运行”不能只是一句文字。它还应该绑定一个最小探针:端口监听、进程状态、一次真实请求,或者更接近业务目标的端到端验收。

共享层的价值不在于集中保存更多文字,而在于把“事实”变成可验证的契约。

🔗 私有记忆只存指针,不存易变值

接入共享事实层后,Agent 的私有记忆仍然有用,但边界要改变。

不再写:

消息通道 X 已开启,模型链是 A → B → C。

而是写:

消息通道状态见共享事实 channel.agent.x。
模型链状态见共享事实 model.agent.chain。

这样做看似少记了一些,实际上减少了最危险的一类信息:看起来具体、读起来可信、但已经失效的旧值。

开工时同步一次公共层;准备依赖某项能力时,查看对应事实;如果状态过期或异常,先实测再使用。私有记忆负责告诉 Agent“去哪里查”,共享层负责回答“现在是什么”。

🧪 探针结果必须高于登记值

即使有统一账本,也不能把登记值当成现实本身。配置可能被其他程序改写,服务可能崩溃,账号权限也可能在外部发生变化。

因此需要明确优先级:

当前实测 > 共享账本登记值 > 私有记忆 > 对话中的旧说法

如果实测与登记值冲突,只有两种处理:

  • 环境被改了但账本没更新:修正账本;
  • 环境坏了:修复环境,再重新验证。

不能为了让探针变绿而降低验证标准,也不能因为文档写着“正常”就忽略失败的真实调用。

对无法自动验证的事实,也要明确标为人工声明,而不是伪装成机器已确认。对已经决定搁置的事项,则应该禁止 Agent 反复重测,避免浪费资源和重新引入风险。

🧱 方法、状态和秘密还要继续分层

共享并不意味着把所有东西都塞进同一份账本。

  • 方法进入 skill:描述如何诊断、如何操作、如何验收。
  • 状态进入事实层:描述当前启用什么、谁在使用、最近何时验证。
  • 秘密留在凭据系统:事实层只保存引用位置和不可逆指纹,不保存明文。
  • 项目进度留在项目状态文档:事实层只记录跨项目、跨 Agent 都需要依赖的环境事实。

这个分层能避免另一种常见污染:把实时持仓、运行数据或账号状态写进“可复用方法”,导致 skill 每次分发都产生冲突;或者把秘密为了共享方便写进公共文档。

✅ 结论

多 Agent 系统里的记忆同步,不该靠所有参与者反复复制同一批运行状态。复制得越多,失效点越多。

更可靠的结构是:稳定经验进入记忆和 skill,易变事实进入可验证的共享账本,私有记忆只保存指针,真实探针永远高于文档。

当每个 Agent 都知道从哪里取得当前事实、怎样验证它、变更后怎样回写,协作才不再依赖“谁最后记得更新自己的那一份”。


马启航Marvis