去年十二月,Boris Cherny 一个月内提交了 259 个 Pull Request。每个都由 Claude 写成。他说自己全程没打开过编辑器。
他的工作不再是写代码,而是写那个写代码的东西。Peter Steinberger 用两句话概括了这个概念,这两句话已被阅读超过 800 万次:"你不应该再手动给编码 Agent 写提示了。你应该设计循环来给你的 Agent 写提示。"
这就是循环工程。你构建一个小型系统,让它自己找任务、交给 Agent、检查结果、决定下一步行动,然后在你睡觉时让它自己运行。
但就在同一个月,问题也出现了。某人的循环无人看管地运行了十一天,烧掉了 47,000 美元才被发现。所以这其实是两种技能,而几乎所有人只教了第一种:构建能产出工作的循环,以及构建能防止它失控的刹车。
一个关键问题决定了你构建的是哪种循环:它是在收敛于某个真实目标,还是只是一次昂贵的随机游走?
1. 一个循环由六个部分组成和一个核心问题
抛开各种噪音,一个可运行的循环由六部分组成。这个列表第一次看会觉得太简单。但每个部分内部的细节,才决定了循环是稳定运作,还是会在夜间悄悄流失资金。
现在你不再需要手动构建这些东西了。一年前,一个循环意味着你要自己维护一堆 shell 脚本,并且要一直盯着它们。现在这些组件已经内置在产品里了,同样的六个部分同时映射到了 OpenAI Codex 应用和 Claude Code 上。一旦你看清了这一点,工具就不再是关键争论点,循环本身才是设计的核心。
1组件 在循环中的作用 Codex Claude Code2------------- ------------------------ ------------------------- --------------------------3状态 (State) 跨运行记住信息 markdown / Linear (MCP) markdown / Routines + MCP4自动化 (Automations) 按计划运行 Automations 标签页 + Triage /loop (技能), Routines, /goal5工作树 (Worktrees) 隔离并行 Agent 每个线程一个 Worktree --worktree, isolation: worktree6技能 (Skills) 将你的意图编码成文 ~/.agents/skills/SKILL.md ~/.claude/skills/SKILL.md7连接器 (Connectors) 连接你的真实工具 MCP 服务器 (config.toml) MCP 服务器 (.mcp.json)8子 Agent (Sub-agents) 分离编写者和检查者 TOML 在 .codex/agents/ .claude/agents/ + agent teams
2. 状态是下一次运行唯一继承的东西
从底层开始讲,因为其他一切都依赖它。
模型在运行结束后会忘记一切。对话结束、上下文清空,下一次运行醒来时一无所知。聊天中的记忆随着运行而消亡。它必须存储在磁盘上。
在实践中,这通常是一个文件。仓库里的 STATUS.md,或者通过连接器访问的 Linear 项目,记录已完成、正在进行、下一步要做的事,以及循环绝对不能碰的少数几件事。
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 不能给自己打分。
1# Claude Code: 持续运行直到真正完成,而不是感觉完成2/goal test/auth 中的所有测试通过且 lint 步骤干净34# Claude Code: 一个周期性的云端任务(最小间隔 1 小时)5/schedule 每天早上 9 点进行 PR 分类67# Codex: 一个自动化提示词(在表单中设置频率)8"工作日 9 点:扫描开放的 PR,标记 CI 失败或没有审阅者的,发布到 Triage。"
把停止条件写得像一份合同。"test/auth 中的所有测试通过"是份合同。"让它变得更好"则是让循环一直跑到发薪日的方式。
4. 工作树让并行 Agent 互不干扰
一旦运行超过一个 Agent,失败模式就变了。问题不再是模型本身,而是两个 Agent 写入同一个文件。就像两个工程师在互不知情的情况下提交到同一行代码。
Git 工作树就是它们之间的屏障:每个 Agent 在自己的分支上有一个独立的工作目录,共享仓库历史,这样其中一个的修改就无法触及另一个的检出目录。
1# Claude Code: 每个 Agent 一个隔离的检出目录2claude --worktree feature-auth34# 或者在子 Agent 的 .claude/agents/<name>.md 前置元数据中:5# isolation: worktree67# Codex: 打开线程时选择 "Worktree"(每个线程一个独立的 HEAD)
有一个工具不会提的注意事项。工作树消除了冲突,但没有消除瓶颈。你仍然是天花板。无论你启动多少个 Agent,你自己的审查带宽决定了你能信任多少个。
5. 技能是你的意图,写一次,放在外部
Agent 每次运行都从零开始,并用自信的猜测来填补你意图中的任何空白。技能就是把这些意图记录下来,让模型每次都能读到,从而停止猜测。
两种工具的格式相同:一个包含 SKILL.md 的文件夹,里面存放指令和描述,以及任何需要的脚本。当你通过名称调用它,或者当你的任务匹配其描述时,它就会被触发。这正是为什么一个直白、字面的描述比一个巧妙的描述更好。
1# .claude/skills/triage/SKILL.md (Codex: ~/.agents/skills/triage/SKILL.md)2---3name: triage4description: 读取昨天的 CI 失败信息、开放的问题和最近的提交;5 将每个发现作为任务写入 STATUS.md。6---71. 提取失败的 CI 信息并按根本原因归类。82. 将每个失败与导致它的开放问题或提交相匹配。93. 为每个真实的发现写一个 STATUS.md 任务。忽略噪音。
没有技能,每次循环都要从头重新学习你的项目。有了技能,循环每天早上都会变得更精准一些。
6. 连接器让循环不仅能说,还能做
一个只能访问文件系统的循环只是个玩具。建立在共享 MCP 标准之上的连接器,让 Agent 能够读取你的问题追踪器、调用测试环境 API、查询数据库、在频道中发帖。
1# Claude Code2claude mcp add --transport http linear https://mcp.linear.app/mcp34# Codex5codex mcp add linear --url https://mcp.linear.app/mcp
这区分了"说'这是修复方案'"的 Agent 和"自动创建 Pull Request、关联工单、并报告一切正常"的循环。因为两种工具都支持 MCP,你为一个工具配置的连接器通常可以直接用于另一个工具。
7. 子 Agent 让编写者和检查者分离
在任何循环中,最高价值的操作是将编写的 Agent 和检查的 Agent 分离开来。
一个模型审查自己的工作总是能通过。第二个 Agent,使用不同的指令,理想情况下是不同类型的模型,能够发现第一个 Agent 说服自己接受的问题。
1# Codex: .codex/agents/reviewer.toml2name = "reviewer"3description = "对抗性 PR 审阅者:检查正确性、安全性、缺失的测试。"4developer_instructions = "像项目所有者一样审阅。假设作者是错的,5 直到代码差异证明其正确。"6model_reasoning_effort = "high"78# Claude Code: .claude/agents/reviewer.md 前置元数据9# name: reviewer10# description: 对抗性审阅者。在任何代码变更后使用。11# model: opus
一个负责探索,一个负责实现,一个负责对照规范验证。这正是 /goal 在底层已经做的事情:一个全新的模型来裁决工作是否完成。第二意见需要消耗 Token,因为每个 Agent 都运行自己的模型和工具,所以在犯错代价高昂的地方才使用它。
8. 一个循环的样子
把六个部分组合起来,一个简单的线程就变成了一台小型机器。
一个预定的自动化任务每天早上在仓库上运行。它调用你的 triage 技能,读取隔夜的 CI 失败信息、开放问题和最近的提交,并将每个真实发现写入 STATUS.md。对于每个值得处理的发现,循环会打开一个独立的工作树,派一个子 Agent 起草修复方案,再派另一个根据你的技能和测试来审查它。连接器会创建 PR 并更新工单。任何循环无法处理的事情都会留在你的 Triage 收件箱里。STATUS.md 记住了哪些通过了,哪些仍然开放,所以明天可以从今天停止的地方继续。
你早上醒来看到的是一份简短的交接笔记,而不是满屏的日志:
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,一个分析器和一个验证器,很有礼貌地互相请求更多工作,没有步骤限制、没有预算上限、没有停止条件。它运行了十一天。任何一个限制措施都能在第一天就终止它。
在安装动力系统之前,先装好刹车。 在安装刹车踏板之前,不要把引擎装上去。
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 美元的套餐上,能产生回报的循环是小的、有上限的,并且专注于一个枯燥的任务,而不是一个集群。
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 开始的。他们是从一个他们信任的循环开始的,并且在整个过程中都保持了工程师本色。就从构建那一个循环开始。


![成田悠辅的天才 AI 使用技巧 [珍藏版]](https://youmind.club/__ym/cms-assets/media/1784137658627_u4bwry_HNMS89bbsAAUPJI.jpg)


