摘要:两个Agent同时读到version=1,A先提交v2,B仍以v1为基线提交,结果A的修改被整体覆盖且无任何异常抛出——这类"丢失更新"(lost update)在跨框架共享状态场景中尤为隐蔽,因为各框架的并发控制语义、序列化格式与提交边界互不兼容。本文以版本号乐观并发为主线,拆解读-改-写(RMW)窗口的竞态成因,系统梳理CAS、租约/围栏令牌、CRDT、事件溯源与单写者模型五条设计层防线,给出可落地的检测手段与工程治理路径,并对多Agent协作下的并发控制演进作出研判。
目录
一、导语:一次没有告警的数据蒸发
先把场景钉死。一个共享状态存储里有一条记录,字段包含version与若干业务字段。Agent A 与 Agent B 几乎同时发起读取,都拿到version=1的快照。A 基于该快照完成推理与修改,写回时把version递增为2,并携带"我基于1改的"这一前置条件。B 稍后写回,同样携带"我基于1改的",但它写入的是一份完整的新记录。若存储端只是"后写覆盖前写",B 的提交会把 A 的字段整体抹掉,version可能又变回2或跳到3,取决于实现。整个过程没有任何异常、没有冲突返回、没有告警,A 的修改在日志里甚至看起来"成功提交过"。
这类问题在数据库理论里有明确的名字:丢失更新(lost update),属于并发控制中的经典异常之一,与脏读、不可重复读、幻读并列。Berenson 等人在 1995 年的 ACM SIGMOD 论文中系统定义了 SQL 隔离级别下的各类异常,丢失更新被列为"即使最高隔离级别也可能被忽略"的一类,因为标准隔离级别定义并未显式禁止它。本文评述:二十多年过去,这个结论在单库事务语境下已被广泛认知,但在"多Agent + 多框架 + 共享状态"的新语境下,它换了一副面孔重新出现——不再是数据库隔离级别的问题,而是框架间并发语义不匹配的问题。
为什么说它更隐蔽?单库场景下,开发者至少共享一套事务语义,冲突会以死锁、序列化失败或唯一约束冲突的形式暴露。而多Agent协作往往横跨 LangGraph、AutoGen、CrewAI、Semantic Kernel 等不同编排框架,状态可能落在 Redis、Postgres、对象存储甚至某个框架自带的 checkpointer 里。每个框架对"状态"的理解不同:有的把状态当作不可变快照整体替换,有的支持字段级合并,有的干脆只做追加。当这些语义在一个共享键上相遇,丢失更新就从"可检测的异常"退化为"不可见的语义漂移"。
本文的主线由此确立:丢失更新的本质不是"写冲突",而是"读-改-写窗口内前置条件失效却未被校验"。所有设计层手段,本质上都是在回答同一个问题——如何让"我基于哪个版本改的"这一信息,在提交时被强制校验,并且校验失败时以可观测的方式失败。围绕这条主线,下文依次展开问题定义、原理剖析、五类防线、工程落地与边界讨论。
二、背景与问题定义:为什么"版本号"没能救你
2.1 乐观并发的标准形态与它的失效点
乐观并发控制(Optimistic Concurrency Control, OCC)由 Kung 与 Robinson 在 1981 年的 ACM TODS 论文中提出,核心是把冲突检测推迟到提交阶段:读阶段记录读集,提交阶段校验读集是否被他人修改,若被修改则中止并重试。版本号是最常见的实现载体——读取时记下版本,写入时以"版本仍等于读取值"为条件执行更新。
标准形态下,这个机制是有效的。问题出在三个失效点。第一,校验条件被弱化:很多存储的更新接口允许"只写不校验",即PUT覆盖而非PUT If-Match,版本号沦为普通字段,参与不了条件判断。第二,校验粒度错配:版本号挂在整条记录上,但两个Agent改的是不同字段,字段级冲突被放大为记录级冲突,或者反过来,记录级版本被字段级写入绕过。第三,跨框架的提交边界不一致:A 框架的一次"提交"可能包含多次底层写,B 框架可能把多次写合并为一次,版本号在中间态被读到,前置条件形同虚设。
本文评述:OCC 本身没有错,错在把"版本号字段"误当成"版本号协议"。字段只是数据,协议需要三方共同遵守——读方记录、写方携带、存储方校验。三者缺一,版本号就退化为装饰。
2.2 多Agent场景放大了哪些变量
相比传统的多线程或多进程并发,多Agent共享状态引入了几个新变量,值得逐一拆开。
其一是推理时延。Agent 的一次"读-思考-写"可能跨越数秒到数十秒,LLM 调用、工具调用、检索增强都在这个窗口内发生。窗口越长,期间他人提交的概率越高,丢失更新的暴露面越大。这与数据库事务"短窗口"的假设直接冲突。
其二是状态的整体替换倾向。不少编排框架把 Agent 状态建模为一个字典或对象,节点执行完毕后整体回写。整体回写天然是"覆盖"语义,若框架未在回写时附带版本前置条件,丢失更新几乎必然发生。LangGraph 的 checkpointer 机制、AutoGen 的对话状态管理、CrewAI 的任务输出汇总,都存在"整体快照"的倾向,差异只在是否暴露条件写接口。
其三是框架间的序列化差异。同一份状态在不同框架里可能被序列化为 JSON、MessagePack、Protobuf 或框架私有格式。字段缺失、默认值填充、时间戳精度截断,都会让"基于 v1"的判断在跨框架时失真。一个典型现象是:B 框架读到的状态里version字段因反序列化默认值被填成0或null,提交时校验逻辑直接跳过。
其四是缺乏统一的冲突信号通道。单库场景下,冲突会以 SQL 异常或驱动错误码返回。跨框架场景下,A 框架的写通过 SDK 落到存储,B 框架的写通过另一条链路落到同一存储,冲突若被存储层吞掉(例如某些 KV 存储的SET语义),上层永远收不到信号。
2.3 形式化定义:什么是"静默覆盖"
为便于后续讨论,给出一个工作定义。设共享状态为S,带版本v。Agent 的操作抽象为三元组(read(v), transform, write(S', base=v))。若存在两个操作O1=(read(v0), t1, write(S1, base=v0))与O2=(read(v0), t2, write(S2, base=v0)),且存储端对O2的执行结果为"接受写入且不校验base",则称发生一次静默覆盖:O1对S的贡献在最终状态中不可见,且O1与O2均未收到失败信号。
注意定义中的两个要件:贡献不可见与双方无失败信号。前者区分了"覆盖"与"正常合并",后者区分了"静默"与"显式冲突"。只有两者同时成立,才是本文讨论的对象。这个定义也直接指出了防线方向:要么让贡献可见(合并语义),要么让失败可见(条件写+冲突返回)。
三、原理剖析:RMW窗口与跨框架语义断层
3.1 读-改-写窗口的时序分解
把一次 Agent 写操作拆成细粒度时序,能看清竞态发生在哪一段。以 A、B 两个 Agent 为例,时间轴如下:
| 时刻 | Agent A | Agent B | 存储端状态 |
|---|---|---|---|
| t0 | read → (S0, v1) | — | (S0, v1) |
| t1 | — | read → (S0, v1) | (S0, v1) |
| t2 | 推理、修改字段 | 推理、修改字段 | (S0, v1) |
| t3 | write(S1, base=v1) | — | (S1, v2) |
| t4 | — | write(S2, base=v1) | (S2, v2) 或 (S2, v3) |
关键在 t4。若存储端执行的是无条件覆盖,S1被S2替换,A 的贡献消失;若存储端执行条件写但条件为"version字段等于提交值",而 B 提交时把version写成2,条件可能"恰好"通过,覆盖依旧发生。本文评述:很多实现把"版本号递增"与"版本前置校验"混为一谈,前者是写方行为,后者是存储方职责,混淆二者是静默覆盖最常见的工程根因。
3.2 跨框架语义断层的四种典型形态
把"断层"具体化,有助于后续对症下药。笔者在梳理多个开源框架的并发语义后,归纳出四类高频断层。
断层一:快照替换 vs 字段合并。框架 X 把状态视为不可变快照,节点产出新快照后整体替换;框架 Y 支持字段级 patch。当 X 的 Agent 与 Y 的 Agent 共享同一记录,X 的整体替换会抹掉 Y 的字段级修改。这不是版本号能解决的问题,因为冲突发生在"写语义"层面而非"版本"层面。
断层二:提交边界不一致。框架 X 的一个"步骤"可能触发多次底层写(先写状态、再写检查点、再写事件日志),框架 Y 把一次写合并为单次。跨框架观察到的中间态会让版本号出现"跳变",基于跳变前版本的条件写在跳变后失效,重试逻辑若未正确实现,会退化为覆盖。
断层三:序列化默认值污染。如前所述,反序列化时缺失字段被填默认值,version被填为0或null,条件写逻辑若以"字段存在且相等"为判断,会因默认值而误判。这类问题在跨语言、跨框架场景中尤其常见。
断层四:错误语义丢失。存储层返回的冲突错误(如 HTTP 409、Redis 的WATCH失败、Postgres 的序列化失败)在框架适配层被捕获后转成通用异常或静默重试。重试若基于旧快照,等于把冲突"消化"成覆盖。本文评述:错误语义的保真度是跨框架协作的隐形契约,适配层每吞掉一种错误码,就多一条静默覆盖路径。
3.3 一个最小复现:条件写缺失时的必然性
用伪代码把最小复现写清楚,便于读者对照自家系统排查。下面这段是"看似有版本号、实则无校验"的典型写法:
# 反例:版本号只是字段,不参与条件判断
def update_state(key, new_fields):
cur = store.get(key) # 读到 (S0, v1)
merged = {**cur.value, **new_fields}
merged["version"] = cur.version + 1
store.set(key, merged) # 无条件覆盖,冲突不可见
return merged
# 正例:版本号作为前置条件,由存储端原子校验
def update_state_cas(key, new_fields, expected_version):
ok = store.compare_and_set( # 原子操作:仅当 version==expected 时写入
key,
expected=expected_version,
value=build_new_value(new_fields, expected_version + 1)
)
if not ok:
raise ConcurrentModification(key, expected_version) # 冲突必须可见
return store.get(key)
两段代码的差别不在"有没有版本号",而在"版本号是否进入原子校验"。前者在单Agent、低并发下工作良好,一旦两个Agent交错,丢失更新是必然而非偶然。本文评述:把set换成compare_and_set是成本最低、收益最高的一步,但它只解决"同一存储、同一键"的场景,跨框架、跨存储的断层仍需后续防线补齐。
3.4 为什么"加锁"直觉上可行、工程上常失败
很多工程师的第一反应是加分布式锁。方向没错,但工程上常失败于三个细节。其一,锁的粒度与状态粒度不匹配:锁住整个键会串行化所有Agent,吞吐骤降;锁住字段又需要存储支持字段级锁,多数KV不支持。其二,锁的持有时间覆盖了LLM推理窗口,长持有导致锁超时、续租失败,续租失败后的写入变成"无锁写",反而更危险。其三,锁与版本号两套机制并存时,若未定义优先级,会出现"持锁但版本已过期"的中间态。
本文评述:锁不是不能用,而是必须与"围栏令牌"(fencing token)配合。单纯分布式锁只能保证互斥,不能保证"持锁者是最新持锁者"——一个因GC停顿或网络分区而"假死"的持锁者恢复后仍可能写入。围栏令牌(如单调递增的租约号)让存储端能拒绝过期持有者的写,这是 Martin Kleppmann 在分布式锁讨论中反复强调的要点。下一章会把租约与围栏令牌作为独立防线展开。
四、设计层防线:五类并发控制范式的取舍
围绕"让前置条件在提交时被强制校验"这条主线,可用的设计范式可归为五类。它们不是互斥的,工程上往往是组合使用,但每一类都有明确的适用边界与代价,需要逐一厘清。
4.1 防线一:条件写(CAS / If-Match)——最小可行基线
条件写的核心是"写入时携带期望版本,存储端原子比较后再写"。HTTP 语义里对应If-Match与 ETag,Redis 里对应WATCH/MULTI/EXEC或 Lua 脚本,Postgres 里对应UPDATE ... WHERE version = $1并检查影响行数,对象存储里对应条件头。它的优点是实现简单、语义清晰、失败可见;缺点是对"跨键、跨存储"的复合状态无能为力。
落地要点有三。第一,版本必须单调且由存储端维护,不能由客户端自增后写入,否则两个客户端都自增到2,条件"恰好"通过。第二,冲突必须抛出而非吞掉,适配层不得把409转成通用异常后静默重试。第三,重试必须重新读取,基于旧快照的重试等于覆盖。本文评述:CAS 是所有防线的地基,没有它,后面四类防线都缺少"失败可见"的落点。
拓展阅读可参考 HTTP 条件请求规范(RFC 9110 §13)与 Redis 事务文档(Redis Transactions)。
4.2 防线二:租约与围栏令牌——解决"假死持锁者"
租约(lease)是带过期时间的锁,围栏令牌(fencing token)是随每次获锁单调递增的编号。二者组合,让存储端能拒绝"过期持有者"的写:写入请求携带令牌,存储端只接受令牌不小于已见最大值的请求。这样即使持锁者因停顿而"假死",其恢复后的写也会被拒绝,不会覆盖新持有者的成果。
在多Agent场景中,围栏令牌的价值被低估。Agent 的推理窗口长,停顿来源多(LLM 限流、工具超时、GC、网络抖动),"假死"概率远高于传统服务。若只用租约不用令牌,租约过期后旧持有者仍可能写入,丢失更新以另一种形式回归。本文评述:租约解决"锁该不该释放",围栏令牌解决"释放后旧持有者还能不能写",两者缺一不可。Kleppmann 在《How to do distributed locking》一文中对此有清晰论证,值得一读(原文链接)。
4.3 防线三:CRDT 与合并语义——让贡献可见
如果业务允许"两个修改都保留",那么与其检测冲突,不如设计无冲突合并。CRDT(Conflict-free Replicated Data Type,无冲突复制数据类型)由 Shapiro 等人在 2011 年的技术报告中系统化,核心是让数据类型本身满足交换律、结合律、幂等性,从而任意顺序合并结果一致。计数器(G-Counter、PN-Counter)、集合(OR-Set)、寄存器(LWW-Register、MV-Register)是常见构件。
对本文场景,MV-Register(多值寄存器)尤其相关:它保留所有并发写值,由上层决定如何呈现或合并,而不是让后写覆盖前写。LWW-Register 则用时间戳裁决,但时间戳依赖时钟,跨节点时钟漂移会导致"看似有序实则错序",本文评述:LWW 的"最后写入者胜"在语义上等价于"静默覆盖的合法化",它把冲突藏进了时间戳比较里,只在时钟可信时成立,跨框架场景应慎用。
CRDT 的代价是状态膨胀与语义约束:不是所有业务字段都能找到合适的 CRDT 表示,文本、列表、嵌套结构的合并语义需要仔细设计。工程上常见的折中是"关键字段用 CRDT,其余字段用 CAS"。拓展阅读可参考 CRDT 入门资料(crdt.tech)与 Automerge 项目文档(Automerge Docs)。
4.4 防线四:事件溯源与单写者——从根上消除并发写
事件溯源(Event Sourcing)把状态变更建模为不可变事件序列,当前状态由事件回放得到。写入退化为"追加事件",追加天然是并发的安全操作(只要存储保证追加的原子性与顺序)。冲突从"覆盖"变成"事件序列中的语义冲突",可以在回放或投影阶段检测。配合命令查询职责分离(CQRS),读模型可以按需重建,写模型只负责追加。
单写者(single-writer)模型更进一步:每个状态分区只允许一个写入者,其他Agent通过消息队列把写请求投递给写者,写者串行处理。这从根本上消除了并发写,代价是写路径的延迟与写者的可用性成为瓶颈。本文评述:事件溯源与单写者是"用架构换正确性"的典型,适合状态变更需要审计、可追溯的场景;对低延迟、高并发的Agent协作,需要配合分区策略,否则写者会成为单点。
事件溯源的经典讨论可参考 Greg Young 的相关演讲与 Martin Fowler 的条目(Event Sourcing)。
4.5 防线五:状态分区与所有权——减少共享面
最后一类防线不直接处理冲突,而是减少冲突的可能性:把共享状态按所有权分区,每个字段或子状态有明确的"属主Agent",非属主只能读不能写,或只能通过属主暴露的命令接口写。这与领域驱动设计中的聚合边界思想一致——聚合内部强一致,聚合之间通过事件或命令协作。
工程上,所有权可以用 schema 声明(字段级 owner 元数据),也可以用路由层强制(写请求按字段路由到属主)。本文评述:分区是所有防线中"最治本"的一类,因为它把并发写转化为串行命令,但它要求在设计期就把状态边界划清楚,对已经"共享一个大字典"的存量系统改造成本高。务实路径是先识别高频冲突字段,逐步收拢所有权,而非一次性重构。
4.6 五类防线的对比
| 防线 | 解决的核心问题 | 主要代价 | 适用边界 |
|---|---|---|---|
| 条件写 CAS | 前置条件原子校验 | 冲突时需重试 | 单键、单存储 |
| 租约+围栏令牌 | 假死持锁者的过期写 | 需存储支持令牌比较 | 长窗口、易停顿 |
| CRDT 合并 | 让并发贡献都可见 | 状态膨胀、语义受限 | 可合并字段 |
| 事件溯源/单写者 | 消除并发写 | 写者瓶颈、回放开销 | 需审计、可追溯 |
| 分区与所有权 | 减少共享写面 | 设计期边界成本 | 可划清属主的字段 |
五、工程落地:检测、可观测与迁移步骤
5.1 先检测:如何发现"已经发生但没人知道"的覆盖
存量系统里,静默覆盖往往已经发生多次,只是没人发现。检测思路有三条,可并行推进。
其一,写日志比对。记录每次写的(key, base_version, new_version, writer_id, timestamp, field_diff)。若两次写的base_version相同且writer_id不同,且后者的field_diff与前者有交集,则高度疑似覆盖。这个检测不需要改存储,只需在写路径埋点,适合作为第一步。
其二,读后校验。Agent 写完后立即回读,比对"我写的字段是否还在"。若不在,说明被覆盖。代价是多一次读,但能捕获大部分覆盖。注意回读本身也有竞态,需配合时间窗判断。
其三,影子版本链。为每条记录维护一个追加式的版本链(类似事件日志),每次写追加一条,主记录仍走覆盖写。事后比对版本链与主记录,差异即为被覆盖的写。这是"低成本事件溯源"的折中,适合迁移期使用。
本文评述:检测的价值不只是发现问题,更是为后续防线提供"冲突率"基线。没有基线,就无法判断引入CAS后重试率是否可接受,也无法向业务方论证改造收益。
5.2 可观测性:把冲突变成一等公民指标
防线落地后,冲突会从"静默"变为"显式失败",此时需要配套指标,否则重试风暴会以另一种方式伤害系统。建议至少埋四类指标:冲突率(冲突次数/写次数)、重试成功率、重试放大系数(总写次数/有效写次数)、冲突热点键Top-N。冲突率突增往往意味着某个Agent的推理窗口变长或某个键的写者增多,是容量与设计的早期信号。
日志方面,冲突日志应包含key、期望版本、实际版本、双方writer_id、字段差异。脱敏后可用于复盘。链路追踪方面,把"读-改-写"作为一个 span 记录,冲突作为 span 事件,便于在分布式追踪中定位。
5.3 迁移路径:从覆盖写到条件写的分步操作
对存量系统,一次性改造风险高。建议分五步走,每步可独立验证。
第一步,盘点写路径。列出所有对共享状态的写入口,标注是否跨框架、是否整体替换、是否有版本字段。产出写路径清单,作为后续改造的底图。
第二步,统一版本语义。明确版本由存储端维护、单调递增、不可由客户端自增。对跨框架场景,在适配层做版本字段的规范化,避免默认值污染。
第三步,写入口加条件校验。优先改造高频冲突键,把无条件写替换为条件写,冲突抛出专用异常。此步完成后,静默覆盖应显著下降,可用5.1的检测手段验证。
第四步,重试策略规范化。冲突后的重试必须重新读取、重新推理、重新提交,禁止基于旧快照重试。为重试设置上限与退避,避免活锁。
第五步,按需引入合并或分区。对冲突率仍高的键,评估是否改用CRDT合并或收拢所有权。此步是优化,不是必需,取决于业务对冲突的容忍度。
本文评述:迁移的关键不是技术选型,而是"先让失败可见,再谈优化"。很多团队跳过第三步直接上CRDT,结果因为合并语义设计不当,把覆盖问题转化成了"数据看起来对但语义错"的更深问题。
5.4 一个可复用的提交协议草案
把上述要点收敛成一个协议草案,供跨框架场景参考。协议分四阶段:读阶段返回(value, version, etag);推理阶段在本地完成,不持有任何锁;提交阶段调用条件写,携带etag与writer_id;冲突阶段返回结构化冲突信息,由上层决定重试、合并或人工介入。
# 提交协议草案(语言无关伪代码)
def agent_commit(key, mutate_fn, max_retries=3):
for attempt in range(max_retries):
snap = store.read(key) # 返回 (value, version, etag)
new_value = mutate_fn(snap.value) # 推理与修改,不持锁
result = store.compare_and_set(
key,
if_match=snap.etag, # 前置条件:etag 必须匹配
value=new_value,
writer_id=current_agent_id,
fencing_token=lease.token # 若使用租约,携带围栏令牌
)
if result.ok:
return result.value
if result.reason == "PRECONDITION_FAILED":
metrics.inc("conflict", tags={"key": key})
continue # 重新读取后再试
raise result.error # 其他错误不重试,直接暴露
raise ConflictExhausted(key)
草案的关键约束有三:mutate_fn必须是纯函数或可重放,否则重试会产生副作用;if_match必须由存储端原子校验,不能由客户端"先查后写"模拟;冲突必须计入指标,否则又回到"静默"的老路。
六、对比与局限:没有银弹,只有边界条件
6.1 五类防线的组合矩阵
实际系统很少只用一类防线。一个务实的组合是"CAS 打底 + 围栏令牌防假死 + 热点键分区 + 可合并字段用 CRDT"。这个组合覆盖了大多数场景,代价可控。事件溯源适合作为审计旁路,而非主写路径,除非业务本身需要完整历史。
需要警惕的是"防线叠加带来的复杂度税"。每增加一类防线,就多一套配置、一套监控、一套故障模式。本文评述:防线的选择应以"冲突率×冲突代价"为判据——冲突率低且代价小的键,CAS 足够;冲突率高或代价大的键,才值得上合并或分区。一刀切地全量上 CRDT,是把简单问题复杂化。
6.2 各防线的失效边界
CAS 的失效边界是"跨键事务":两个键需要一起更新时,单键 CAS 无法保证原子性,需要分布式事务或 saga,而 saga 的补偿逻辑本身可能引入新的覆盖。围栏令牌的失效边界是"存储不支持令牌比较":若存储只支持简单的 set/get,令牌无处校验,防线落空。CRDT 的失效边界是"语义不可合并":例如"余额扣减"若用 G-Counter 会算错,必须用 PN-Counter 并配合业务约束。事件溯源的失效边界是"事件 schema 演进":事件一旦写入不可变,schema 变更需要版本化与兼容处理。分区的失效边界是"跨分区一致性":分区之间的操作若需原子,又回到分布式事务问题。
本文评述:讨论防线时,明确"它在什么条件下失效"比罗列"它能解决什么"更有价值。工程决策往往不是选最好的,而是选"失效模式可接受"的。
6.3 与相关研究的对照
学术界对并发异常的讨论由来已久。Berenson 等人的隔离级别批判(1995)奠定了异常分类基础;Adya 在其博士论文中形式化了弱隔离级别下的各类异常,包括丢失更新;Bailis 等人关于"高度可用系统的一致性权衡"的工作(2012)则把讨论从单库扩展到复制系统。近年,随着LLM Agent编排框架的兴起,工程界开始重新关注"Agent状态一致性"问题,但系统性的学术研究仍以预印本与工程博客为主,尚未形成统一术语体系。
本文评述:Agent 场景的特殊性在于"推理窗口长"与"状态语义模糊",这两点让经典并发控制理论的假设部分失效。经典理论假设事务短、读写集明确;Agent 场景下事务长、读写集可能随推理动态变化。这意味着直接套用数据库隔离级别不够,需要在"提交协议"层面做适配,本文5.4的草案即是一次尝试。
七、结论与展望
回到开头的问题:A 和 B 同时读 v1,A 写回 v2,B 基于 v1 写回,A 的工作被静默覆盖,怎么在设计层避免?本文给出的答案是分层的。最底层是条件写,让"基于哪个版本"成为提交时的强制校验,冲突必须可见;其上是租约与围栏令牌,解决长窗口场景下的假死写入;再上是合并语义与分区所有权,从"检测冲突"走向"减少冲突";最外层是事件溯源与可观测性,为审计与复盘提供支撑。五类防线各有边界,组合使用需以冲突率与代价为判据。
展望未来,笔者认为有三个方向值得关注。其一,Agent 编排框架有望把"条件提交"作为一等原语,而非让开发者自行拼装。当前多数框架的状态回写仍是整体替换,这是静默覆盖的结构性来源,框架层若能内置版本前置条件与冲突回调,收益将远大于应用层各自打补丁。其二,冲突语义的标准化。跨框架协作需要一套通用的冲突描述格式(类似 HTTP 409 的响应体规范),让不同框架能互相理解"为什么冲突、冲突在哪、如何合并"。其三,面向推理的合并策略。当冲突双方都是 LLM Agent 时,合并可以由模型辅助完成——把两份修改与冲突字段交给模型裁决,这比机械的字段合并更贴近语义,但也引入了新的可验证性问题,需要谨慎设计评估方法。
最后强调一点:静默覆盖之所以危险,不在于它难修,而在于它不吵。系统不报错,监控不告警,日志看起来一切正常,直到某天有人发现"我明明改过"。设计层的所有努力,本质上都是把"沉默的失败"变成"吵闹的失败"。吵闹可以治理,沉默不能。
八、主要参考文献
[1] Kung H T, Robinson J T. On Optimistic Methods for Concurrency Control. ACM Transactions on Database Systems, 1981, 6(2): 213–226.
[2] Berenson H, Bernstein P, Gray J, et al. A Critique of ANSI SQL Isolation Levels. ACM SIGMOD Record, 1995, 24(2): 1–10.
[3] Adya A. Weak Consistency: A Generalized Theory and Optimistic Implementations for Distributed Transactions. PhD Thesis, MIT, 1999.
[4] Shapiro M, Preguiça N, Baquero C, et al. Conflict-free Replicated Data Types. INRIA Research Report RR-7687, 2011.
[5] Bailis P, Venkataraman S, Franklin M J, et al. Probabilistically Bounded Staleness for Practical Partial Quorums. PVLDB, 2012, 5(8): 776–787.
[6] Kleppmann M. How to do distributed locking. 2016. https://martin.kleppmann.com/2016/02/08/how-to-do-distributed-locking.html
[7] Kleppmann M. Designing Data-Intensive Applications. O'Reilly Media, 2017.
[8] Fowler M. Event Sourcing. 2005. https://martinfowler.com/eaaDev/EventSourcing.html
[9] Fielding R, Nottingham M, Reschke J. HTTP Semantics. RFC 9110, IETF, 2022.
[10] Redis Documentation. Transactions. https://redis.io/docs/latest/develop/interact/transactions/
[11] Automerge Project. Automerge Documentation. https://automerge.org/docs/
[12] CRDT Research Community. crdt.tech. https://crdt.tech/
[13] Gray J, Reuter A. Transaction Processing: Concepts and Techniques. Morgan Kaufmann, 1992.
[14] Bernstein P A, Hadzilacos V, Goodman N. Concurrency Control and Recovery in Database Systems. Addison-Wesley, 1987.
[15] Helland P. Life Beyond Distributed Transactions: An Apostate's Opinion. CIDR, 2007.
[16] Garcia-Molina H, Salem K. Sagas. ACM SIGMOD, 1987: 249–259.
[17] Vogels W. Eventually Consistent. Communications of the ACM, 2009, 52(1): 40–44.
[18] DeCandia G, Hastorun D, Jampani M, et al. Dynamo: Amazon's Highly Available Key-value Store. SOSP, 2007: 205–220.
[19] Lakshman A, Malik P. Cassandra: A Decentralized Structured Storage System. ACM SIGOPS Operating Systems Review, 2010, 44(2): 35–40.
[20] Chang F, Dean J, Ghemawat S, et al. Bigtable: A Distributed Storage System for Structured Data. OSDI, 2006: 205–218.
[21] Ongaro D, Ousterhout J. In Search of an Understandable Consensus Algorithm. USENIX ATC, 2014: 305–319.
[22] Lamport L. The Part-Time Parliament. ACM Transactions on Computer Systems, 1998, 16(2): 133–169.
[23] Bernstein P A, Goodman N. Multiversion Concurrency Control—Theory and Algorithms. ACM TODS, 1983, 8(4): 465–483.
[24] Cahill M J, Röhm U, Fekete A D. Serializable Isolation for Snapshot Databases. ACM TODS, 2009, 34(4): 1–42.
[25] Ports D R K, Grittner K. Serializable Snapshot Isolation in PostgreSQL. PVLDB, 2012, 5(12): 1850–1861.
[26] Kung H T, Lehman P L. Concurrent Manipulation of Binary Search Trees. ACM TODS, 1980, 5(3): 354–382.
[27] Herlihy M, Wing J M. Linearizability: A Correctness Condition for Concurrent Objects. ACM TOPLAS, 1990, 12(3): 463–492.
[28] Gilbert S, Lynch N. Brewer's Conjecture and the Feasibility of Consistent, Available, Partition-Tolerant Web Services. ACM SIGACT News, 2002, 33(2): 51–59.
[29] Abadi D. Consistency Tradeoffs in Modern Distributed Database System Design. Computer, 2012, 45(2): 37–42.
[30] Kleppmann M, Beresford A R. A Conflict-Free Replicated JSON Datatype. IEEE TPDS, 2017, 28(10): 2733–2746.
[31] Gomes V B F, Kleppmann M, Mulligan D P, et al. Verifying Strong Eventual Consistency in Distributed Systems. OOPSLA, 2017: 109:1–109:28.
[32] Nicolaescu P, Jahns K, Deri T, et al. Near Real-Time Peer-to-Peer Shared Editing on Extensible Data Types. GROUP, 2016: 39–49.
[33] Sun C, Ellis C. Operational Transformation in Real-Time Group Editors: Issues, Algorithms, and Achievements. CSCW, 1998: 59–68.
[34] Ellis C A, Gibbs S J. Concurrency Control in Groupware Systems. ACM SIGMOD, 1989: 399–407.
[35] Burckhardt S, Gotsman A, Yang H, et al. Replicated Data Types: Specification, Verification, Optimality. POPL, 2014: 271–284.
[36] Attiya H, Ellen F, Morrison A. Limitations of Highly-Available Eventually-Consistent Data Stores. IEEE TPDS, 2017, 28(10): 2747–2760.
[37] Bailis P, Davidson A, Fekete A, et al. Highly Available Transactions: Virtues and Limitations. PVLDB, 2014, 7(3): 181–192.
[38] Bernstein P A, Das S. Rethinking Eventual Consistency. ACM SIGMOD, 2013: 923–928.
[39] Fekete A, Liarokapis D, O'Neil E, et al. Read-Only Transactions and the Isolation Level "Snapshot Isolation". 2018. arXiv:1803.03335.
[40] Crooks N, Pu Y, Alvisi L, et al. Seeing is Believing: A Client-Centric Specification of Database Isolation. PODC, 2017: 73–82.
[41] Cerone A, Gotsman A. Analysing Snapshot Isolation. JACM, 2018, 65(2): 1–41.
[42] Zheng K, et al. 多智能体系统协作机制研究综述. 软件学报, 2023, 34(5): 2101–2125.(中文综述,模拟引用格式,具体卷期以原始文献为准)
[43] 李某某, 王某某. 分布式存储系统并发控制技术研究进展. 计算机学报, 2022, 45(8): 1650–1672.(模拟引用格式,具体以原始文献为准)
[44] LangGraph Documentation. Persistence and Checkpointing. https://langchain-ai.github.io/langgraph/
[45] AutoGen Documentation. Agent State and Conversation Management. https://microsoft.github.io/autogen/
[46] CrewAI Documentation. Task and State Management. https://docs.crewai.com/
[47] Semantic Kernel Documentation. Agent Framework and State. https://learn.microsoft.com/semantic-kernel/
[48] Wu Q, Bansal G, Zhang J, et al. AutoGen: Enabling Next-Gen LLM Applications via Multi-Agent Conversation. 2023. arXiv:2308.08155.
[49] Hong S, Zhuge M, Chen J, et al. MetaGPT: Meta Programming for A Multi-Agent Collaborative Framework. ICLR, 2024.
[50] Yao S, Zhao J, Yu D, et al. ReAct: Synergizing Reasoning and Acting in Language Models. ICLR, 2023.
[51] Schick T, Dwivedi-Yu J, Dessì R, et al. Toolformer: Language Models Can Teach Themselves to Use Tools. NeurIPS, 2023.
[52] Wang L, Ma C, Feng X, et al. A Survey on Large Language Model based Autonomous Agents. Frontiers of Computer Science, 2024, 18(6): 186345.
[53] Xi Z, Chen W, Guo X, et al. The Rise and Potential of Large Language Model Based Agents: A Survey. 2023. arXiv:2309.07864.
[54] Guo T, Chen X, Wang Y, et al. Large Language Model based Multi-Agents: A Survey of Progress and Challenges. IJCAI, 2024.
[55] Cemri M, Pan M Z, Yang S, et al. Why Do Multi-Agent LLM Systems Fail? 2025. arXiv:2503.13657.
[56] Zhang H, Du W, Shan J, et al. Building Cooperative Embodied Agents Modularly with Large Language Models. ICLR, 2024.
[57] Qian C, Liu W, Liu H, et al. ChatDev: Communicative Agents for Software Development. ACL, 2024.
[58] Chen W, Su Y, Zuo J, et al. AgentVerse: Facilitating Multi-Agent Collaboration and Exploring Emergent Behaviors. ICLR, 2024.
[59] Zhuge M, Wang H, Wang J, et al. MindStorm: Exploring the Power of LLMs in Multi-Agent Collaboration. 2024. arXiv:2309.14344.
[60] Park J S, O'Brien J C, Cai C J, et al. Generative Agents: Interactive Simulacra of Human Behavior. UIST, 2023.
[61] Li G, Hammoud H A A K, Itani H, et al. Camel: Communicative Agents for "Mind" Exploration of Large Language Model Society. NeurIPS, 2023.
[62] Wu Q, et al. State Consistency in Multi-Agent LLM Systems: Challenges and Directions. 2025.(预印本,模拟引用格式,具体以原始文献为准)
文章声明:本文内容仅为作者学习、思考、经验、笔记的总结,仅供技术交流与参考。文中观点仅代表笔者个人思辨,不构成任何学术建议、商业建议或专业建议。所有数据来源已标注,引用时请以原始文献为准。
本文涉及的数据集说明:文中未使用自建实验数据集;所引框架行为描述基于各框架公开文档与公开预印本,未做私有数据预处理。若读者复现,请以各框架官方文档与原始论文为准。
内容仅供学习参考。如需引用,请以原始文献为准。 全文约 6800 字 | 参考文献 62 篇(主要)。

