状态同步与记忆共享

Synchronization and memory sharing

当多个 AI 智能体围绕同一任务协同工作时(例如在购物助手中,由不同智能体分别负责商品搜索、库存核查、价格计算与个性化推荐),它们需要高效共享当前会话的工作记忆并同步各自的操作状态。本课涵盖以下核心内容:

  • 多智能体系统中共享短期记忆的含义、与长期记忆的区别,以及多实体并发协作面临的挑战。
  • 如何保障数据一致性,妥善处理竞态条件(Race Conditions)与并发更新冲突。
  • 如何使用 Redis、LangGraph 图状态、消息队列(Pub/Sub)、锁机制与任务认领(Task Claiming)协调多智能体工作。
  • 不同同步方案在一致性、延迟、容错、扩展性与实现复杂度上的工程取舍。

多智能体系统中的共享短期记忆

短期记忆保存当前会话或任务执行期间的临时上下文(如多轮对话历史、当前购物车商品清单及任务中间结果),通常以单个会话线程(thread)为边界;而长期记忆则用于跨会话持久化保存领域知识或用户画像。

在多智能体协作中,所有参与方必须对当前最新状态保持一致认知。例如,当 Cart Agent 将商品加入购物车后,Shipping Agent 与 Inventory Agent(即便在当前阶段尚未完全实现)也应能立即读取到更新后的购物车清单。如果各智能体各自维护孤立的私有记忆,就会出现“库存智能体不知道商品已加购”或“两个智能体重复添加同一商品”等状态割裂问题。

资源争用与更新覆盖(竞态条件):例如两个智能体同时向同一购物车应用优惠券,后写入者可能覆盖先写入者的结果,或双方均基于过期数据计算折后总价。

状态同步的核心要求

同步意味着协调操作及数据访问,使整体状态保持一致。主要要求包括以下方面。

  • 一致的记忆可见性:当一个智能体修改状态后,其他智能体应在符合系统一致性预期的时限内读到最新数据(例如库存扣减后,Cart Agent 应基于最新余量做判断),可通过读写统一存储或订阅变更通知实现。
  • 写入互斥(Mutual Exclusion):当多个智能体可能修改同一份数据时,必须通过锁机制或指定唯一写入者(Single Writer)防止并发写冲突(如防止两个定价智能体同时叠加互斥折扣)。
  • 严格的先后顺序与前置依赖:例如“发起扣款支付”必须在“确认库存充足”且“锁定购物车清单”之后执行,需由协调器或状态校验逻辑强制检查前置条件。
  • 明确的冲突裁决策略:当一个智能体尝试移除商品而另一个智能体同时尝试增加该商品数量时,需依据预设业务规则裁决哪项更新生效(或终止其中一项操作);即便部分非关键字段采用“最后写入生效(Last-Write-Wins)”,也必须确认该策略符合业务逻辑。

控制策略决定智能体如何协调操作,记忆共享策略决定如何交换状态。前一课讨论了集中式与分布式控制,本课进一步介绍共享存储、发布订阅及锁机制。

共享记忆与同步的三大协调机制

常见机制包括以下三类。

  • 共享记忆存储(Shared Memory Store):所有智能体读写同一个权威状态源,构成黑板(Blackboard)或公共草稿本(Scratchpad)式的工作空间。
  • 事件驱动通信(Publish/Subscribe,发布/订阅):当状态发生变化时主动广播事件,由订阅了相关主题的智能体异步响应,降低组件间的直接耦合。
  • 锁机制、原子操作与任务认领(Locks & Task Claiming):控制对共享数据的并发写入,并通过原子认领机制防止多个智能体重复抢做同一任务。

这些机制可以相互补充。例如,共享存储保存状态,事件通知告知其他智能体数据已经变化。

共享工作记忆

可以使用统一数据存储作为短期状态的权威来源,包括内存数据库、键值存储,或同一进程中的数据结构。这类 blackboard/scratchpad 架构允许智能体向共同工作区写入知识和部分结果,也能读取整体进度。在完全采用共享记事板的设计中,智能体可以仅通过该工作区交流,无需直接联系。

