跳到主要内容
多 Agent 并发与事务

第1章:多 Agent 并发与事务的关系 —— 为什么 79% 的多 Agent 任务在主流框架下会损坏

用一个具体的航班预订 race condition 把多 Agent 并发问题钉死,划清 Agent 事务与 DB 事务、Saga、Reflexion 的边界,建立看任何 multi-agent 系统的并发坐标系

多Agent 并发 事务 race condition AutoGen AgentSTM

打开 AutoGen 文档,5 行代码就能让 3 个 Agent 并发跑。看起来一切美好——直到你让它们同时改一份机票订单,有 79% 概率得到一份乱码(AgentSTM ARR 2026 投稿数据:14 个 ground-truth 任务,10 轮均值,无保护并发下只有 3 个能通过校验)。这不是 LLM 不够聪明,是多 Agent 系统忘了把数据库 1970 年代就解决的并发问题接进来。本章不解决问题,只把问题钉死:race condition 在 Agent 工具调用层是怎么发生的、它和数据库事务的相同与不同、它和 Reflexion 这种”单 Agent 反思”为什么不是一回事。读完你会拿到一个”5 秒判别工具”——给你任何一个 multi-agent 系统,问 4 个问题就能判断它有没有事务保护、属于哪一档。

📑 目录


1. 一个反直觉的开场:你以为 AutoGen 帮你管了,其实没有

下面这段 AutoGen 代码是文档里的标准多 Agent 模式:

# 简化的 AutoGen 多 Agent 示例
from autogen import AssistantAgent, GroupChat

shared_db = {"booking_42": {"passengers": [], "baggage": 0, "flight": "AA100"}}

agent_a = AssistantAgent("PassengerEditor", tools=[update_passengers])
agent_b = AssistantAgent("BaggageEditor", tools=[update_baggage])
agent_c = AssistantAgent("FlightEditor",  tools=[update_flight])

# 三个 agent 并发处理同一份预订
group = GroupChat(agents=[agent_a, agent_b, agent_c], messages=[task])
group.run_concurrent()

直觉上这段代码应该工作——三个 Agent 改 booking 的不同字段,互不影响。但实际跑起来:

Agent A: read booking_42 → passengers=[]
Agent B: read booking_42 → baggage=0
Agent C: read booking_42 → flight=AA100
Agent A: write booking_42.passengers = ["Alice", "Bob"]    # ✓ 正确
Agent B: write booking_42 = {passengers: [], baggage: 30}  # ✗ 整体写回,丢了 A 的 passengers
Agent C: write booking_42.flight = "AA101"                  # 取决于 tool 实现

问题的根源:LLM Agent 调工具时不知道”字段级写”还是”整体写”。Tool 接口写法不规范、提示词不够精确,一行 update_booking(booking_42, ...) 就可能把整张记录覆盖。这就是经典的 lost update——数据库教科书第 3 章的内容,在 multi-agent 框架里完整复活。

🌟 结论:AutoGen / CrewAI 这类框架只管并发调度,不管并发一致性。后者是它们没有解决、也不打算解决的问题——但你的项目要解决。


2. 在 Agent 工具调用层,race condition 长这样

把上一节的 lost update 推广,能在 Agent 工具调用层观察到至少 4 类经典并发冲突:

2.1 写写冲突(Lost Update)

Agent A: counter ← read()       # 读到 5
Agent B: counter ← read()       # 也读到 5
Agent A: write(counter + 1)     # 写 6
Agent B: write(counter + 1)     # 也写 6(应该是 7)

症状:计数器 +2 但只 +1;批量任务计数对不上;reservation 名额超卖。

2.2 读写冲突(Stale Read)

Agent A: profile ← read_user_profile("user_42")
Agent A: ... 用 profile 生成 5 段对话回复 ...
Agent B: write_user_profile("user_42", new_profile)  # 中间发生
Agent A: send_email(content_based_on_profile)        # 发出去的邮件用了旧 profile

