跳到主要内容

多用户共享智能体状态:你真正需要的并发原语

· 阅读需 12 分钟
Tian Pan
Software Engineer

每篇智能体教程都从单个用户、单个会话和单个上下文窗口开始。智能体读取状态、推理、行动、写回。清晰、确定。对于团队实际使用的场景来说,这种假设完全错误。

真实的协作产品——共享规划看板、多用户支持队列、文档协作副驾驶、团队项目助手——需要多个用户同时与同一个智能体交互。当两个人在同一秒内向智能体发出相互矛盾的指令时,其中一个人的修改就会消失。智能体不会告诉他们,甚至自己都不知道发生了什么。

这就是多用户共享智能体状态问题,它是一个披着AI外衣的分布式系统问题。

规模化时崩溃的假设

根本原因是大多数智能体框架早期做出的一个隐性架构决策:智能体状态是一个单一的可变对象,会话是隔离的单位。

这种设计对单用户场景完美适用。但对共享工作区却会失效,因为它将智能体的工作内存视为单线程变量。当用户A读取当前规划文档状态、通过智能体修改它并写回——而用户B在400毫秒后做了同样的事情——B的写入会无声地覆盖A的修改。没有冲突通知,没有合并逻辑,没有报错。从智能体自身角度来看,它正确地处理了两条指令。

这是经典的最后写入优先(last-write-wins)问题。分布式数据库已经解决了这个问题。AI智能体基础设施中这个问题基本上仍未得到解决。大多数团队在生产环境中才发现它,那时用户已经在抱怨他们的修改"一直在丢失",而要将这个投诉与竞态条件而非模型失败联系起来,往往需要数周时间。

解决方案不是更聪明的提示词。解决方案是像对待分布式数据存储的并发写入一样对待智能体状态更新:使用适当的并发控制。

乐观锁:最低成本的安全保障

最廉价的正确性改进是乐观并发控制。与其在读取前锁定状态,不如自由地读取,然后在写入时验证自读取以来没有发生任何变化。

机制很简单:每个智能体状态都带有版本号。当用户A读取状态时,他们得到 {..., version: 42}。当他们的智能体操作尝试写回时,它包含这个版本号:"仅当当前版本仍为42时才应用此更改。"如果用户B的写入已经将状态提升到版本43,A的写入将被拒绝,系统可以用最新状态重试。

在实践中,这意味着:

  • 智能体的工具调用在实际更新负载旁边包含一个 state_version 参数。
  • 状态存储(Redis、Postgres、文档数据库)执行条件写入:UPDATE agent_state SET ... WHERE id = ? AND version = ? 并检查恰好有一行受到影响。
  • 版本不匹配时,智能体重新尝试完整的推理步骤,使用当前状态——而不仅仅是重试写入。

最后一点很重要。如果你只重试写入而不重新读取和重新推理,你将把一个过时的决策应用于新鲜的状态,这可以说比最后写入优先还要糟糕。重试必须回到上下文构建步骤。

乐观锁的实际限制是高并发下的竞争。如果十个用户同时操作同一个状态对象,重试率会变得难以接受。对于大多数共享工作区用例——用户协调多于冲突的场景——乐观锁已经足够。对于真正并发写入的热点对象,你需要不同的数据模型。

事件溯源:以不可变性为基础

更持久的解决方案是完全停止将智能体状态视为可变对象。相反,将每次状态转换建模为不可变日志中追加的事件。

在事件溯源下,当用户A的智能体指令执行时,它不会覆盖文档,而是追加一个事件:{type: "section_updated", author: "user_a", timestamp: ..., payload: {...}}。用户B的并发操作追加自己的事件。当前状态始终通过重放事件流推导出来,而不是读取单条记录。

这对多用户智能体有几个直接影响:

冲突变得可见且可延迟。 当影响相同状态的两个事件到达时,你可以显式地检测冲突,而不是无声地丢弃其中一个。你可以将其呈现给用户、排队等待人工解决,或应用特定领域的合并策略。

重放实现调试。 当用户的修改似乎消失了,你可以重放事件流并精确显示是哪个后续事件覆盖了它。这将谜题转变为日志条目。

部分失败可以恢复。 如果智能体操作写入了一个事件但随后在更新派生状态前崩溃,你可以通过重放来重建。没有任何数据丢失。

标准实现模式:每个智能体映射到领域驱动设计中的聚合。其事件流是事实的来源。投影维护针对智能体上下文窗口优化的读视图。写入通过事件存储进行,在流级别使用乐观并发——如果两个并发追加针对同一流的相同预期版本,一个胜出,另一个重试。

需要注意的失败模式是无限制的事件日志增长。如果每次智能体操作——包括中间推理步骤和工具调用重试——都作为事件存储,流可能变得重放成本极高。常见的缓解措施:定期对聚合状态做快照,只从最近的快照开始重放。

CRDT:用于天然可合并状态

某些智能体状态的结构使得合并在数学上是安全的,根本无需冲突检测。这就是无冲突复制数据类型(CRDT)的适用场景。

CRDT是一种数据结构,设计为无论操作顺序如何,所有并发修改都可以合并成一致的最终状态。Google Docs使用CRDT处理文本。Figma将其用于设计元素。当多个用户并发更新具有集合或计数器语义的智能体状态时,同样的属性很有用。

具体而言:如果你的共享智能体状态包含用户可以并发添加的活跃任务列表,将其建模为只增集合(G-Set)。任何用户都可以添加任务,所有添加都会自动合并。不可能出现冲突,因为模型中不存在删除——软删除通过在应用层跟踪单独的"已删除"项集合来处理(这就变成了2P-Set)。

