造一个真的循环:选题、从零搭起来

第一个循环该小到不像个系统。但六个要素里,前两个决定它能不能转,后四个决定它转起来之后会不会闯祸——而新手通常只装前两个。

位置
第 04 篇 / 共 5 篇
预计
6 分钟

前三篇是原理。这一篇动手。

先说一句最重要的:Stripe 那套每周合并一千三百个 PR 的流水线,是终点不是起点。 第一个循环应该小到几乎不像个系统 —— 一个按时去看一眼某样东西的小玩意儿。

选题:为什么是这两个

两个特别适合入门的题:客服 agentbug 分诊循环

它们有一个共同点,而这个共同点正是选题的判据:输入是天然流进来的,而且有现成的判据说对不对。

输入从哪来 怎么知道做对了
bug 分诊 CI 失败、新开的 issue、刚合的提交 测试能不能跑绿
客服 工单队列、聊天记录 问题解没解决、要不要转人工

对照着看,不适合当第一个循环的题长什么样:

  • 没有稳定输入源的 —— 你还得每天早上告诉它干什么,那就只自动化了「做」,没自动化「找」。而选择做什么,往往才是贵的那部分
  • 没有便宜判据的 —— 比如「优化文案风格」。没有验证器,循环转得越勤,坏东西堆得越多。
  • 不可逆动作多的 —— 比如直接改生产数据。第一个循环不该有这种权限。

选题的核心是选一个「有现成 oracle」的领域。 这也是为什么早期成功案例集中在编码、测试、分诊 —— 不是因为它们更重要,是因为它们能被便宜地判对错。验证器决定上限这条规律,在选题这一步就开始起作用了。

从零搭:五步

用 bug 分诊做例子,一步一步加。每一步都能独立跑,不留半成品。

第一步:先让它重复跑

最小的循环就是「按间隔重跑同一件事」。

/loop 5m check the deploy # 固定每 5 分钟
/loop check the deploy # 让 agent 自己掌握节奏
/loop # 跑 .claude/loop.md 里写的东西

这一步之后你有的是「重复」,还不是循环。因为它每次都从同一个地方开始,而且是你告诉它干什么。

第二步:让它自己找活

重跑一行命令不算循环。给它三样东西去看,让它自己列出值得处理的。

关键是:发现逻辑要写成 skill,不要写进定时任务里。

.claude/skills/morning-triage/SKILL.md
NAME: morning-triage
WHEN: 每天早上由自动化触发
READ:
- 昨天以来失败的 CI 运行
- 24 小时内新开的 issue
- 上次运行以来合并的提交
JUDGE: 逐条判断值不值得处理,噪音跳过,只留可行动的
OUTPUT: 把发现和状态写进 ./state/triage.md(一条一行)

为什么必须是 skill 而不是塞进 cron 的一大段指令?因为塞进定时任务里的那堆字,没有人会再去更新它。skill 是能被复用、被维护的一个文件;一大段提示词不是。

定时 + 自己找活,是循环的入门线。

第三步:加状态文件

不要把结果留在对话窗口里。

# ./state/triage.md(循环的记忆)
| 发现 | 来源 | 状态 |
|--------------|-----------|--------|
| auth 测试不稳 | CI #4821 | 修复中 |
| 空指针 | issue 92 | PR 已开 |
| 依赖过期 | commit a3 | 待人看 |

agent 会忘,仓库不会。 上下文一清空,agent 什么都不记得;而这个文件让明天的那一轮知道今天做到哪儿了。

这一条也是「记忆」和「上下文」的区别:上下文是它这一轮看见的东西,刷新就没;记忆跨轮跨天存在。

第四步:加评估器(最关键,最容易跳过)

前三步做完,你有一个会自己转、有记忆的循环 —— 而它到现在为止,从没说过一次「不行」。

评估器要满足三个条件:

  1. 是另一个 agent,带完全不同的指令,最好换个模型
  2. 默认怀疑:一开口就是「我假设这段代码是坏的,除非你证明给我看」
  3. 要动手,不能只读:真的去点按钮、真的截图、真的看页面变了没有
.claude/agents/reviewer.md
ROLE: 对抗式代码审查者
ASSUME: 这段代码是坏的,直到被证明不是
DO NOT: 夸奖
按顺序检查:
1. 它能跑吗?(执行,不是阅读)
2. 测试:真跑一遍,把真实输出贴出来
3. 作者跳过的边界情况
4. 行为和工单描述对得上吗
结论:每一条都成立才算 PASS,否则 REJECT 并逐条列出理由

停止条件交给一个新的模型判:

/goal all tests in test/auth pass and the lint step is clean

为什么必须换一个 agent? 因为写代码的那个,脑子里装的是「我为什么这么写」的一整套理由 —— 它看到的不是结果,是那串说服自己的过程。让作者自我批评很难,让一个外人挑刺很容易。

第五步:并行时加隔离

多个 agent 同时改同一个工作目录,冲突会乱成一团。git worktree 让每个任务有自己的目录。

Terminal window
claude --worktree fix/auth-test "起草修复"
claude --worktree fix/null-deref "起草修复"

这个问题只在并行时才现形 —— 单 agent 跑得好好的,五个一起上的第一天就炸。

六个要素:前两个让它转,后四个防它闯祸

搭完之后对着这张表检查一遍:

要素 问自己
发现来源 它定时去读什么?(CI / issue / 提交 / 收件箱)
调度 什么东西触发它?不依赖你记得按启动
状态文件 哪个磁盘文件存跨轮记忆?
评估器 有没有一个能说「不行」的独立检查?
隔离 每个并行 agent 有自己的 worktree 吗?
人工检查点 哪一步会停下来等你看,而不是一路自动到底?
预算上限 设了花费天花板吗?它跑飞了谁来停?

前两个决定循环能不能转,后面几个决定它转起来之后会不会闯祸。

而新手最常见的做法是只装前两个就上线 —— 因为那两个能产出看得见的结果。结果是一个没人看着、没人能停、还一直对自己点头的循环。

边界与代价

第一个循环宁可太小。 小到「就检查一件事」都行 —— 但那个能说「不行」的检查和人工检查点,一开始就要装齐。先小后大可以,先没有检查后补很难,因为那时候你已经习惯了它一路绿灯。

skill 有维护成本。 把发现逻辑写成文件,意味着它会过期 —— 项目结构变了、CI 换了,那个文件不会自己更新。它比塞在 cron 里的提示词好,但不是免维护。

worktree 也不是万能的。 它成立的前提是任务能被切成互不重叠的文件级改动。需要细粒度协商的任务,文件级隔离就不够了。

我自己没跑过完整的循环。 我那套东西有 harness、有状态文件、有恢复,但没有定时器 —— 每次还是我去按启动。按这个清单,我装的是「状态文件 + 隔离 + 预算上限」,缺的恰恰是调度能说不行的评估器。这两格一个让它成为循环,一个让它不闯祸。

下一篇

循环搭起来了,现在它会在你睡觉的时候跑。

最后一篇讲怎么让它安全地跑:错误怎么在轮次之间复利、读进来的材料里藏着指令怎么办、预算和沙箱该怎么设,以及往下走还有什么。