
Loop engineering is replacing yourself as the person who prompts the agent
过去两年,我们与 AI 编程助手的相处方式几乎一成不变:你写一句 prompt,丢进去足够的上下文,读一读它吐出来的东西,再写下一句。一来一回,你握着方向盘,agent 是你手里的工具。但最近,这个姿势正在悄悄变化——你不再是那个"按回车的人",而是那个"设计系统让它自己按回车"的人。这就是 Loop Engineering,循环工程。

两位行业老兵说了一句几乎一样的话
OpenAI 的 Peter Steinberger 近期发文:"你不应该再提示 coding agent 了,你应该设计一个循环,让它去提示你的 agent。"Anthropic Claude Code 负责人 Boris Cherny 的说法如出一辙:"我不再直接提示 Claude 了。我跑着一些循环,让它们去提示 Claude,自己决定下一步该干什么。我的工作就是写循环。"
听起来很玄,但拆开看,它描述的转变非常具体。
怎么从"人持工具"走到"系统持工具"
老范式里,你和 agent 是一对一的关系,每一次交互都占用你的注意力。新范式里,你搭一个小型系统:这个系统去发现工作、分派工作、验收工作、记录结果、决定下一步——然后由它去戳那些 agent,你只在旁边看着。
我之前写过两个相关概念:
- Agent Harness Engineering(代理脚手架工程):给单个 agent 装上适合它跑的环境。
- Factory Model(工厂模型):那个能自己造软件的系统。
Loop Engineering 站在这两者再往上一层:脚手架之上,一个按时间表跑的循环,它会孵化小帮手,然后喂给自己。
有意思的是,这已经不再是谁独有的秘密武器了。一年前,你想搭一个循环,得自己写一堆 bash 脚本,维护到天荒地老,那是你私有的宝藏。现在,这些原语直接内建在产品里了。Steinberger 列出的那五件套,几乎和 Codex app 一一对应,再往下看,又几乎和 Claude Code 一一对应。等你意识到两边的形状一样,你就会停止争论到底用哪把锤子——直接设计一个不管你坐在哪把锤子前都能跑的循环。
五个组件,加一个记忆
一个循环需要五样东西,再加一个放记忆的地方。先列清单,再做对照。
- Automations(自动调度):按时间表自动发现和分诊任务。
- Worktrees(工作树):让并行跑的 agent 不踩到对方脚上。
- Skills(技能):把项目里那些 agent 每次都靠猜的知识写死。
- Plugins and Connectors(插件与连接器):把 agent 接到你已经在用的工具上。
- Sub-agents(子代理):一个想,一个验。
第六样是记忆(State)。一个 markdown 文件、一个 Linear 看板,任何活在单次对话之外、能记下"做了什么、还差什么"的东西。看起来土得掉渣,但所有长期运行的 agent 都靠这同一招——模型每次启动都是失忆的,所以记忆必须写在硬盘上,不能塞在上下文里。Agent 会忘,仓库不会。
两件产品现在都把这五件配齐了。
| 原语 | 在循环里的职责 | Codex app | Claude Code |
|---|---|---|---|
| 自动调度 | 按时间表发现 + 分诊 | Automations 标签页:选项目、写 prompt、定节奏、选环境;结果进 Triage 收件箱;/goal 跑到完成为止 |
定时任务和 cron,/loop,/goal,hooks,GitHub Actions |
| 工作树 | 隔离并行功能 | 每个 thread 内建独立 worktree | git worktree,--worktree 标志,子代理上的 isolation: worktree |
| 技能 | 沉淀项目知识 | Agent Skills(SKILL.md),用 $name 显式调用或按描述隐式触发 |
Agent Skills(SKILL.md) |
| 插件 / 连接器 | 接外部工具 | Connectors(MCP)+ 插件分发机制 | MCP servers + 插件 |
| 子代理 | 创意 + 验证 | 在 .codex/agents/ 里用 TOML 定义的 Subagents |
.claude/agents/ 里的 Task subagents,agent teams |
| 状态 | 追踪已完成项 | 通过 connector 接 Markdown 或 Linear | Markdown(AGENTS.md、进度文件)或经由 MCP 接 Linear |

