§03一个循环的五个动作

The Five Moves of One Loop

把一个loop转一圈拆开看,里面只有五个动作:发现、交付、验证、持久化、调度。

循环这个词容易让人想偏,一听就以为是一段反复执行的代码,转个不停。loop engineering里的循环每转一圈,都在干一件具体的活:发现一件值得做的事,把它交给agent,验证结果对不对,把状态存下来,然后决定下一步。少一个,loop就转不起来,或者转起来也是空转。

一个例子

Addy在文章里描述了一种他常用的形态,原话是「Here is one shape I keep using」:一个每天早上在仓库上跑的triage(分诊)loop。

早上一个automation自动跑起来。它调用一个triage skill,去读昨天CI跑挂的测试、还开着的issue、最近的commit,把分诊结果写进一个markdown文件或者Linear看板。每个值得动手的发现,开一个隔离的worktree。一个子agent起草修复,第二个子agent对照项目的skill和测试做审查。connector自动开PR、更新ticket。处理不了的进收件箱等人。状态文件留着,第二天接着这里跑。

动作一:发现

loop转一圈,第一件事是搞清楚这一圈该干什么。在Addy的例子里,这一步是triage skill干的:CI失败、open issues、最近commits,合起来就是昨天到今天系统里出了哪些值得管的事。

要让agent自己去找活。你要是每天早上手动列一遍今天修哪几个bug,那loop还是靠你启动的,没省下你。

Addy强调,automation里调用的是skill,不是一大段指令:你触发一个$skill-name ,别往一个没人会去更新的定时任务里贴一大面墙的指令。发现逻辑变了,改skill就行。

发现这一步做得好不好,决定了整个loop的质量上限。它找出来的活要是没价值,后面四个动作都白做。

动作二:交付

发现了活,得把它交到干活的agent手里,这一步叫handoff。Addy的做法是,每个值得做的发现单独开一个隔离的worktree。worktree是git的一个机制,让多个agent在各自的工作目录里改代码,互不踩脚(§04零件二)。

交付之后,真正干活的是子agent。一个起草修复,写出第一版改动。任务切得越干净,后面验证和合并就越省事:一个发现对应一个worktree,对应一份明确的改动,谁出问题都好定位。

动作三:验证

第一个子agent起草修复之后,第二个子agent来审查。它对照的是项目的skill和测试,指令跟第一个不一样,有时候连模型都换一个。写代码的那个agent给自己的作业打分时太手软(原话见§04零件五),换一个专门挑刺的,才抓得住第一个自我说服放过去的问题。

Addy在讲子agent的那一节写得很直接:

原文:the loop runs while you are not watching, so a verifier you actually trust is the only reason you can walk away.

循环是在你不看的时候跑的,所以一个你真信得过的验证者,是你能走开的唯一理由。用我自己的话说:验证这一步,就是往循环里放一个能说「不」的东西(§05)。

动作四:持久化

验证通过,结果得落到一个能活过这次对话的地方。Addy用的是两样东西:改动本身通过connector自动开PR、更新ticket,落进代码仓库和工单系统;处理不了的发现进triage收件箱,等人工。还有一个贯穿始终的状态文件,记着转到哪了。

上下文一清空,agent就忘干净了,写进markdown或者看板的东西不会忘。没有持久化,loop每转一圈都像第一次睁眼;有了它,今天没干完的,明天能接着干。

§01那篇arXiv论文发现,真在跑循环的仓库几乎都没把状态文件提交进版本控制。我读这句的理解是:持久化必须有,但不一定非得是一份commit进仓库的markdown;要紧的是下一轮醒来时能读到它,而且你自己也能读到它。

动作五:调度

Addy的triage loop早上自动跑,不用他每天去点;状态文件让今天没处理完的发现留到明天,明天那一圈接着这里开始。调度,把「我手动跑了一次」变成了「它自己一圈一圈在转」。

没有调度,就得你每天记着去跑一遍,哪天忘了就断了。

五个动作一张表

动作干什么在triage loop里
发现自己找出这圈该做的事skill读CI失败、issue、commit
交付把任务隔离着交给agent每个发现开一个worktree
验证换个agent说「不」第二个子agent对照测试审查
持久化把状态写到对话之外开PR、收件箱、状态文件
调度让它一圈圈自动转早上automation自动跑