循环工程:构建一个在你睡觉时也能编程的 AI

@phosphenq
英语4周前 · 2026年6月20日
821K
939
132
23
2.3K

TL;DR

本指南介绍了循环工程,这是一种通过状态、自动化和安全上限来管理编程任务的自主 AI 系统构建方法。文中强调了设置刹车机制的重要性,以防止昂贵的失控进程。

去年十二月,Boris Cherny 一个月内提交了 259 个 Pull Request。每个都由 Claude 写成。他说自己全程没打开过编辑器。

他的工作不再是写代码,而是写那个写代码的东西。Peter Steinberger 用两句话概括了这个概念,这两句话已被阅读超过 800 万次:"你不应该再手动给编码 Agent 写提示了。你应该设计循环来给你的 Agent 写提示。"

这就是循环工程。你构建一个小型系统,让它自己找任务、交给 Agent、检查结果、决定下一步行动,然后在你睡觉时让它自己运行。

但就在同一个月,问题也出现了。某人的循环无人看管地运行了十一天,烧掉了 47,000 美元才被发现。所以这其实是两种技能,而几乎所有人只教了第一种:构建能产出工作的循环,以及构建能防止它失控的刹车。

一个关键问题决定了你构建的是哪种循环:它是在收敛于某个真实目标,还是只是一次昂贵的随机游走?

1. 一个循环由六个部分组成和一个核心问题

抛开各种噪音,一个可运行的循环由六部分组成。这个列表第一次看会觉得太简单。但每个部分内部的细节,才决定了循环是稳定运作,还是会在夜间悄悄流失资金。

现在你不再需要手动构建这些东西了。一年前,一个循环意味着你要自己维护一堆 shell 脚本,并且要一直盯着它们。现在这些组件已经内置在产品里了,同样的六个部分同时映射到了 OpenAI Codex 应用和 Claude Code 上。一旦你看清了这一点,工具就不再是关键争论点,循环本身才是设计的核心。

text
1组件 在循环中的作用 Codex Claude Code
2------------- ------------------------ ------------------------- --------------------------
3状态 (State) 跨运行记住信息 markdown / Linear (MCP) markdown / Routines + MCP
4自动化 (Automations) 按计划运行 Automations 标签页 + Triage /loop (技能), Routines, /goal
5工作树 (Worktrees) 隔离并行 Agent 每个线程一个 Worktree --worktree, isolation: worktree
6技能 (Skills) 将你的意图编码成文 ~/.agents/skills/SKILL.md ~/.claude/skills/SKILL.md
7连接器 (Connectors) 连接你的真实工具 MCP 服务器 (config.toml) MCP 服务器 (.mcp.json)
8子 Agent (Sub-agents) 分离编写者和检查者 TOML 在 .codex/agents/ .claude/agents/ + agent teams

2. 状态是下一次运行唯一继承的东西

从底层开始讲,因为其他一切都依赖它。

模型在运行结束后会忘记一切。对话结束、上下文清空,下一次运行醒来时一无所知。聊天中的记忆随着运行而消亡。它必须存储在磁盘上。

在实践中,这通常是一个文件。仓库里的 STATUS.md,或者通过连接器访问的 Linear 项目,记录已完成、正在进行、下一步要做的事,以及循环绝对不能碰的少数几件事。

