ACDL研发流程08:让多个Agent在不同worktree工作

ACDL研发流程系列第8篇,共15篇。

上一篇:ACDL研发流程07:把设计拆成可以独立验证的任务

下一篇:ACDL研发流程09:完成代码、验证并更新环境

多Agent不等于把同一个任务切成多份

Agent可以很快地读取代码和生成实现,所以多个Agent同时工作看上去是最直接的加速方式。但如果它们正在等待同一个未定稿接口,修改同一批文件,或者各自理解了不同的产品结果,并行只会把返工也同时放大。

当前项目并行的基本单位不是Agent,而是第7章已经拆好的独立任务。每项任务有自己的工作来源、ACL、目标、非目标、起点和验证结果,然后再交给一个主要Agent。不把数据库、接口、页面和测试分给几个Agent,让它们在同一项尚未定稿的改变中相互等待。

如果当前只有一项端到端任务,一个Agent保持完整上下文通常更快。只有出现两项或更多能够真正独立推进的工作时,才需要组织并行开发。

第一步:先确认这些任务能否并行

可以独立验证是并行的第一个条件,但还不够。Director和Agent还要看任务之间的依赖、文件交叉和外部资源。

两项任务通常适合并行,需要同时满足以下条件:

  • 它们不需要等待对方的未定稿结论,已知依赖要么已经完成,要么已经确认接口和数据格式在并行期间不会变化;
  • 它们的主要修改范围能够分开,少量共同文件也能预先说明谁先改、谁在集成时适配;
  • 它们可以使用不同的测试数据库、端口、容器、账号或证据目录,不会互相改写外部状态;
  • 需要隔离文件修改时,每项工作都能在自己的worktree中实施、测试、提交和记录;
  • Director已经知道谁负责最终集成,以及几项结果以什么顺序进入主线。

上一章把收藏会话拆成“保存收藏状态”和“筛选收藏内容”两个结果,但第二项依赖第一项,它们仍然需要串行。假如当前还有一项Runtime恢复缺陷和一项文档检查工具优化,而它们分别有自己的工作来源和验证方法,就可以与收藏会话同时开展:

1
2
3
4
同一个已确认起点
├─收藏会话ACL→worktree A→Agent A
├─Runtime恢复ACL→worktree B→Agent B
└─文档工具ACL→worktree C→Agent C

这里同时推进的是三项工作,不是三个Agent共同完成收藏会话。

如果两项工作同时改动一个核心契约,共用一个无法分离的真实环境,或者第二项的验证结果完全取决于第一项的实现,就先保持串行。不需要为了让Agent都有事做而制造并行任务。

第二步:需要文件隔离时,一项任务使用一个worktree

worktree是Git在同一个仓库上同时保留多个工作目录的方式。每个worktree检出自己的分支,Agent可以在其中查看、修改和测试文件,不会把未提交差异混到其它任务的目录里。

存在文件冲突风险时,推荐使用以下对应关系:

1
2
3
4
5
一项独立任务
→一轮ACL
→一个短期分支
→一个worktree
→一个主要Agent

分支、worktree和Pull Request都按实际需要使用。只做只读调查、修改范围完全不相交,或者当前Harness已经提供其它可靠隔离时,不为了形式机械创建。需要隔离文件差异时,主工作树保留共同起点,每个并行任务在独立worktree中开展。

分支名称可以由小写ACL编号和简短主题组成,例如acl-000039-conversation-favorites。分支跟踪的是工作而不是Agent身份,不要使用模型名或Agent名命名。

建立worktree前,先根据当前运行时确认是哪一种Harness。Orca、Codex或其它Harness已经提供原生worktree能力时,优先使用它的创建和交付入口;原生能力不可用或不适合当前任务时,才用Git命令作为后备,并选择稳定、可识别的非临时目录。无论由哪种工具创建,都先记下完整起点提交、分支和目录。

不同任务可以从同一个已确认提交开始,也可以根据已知依赖从不同提交开始。无论怎样选择,每轮ACL的启动方案都保存自己的分支、明确的起点提交和worktree路径,不用“从最新代码开始”这种无法复现的说法。

同一任务需要多个Agent时,可以串行接棒