名字略有差异,但能力是同一件事。下面挨个拆开聊——细节决定一个循环是能稳稳跑起来,还是在某处悄悄漏。
自动调度:循环的心跳
没有自动调度,循环就只是你亲手跑的一次任务,谈不上循环。
在 Codex app 里,你到 Automations 标签页,新建一条:选项目、写 prompt、设频率、决定是跑在你本地 checkout 上还是后台 worktree 上。跑出东西的进 Triage 收件箱,没跑出东西的安静归档。OpenAI 自己内部也用这套机制干些无聊活——每天扫一遍 issue、做 CI 失败摘要、写 commit briefing、追查上周谁新引入的 bug。Automation 还能调用 skill,所以那些重复的活儿能一直保持可维护,你调一次 $skill-name,而不是往日程里贴一整面墙的指令,再也没人去更新它。
Claude Code 走的是调度加 hooks 这条路。/loop 让你按节奏重跑,/goal 一直跑到你写的条件真成立——每轮之后由一个独立的小模型判定"完事了没",写代码的 agent 和打分的 agent 不是同一个。给它一句"test/auth 下所有测试通过,lint 干净",你就可以走开了。Codex 也有 /goal,同样能跨多轮持续工作直到可验证的停止条件成立,支持暂停、恢复、清除。同一原语,两件工具,这其实是贯穿全文的一个反复出现的模式。
值得一提的还有两个 in-session 原语。/loop 按节奏重跑;/goal 持续工作直到你写的条件真的成立——并且每轮之后由一个独立的小模型判定"完事了没",写代码的 agent 不再同时是给自己打分的 agent。你给它一句"test/auth 下所有测试通过,lint 干净",就可以走开。Codex 的 /goal 同样跨多轮工作,支持暂停、恢复、清除。同一原语,两件工具,这其实是贯穿本文反复出现的模式。
这一层负责把工作从仓库里挖出来。后面几层负责把工作做掉。
Worktree:别让并行变成车祸现场
你一旦跑两个以上的 agent,文件就开始撞车,那才是真正的失败。两个 agent 写同一个文件,等于两个工程师在没人打招呼的情况下都改了同一行——后果完全一致。git worktree 解决了这件事:独立的 working directory,独立的分支,共享同一份仓库历史,物理上不可能互相覆盖。
Codex 把 worktree 支持内建好了,多个 thread 一起打同一个 repo 互不干扰。Claude Code 给你同等的隔离:git worktree、--worktree 标志把一个 session 开到独立 checkout 里,子代理上加一个 isolation: worktree 设置,让每个小帮手拿一个用完即弃的 checkout。我之前在 The Orchestration Tax 里讨论过这件事的人力侧——worktree 解决的是机械碰撞,但天花板还是你,你的审阅带宽决定了你实际能并行跑多少个。
Skills:别再每次重新解释项目
Skill 是让你不用像金鱼一样每次都重新解释项目背景。两件工具用同一种格式:一个文件夹,里面放 SKILL.md,写明指令和元数据,再附带可选的脚本、引用、资源。Codex 里你用 $ 或 /skills 显式调用,或者当你的任务匹配 skill 的描述时自动触发——这也是为什么一段朴素、精确的描述胜过花里胡哨的那一句。Claude Code 完全一样。
Skill 还有一个更深的价值:把"意图"从每次重复消耗里省出来。我之前在 The Intent Debt 里论证过,agent 每次开局都是冷启动,它会用一段"自信的猜测"去填你意图里所有的洞。Skill 就是把那段意图外化、写死——约定、构建步骤、"我们不这样干是因为那次事故"——写一次,agent 每次跑都去读它。没有 skill 的循环每次都从零重新推导整个项目;有了 skill,它在某种意义上开始复利。