text
1# STATUS.md (循环首先读取这个文件,最后再写入它)
2## 已完成
3- [x] auth: 迁移到 token v2,测试通过
4## 进行中
5- [ ] billing: webhook 重构 (PR #214, CI 报错)
6## 下一步
7- [ ] dashboard: test/charts 中的不稳定测试
8## 禁止操作
9- 未经人类确认,不得修改 infra/

把循环想象成一个你永远不会去盯着的夜班。评判你的不是它在凌晨三点做了什么,而是九点钟时留在你桌上的笔记。先设计好那份笔记,循环的大部分设计就自然完成了。

3. 自动化是区分"循环"和"一次性运行"的关键

一个循环只有当它能自动触发时才配得上这个名字。

在 Codex 应用中,你可以在 Automations 标签页 构建它:指定仓库、提示词和运行频率。有发现的运行结果会进入 Triage 收件箱;没有发现的则会自动归档。OpenAI 用它来处理代码库中不起眼但重要的后台任务:每日的问题分类、CI 失败摘要、捕捉上周偷偷溜进来的 bug。

Claude Code 通过几个基本功能来实现这一点,因为一些流行的介绍文章细节有误,所以值得精确说明。/loop 是一个技能,而不是内置命令,它会在你会话打开期间按频率重复运行一个提示词。循环的云端作业是 Routines,通过 /schedule 设置,最小间隔为一小时,即使合上笔记本电脑也会继续运行。没有本地的 crontab。

最值得学习的是 /goal。它会一直运行直到你设定的条件为真,并且在每次运行结束后,一个独立的、更小的模型会检查你是否真的完成了。那个写代码的 Agent 不能给自己打分。

text
1# Claude Code: 持续运行直到真正完成,而不是感觉完成
2/goal test/auth 中的所有测试通过且 lint 步骤干净
3
4# Claude Code: 一个周期性的云端任务(最小间隔 1 小时)
5/schedule 每天早上 9 点进行 PR 分类
6
7# Codex: 一个自动化提示词(在表单中设置频率)
8"工作日 9 点:扫描开放的 PR,标记 CI 失败或没有审阅者的,发布到 Triage。"

把停止条件写得像一份合同。"test/auth 中的所有测试通过"是份合同。"让它变得更好"则是让循环一直跑到发薪日的方式。

4. 工作树让并行 Agent 互不干扰

一旦运行超过一个 Agent,失败模式就变了。问题不再是模型本身,而是两个 Agent 写入同一个文件。就像两个工程师在互不知情的情况下提交到同一行代码。

Git 工作树就是它们之间的屏障:每个 Agent 在自己的分支上有一个独立的工作目录,共享仓库历史,这样其中一个的修改就无法触及另一个的检出目录。

text
1# Claude Code: 每个 Agent 一个隔离的检出目录
2claude --worktree feature-auth
3
4# 或者在子 Agent 的 .claude/agents/<name>.md 前置元数据中:
5# isolation: worktree
6
7# Codex: 打开线程时选择 "Worktree"(每个线程一个独立的 HEAD)

有一个工具不会提的注意事项。工作树消除了冲突,但没有消除瓶颈。你仍然是天花板。无论你启动多少个 Agent,你自己的审查带宽决定了你能信任多少个。

5. 技能是你的意图,写一次,放在外部

Agent 每次运行都从零开始,并用自信的猜测来填补你意图中的任何空白。技能就是把这些意图记录下来,让模型每次都能读到,从而停止猜测。

两种工具的格式相同:一个包含 SKILL.md 的文件夹,里面存放指令和描述,以及任何需要的脚本。当你通过名称调用它,或者当你的任务匹配其描述时,它就会被触发。这正是为什么一个直白、字面的描述比一个巧妙的描述更好。

text
1# .claude/skills/triage/SKILL.md (Codex: ~/.agents/skills/triage/SKILL.md)
2---
3name: triage
4description: 读取昨天的 CI 失败信息、开放的问题和最近的提交;
5 将每个发现作为任务写入 STATUS.md。
6---
71. 提取失败的 CI 信息并按根本原因归类。
82. 将每个失败与导致它的开放问题或提交相匹配。
93. 为每个真实的发现写一个 STATUS.md 任务。忽略噪音。

没有技能,每次循环都要从头重新学习你的项目。有了技能,循环每天早上都会变得更精准一些。

6. 连接器让循环不仅能说,还能做

一个只能访问文件系统的循环只是个玩具。建立在共享 MCP 标准之上的连接器,让 Agent 能够读取你的问题追踪器、调用测试环境 API、查询数据库、在频道中发帖。

text
1# Claude Code
2claude mcp add --transport http linear https://mcp.linear.app/mcp
3
4# Codex
5codex mcp add linear --url https://mcp.linear.app/mcp

这区分了"说'这是修复方案'"的 Agent 和"自动创建 Pull Request、关联工单、并报告一切正常"的循环。因为两种工具都支持 MCP,你为一个工具配置的连接器通常可以直接用于另一个工具。

7. 子 Agent 让编写者和检查者分离

在任何循环中,最高价值的操作是将编写的 Agent 和检查的 Agent 分离开来。

一个模型审查自己的工作总是能通过。第二个 Agent,使用不同的指令,理想情况下是不同类型的模型,能够发现第一个 Agent 说服自己接受的问题。

text
1# Codex: .codex/agents/reviewer.toml
2name = "reviewer"
3description = "对抗性 PR 审阅者:检查正确性、安全性、缺失的测试。"
4developer_instructions = "像项目所有者一样审阅。假设作者是错的,
5 直到代码差异证明其正确。"
6model_reasoning_effort = "high"
7
8# Claude Code: .claude/agents/reviewer.md 前置元数据
9# name: reviewer
10# description: 对抗性审阅者。在任何代码变更后使用。
11# model: opus

一个负责探索,一个负责实现,一个负责对照规范验证。这正是 /goal 在底层已经做的事情:一个全新的模型来裁决工作是否完成。第二意见需要消耗 Token,因为每个 Agent 都运行自己的模型和工具,所以在犯错代价高昂的地方才使用它。

8. 一个循环的样子

把六个部分组合起来,一个简单的线程就变成了一台小型机器。

一个预定的自动化任务每天早上在仓库上运行。它调用你的 triage 技能,读取隔夜的 CI 失败信息、开放问题和最近的提交,并将每个真实发现写入 STATUS.md。对于每个值得处理的发现,循环会打开一个独立的工作树,派一个子 Agent 起草修复方案,再派另一个根据你的技能和测试来审查它。连接器会创建 PR 并更新工单。任何循环无法处理的事情都会留在你的 Triage 收件箱里。STATUS.md 记住了哪些通过了,哪些仍然开放,所以明天可以从今天停止的地方继续。

你早上醒来看到的是一份简短的交接笔记,而不是满屏的日志:

text
1# 9:00 — 循环的隔夜交接结果(你的 Triage 收件箱)
2准备合并
3 PR #218 修复 test/charts 中的不稳定测试 CI 通过
4 PR #219 在 429 错误时重试 webhook,添加退避测试 CI 通过
5需你处理
6 auth/session.ts 有两种安全修复方式;我都没选,你来决定
7静默运行
8 7 个预定运行未发现任何问题,已自动归档

你只设计了一次。你全程没有输入任何提示词。

9. 在你离开之前,先装好刹车

这是没人教的那一半,它决定了你的循环是资产还是负债。

那笔 47,000 美元的账单,并不是某个聪明的模型失控了。而是两个 Agent,一个分析器和一个验证器,很有礼貌地互相请求更多工作,没有步骤限制、没有预算上限、没有停止条件。它运行了十一天。任何一个限制措施都能在第一天就终止它。

在安装动力系统之前,先装好刹车。 在安装刹车踏板之前,不要把引擎装上去。

text
1# 在离开之前,务必先装上这些:
2- 步骤上限: --max-turns 50 (硬性停止,无例外)
3- 预算上限: claude -p --max-budget-usd 10 (打印模式;按阶段计)
4- 影响范围: 一个工作树,一个分支,src/ 之外只读
5- 断路开关: 同一工具 + 相同参数连续运行 3 次 = 停止
6- 死亡检测: 每次运行在 STATUS.md 中写入心跳信号;循环静默时通知你

根据循环可能造成的破坏来划定其范围,而不是根据你希望它做什么:哪些仓库、哪些分支、多少美元、在强制退出前允许多少步骤。先选择影响范围,再选择任务。

并且要诚实地评估成本。Steinberger 那个一百个 Agent 的集群是真实存在的,每月运行成本大约 130 万美元。它能运行是因为 OpenAI 现在雇佣了他并承担账单。这个前沿案例是有赞助的。你的不是。 在 20 到 200 美元的套餐上,能产生回报的循环是小的、有上限的,并且专注于一个枯燥的任务,而不是一个集群。

text
1成本分布(均真实案例,均来自过去六个月)
2-----------------------------------------------------------------
330 天内 259 个 PR 一名工程师,100% 由 Claude 编写
411 天内 47,000 美元 一个失控的循环,没有上限,无人看管
5每月约 130 万美元 一个 100 Agent 的集群(账单有赞助)
6-----------------------------------------------------------------
7技术相同。区别在于刹车。

10. 循环是如何失败的

每个失败的循环都死于四种方式之一。现在了解它们的名字,以便在凌晨三点时能识别出来。

失控递归。 两个 Agent 永远地互相喂食。解决方案就是上面提到的步骤上限和预算上限,没有更聪明的办法。

静默死亡。 某个开发者的隔夜运行遇到了上下文窗口已满的问题,停止了,然后不断尝试恢复,却遇到了相同的障碍,同时表面上看起来还在运行。你的循环可能已经死了好几个小时,却仍在报告进度。 解决方案是心跳信号和每个阶段使用新的上下文,而不是一个无休止的运行。

随机游走。 没有可验证的停止条件,循环会偏离目标,而不是朝着目标前进。一个可以通过的测试套件是一个它可以达到的固定点。"看起来完成了"则不是。

理解债务。 循环提交你没有编写的代码的速度越快,你的仓库实际在做的事情和你所理解的事情之间的差距就越大。让它长时间无人阅读地运行下去,你就不再是工程师,而成了一个橡皮图章。解决方案是一个循环永远不允许跳过的、由人类阅读的门禁。

11. 构建循环。保持工程师本色。

两个人可以构建完全相同的循环,但得到相反的结果。一个人用它来加速完成他们了如指掌的工作。另一个人用它来完全停止理解工作。循环无法区分他们。但你能。

Cherny 的观点从来不是工作变容易了。而是杠杆发生了转移:从提示词到循环,从打字到判断。这是一个比写提示词更难的工作,而不是更轻松。

所以,这就是接下来的步骤,它有意设计得很小,因为现在还为时尚早,成本波动也很大。明天早上,把你仍然手动完成的最无聊的工作——分类 CI 结果、关闭陈旧的问题、追踪一个不稳定的测试——包裹在一个有上限的循环里。先装刹车。足够小,以至于你仍然会阅读它提交的每个差异。

没有一个每月提交 200 个 Pull Request 的人是从一百个 Agent 开始的。他们是从一个他们信任的循环开始的,并且在整个过程中都保持了工程师本色。就从构建那一个循环开始。

一键保存

使用 YouMind AI 深度阅读爆款文章

保存原文、追问细节、总结观点,并在一个 AI 工作空间里把爆款文章沉淀成可复用笔记。

了解 YouMind
写给创作者

把你的 Markdown 变成干净的 𝕏 文章

图片上传、表格、代码块,往 𝕏 上手动重排太痛苦。YouMind 把整篇 Markdown 一键转成干净、可直接发布的 𝕏 文章草稿。

试试 Markdown 转 𝕏

更多可拆解样本

近期爆款文章

探索更多爆款文章