并行规则解决的是多项独立任务怎样同时推进。另一种常见情况是,同一项任务先由ChatGPT整理需求或设计候选,再由本地Agent实施和验证,最后交给ChatGPT或其它Agent评审。它们处理的是同一轮工作,不需要为了参与者不同而拆成多个ACL,适合按阶段串行接棒。

本机Agent通常使用worktree取得完整文件、依赖和验证反馈;通过GitHub参与的远端Agent通常使用远端分支、提交和Draft Pull Request取得隔离空间。远端Agent是否能够写入,取决于连接器和仓库权限:能够写入时可以直接准备候选,只有读取能力时则提交分析或评审意见,由当前写入者落地。工具能力不同,不改变仓库事实源和Director确认边界。

同一分支由多个Agent接力时,推荐采用以下约定:

1.任一时刻只指定一个当前写入者,其他Agent只读或评审;
2.交接前提交并推送候选变化,记录完整HEAD提交;
3.接棒者先核对远端分支仍指向交接提交,再开始修改;
4.已经交接的共享分支不强制推送、不改写交接历史;
5.两个Agent要探索不同方案时使用不同分支,不在同一分支互相覆盖;
6.共同决定写回REQ、设计、ADR或Loop记录,Pull Request只保存差异讨论和交接摘要。

这些约定用于降低远端与本机协作中的竞态,不表示每项工作都必须创建Pull Request。只有一名Agent、没有远端评审或无需隔离时,继续使用原来的短路径即可。

需要反复交接时,可以在Draft Pull Request顶部维护一段简短的当前状态:

1
2
3
4
5
6
7
## 协作状态

- 当前阶段:需求、设计、实现、验证、评审或待确认
- 当前写入者:当前负责修改分支的人或Agent
- 当前候选:完整HEAD提交
- 下一接棒者:下一位参与者
- 下一步:一句话说明要完成的动作

每次正式交接再用Pull Request评论保留固定快照,至少说明基线、当前候选、正式依据、本轮目标和非目标、实际修改、已运行与未运行的验证、剩余风险和下一步。新会话先读取这段交接、正式文档和固定提交,不依赖上一段聊天记录恢复现场。

第三步:把代码之外的资源也分开

worktree隔离了文件目录、当前分支和未提交差异,但它们仍然属于同一个Git仓库,也仍然在同一台机器或同一套基础设施上工作。它不会自动分开:

  • Git的共享引用和对象;
  • 测试数据库及其中的数据;
  • 本机端口、进程、容器、网络和数据卷;
  • 开发或真实环境;
  • 测试账号、外部系统和限额;
  • 日志、截图、检查结果和其它证据目录。

因此,Director在启动并行任务时,为每轮ACL分配不会冲突的外部资源。例如,每项数据库测试使用独立的专用测试库,每个本地服务使用不同端口,每轮验证写入自己的证据目录。只有一套的真实环境默认串行更新,不让两个Agent同时发布并相互覆盖结果。

这些分配写入各自启动方案。如果无法把一项关键外部资源分配成互不影响的独立资源,就把需要它的步骤排成明确的串行顺序,不用“小心一点”代替隔离。

第四步:为每个Agent准备独立上下文

每个主要Agent只需要读取完成自己任务所需的上下文,不需要理解所有并行任务的实施细节。交付一个worktree时,至少让Agent知道:

  • 它负责的ACL编号、工作来源和启动方案;
  • 需要遵守的REQ、Accepted设计和ADR;
  • worktree路径、当前分支和明确的起点提交;
  • 可以修改的范围、已经分配的外部资源和不可执行的高风险动作;
  • 任务与其它ACL的已知依赖、预计集成顺序和交付方式;
  • 完成前需要运行的定点验证和需要保留的证据。

不需要把Director与其它Agent的全部聊天记录同步到每个worktree。共同决定写回REQ、设计或启动方案,当前进展写入各自实施记录的“当前摘要”。任务在新会话中继续时,Agent重新读取这些内容并核对当前Git差异,不从记忆中猜测上一次做到了哪里。

第五步:让每个Agent交付一个可以独立验证的完整结果