症状:客服 Agent 给用户发了”基于你过去 30 天偏好”的内容,但偏好刚被 Agent B 更新过;推荐用旧标签。

2.3 因果违反(Write Skew)

约束:账户 A + 账户 B 的余额必须 ≥ 0
A: read(account_a)=100, account_b=100
A: 决定从 a 转 50 到外部
B: read(account_a)=100, account_b=100
B: 决定从 b 转 50 到外部
A: write(account_a=50)  ← 各自看局部都合法
B: write(account_b=50)  ← 各自看局部都合法
最终:a=50, b=50, 总=100,但中间各自看的都是合法状态——约束没有被任何一个 agent 单独违反,却被并发整体违反

症状:账户余额、库存、配额这类”跨实体不变式”被悄无声息地打破。最难调试的一类。

2.4 计划级冲突(Plan-Level Conflict)

这是 Agent 时代独有的一类——因为 Agent 的”原子单位”不是单条 SQL,而是一个 plan

Agent A 的 plan:[读 doc.md → 改 §2 → 写回]
Agent B 的 plan:[读 doc.md → 改 §3 → 写回]

并发执行:
A: 读 doc.md
B: 读 doc.md
A: 改 §2,写回 doc.md
B: 改 §3(基于自己读到的旧版),写回 doc.md  ← B 的 §2 还是旧的,覆盖了 A

🍎 直觉比喻:传统数据库的事务粒度像”一颗螺丝”,agent plan 的粒度像”装一辆自行车”——并发装两辆车,光保证每颗螺丝原子是不够的。

2.5 四类冲突的混合矩阵

冲突类型是否被 ACID 单条事务解决Agent 框架默认是否检测论文里的标准对应
Lost Update✅ 单 SQL 级OCC 经典
Stale Read✅ Snapshot IsolationMVCC
Write Skew⚠️ 需要 SerializableSSI
计划级冲突❌(DB 事务粒度太小)AgentSTM 主战场

关键观察:前 3 类是数据库领域已经解决的问题,在 Agent 工具调用层退化重现;第 4 类是 Agent 时代新增的——plan 级别的并发,需要 plan 级别的事务粒度,而这正是 AgentSTM 的核心贡献。


3. Agent 事务 vs 数据库事务:相同与不同

第 2 节让”agent 也需要事务”听起来很自然——但 Agent 事务不是数据库事务的简单移植。它在 4 个维度上有本质差异:

