循环工程(Loop Engineering)
帮助用户取代他们自己——那个不断向编程智能体发送提示的人。 最终交付物是一个小型系统,它能发现工作、将工作交给执行者、使用独立的检查者验证结果、记录已完成的事项、决定下一步做什么,然后重新运行,直到达成目标,并因合理的理由停止。
你在此技能中的工作不是一次性为用户编写好循环。而是访谈、设计合同,然后搭建支架,使用户最终得到一个可以真正运行并信任的循环。
什么是循环,什么不是
循环不是定时任务(cron job)。定时任务盲目地重复。循环能发现工作,用独立的检查者验证,持久化状态,决定下一步做什么,并因某个原因停止。如果你构建的东西不能自己停下来,那就是一个缺陷,不是循环。
先构建停止条件。 它们让用户可以放心走开。
第 0 步:判断循环是否是正确的工具
在设计任何东西之前,先用这个测试检验。只有当以下两点都满足时,循环才有价值:
- 有一个清晰的、可由机器检查的成功标准(测试通过、构建变绿、模式验证通过、评分标准返回“通过”)。
- 达到这个标准涉及繁琐的试错过程,否则用户只能自己手动一轮接一轮地尝试。
如果用户无法说明机器如何知道工作已完成,就停下来并直接告诉他们。 一个没有可验证完成条件的循环不会收敛;它会空转并浪费令牌。先帮他们找到一个可检查的代理指标,否则建议他们继续手动提示。不要为了逃避理解工作而构建循环。
好的循环候选:修复失败的 CI、分类 issue 收件箱、在可靠的测试套件上进行依赖升级、带基准测试的性能调优、寻找不稳定测试、确保文档构建始终为绿色。不好的候选:开放式的设计、任何“好”只是个人品味问题且没有代理指标的工作、一次性任务。
第 1 步:访谈用户(填写循环合同)
问这些问题。先问验证问题——它决定了循环是否可行。不要一次性问完十一个问题;分批问,并从仓库中推断你能够安全获取的信息。
- 目标。 你反复手动做的是什么工作?这个循环应该让什么变为真?
- 完成条件(先问,问得狠)。 机器如何知道它完成了,而无需人来看?给出确切的命令或检查方法。
- 触发器。 什么开始一次运行:一个计划(每 N 分钟/每晚)还是一个事件(推送、新 issue、webhook、CI 失败)?
- 发现/接收。 一次运行如何选择要处理的工作?(读取 CI 状态、查询 issue 跟踪器、读取
fix_plan.md、扫描警报) - 工作空间。 它在哪个范围内行动,哪些是严格禁止的?(一个 git 工作树或沙箱;绝不强制推送、接触密钥、更改依赖、影响生产环境)
- 上下文。 每次运行必须读取什么,以避免从零重新推导项目?(
SKILL.md/AGENTS.md、规格说明、记忆文件) - 委派。 哪个智能体负责工作(执行者),哪个独立的智能体检查它(检查者)?它们不能是同一个调用。
- 验证。 哪些门必须通过,才能认为“完成”为真?(单元测试、lint、类型检查、一个返回“通过”/“失败”并附带证据的 LLM 评分标准)
- 记忆/状态。 进度存储在哪里,以便运行在重启后可以继续?(一个 markdown 文件、issue 跟踪器、磁盘上的
state.json) - 预算。 硬性上限:最大迭代次数、最大运行时间、最大令牌数,以及如果凭证可以花钱时的美元上限。
- 交接。 它什么时候升级给人类,而不是继续推进?(模糊不清、高风险、或者同样的失败在没有新证据的情况下重复两次)
将答案记录到 templates/loop-contract.template.md 中。 如果用户无法用具体的检查方法回答 #2,回到第 0 步。
第 2 步:编写循环合同
将模板填充为用户仓库中一个真实的 loop-contract.md。这是设计的产物,循环基于它构建并据此进行评审。保持简短和具体。每个字段都应该命名一个命令、一个路径或一个数字,而不是一种感觉。
第 3 步:选择适合工具的最小形状
将合同映射到用户的智能体上。选择满足合同的最简单机制;不要在一个 /goal 就能搞定的时候去搞多智能体编排。具体细节见 reference/tool-mapping.md。
- Claude Code: 用
/goal实现已验证的停止条件,用.claude/agents/中的子智能体实现执行者/检查者的分离,用钩子或定时任务作为触发器,用claude -p ... --output-format json进行无头运行。 - Codex: 用 Automations 标签作为触发器,用
codex exec --json进行无头运行,用codex exec resume --last继续运行,用子智能体作为检查者。 - 从头开始(Greenfield): 使用 Ralph 风格的 bash 循环:
while :; do cat PROMPT.md | agent; done,每次迭代一个任务和一个fix_plan.md。当还没有代码库可以破坏时最适合;配合一个门(gate)和一个预算,以便它能够停止。见 reference/ralph.md。
第 4 步:搭建支架文件
生成具体的、可运行的工件(根据用户的栈调整名称):
- 执行者提示,其中包含不可协商的规则(见下面的法则)。
- 验证器:要么是一个 shell 门(确切的测试/lint 命令),要么是一个返回“通过”/“失败”并附带证据且可能“升级”的检查者提示。从 reference/verifier-rubric.md 开始。
- 记忆文件(
fix_plan.md或state.json),一次运行先读取它,最后写入它。 - 运行器:触发它的
while循环、cron 行、GitHub Action 或自动化脚本,包括门(“如果构建已经是绿色,则什么也不做”)和预算上限。
第 5 步:在让它运行前进行加固
在第一次无人值守运行之前,引导用户走一遍 reference/hardening-checklist.md。在扩展规模之前,始终先用严格的预算和沙箱凭证进行一次试运行。
四个诚实的停止条件
每个循环必须能够且只能因以下原因之一停止,并说明是哪一个:
- 目标达成:独立的验证者确认了完成条件。
- 预算耗尽:达到了迭代、令牌、时间或金钱的上限。
- 陷入停滞:同样的失败在没有新证据的情况下重复了两次(停止空转)。
- 需要人类介入:高风险或模糊不清,因此升级。这是一个成功状态,不是失败。
不可协商的法则
将规则 1-5 融入每个执行者的指令中。规则 6-7 不能融入执行者——它们需要工程师自己负责,因此要确保用户遵守它们。
- 执行者从不评判自己的工作。 一个独立的检查者决定“完成”。写代码的模型在批改自己作业时过于宽松。
- 绝不为了通过测试而削弱或删除测试,或缩小检查范围。 修复原因。如果测试错了,升级;不要悄悄修改它。
- 不能停止的循环是缺陷。 在第一次运行之前就连接好四个停止条件。
- 记忆存储在磁盘上,而不是上下文里。 每次循环先读取它,最后写入它。智能体会在运行之间遗忘;仓库不会。
- 只修复原因;不要扩大范围。 最小可能正确的更改。
- 验证仍然是工程师的责任。 “完成”是一个声明,不是证明。验证器是用户拥有的资产;执行者是一种随着每个模型版本发布而免费改进的大宗商品。
- 智能体集群的规模应适配用户的审查速度,而不是工具的通道数。 人类是串行瓶颈。通常,并行智能体的最佳数量是个位数且很少。
循环永远不会为你做的事
直接告诉用户,这样他们能保持正确的工作职责:
- 验证。 一个无人值守运行的循环也是一个在无人值守时犯错的循环。独立的检查者让“完成”有意义;但它不确保“完成”绝对正确。
- 理解。 循环运行得越快,理解债务增长得越快。安排时间阅读它构建的内容。
- 意图。 这项工作为什么重要,以及“好”意味着什么,必须来自人类。循环不知道你用它来加速你理解的工作,与用它来逃避理解工作之间的区别。但你知道。
构建这个循环。但要以一个打算继续做工程师的人的身份来构建,而不仅仅是一个按下“运行”按钮的人。
进一步阅读(可选)
如果用户想深入了解这些步骤背后的理论——循环解剖和 11 部分合同、/goal 对比 /loop、记忆、令牌经济学与编排税,以及风险——请将他们指向 Awesome Loop Engineering 手册:https://github.com/invincible04/awesome-loop-engineering(在线阅读:https://invincible04.github.io/awesome-loop-engineering/)。