具体实现可以是数据库表、表示当前购物车或对话的 NoSQL 文档,或 Redis 等内存存储。例如,一个 Redis hash 或 DynamoDB item 保存购物车,需要读写时都访问同一记录。

在编排框架层面,LangGraph 直接将工作流建模为有状态图(StateGraph):图状态本身就是系统的共享工作记忆,各节点读取状态并返回局部更新,当多个节点并行执行时则通过 reducer 函数安全合并各自字段的更新,并支持通过数据库 Checkpointer 持久化保存,大幅减轻了应用层手动维护外部临时存储的负担。

按字段划分唯一写入职责:例如规定只有 Cart Agent 有权修改 cart_contents 字段、只有 Inventory Agent 有权修改 inventory_status 字段,其余智能体对这些字段仅拥只读权限。

附带版本号与操作审计背景:为状态记录附加版本号、更新时间戳及操作摘要(例如记录“Agent A 于 10:00 将 Item X 加入购物车”),方便其他智能体区分新旧状态并理解前序操作脉络。

Redis 示例:一个 key 保存购物车 JSON,智能体通过 GET 或 SET 访问;另一个 list 或 stream 记录事件,例如使用 LPUSH 添加操作说明。单条 Redis 命令具有原子性,因此读取单次 SET 的结果时不会看到半写入的值。多条命令组成的读取、修改和写入流程仍需要额外控制;涉及多个 key 的整体更新,可以使用适当事务、Lua 脚本或其他正确的并发控制方案。锁机制也需要所有写入者共同遵循。

2. 事件驱动通信:发布/订阅(Pub/Sub)

共享存储本身较为被动,智能体需要轮询才能发现变化。事件驱动消息可以补充这一点:智能体主动发布操作或重要变化,其他智能体订阅相关主题并接收通知。

例如,当 Cart Agent 将商品加入购物车后,只需向总线发布一条 cart.item_added 事件(附带商品 ID 与数量),而无需逐一调用下游;订阅了该主题的 Inventory Agent、Pricing Agent 和 Shipping Agent 收到事件后会各自执行库存核查、总价重算与运费估算。后续若需新增其他智能体,只需订阅既有事件主题即可,实现了信息生产者与消费者的解耦。

Pub/Sub 将信息生产者和使用者分开。新增智能体可以订阅已有事件,减少对其他组件的修改。即使底层使用中央消息代理,逻辑上的参与者仍保持相对独立。

RabbitMQ 与 Kafka 的消费确认(ACK)、失败重投递、分区顺序与消息保留策略需按实际部署要求配置;而 Redis Pub/Sub 采用“至多一次(At-most-once)”投递语义,期间離线的订阅者将永久错过消息,不会自动补发。因此,涉及权限撤回与资料删除等关键变更时,必须采用持久化事件处理 + 定时全量对账的双保险机制。

事件示例:购物助手可以使用 product.search.completed、cart.item_added、inventory.out_of_stock 和 order.checkout.requested。各智能体遵循“收到事件 X,执行操作 Y”的逻辑。下一课将讨论 A2A 协议;Pub/Sub 也是组织智能体通信的一种方式。例如,Inventory Agent 订阅 item_added_to_cart,收到 Cart Agent 发布的事件后执行处理。

共享记忆与 Pub/Sub:消息系统传递变化,共享存储保留状态,两者常共同使用。也可以把完整购物车内容放入消息,仅通过消息同步;但离线智能体可能错过通知,因此通常保留持久存储,供后续加入的成员读取最新状态。

顺序与投递:消息可能重复、延迟或乱序,某些情况下也可能丢失。Kafka 在同一分区内保持顺序,SQS FIFO 则按消息组管理顺序。购物车事件需要顺序处理时,应选择适当机制,或在事件中加入序号、时间戳,并由接收者检查顺序。

