那天我在看一组并行制作的海报模板。原本的分工很简单:几个 Agent 各自负责几张模板,最后统一渲染、检查,再把通过的版本交给验收。看起来这是一个适合并发的任务,文件彼此独立,检查规则也已经写清楚了。
但很快,问题变成了另一种样子。某个 Agent 刚说自己的模板已经完成,另一个 Agent 就发现同名文件已经换了一版;刚刚通过自检的预览图,回头再看,已经不是当前磁盘里的内容。一个模板被重复覆盖了几次,其他几个文件也出现了类似迹象。表面上大家都在推进,实际上没有人能确定最后留下来的东西是谁写的。
这件事让我重新意识到,并发的难点不是让更多 Agent 同时开始,而是让每一次写入都能被追溯、被拒绝或被验收。只要多个执行者拥有同一个文件的无条件写权限,所谓分工就只是口头约定。
文件看似分开,写入边界却没有分开
我一开始以为这是某个 Agent 没有看清任务书,后来发现原因更基础:大家共享同一个目录,也都按照自己的理解寻找“应该交付的文件”。任务层面写了每个模板的名字,却没有把“谁拥有最终写入权”变成硬约束。
于是,2 个 Agent 可能同时认为自己负责同一个文件。它们各自的代码、预览和判断都没有问题,但最后写入的对象相同,后写入者自然会覆盖先写入者。文件系统并不知道哪一版更接近验收结果,也不会替我们保留此前那份内容。
这里最容易误判的是:文件还在,大小也正常,甚至静态检查仍然能通过,就以为没有严重问题。可是“文件存在”只证明路径上有一个结果,不证明它属于正确的任务,也不证明已经验收的图片对应它。并发写文件首先是归属问题,其次才是内容问题。
如果不处理这个边界,后果不只是丢掉几行代码。预览图可能来自旧版本,检查记录可能来自另一版本,最后交付的文件则来自第 3 个版本。每份证据单独看都像真的,合在一起却无法证明“这就是被验收过的那一版”。
先停住冲突,再谈谁的版本更好
发现重复覆盖后,最自然的反应是继续重写:谁发现文件不对,谁马上再写一版,直到自己满意为止。这个错误捷径看起来积极,实际只会让竞态加速。一个 Agent 正在恢复,另一个 Agent 仍可能把旧思路写回去,新的预览又会被旧的写入弄失效。
我选择先暂停冲突写入,是因为在归属没有确定之前,任何修复都可能成为下一次覆盖。先把正在修改同名文件的动作停住,留下当前状态和已有验收证据,再逐个确认原始分工。这样做短时间内看起来像“什么都没做”,却是让现场重新获得可判断性的必要动作。
确认之后,规则变得很朴素:一个文件只允许一个 owner。owner 不是“最后一次写它的人”,而是合流前已经锁定的唯一负责者。其他 Agent 可以提出建议、检查结果,甚至在自己的隔离副本里尝试,但不能直接把结果写回共享目录。
这条规则的价值不在于它多复杂,而在于它把争论从“哪一版更好”提前变成“谁有权提交这一版”。如果归属错了,应该先改分工登记;如果内容错了,再由 owner 修复。两件事分开,才能避免所有人用写文件来表达意见。
写入必须像一次可撤回的提交
锁定 owner 后,还需要处理另一个风险:owner 自己也可能写出半成品,或者在渲染过程中被中断。如果直接打开目标文件清空再写,其他检查进程可能读到截断内容;如果写到一半程序退出,目录里留下的就是一个看似存在、实际不可验收的文件。
因此,恢复时我采用了临时文件加原子替换。完整内容先写到同一目录下的临时位置,写完后再一次性替换目标文件。读取者要么看到旧的完整版本,要么看到新的完整版本,不会看到中间状态。它不能解决 2 个 owner 同时提交的问题,却能把“半写入”从共享状态里排除掉。
这里我没有把原子替换当成万能锁。它只保证一次替换动作的完整性,不负责判断内容是否正确,也不负责阻止另一个进程稍后覆盖。真正安全的组合是:先按文件划 owner,再用原子替换落盘,最后重新验证内容。少了第 1 步,权责仍然混乱;少了第 3 步,完整写入也可能是完整地写错。
文件指纹要和验收证据绑在一起
接下来要确认的,不是“现在这个文件看起来像不像那一版”,而是它是否仍然是验收时那一版。我的做法是给文件留下几类轻量指纹:内容摘要、行数、关键字段是否存在,以及禁止模式是否出现。这里不需要公开内部摘要值,重点是让同一份内容在不同时间、不同机器上能被比较。
例如,预览图验收前记录文件指纹;恢复后重新计算。如果指纹不同,就不能直接把旧的验收结论套到新文件上。行数和关键字段可以帮助快速定位变化,禁止模式则能挡住一些表面上能渲染、实际上违反契约的内容。
这一步看似偏技术,实际是在保护人的判断。人眼容易把相似的版式当成同一版本,尤其在多张图连续出现时。指纹把“我记得就是它”换成了“我能证明就是它”。验收结论必须绑定具体版本,而不能绑定一个模糊的文件名。
现场曾出现过一个很典型的视觉偏差:替代版本的标题被拆成 4 行,页脚重复了品牌,数字还贴近边缘。它并不是完全不能打开,所以只做存在性检查很可能放过它。静态指纹能确认文件没有偷偷换版,但还不足以证明画面可靠,视觉结果仍要重新获得证据。
最后重渲染,才算把冲突真正收口
恢复文件后,我没有只渲染一个默认尺寸。因为模板在不同画布比例下可能改变换行、留白和数字位置,所以重新覆盖了 3:4、1:1、9:16、16:9。每个关键尺寸都检查生成结果是否成功、尺寸是否正确、是否仍然满足零外链要求,再逐张看标题、页脚、数字和边距。
这样做的原因是,文件一致和画面正确是 2 个不同问题。文件指纹回答“磁盘上的内容有没有被换掉”,渲染验收回答“这份内容在使用场景里是否仍然成立”。只做其中一个,都会留下盲区:只验文件,可能保留了稳定但难看的版本;只看图片,可能验收完又被别的写入覆盖。
我也不再把某个 Agent 自己报告的“已通过”当作最终结论。它的报告可以作为线索,但合流前要由统一验收流程重新执行,并确保读取的文件就是 owner 最后原子替换后的文件。这个顺序很重要,因为验收不是对一段历史对话盖章,而是对当前可交付状态负责。
表面上我是在修复几个被覆盖的模板,其实我是在修复证据链:谁写、写了什么、哪一版被检查、检查后有没有再变。一个流程成熟的标志,不是它能在顺利时并行跑完,而是遇到覆盖时,仍能知道该停在哪里、恢复什么、重新证明什么。
下次我会怎么做
下次遇到多个 Agent 并行修改共享产物,我会在启动前先做 1 张文件归属表:每个文件只有 1 个 owner,其他人默认只读;需要换人时先改归属,再允许写入。并发任务不再只分“工作内容”,还要分“最终提交权”。
开始执行后,我会把写入规则固定为:先写临时文件,完成后原子替换;替换前后记录内容指纹、行数和关键约束;任何自检图只对当时的指纹负责。发现同名文件被 2 个执行者修改时,先暂停冲突写入,不让“再试一版”把现场变得更不清楚。
最后,我会把统一验收放在合流之后,而不是把各自的自检报告简单相加。关键尺寸要重新渲染,静态规则和视觉硬伤都要重查,确认通过后才交付。多代理协作真正需要的不是更多同时动作,而是每个动作都有明确的主人、稳定的落点和可复核的结果。
这件事让我更愿意把 owner、原子替换、版本指纹和最终重渲染看成一种工作习惯,而不是 4 个孤立技巧。它们共同解决的是同一个问题:当很多人都能改变结果时,怎样仍然让结果保持可解释、可恢复、可验收。只要这条证据链还在,并发带来的速度才不会变成返工的来源。