审核门禁与自动接受
任务做完之后,结果怎样经过审核门禁被认可,以及哪些节点值得停下来由人审核。
任务做完之后,结果要先经过审核,才会交给下游;全部任务的结果合到一起之后,整个工作流还要再经过一次审核。两处审核默认都自动通过,而自动通过并不检查结果对不对,所以需要有人把关的节点,要事先设成停下来等你,提交之后就不能再改。流程停下之后,你可以接受结果、让 Agent 接着改或从头重做,也可以不要这个结果;结论一旦给出,在这次执行里不能更改。
审核门禁
任务 Agent 结束工作,不等于结果可用;有问题的结果直接交给下游,建立在它之上的工作都要重做。所以结果在交给下游之前要先经过审核,得到认可才放行,认可可以由你给出,也可以按事先定好的规则自动给出。流程里进行这种审核的位置,就是审核门禁(review gate)。
CodeDAG 的门禁有两道。任务级门禁在每个任务完成之后、依赖它的下游开始之前,决定这个任务的结果能不能交给下游。工作流级门禁在整个工作流的最后:每个任务的结果单独看都没有问题,合在一起却未必如此,所以全部任务都有了结论、结果合到一起之后,还要对整套结果再做一次决定,工作流才算结束。
任务完成时状态变为 done,接受任务级门禁的审核;通过之后,任务进入 reviewed 阶段,依赖它的下游这才开始。全部任务都进入 reviewed 之后,在默认的隔离分支模式下,CodeDAG 把它们的结果合并到集成分支,工作流随即接受工作流级门禁的审核;通过之后,工作流进入 reviewed,离开队列,排在后面的工作流开始执行。两道门禁分别用 cdg task review 和 cdg dag review 审核。
每道门禁都可以设为开或关:设为开时结果自动通过,设为关时流程停下来,等你给出结论。
%%{init: {"flowchart": {"rankSpacing": 34}}}%%flowchart TD t1["任务完成:done"] --> g1{{"任务级门禁"}} g1 -->|设为开,自动接受| r1["任务进入 reviewed"] g1 -->|设为关| w1["停下,等你审核"] w1 -->|你给出最终结论| r1 r1 --> d1["依赖它的下游任务开始"] r1 -.->|全部任务都进入 reviewed| m1["结果合并到集成分支"] m1 --> g2{{"工作流级门禁"}} g2 -->|设为开,自动接受| r2["工作流进入 reviewed<br/>离开队列"] g2 -->|设为关| w2["停下,等你审核"] w2 -->|你给出最终结论| r2自动接受
每个结果都要等人审核,无人值守就变回了有人值守,而多数结果并不需要逐个过目。所以 CodeDAG 的两道门禁默认都设为开:结果一完成就自动通过,这称为自动接受(auto-accept)。你只在值得亲自审核的节点把门禁设为关,流程就会在那里停下等你。
门禁设为开还是关,写在工作流文件里:任务的 autoAccepted 管这一个任务,工作流的 taskAutoAccepted 是其中所有任务的默认值,dagAutoAccepted 管工作流级门禁。值为 none 时,对应的门禁就是关;全部取值见自动接受的取值。
哪些节点值得把门禁设为关
设为关的门禁要少而准,因为每一道都有代价。任务停在门禁前期间,依赖它的下游也在等待;在隔离分支模式下,它还一直占用自己的工作区,能同时执行的任务因此变少。工作流级门禁设为关时,队列里排在后面的工作流也要等你给出结论才会开始。通常值得设为关的是这几类节点:
- 后续任务都建立在它之上的节点。 比如实现方案、接口契约,它一旦出错,下游全部白做;在它之后停一下,代价最小。
- 第一次运行的新工作流。 还不确定 prompt 写得够不够清楚时,可以把
taskAutoAccepted设为none,逐个任务看一遍,确认没有问题之后再改回自动接受。 - 后面还排着其他工作流的工作流。 不写
baseRef时,下一个工作流默认接着这个工作流的结果开始(见起点);把工作流级门禁设为关,就能在下一个工作流开始之前确认这份结果。
反过来,只运行一个工作流时,工作流级门禁通常保持默认就够了:CodeDAG 不会改动你的主分支,结果最终要不要进入主分支,本来就由你决定。
没有留下改动的任务不会被自动接受
在隔离分支模式下,任务完成时如果没有留下任何改动,即使门禁设为开,也不会被自动接受,而是停下来等你审核。这个模式下,任务的成果都体现为分支上的改动;一个任务什么都没改就结束,常常意味着它没能真正完成,比如中途被打断、结论没有写进文件,这时自动放行,下游就会带着缺失的输入开始。确实不需要改动任何文件的任务,由你看过之后手动接受即可。
共享工作区模式下,这项检查只提示,不拦下任务,见共享工作区模式下审核有什么不同。
审核动作
流程停在门禁前时,你可以执行的审核动作分为两类:最终动作给出结论,这个节点就此结束;继续动作不给结论,让任务接着改,改完再回到门禁前。
最终动作有三个:accept(接受)放行结果;cancel(取消)表示不要这个结果;defer(推迟)表示这一步暂不采用,留到以后再处理。三者都让任务进入 reviewed。取消和推迟时,在隔离分支模式下任务自己的改动不会交给下游;下游是继续执行、停下等你还是一并结束,在审核时选择。自动接受就相当于 CodeDAG 按规则替你执行了 accept,审核结果记为 auto-accepted,以区别于你亲手给出的 accepted。
继续动作也有三个,区别在于由谁来改、从哪里改起:revise(自行修订)由你自己在任务的工作区里修改,改完再给出最终结论;request-changes(要求修改)把你的意见交给原来的会话,让它在现有结果上接着改;rework(重做)把当前结果存进快照或丢弃,从任务开始前的干净起点开一个全新的会话,从头再做一遍,原理见不满意时的退路。后两种由 Agent 改完之后,任务重新变为 done,按同样的规则审核。
工作流级门禁只有三个最终动作。这时每个任务都已经有了结论,工作流级审核只对整套结果做决定。在隔离分支模式下,接受时集成分支保留合并好的结果;取消或推迟时,集成分支回到本次工作流的起点。所以,如果希望发现问题时还能让 Agent 接着改,就要把任务级门禁设为关,比如工作流最后一个任务的门禁,而不是只把工作流级门禁设为关。每个动作怎样使用、有哪些选项,见审核任务与工作流。
验证节点
人能仔细审核的结果有限,自然会想先让机器检查一遍,只把通过检查的结果交给人。CodeDAG 没有内置的测试门禁:它不会自己运行你的测试,自动接受也不看测试结果。但任务 Agent 可以运行测试。把“运行全部测试,修复失败项,直到全部通过”写成一个任务,放在要检查的任务之后,检查就成了工作流里固定的一步:每次运行都会执行,发现问题就地修掉。
这样的任务称为验证节点,工作原理中菱形工作流的任务 4 就是一个。检查也不限于测试,构建、类型检查、lint,或者让另一个 Agent 审查前面的改动(见一家做完,另一家检查并修复),都可以这样写成任务。
验证节点仍然是一个 Agent 任务,CodeDAG 判断它完成的依据和其他任务一样,是 Agent 结束了工作,而不是测试通过了。Agent 修不好、最后放弃时,任务同样会变为 done,门禁设为开时多半就被自动接受了。所以验证任务的 prompt 要写清完成标准,并要求它把结果写进文件:运行了哪些检查,修了什么,还有什么没有通过。这份记录就是人最后要看的东西。在隔离分支模式下,它还有一个用处:验证任务如果检查全部通过、什么也没改,会因为没有留下改动而停下等你审核,写下记录就不会这样。
在验证节点之后再留一道人工门禁,就是机器先把关、人最后看一眼。把验证节点自己的门禁设为关,读完记录后如果还有问题,可以让它接着修;也可以把工作流级门禁设为关,对整套结果做最终决定。
审核结论不能更改
最终结论一旦给出,在这次执行里就不能更改,自动接受给出的也一样,因为下游任务随即在被接受的结果之上开始工作。
自动接受的设置在工作流提交之后也不能修改,所以需要你亲自审核的任务,要在提交之前把它的 autoAccepted 设为 none。
不能更改的只是审核结论,代码结果仍然可以补救:事后发现问题,用 Git 处理任务的改动,再用新的工作流重做,做法见任务已经有了审核结论,才发现问题。
最后更新