消息顺序、主题过滤与点对点通信:网络消息可能出现重复、延迟或乱序(Kafka 可在单分区内保序,SQS FIFO 按消息组保序;对顺序敏感的购物车事件应选用保序队列或在事件中附带递增序号与时间戳供接收端校验)。同时,每个智能体应仅订阅与自身职责相关的细分主题(如 Inventory Agent 仅订阅 cart.item_added 与 cart.item_removed,无需接收每条 user.message)。对于一对一的明确任务委派或类似 RPC 的请求(如 Cart Agent 直接请求 Inventory Agent “预留 2 件 Item123”),则可使用点对点任务队列或专用目标主题。

直接消息与广播:Pub/Sub 常用于一对多通知,一对一任务可以使用任务队列或直接消息。例如,Planner 向 QA 的队列发送任务,或使用每个智能体独立主题及目标字段。Cart Agent 也可以直接请求 Inventory Agent“保留两件 Item123”。这种请求与结果交互类似 RPC,也可以建立在消息系统上。

3. 锁机制、乐观并发控制与任务认领

并发控制保证共享数据更新安全,任务认领则减少重复执行。

互斥锁(Lock / Mutex)与乐观锁(OCC):当多个智能体确需修改同一份共享数据时,可在临界区加互斥锁(例如更新购物车前先获取 cart_123_lock,完成“读取 → 修改 → 写回”后再释放锁,其余遵循同一锁协议的写入者排队等待),或利用数据库事务保护更新。若严格加锁导致并发吞吐受限,可改用乐观并发控制(Optimistic Concurrency Control):提交更新时比对数据版本号(Version),若发现版本号已被其他智能体更新则触发重试或冲突合并。

严格加锁影响性能时,可以采用乐观并发控制。智能体提交更新时检查版本号,发现冲突则重试或执行冲突处理,类似版本管理中的合并冲突,以及数据库的并发版本检查。

任务认领(Task Claiming):在分布式环境中,多个智能体可能同时扫描到同一条待办任务或模糊请求。借助消息队列的消费独占机制(如 SQS 的可见性超时 Visibility Timeout,或 RabbitMQ 的投递确认机制),可确保同一时刻只有一个工作节点领走该消息(注意:由于超时重投递仍可能发生,业务处理逻辑本身必须保持幂等)。若基于共享存储自行实现认领,则可通过原子比较并交换(CAS)操作将状态更新为 item_X_status = "in_progress_by_agentY",让其他智能体知晓该任务已有主,并配套超时自动释放恢复机制。

购物助手同时收到两个修改购物车的请求时,可以按会话购物车串行处理,或使用锁及令牌管理。同样,两个智能体都发现新商品需要归纳时,其中一个先原子地认领任务,另一个就无需重复执行。

需要注意,加锁与串行化(如按会话购物车 ID 串行处理修改请求)在保障一致性的同时也会增加等待延迟,因此应将锁的粒度严格限制在确有并发冲突风险的关键写操作上。

实时协作中的共享状态

多智能体系统可以通过共享状态存储、Pub/Sub、锁机制及任务认领协调行动。短期记忆提供共同工作背景,适当的同步和并发控制则帮助各智能体在生产环境中可靠地协作。

共享状态与更新顺序

PostgreSQL 保存任务及版本状态,Redis 可作缓存,RabbitMQ 或 Kafka 处理需要重投递的消息。定义资料更新与权限撤回事件,使用事件 ID 去重;消费者确认前完成可恢复的状态更新。Redis Pub/Sub 离线消息不会补发,删除和撤权还需定时核对。

练习:记录本课所用配置、输入、预期结果与失败分支,并用脱敏数据复现。

同步通知状态与任务事件

共享数据库统一维护 outbox 表,由独立的发送工作进程按各平台接口配额消费发送;资料来源读取权限、任务执行权限与通知发送目标必须分别独立校验。

通知 Webhook 仅用于发送已脱敏组装的状态摘要消息,而企业知识资料正文仍继续通过飞书或钉钉 OpenAPI 读取;全链路记录 event_id、资料版本、ACL 版本与发送状态,以便快速排查重复通知或过期内容。

搜索课程

正在加载课程目录…