并行开始以后,每个Agent在自己的worktree中推进完整任务。它可以修改前端、接口、领域逻辑、数据和测试中真正受影响的部分,不被“你只是前端Agent”之类的职能划分限制。完成时留下的是一个能被验证的结果,不是一批等别人收尾的文件。

并行开发不需要让Agent之间持续互相播报每个实施细节。他们只需要告知会影响其它任务的变化:稳定契约改变、共享资源冲突、起点被修正,或者原定依赖不再成立。Director根据这些事实决定调整集成顺序、暂停某项工作,或者回到设计重新确认。

如果一个Agent发现需要改动另一项ACL的范围,它不直接进入对方worktree修改。它先记录新事实和影响,由Director判断这是可以在集成时处理的局部适配,还是原来的任务拆分已经不再成立。如果会改变已确认的产品行为或技术边界,就暂停受影响的实施并回到设计。

第六步:主线依次接收并行结果

多项任务可以同时开发,但不能同时改写主线。每个Agent先在自己的分支上完成范围内的代码、文档、定点验证和实施记录,并把修改整理成容易理解、目的单一的提交。Director或当次指定的集成Agent根据依赖和风险决定接收顺序。

第一项结果进入主线以后,下一项先取得最新的main,处理它与当前main的差异,再重新运行受影响的定点验证。希望保持线性历史时,任务分支可以先同步当前主线:

1
git rebase main

确认冲突已经解决且相关验证仍然通过后,再在主工作树中接收该分支:

1
git merge --ff-only acl-000039-conversation-favorites

代码冲突有两种。一种只是同一文件不同位置的机械冲突,集成Agent根据两边已确认的结果处理并重新测试。另一种暴露了两项任务对对象、状态、接口或权限的理解不同,这不是选择哪边代码更好合并的问题,而是设计矛盾。Director与Agent需要先回到相关设计统一答案。

每项结果进入主线时做受影响的验证,全部接收后再做跨任务的整体验证。分支能够合并只证明Git接受了这些差异,不证明几项工作组合后的系统能够工作。

第七步:完成交付后再清理worktree

一项分支进入主线,不表示它的ACL已经结束。实际修改、验证、失败和跳过项、剩余问题、Director的结论确认以及实际合入提交仍要完整保留。ACL只有在这些事实齐全后才能进入Completed

确认分支结果已进入主线、所有需要的记录和证据已经交付,而且没有Agent继续使用该目录后,才移除worktree和对应短期分支。未合并结果、失败现场、待复核差异和其它Agent仍在使用的worktree都需要保留,不为了目录整洁而提前删除。

并行数量取决于Director能够评审和合并多少结果

可用Agent数量不是并行数量的上限判断。Director还要看有多少真正独立的任务,外部资源能分成几份,以及自己能否及时处理歧义、评审结果和组织集成。

如果五个Agent同时完成五个分支,但主线一次只能安全接收一个,其它分支就会迅速过期,后续时间都用在重新同步、解决冲突和补做验证上。少量稳定的并行通常比一次启动尽可能多的Agent更快。

回头检查这条路径

1
2
3
4
5
6
7
多项已启动的独立ACL
→检查依赖、修改范围和外部资源
→按冲突风险决定是否建立分支和worktree
→为每个主要Agent交付独立上下文
→各自完成可以独立验证的完整结果和定点验证
→按已定顺序依次进入主线
→运行整体验证并保留各轮记录

并行开发的目标是同时推进多项独立结果,不是让更多Agent出现在同一项任务中。worktree把各项任务的文件和未提交修改分开,启动方案和实施记录把上下文分开,外部资源分配和主线集成则让这些结果能够安全重新组合。

同一任务的多Agent协作采用另一条按需路径:

1
2
3
4
5
6
一项已启动的ACL
→当前写入者在隔离空间完成一个固定候选
→提交、推送并记录完整HEAD
→下一位Agent核对基线后接棒或评审
→共同结论写回正式事实源
→本地完成必要验证并由Director确认结果

两条路径可以同时存在:不同任务之间并行,同一任务内部串行。关键是每个时刻都能回答谁在写、正在修改哪个固定候选、下一步由谁接棒,以及哪些结论已经写回仓库。