有一个简单的购物清单应用,还需要添加两项功能:筛选条目,以及将清单导出为 CSV。两项工作几乎没有关联,于是很自然会想到:分给两个人做,半小时就能拿到两部分,而不是等一小时。一名执行者负责筛选,另一名负责导出;两人各有自己的工作目录,避免修改混在一起。至于两部分如何理解清单中的条目,事先并没有讨论。看起来似乎不言自明。

半小时后,两部分都完成了。各自的检查都通过了,合并时也没有任何冲突。但整体流程却跑不通:界面上的筛选结果有三行,导出的文件里对应列却是空的。原因很普通。一名执行者顺手把 completed 字段改名成了 done,因为他觉得后者更易读,而另一名执行者并不知道这件事。

不同的目录隔开了文件,却没有让大家对决策达成一致。我们分三步来看这个问题:先判断这项工作是否值得拆分,再分配修改范围并明确共同约定,最后检查整合后的结果,避免直到最后才发现这种意外。

检查依赖关系

通常有两个理由可以拆分工作。第一个是分别独立调查不同领域:同时查清清单如何显示,以及导出内容如何生成。第二个是同时处理边界已知、结果可验证的不同部分。"这里规划、那里执行、另一处检查"这种安排本身不需要三名参与者,一个会话可以依次完成。对于小任务,从一名执行者开始更合理。

如果确实有理由拆分,接下来要问:在 A 的结果还未知时,B 的哪些工作可以先做?如果 B 完全依赖 A,这些步骤就得按顺序进行。有时 B 可以预先准备好一部分独立工作,但整合结果仍然要等 A 完成。

还是用购物清单的例子,来看三种情况:

要做什么能否同时开始原因
查清当前在哪里筛选清单,以及导出内容由什么生成可以查看的是不同区域,结论互不依赖
针对尚不明确的原因准备最终修复查明原因之后先调查;不同且可验证的假设可以并行调查
编写筛选功能和导出功能明确条目的共同格式之后两部分依赖同一个字段;没有共同约定,结果就会不一致

第三行是最常见的陷阱。筛选在 src/filter.js,导出在 src/export-csv.js,看起来两部分互不相关,毕竟文件不同。但它们读取的是同一条记录和同一个 completed 字段。文章开头的流程正是因此出错,不同文件也没能避免问题。是否独立,取决于行为和共同约定,而不是代码分散在几个文件里。

可以让智能体负责拆分任务,但先不要启动执行者:

将任务拆分成多个部分。为每部分列出输入、结果、依赖关系和验证方法。
标明哪些部分现在可以开始。
暂时不要启动执行者。

启动前可以检查这样的拆分结果。没有未解决依赖的部分,就是可以同时启动的候选。依赖列为空的部分,最好再对照项目核实一遍:智能体可能没注意到共用的数据模型或配置。

计算得到整体结果所需的时间

人们通常用一个数字衡量提速:工作本身花了多久。但真正要计算的是得到验收通过的整体结果需要多久。除了实际工作,还要算上给每名执行者说明任务的时间、他们各自重新阅读项目的时间、等待、检查两份结果并将它们整合到一起的时间。

用我们的例子做一个假设性计算。数字仅用于演示算术,不代表性能测量:

计算项目一名执行者依次完成两名执行者同时完成
拆分工作的额外准备:分别说明任务并让执行者达成一致0 分钟5 分钟
执行20 + 20 分钟两部分共 20 分钟
检查结果并整合10 分钟15 分钟
得到验收通过结果的总时间50 分钟40 分钟
总时间(如果因对条目理解不同,有一部分返工了 15 分钟)50 分钟55 分钟

两种方案都需要共同的任务准备,因此计算中没有计入。一次返工就会抵消十分钟的收益;整合成本越高,并行工作需要节省的时间就越多。

除了时间,还有两项容易被忽略的成本。每增加一名执行者,他都要重新阅读项目,这是资源开销;详细结果返回后,也会占用共享对话的上下文空间。第二项成本更重要:您自己的注意力。您需要阅读并比较两份结果,再据此作出决定。如果您来不及阅读收到的内容,速度就不再由您掌控。

如果两部分规模相近、彼此独立,而且额外开销很小,提速接近一倍是有可能的。但执行者的数量本身并不能保证这一点。