维度数据库事务Agent 事务
原子单位一条 SQL / 一个 commit一个 plan(多步 tool calls)
冲突时怎么办重做相同事务重规划成不同 plan(关键差异
状态来源自己的存储外部 API / 文件 / KV / DB(heterogeneous)
隔离机制MVCC / 锁版本化资源 wrapper + commit-time 验证
失败成本微秒级回滚LLM 调用代价 = 重要的优化目标

🧠 关键洞察:数据库事务冲突后做”identical retry”——重做同一笔事务总会成功,因为环境会松。但 Agent 事务在多 Agent 持续争用下,identical retry 永远撞墙——这就是论文里 Theorem 1 (Bounded-Retry Impossibility) 证明的:n > k 个 Agent 抢同一个 r,按 PR 假设至少一个必然永久失败。

🌟 结论:Agent 事务必须有”计划重写”这一新维度。这是普通线程做不到的——LLM 是第一类能 reason about why 失败、并改写自己执行计划的”线程”

3.1 一个具体的”鸽笼证明”(Theorem 1 直观版)

设:3 个 Agent 都要修改资源 r,最大重试 k=2 次
轮 1:3 个并发 commit r,最多 1 个成功 → 2 个失败
轮 2(重试):2 个再次同时 commit r,最多 1 个成功 → 1 个失败
轮 3(无):1 个 Agent 已经用完 k=2 次重试,永久失败

只要 n(并发 Agent 数)> k(重试预算),按”重做同一份 plan”的策略,至少一个 Agent 必然失败——这是数学事实,不能靠”加大重试次数”绕过(k 必须有限,否则不再叫 bounded retry)。


4. Agent 事务 vs Reflexion:单 Agent 反思 ≠ 多 Agent 一致性

读到这里可能有人想:“不就是 Reflexion 吗?让 LLM 反思失败、改下一次尝试不就行了?” ——不是。这是这个领域最大的一个混淆点。

维度ReflexionAgent 事务(AgentSTM 类)
目标单 Agent 自我改进多 Agent 一致性
失败信号任务失败的自然语言反思结构化冲突 metadata(哪个资源、被谁改、当前版本)
反思后做什么改提示词,再次执行同样的任务必须改 plan(不同资源 / 不同顺序 / 不同分解)
失败原因假设单 Agent 推理质量不够多 Agent 资源争用
能解决并发吗❌ 解决不了

AgentSTM 论文做了一个很巧妙的”same-plan verbal-retry control”实验来证明这点:让 LLM “verbal 上反思”但 executed plan 不变,结果——回复文本的 Jaccard token 保持率 0.115(看起来很高,接近 Structured+Full 的 0.143),但 conflict 次数没有下降(4.4±0.5 vs intent-preserving 的 4.0±0.0),因为它说的不一样了,做的还是同一件事

🧠 关键洞察Verbal 反思 ≠ Plan 改写。Reflexion 提供的是前者——给单 Agent 性能加成——但放在多 Agent 并发场景下解决不了 race,因为 race 不是”agent 推理不够好”造成的,是”两个 agent 同时争用资源”造成的。

互补:Reflexion 和 AgentSTM 不是替代关系。Reflexion 改 task 表征质量,AgentSTM 改并发恢复策略——一个项目可以两个都用:单 Agent 任务难度问题用 Reflexion,多 Agent 并发问题用 AgentSTM。


5. Agent 事务 vs Saga:为什么”补偿”不够用

Sagas(García-Molina & Salem, 1987)解决的是”长事务怎么办”:把一个长事务拆成多个短事务,每个短事务配一个补偿动作(compensation),失败时反向执行。SagaLLM (VLDB 2025) 把这套搬到 LLM workflow——这是历史上第一篇明确用”事务”概念组织 Agent workflow 的论文。

但 Saga 在多 Agent 并发下有两个根本性问题:

5.1 串行化代价

为了让”补偿动作链”可执行,Saga 隐式假设事务以串行顺序执行——并发版本的 Saga 在工业界几乎没有成功案例。SagaLLM 的实测显示在 τ-bench airline benchmark 上,serial Saga 的吞吐是 66 tasks/s,而支持真并发的 AgentSTM 是 205 tasks/s(3.1× 差距)。

5.2 补偿级联(Compensation Cascade)

更严重的问题:Saga 的失败处理是全 chain 回滚。在 30% fault injection 下:

系统完成率原因
SagaLLM10%(5/50 任务)任何一步失败 → 触发 chain compensation → 之前的工作也回滚
AgentSTM58%(29/50 任务)每 Agent 的事务独立,单 Agent 失败不波及他人

🌟 结论:Saga 适合”长流程、低并发、强补偿语义”场景(订单 → 支付 → 发货 → 物流,可补偿)。多 Agent 并发改共享 state 不属于这类场景——这里需要的是 OCC 式的”乐观执行 + 验证 + 重规划”,不是补偿链


6. 5 秒判别工具:4 个问题

给你任何一个 multi-agent 系统(开源框架 / 论文 / 自家产品),问 4 个问题:

Q1: 多个 Agent 能否真正并发改同一份 state?
    └ NO → 串行系统(MetaGPT / ChatDev / SagaLLM)。无并发问题但放弃吞吐
    └ YES → 继续

Q2: 框架是否在 commit/write 时验证"读时版本"是否还有效?
    └ NO → 无保护并发(AutoGen / CrewAI)。79% 损坏率
    └ YES → 继续

Q3: 冲突时框架做什么?
    └ 重做同一计划 → Plan-Rigid Retry。Bounded-Retry Impossibility 适用
    └ 让 LLM 反思但任务不变 → Reflexion-style 同 plan retry。无效
    └ 让 LLM 重写 plan → 真正的 intent-preserving replan ✓

Q4: 重试预算用尽后兜底是什么?
    └ 抛错给用户 → 系统脆弱
    └ 降级到悲观锁串行执行 → graceful degradation ✓

4 个问题全选 ✓ 才是真正的多 Agent 事务系统。截至 2026-05,符合这个标准的开源框架几乎没有——AgentSTM 论文是第一个把所有 4 个问题都答对的方案。


7. 本模块的边界外

为了避免后面 7 章误入歧途,先把”本模块不讲”的事讲清楚:

  • 单 Agent 任务难度:那是 Reflexion / LATS / Tree-of-Thought 的范畴,模块六(Agent Runtime)和模块七(Agentic RL)覆盖
  • Agent 间消息一致性 / 共识:Aegean 这类共识协议解决的是”多 Agent 决策投票一致”,不是”多 Agent 共享 state 一致”——前者本模块只在第 4 章一带而过
  • 分布式部署的网络一致性:本模块假设单机或局域网,跨数据中心的 Agent 一致性是另一个话题(参考模块十三)
  • Byzantine Agent:恶意 Agent 故意写冲突值的场景。AgentSTM 假设 cooperative Agent
  • 代码 merge / git 并发:CodeCRDT 解决的代码协同编辑问题,第 4 章会精读,但不是模块主线(主线是”shared state 上的 transactional consistency”)

✅ 自我检验清单

  • Race 类型:能用一句话区分 Lost Update / Stale Read / Write Skew / 计划级冲突,并各举一个 Agent 场景
  • AutoGen 缺陷:能解释为什么 AutoGen 默认配置在多 Agent 场景下会损坏 79% 的任务
  • DB vs Agent 事务:能列出 Agent 事务相对数据库事务的 4 个本质差异
  • Reflexion 区别:能解释”verbal 反思”和”plan 改写”的差别,并讲清前者解决不了多 Agent 并发的原因
  • Saga 局限:能解释 SagaLLM 在 fault injection 下崩塌到 10% 完成率的根因(compensation cascade)
  • 5 秒判别:拿到一个新 multi-agent 框架,能用 4 问判别它的并发保护等级
  • Bounded-Retry:能用鸽笼原理直观解释”为什么 plan-rigid retry 必然在 n>k 时永久失败”

📚 参考资料

概念入门

  • 数据库事务 ACID —— Wikipedia:ACID
  • Lost Update / Write Skew 的标准定义 —— Berenson et al. 1995, “A Critique of ANSI SQL Isolation Levels”
  • OCC(Optimistic Concurrency Control)入门 —— Wikipedia:Optimistic concurrency control

关键论文

  • Reflexion: Language Agents with Verbal Reinforcement Learning(Shinn et al., 2023)arXiv 2303.11366 —— 单 Agent 反思的奠基;本章 §4 的对比基线
  • Sagas(García-Molina & Salem, 1987):SIGMOD 1987 —— 长事务补偿链的祖师爷
  • SagaLLM(Bui et al., VLDB 2025):VLDB 2025 —— LLM workflow 的 Saga 化,本章 §5 主要对比对象
  • AgentSTM(Anonymous, ARR/EMNLP 2026) ⭐:本章数据来源;OCC + LLM replan 把 multi-agent 并发讲透的工作之一
  • AutoGen(Wu et al., 2023)arXiv 2308.08155 —— 多 Agent 框架代表,本章 §1 用作”无保护”案例

行业讨论

  • AutoGen GitHub issues 中的并发问题 —— 搜索 “race condition” / “concurrent state” 关键词

框架文档