CRDT不是通用解决方案。它们在状态可以建模为累加器时有效——增长的事物、递增的计数器、字段上的最后写入优先寄存器(当一个答案总是正确时)。当业务逻辑需要严格的操作顺序,或者两个并发修改在语义上不相容时(例如,"将此任务分配给Alice"和"将此任务分配给Bob"不能同时为真),它们就会失效。

实用的方法是分层:对天然累积的智能体状态部分使用CRDT(任务列表、偏好评分、能力标志),对需要严格一致性的部分使用带乐观锁的事件溯源(当前计划状态、财务承诺、授权决策)。

归因模型:谁驱动了什么

正确性只是问题的一半。另一半是问责制。当多用户智能体执行某个操作时——发送电子邮件、修改记录、分配资源——哪个用户负有责任?

大多数智能体实现在其审计日志中存储"智能体做了这个"。这是不够的。适当的归因模型需要跟踪完整的主体链:哪个用户在对话的哪个点给出了指令,导致了哪个智能体决策,触发了哪个工具调用。

这比听起来要难,因为智能体推理是非局部的。用户A在第5轮的指令可能与用户B在第8轮的指令结合,在第12轮产生一个操作。归因不是单个指针——它是贡献输入的有向无环图。

一个可行的实现方法:

  • 为每条用户指令分配唯一的指令ID。
  • 在构建智能体的上下文窗口时,用其指令ID和提供该指令的用户来注释每个先前的轮次。
  • 当智能体发出操作时,包含其上下文窗口中被标记为因果相关的指令ID集合。
  • 将这些作为结构化元数据与操作日志一起存储。

这不需要智能体显式地推理归因。它需要基础设施来维护它。智能体不需要知道——系统需要知道。

对于合规用例(金融服务、医疗保健、HR系统),这个归因图是强制性的。你需要能够回答:"用户B给出了与用户A现有计划相矛盾的指令——智能体遵循了哪条指令,为什么?"如果你的事件日志无法回答这个问题,你就有治理缺口。

权限边界问题

多用户智能体引入了单用户智能体从未面临的权限冲突:当两个用户具有不同授权级别而智能体在共享上下文中操作时,会发生什么?

简单的回答是"智能体在所有用户权限的交集下操作"。在实践中,这过于限制——一个团队规划智能体不能因为权限最低的团队成员而受到束缚。

更有用的模型是指令范围权限。每个用户操作以该用户的权限级别执行。智能体维护每用户而非每会话的权限上下文。当用户A的指令尝试一个操作时,它根据用户A的权限进行评估。当智能体合成需要组合两个用户委托能力的响应时,它仅在两个用户都明确同意委托的情况下才使用并集。

这要求智能体的工具执行层在每次工具调用旁边接受一个主体参数,而不仅仅是会话令牌。这也意味着你的工具实现需要按调用而非按会话强制执行权限。

构建多用户状态:决策清单

在实现之前,在这些维度上做出决策:

冲突率:并发用户实际上同时修改相同状态对象的频率有多高?低竞争使乐观锁足够。高竞争需要事件溯源或CRDT结构化状态。

冲突语义:当两个用户给出相互矛盾的指令时,是否有正确的合并答案,还是需要人工决定?可合并语义允许CRDT。不相容语义需要明确的冲突浮现。

重放需求:你需要重建发生了什么以及为什么吗?如果是,事件溯源不是可选的。

归因深度:你需要知道哪个用户的指令贡献了哪个操作吗?浅层归因(最后指令优先)成本低;因果归因图需要在上下文装配层进行仪器化。

权限模型:共享会话中所有用户统一,还是因用户而异?每用户权限上下文需要重构工具执行层处理授权的方式。

要避免的结构性错误

最常见的实现错误是事后将多用户支持拼接到单用户智能体架构上。团队在其状态对象中添加一个会话ID字段,认为并发用户很少会发生冲突,然后发布。

失败模式在三个月后出现,当客户抱怨共享规划智能体损坏了他们团队的项目状态时。根本原因是两个用户编辑之间200毫秒的竞态条件。看起来像幻觉。实际上不是。这是一个未检测到的并发写入,采用了最后写入优先解决方案。

事后修复需要将状态从可变对象迁移到事件溯源模型、添加版本跟踪、并重新连接工具执行以携带主体上下文。这些都不难构建——但迁移比从头构建要困难得多。

如果你知道你的智能体将服务于共享工作区,从一开始就为此设计。在需要之前就在状态模式中添加版本号。追加事件而不是覆盖。在整个工具调用链中携带用户身份。设计时的增量成本很小。生产时的改造成本则不小。

结论

服务多个同时在线用户的协作智能体不是单用户智能体架构的专业化——它们是一个根本上不同的并发问题。分布式系统社区花了几十年解决共享状态的并发写入:乐观锁、事件溯源、CRDT、向量时钟、归因链。这些解决方案可以直接移植到AI智能体基础设施中。

转化工作在于理解哪种分布式系统原语适用于智能体的哪一层。状态一致性映射到乐观锁或事件溯源。无冲突累积映射到CRDT。因果排序映射到指令归因图。权限强制执行映射到每主体工具执行。

这些都不需要新的原语。它需要认识到多用户智能体是一个分布式系统,并从一开始就相应地设计它。

References:Let's stay in touch and Follow me for more thoughts and updates