重复工作还是交叉检查

重复工作往往不会出现在报告里。两名执行者默默打开同一批文件,分别研究清单条目如何组织,然后都如实写下自己读过代码。但有时第二次检查是刻意安排的:某个假设很关键,您希望由没看过第一个人的推理过程的人来验证。它与意外重复的区别在于,检查对象、检查原因,以及结论不同时的处理方式都事先明确了。缺少最后一项,检查就会变成收集意见。

再看相反的情况。有人问两名执行者,清单记录中的 completed 表示什么。他们的回答相同:标记商品已经买下。看起来像是两个独立确认。

实际上,他们读的是同一行一年前写进 README.md 的说明,而代码中的字段早就另有所指。他们一致的不是结论,而是信息来源。

因此有两个实用习惯:

  • 请对方展示答案的依据:文件、行号或代码片段。不要只听复述,而要看您自己也能打开核对的内容;
  • 对共同假设单独做真实验证:检查代码做了什么,以及流程中实际发生了什么。即使所有人都同意也一样。

不同会话并不能保证错误彼此独立:共同的信息来源会带来共同的失误。答案不同时,要检查依据,而不是统计票数:一个人可能查看了最新代码,另外两个人却参考了过时的笔记。

经过代码核实的字段含义,才是共同数据模型的基础,大家要在开始前就达成一致。如果经过这三项检查,拆分看起来仍然划算,我们就可以开始分配工作。

为每个修改范围指定负责人

并行工作期间有条简单规则:每个修改范围只指定一名负责人。不是说"这个文件绝对不能由两个人碰",而是"这两项任务进行期间,这部分由他来改"。这是阶段性约定,不是项目本身的属性。

规则的另一半更重要,也更容易被忘记。整体结果也需要负责人:由他把各部分整合起来,并判断整体是否已经完成。如果没有指定整合负责人,最后完成的人就会接手,而他恰好最不了解其他人的工作。

启动前先查看项目,确认需要处理的部分已经有一定划分。如果没有,也不必为了并行而启动大规模重构:重构本身就会变成当天最大的一项任务,到时也就没什么可拆分了。

购物清单的工作可以这样分配:

范围修改者约定
src/filter.js, tests/filter.test.js执行者 A根据约定的 completed 字段筛选条目
src/export-csv.js, tests/export-csv.test.js执行者 B按约定格式导出传入的条目集合
src/item-model.js整合负责人在开始前统一条目数据模型;修改前与所有依赖它的人讨论
src/app.js, tests/filter-export.test.js整合负责人接入两个部分,并检查筛选后的清单是否正确导出
package.json, package-lock.json整合负责人执行者不会顺手添加新依赖

这张表分配的是修改责任,而不是访问权限:需要查看共享文件的人都可以读取。

package.json 这一行不是故意设限:npm install 会同时修改两个文件,所以两次并行安装很容易直接造成冲突;而同一个库的两个版本,也可能在整合时带来意外。如果双方都需要某个库,就由执行者说明需求和原因,再由一人决定并只修改一次。

开始前统一数据模型

只按文件划分工作,却没有共同约定,效果往往不好。筛选和导出都依赖同一个条目数据模型。下面是它们接口的示意,并非可执行示例:这里没有展示函数的具体实现。开始前还约定保留条目顺序、不修改原数组,并在 CSV 中将布尔值写成 true/false。CSV 的转义规则保持不变。

// 一条清单记录:这三个字段在开始前约定好,不再改名
const item = { id: 41, title: "oat milk", completed: false };

// filter.js 返回筛选后的条目集合,不负责格式化或导出
filterItems(items, mode);   // mode: "all", "active", "completed"

// export-csv.js 接收筛选后的集合,不再自行筛选
exportCsv(items);           // 返回包含 id,title,completed 列的 CSV 字符串

请注意,这里的约定不是文件名,而是输入和输出。"导出功能接收已经筛选好的清单"听起来只是个小细节,但正是这句话决定了两名执行者中谁负责筛选。如果没有它,双方都可能合理地认为筛选由自己负责,结果导出的文件要么包含所有条目,要么被筛选两次。