别把 skill 和 plugin 混了:skill 是创作格式,plugin 是打包发布方式。你想把 skill 跨仓库共享,或者把几个打包一起,就装成 plugin。Codex 是这样,Claude Code 也是。
插件与连接器:让循环触达你的真实工具
一个只能看文件系统的循环,是个很小的循环。Connector(基于 MCP)让 agent 能读你的 issue 追踪、查数据库、调 staging API、在 Slack 里发消息。Codex 和 Claude Code 都讲 MCP,所以你给一边写的 connector,另一边通常直接能用。Plugin 把 connector 和 skill 打包在一起,队友装一下就完整复刻你的配置,不用自己从头重建。
这就是"agent 说一句'修好了'"和"循环自己开了 PR、关联了 Linear ticket、CI 一绿就在频道里 ping 一声"的差别。Connector 是循环能在你真实环境里动手,而不是只能告诉你"如果能的话我会怎么做"的原因。
子代理:把写代码的和验收的分开
一个循环里最有结构性价值的一件事,是把"作者"和"审稿人"拆开。写代码的那个模型在给自己批改作业时,评分永远偏松。第二个 agent——指令不同、模型不同——能抓住第一个给自己讲通的那些东西。
Codex 只在你要的时候生成子代理,并行跑,然后把结果折回同一个回答。你可以在 .codex/agents/ 里写自己的 TOML 定义:名字、描述、指令、可选的模型和推理 effort——所以你的安全评审员可以是一个高 effort 的强模型,而你的探路者就是一个快、只读的小模型。Claude Code 在 .claude/agents/ 里做同样的事,还用 agent teams 在不同 agent 之间交接任务。常见切法:一个探索,一个实现,一个对照规格验证。
这件事我已经在两个地方讲过——The Code Agent Orchestra 和 Adversarial Code Review。它在一个 loop 里特别重要,是因为 loop 在你不在的时候跑——你唯一能放心走开的理由,是你信得过的验证者在那里盯着。子代理会烧更多 token,因为每个都自己跑模型和工具调用,所以把它们花在一个"第二意见"真正值回票价的地方。这也是 Claude Code 的 /goal 底层在干的事:一个全新的模型判断循环是否结束,而不是那个做了工作的模型自己判断——把作者和审稿人的拆分,应用到了停止条件本身上。
一个完整的循环长什么样
把这些拼起来,一条 thread 就变成了一个小型控制面板。下面是我反复在用的一个形状。
每天早上,一个 automation 在仓库上跑起来。它的 prompt 调一个 triage skill,读昨天的 CI 失败、open issues、最近的 commits,把发现写进一个 markdown 文件或 Linear 看板。对每一条值得做的发现,thread 拉起一个独立 worktree,派一个子代理起草修复方案,再派第二个子代理对照项目 skill 和已有测试做评审。
Connector 让循环自己开 PR、更新 ticket。循环处理不了的,落进 triage 收件箱,等我看一眼。State 文件是整条骨架——它记得试过什么、通过了什么、还敞着口的是什么——所以明早的运行可以从今天停下的地方接上。

回头看你到底做了什么?你只设计了一次。你没提示过上面任何一步。Steinberger 那句话在这一刻变成了现实。同一个循环,放在 Codex 里能跑,放在 Claude Code 里也能跑,因为底下的零件是同一组零件。
循环解决不了的三件事
循环改变了工作的形状,没有把你从工作里删除掉。循环越强,下面三个问题反而越尖锐。
验证仍然在你身上。 一个无人值守的循环,也是一个无人值守地犯错的循环。你把验证子代理和作者分开,正是为了让循环说"做完了"这三个字真的有点分量——即便如此,"做完了"是一个声明,不是证明。我反复引用的那句话来自 Code Review in the Age of AI:你的工作是交付你确认能跑的代码。
理解会继续腐烂,如果你允许的话。 循环越快地产出你没写的代码,"存在"和"你真正理解"之间的鸿沟就越大。这就是 Comprehension Debt。一个顺滑的循环只会让这道沟长得更快,除非你回头读一读循环造出来的东西。
舒服的姿态恰好就是危险的姿态。 当循环自己跑起来,你很容易停止持有观点,照单全收它吐出来的东西。我把这种现象叫做 Cognitive Surrender。带着判断力去设计循环,是解药;为了逃避思考去设计循环,是催化剂。同一动作,相反的结果。
搭循环,但留在工程师的位置上
如果我不再亲自评审代码,或者完全依赖自动循环去修代码,我产品的质量一定会变差。我大概率会陷入一个向下的螺旋,越挖越深。
话虽如此,去搭你的循环吧,但别忘了直接提示你的 agent 也是有效的。一切在于找到合适的平衡点。
搭同一个循环的两个人,可能拿到完全相反的结果。一个人用它在自己深入理解的领域里跑得更快;另一个人用它来彻底逃避理解。循环分不出这两种人,你分得出。
这正是 loop design 比 prompt engineering 更难的地方,而不是更容易的地方。Cherny 那句话的重点不是工作变容易了,而是杠杆点挪了位置。

搭你的循环。但要像一个打算继续当工程师的人那样去搭,而不只是那个按"开始"的人。