开始前还要约定如何验收结果。以我们的例子来说,记录 41 和 43 设为 completed: true,记录 42 的值为 false。"completed"模式应按原顺序显示 41 和 43;CSV 也应包含这两条记录,列名为 id,title,completed,最后一列的值为 true。这个流程一次经过两个部分,正好能发现文章开头的那个问题。

还要单独讨论如何修改共同约定。如果工作过程中发现需要更改共同格式,这就不再是修改一个文件的小事。应当重新检查所有依赖该格式的任务,因为已经完成的部分可能基于旧版本。

各自独立的工作目录(git worktree)不能替代共同约定。它们能在物理上隔离改动,这很有用:在共享目录中运行检查,可能会把相邻任务尚未完成的修改也包含进去,从而验证一种没有任何执行者单独检查过的状态。但目录无法帮助统一条目格式,而且端口、本地数据库和其他外部资源仍然是共享的。未被 Git 跟踪的 .env 默认根本不会出现在新目录中,需要另外复制,例如通过 .worktreeinclude。

给每个人一份简短任务

任务说明不必很长。通常七项就够了:目标、起始版本、负责的文件、共同约定、可验证的结果、回复时要提供什么,以及需要修改其他人负责的范围时该怎么做。

目标:筛选器可以显示全部条目、未完成条目或已完成条目。
从以下版本开始:已统一条目模型的主分支最新 commit。
您负责的文件:src/filter.js 和 tests/filter.test.js。
共同约定:completed 字段保持布尔类型,不更改字段名称;
筛选器返回条目数组,不负责导出。
结果:筛选器测试通过;对包含三条记录的数据集,每种模式
都返回预期的清单。
请返回:实际修改的文件列表、测试运行输出、运行测试的版本,以及未解决的问题。
如果需要修改 src/item-model.js 或 src/app.js:请停下来,
说明需要的改动和原因,然后等待答复。

给第二名执行者的任务也应采用相同结构:各自负责一对文件,遵守相同的条目格式,有可验证的结果,越界时也按相同流程处理。这里没必要把另一份任务完整重写一遍。

再说说执行者的回复。您需要看到实际修改的文件列表和真实的检查输出。写一句"没有碰其他人的文件"很容易;您越是反复强调,这句话越可能出现在答复里。不要只看文字描述,要对照实际修改列表。任务边界是一项约定,不是权限限制:请求文本不会阻止智能体写入文件,访问权限需要单独配置。

如果部分工作由 subagent 完成

在 Claude Code 中,subagent 会在自己的上下文窗口中工作。普通 subagent 看不到您的对话,只会根据 Claude 编写的任务说明执行;fork 模式则会继承整个对话。因此,最好在任务中明确写出共同约定和验收标准。subagent 返回的是摘要,阅读起来方便,但看不出文件具体改了什么,而且摘要本身也会占用主对话的空间。更多信息请参阅:subagent 文档。

重新协商交叉范围

迟早会有人遇到其他人的工作边界。执行者 B 发现,如果不修改 src/app.js,就没有地方接入导出功能:导出按钮根本不会触发。

好的反馈应当说明原因、所需修改和依赖关系。src/app.js 的接入工作已分配给整合负责人,因此 B 可以先完成自己的模块,再提交接入请求。如果没有共同修改就无法继续,那么依赖这项修改的工作应当暂停。

接下来有两种做法。整合负责人可以自己修改共享文件,因为这是他的负责范围;或者明确把这部分转交给执行者 B,但要先确认原负责人此刻不会继续修改该文件。交接时不暂停旧工作,就会造成原本划分责任要避免的情况。

千万不要让执行者绕过边界。比如要求"别动 app.js,想个别的办法",通常只会让他在自己的文件里复制别人的逻辑,或者加一层没人能解释的中间层。表面上遵守了分工,实际上项目里却出现了第二种导出逻辑。

整合行为,而不只是文件

整合前,负责人需要确认三件事:每部分从哪个版本开始、每名执行者检查了什么以及使用哪个版本检查、实际修改了哪些文件。这些内容都应当出现在任务回复中,文件列表则要与真实改动核对。

然后整合各部分,最重要的是运行开始前约定好的整体流程。两类截然不同的问题可能会妨碍这一步。

文本冲突。不同部分修改了同一段内容、删除或重命名了文件,Git 无法自动合并。解决冲突后,还要检查最终行为。

语义不兼容。没有人同时修改同一行,文本也顺利合并,没有冲突提示。我们这个改名的例子恰恰属于这种情况:筛选器读取 done,导出功能读取 completed,因此什么也没导出。两边的检查仍然都通过,因为它们只验证各自的部分和数据。

顺利合并不等于兼容

没有冲突地完成合并,并不能证明行为兼容。您可以通过界面或函数组合测试运行整体流程;局部检查无法替代它。

两部分工作汇入一次整合,并通过整体流程验证执行者 A执行者 B整合负责人整体流程筛选与导出一起验证整合各部分src/filter.jssrc/export-csv.js
由一名负责人整合各部分,只有整体流程才能判断它们是否兼容

请看图中最下面的箭头。上半部分是通常所说的工作拆分:两个独立部分分别位于不同文件中。而是否完成,要看更下一层的整体流程,它会同时经过两个部分。在这条箭头走通之前,您只有两个局部结果,还没有整体结果。如果项目要求运行全套检查,整体流程也不能替代它们。

确定共同结论

整合完成后,整体结果的负责人要决定下一步怎么做。例如:

  1. 接受整体结果:流程通过,改动都能解释清楚,验收标准也都满足。
  2. 让某个部分返工,并明确指出哪里与什么不一致。不要只说"导出好像有问题",而要说"导出读取的字段在数据模型中已经不存在"。
  3. 重新考虑拆分方式:减少执行者,或将各部分改为依次处理。

第三种选择很正常,不代表失败。是否该重新考虑人员安排,通常很快就能看出:

  • 共同的条目格式反复变化,每次都要重做两个部分;
  • 执行者互相等待,说明存在尚未明确的依赖;
  • 结果返回的速度超过了您阅读它们的速度。

最后一种情况最让人头疼,因为表面看起来像成功。一次拆分顺利也不意味着每次都如此:智能体的结果会因每次运行而异,因此重要结论最好在类似任务中再次验证。

部分完成也是合理的结果。筛选功能可能已完成并通过检查,而导出还没有;如实记录即可:两部分中完成了一部分。整体任务仍未结束,不能因为一半已经正常工作就宣告完成,分工再细致也改变不了这一点。

自测

看两个场景。先自己回答,再对照说明。

还没有找到错误原因。
导出有时会生成空文件,您可能想立刻把修复任务交给两个人。先复现问题并调查原因。如果发现了不同且可验证的假设,可以分别交给两名执行者。但仅仅提出两个修复方案还不够:每个方案都要能对应到具体原因,并在原始流程中通过验证。

文件不同,数量却是同一个。
筛选器按件数统计商品,导出却按包装数输出同一批商品。两个部分的检查都通过了,但屏幕和文件中的数字并不一致。这不是代码错误:两个部分都没有越过自己的边界。缺少的是计量单位的共同约定。应当在开始前将它写入条目数据模型,再由整合负责人修改 src/item-model.js,之后重新运行整体流程。

Claude Code 可以负责什么

如文章开头所示,智能体可以先拟出任务拆分方案,再根据您列出的要点整理成完整的任务说明。另外还有三个适用场景,但最终决定仍由您作出:

  • 拟定范围清单。请智能体检查项目并建议每个任务部分需要修改哪些文件,同时列出路径。这只是草案:各范围的负责人仍由您指定。
  • 整合并运行整体检查。智能体可以整合各部分、列出全部改动并运行整体流程。之后请您亲自完整检查这些改动。
  • 处理有争议的地方。两份听起来都很有把握的解释,不代表决策已经作出。请对方提供依据、文件和行号;修改共享文件的人应当事先由表格指定,而不是看谁的回答更有说服力。

归根结底,这一切取决于一个决定和两项任命。首先是是否值得拆分:每增加一名执行者,都应当带来足以抵消任务准备、检查和整合成本的收益。其次,为每个修改范围和整体结果分别指定负责人。购物清单的例子里,缺少的正是这些:既没有约定 completed 字段,也没有人负责一起运行筛选和导出。工具可以承担机械性的工作,但已整合的行为是否真正符合预期,仍然要由人来判断。