跳转至

循环工程(Loop Engineering)

循环工程(Loop Engineering)正在取代你作为"给智能体下 Prompt(提示词)的人"这个角色。你转而设计一套系统来替你做这件事。这里的"循环"可以理解为一个递归的目标:你定义一个目的,AI 不断迭代,直到完成。我认为这可能就是我们使用编码智能体(coding agent)工作的未来形态。不过现在还为时尚早,我对此持怀疑态度,而且你绝对_必须_对 Token(词元)成本保持小心(如果你富裕或拮据,使用模式可能会天差地别),所以我想把它到底是什么、意味着什么讲清楚。

Peter Steinberger 最近说:"你不应该再给编码智能体下 Prompt 了。你应该设计一些循环,让循环去给智能体下 Prompt。"类似地,Anthropic 旗下 Claude Code 的负责人 Boris Cherny说:"我不再给 Claude 下 Prompt 了。我让一些循环持续运行,由它们去给 Claude 下 Prompt,并想清楚该做什么。我的工作是写循环。"

那么,这些到底是什么意思?

大约两年来,你从编码智能体那里得到产出的方式,是写一个好 Prompt,并提供足够的上下文。你输入一句话,阅读返回的结果,再输入下一句。智能体是个工具,而全程都是你在掌控,一轮接着一轮。那个阶段可以说已经结束了,或者至少有人认为它即将结束。

现在你构建一个小系统,由它来发现任务、分派任务、检查结果、记录完成情况,然后决定下一步做什么,而你让这套系统去驱动智能体,而不是你亲自上。

我之前写过它的相近概念——智能体 harness 工程(agent harness engineering),也就是打造单个智能体运行其中的环境;以及工厂模型(factory model)——也就是构建软件的系统。循环工程比 harness 高一层。harness 加上定时运行,它会派生出小帮手,并自我喂养。

让我意外的是,这已经不再真的是"工具"层面的事。一年前,如果你想搭一个循环,得写一堆 bash 脚本,并永远维护那堆脚本,它是你的,且仅属于你。现在这些部件直接随产品发布。Steinberger 列出的清单几乎完全对应 Codex 应用,然后几乎同样对应 Claude Code。一旦你注意到形态是相同的,就不再争论用哪个工具,你只需设计一个无论身处哪个工具都能运作的循环。

五样组成部分,外加若干说明

一个循环需要五样东西,外加一个用来记忆的地方。我先列出来,再逐一对照。

  1. 自动化(Automations):按日程触发,自行完成发现与分诊。
  2. Worktree:让两个智能体并行工作时不互相踩踏。
  3. Skill:把智能体原本会靠猜的项目知识写下来。
  4. 插件与连接器:把智能体接入你已经在用的工具。
  5. 子智能体:让其中一个出主意,另一个来检验。

然后是第六样——记忆。一个 Markdown 文件,或一块 Linear 看板,任何存在于单轮对话之外、记录已完成与待办事项的东西。听起来太简单,不值一提。但这是每个长时运行智能体都依赖的同一招,我在长时运行智能体(long-running agents)里写过:模型在每轮运行之间都会遗忘一切,所以记忆必须落在磁盘上,而不是上下文里。智能体会忘,仓库不会。

两款产品现在都具备这五样。

原语 在循环中的职责 Codex 应用 Claude Code
自动化(Automations) 按日程进行发现与分诊 自动化(Automations)标签页:选择项目、Prompt、频率、环境;结果进入分诊收件箱;用 /goal 持续运行直到完成 定时任务与 cron、/loop、/goal、hooks、GitHub Actions
Worktree 隔离并行功能 每个线程内置 worktree git worktree、--worktree、子智能体上设置 isolation: worktree
Skill 固化项目知识 智能体 Skill(Agent Skills)(SKILL.md),通过 $name 或隐式调用 智能体 Skill(Agent Skills)(SKILL.md)
插件 / 连接器 连接你的工具 连接器(基于 MCP(模型上下文协议))加用于分发的插件 MCP 服务器加插件
子智能体(Sub-agents) 构思并验证 子智能体(Subagents),以 TOML 定义于 .codex/agents/ .claude/agents/ 中的任务子智能体、智能体团队
状态(State) 跟踪完成情况 通过连接器使用 Markdown 或 Linear Markdown(AGENTS.md、进度文件)或通过 MCP 使用 Linear

名称各处略有不同,但能力是同一回事。我逐条讲,因为说真的,细节决定了一个循环是稳固,还是悄悄到处漏。

自动化(Automations):这是心跳

自动化(Automations)让循环成为一个真正的循环,而不只是你跑过一次的单一运行。在 Codex 应用中,你在"自动化"标签页里创建一个,选择项目、它将运行的 Prompt、运行频率,以及它是跑在你的本地检出上还是后台 worktree 上。发现问题的运行会进入分诊收件箱,而一无所获的运行会自行归档——这挺好。OpenAI 在内部把它们用于日常事务,比如每日议题分诊、汇总 CI 失败、撰写提交简报、排查上周某人引入的 bug。而且一个自动化可以调用 Skill,这样反复出现的事就可维护了:你触发 $skill-name,而不是把一大段指令粘贴进一个没人会去更新的日程里。

Claude Code 通过定时任务和 hooks 达到同样的效果。你可以用 /loop 按间隔运行一个 Prompt 或命令,可以排一个 cron 任务,可以在智能体生命周期的某些节点用 hooks 触发 shell 命令,或者如果你希望合上笔记本后仍持续运行,就把整件事推到 GitHub Actions。思路完全一致:你定义一个自主任务,给它一个节奏,结果会回到你手上,于是你不必亲自四处检查。

还有一个值得了解的会话内原语,它更接近这篇文章真正想讲的东西。/loop 按节奏重复运行。/goal 会一直运行,直到你写下的条件真正成立;每一轮之后,一个独立的小模型会检查你是否完成,所以写代码的智能体不是由它自己来打分。你给它类似"test/auth 下所有测试通过且 lint 干净"这样的条件,然后走开。Codex 也有同样的功能,也叫 /goal,它会跨轮次持续工作,直到一个可验证的停止条件满足,支持暂停、恢复和清除。同一原语,两款工具——这差不多就是整篇文章的模式。

所以这是把任务浮现出来的部分。循环的其余部分,是对它采取行动的部分。

Worktree:别让并行变成混乱

你一运行超过一个智能体,文件就开始碰撞,这就成了故障点。两个智能体写同一个文件,和两名工程师提交到同一批代码行、且事先谁都没沟通,是如出一辙的头疼事。git worktree 能解决它:它是共享同一仓库历史、位于独立分支上的独立工作目录,所以一个智能体的修改在物理上不可能碰到另一个的检出。

Codex 把 worktree 支持直接内置,于是多个线程可以同时访问同一仓库而不互相撞车。Claude Code 用 git worktree 给你同样的隔离,用 --worktree 标志在某个自己的检出中打开会话,还有一个 isolation: worktree 设置可以加在子智能体上,让每个帮手都拿到一份会自动清理的崭新检出。我关于这一切"人的一面"写在编排税(orchestration tax)里:worktree 消除了机械层面的碰撞,但你仍是天花板——你能真正跑多少个,取决于你的审查带宽,而非工具。

Skill:别再每次都解释一遍你的项目

Skill 让你不再像金鱼一样,每轮会话都重新解释一遍同样的项目上下文。两款工具用同样的格式:一个内含 SKILL.md 的文件夹,存放指令和元数据,外加可选的脚本、参考与素材。Codex 在你用 $ 或 /skills 调用时运行一个 Skill,或在你的任务匹配 Skill 描述时自动运行——这正是"平实无华的描述胜过花哨描述"的原因。Claude Code 同样如此,我把这套模式整理在智能体 Skill(agent skills)里。

Skill 也是让意图不再反复消耗你的地方。我在意图债务(intent debt)里论证过:智能体每轮会话都从零开始,它会用自信的猜测填补你意图中的任何空洞。Skill 就是把那份意图写在外面——那些约定、构建步骤、"我们之所以不这么做,是因为那次事故"——一次性写下来,智能体每次运行都去读。没有 Skill,循环每个周期都从零重新推导你的整个项目;有了 Skill,它某种程度上会复利增长。

有一点要分清:Skill 是编写格式,而插件是你分发它的方式。当你想跨仓库共享一个 Skill,或把几个打成一包时,就把它们打包成插件。在 Codex 里如此,在 Claude Code 里也如此。

插件与连接器:让循环触达你真正的工具

一个只能看见文件系统的循环,是个很小的循环。基于 MCP 构建的连接器,让智能体能读取你的议题追踪器、查询数据库、调用预发环境 API、在 Slack 里发消息。Codex 和 Claude Code 都说 MCP,所以你为其中一个写的连接器,通常放到另一个里也能直接用。而插件把连接器和 Skill 打包在一起,于是你的同事一次性装好你的配置,而不是凭记忆重建整套东西。

这就是"一个智能体说'这是修复'"和"一个循环自行打开 PR、关联 Linear 工单、并在 CI 变绿后通知频道"之间的区别。连接器正是循环能在你真实环境里行动、而不只是告诉你"如果它能做会怎么做"的原因。

子智能体:让制造者与审查者分离

循环里最有用的结构安排,远远领先其他的,是把"写的人"和"查的人"分开。写代码的那个模型,给自己的作业打分时会过分宽容。第二个带着不同指令、有时是不同模型的智能体,能抓出第一个把自己说服了的那些东西。

Codex 只在你要求时才派生子智能体,让它们同时运行,再把结果合并回一个答案。你把自己的智能体定义为 .codex/agents/ 下的 TOML 文件,每个带名称、描述、指令,以及可选的模型和推理强度——于是你的安全审查者可以是一个高强度的强模型,而你的探索者可以是个快速的只读小东西。Claude Code 在 .claude/agents/ 里用子智能体以及彼此传递工作的智能体团队做同样的事。两款工具常见的切分是:一个探索、一个实现、一个对照规格验证。

这个论点我讲过两次了,一次是代码智能体管弦乐团(code agent orchestra),一次是对抗式代码审查(adversarial code review)。它在循环内尤其重要的原因是:循环在你没盯着时运行,所以一个你真正信任的验证者,是你敢走开的唯一理由。子智能体确实更费 Token,因为每个都做自己的模型和工具工作,所以把它们花在"第二种意见值得付费"的地方。这也基本就是 Claude Code 的 /goal 在底层做的事:一个全新的模型判断循环是否完成,而不是由做工作的那个来判断——把制造者 / 审查者(Maker / Checker)的切分,应用到停止条件本身。

一个循环长什么样

把它们拼起来,一条线程就变成一个小控制台。下面是我一直在用的一种形态。

一个自动化(Automations)每天早上在仓库上运行。它的 Prompt 调用一个分诊 Skill,读取昨天的 CI 失败、开放议题、近期提交,把发现写入一个 Markdown 文件或一块 Linear 看板。对每个值得做的发现,线程打开一个隔离的 worktree,派一个子智能体去起草修复,再派第二个子智能体对照项目 Skill 和既有测试审查那份草稿。

连接器让循环打开 PR 并更新工单。循环处理不了的任何事,都落到分诊收件箱里交给我。状态文件是整个东西的脊梁,它记得试过什么、通过了什么、还开着什么,于是明天早晨的运行从今天停下的地方接上。

看看你其实在那里干了什么。你一次性把它设计好了。那些步骤你一个 Prompt 都没下。这就是 Steinberger 的整个观点变成了现实,而且同样的循环在 Codex 或 Claude Code 里都成立,因为部件是同样的部件。

循环仍然不为你做的几件事

循环改变了工作,但没有将你排除在工作流程之外。而且有三个问题随着循环变好而更尖锐,而不是更容易。

验证仍由你负责。一个无人看管的循环,也是一个会在无人看管时犯错的循环。你把验证者子智能体从制造者中分出来的整个原因,是让循环的"完成了"变得有意义;即便如此,"完成"仍是一种主张,而非证明。我一直重复AI 时代的代码审查(code review in the age of AI)里的同一句话:你的工作是发布你确认能用的代码。

如果你放任,你的理解仍会腐烂。循环越快发出你没写的代码,已存在之物与你真正理解之物之间的差距就越大。这是理解债务(comprehension debt),而顺畅的循环只会让它长得更快——除非你去读循环造出的东西。

而最舒服的姿态也是最危险的。当循环自己跑着时,人们非常容易停止保有主见,只是照单全收它返回的东西。我把那叫做认知投降(cognitive surrender)。设计循环,当你带着判断去做时是解药,当你为了逃避思考去做时是催化剂——同一动作,相反结果。

搭好循环。继续做工程师。

我认为这是我们的工作将如何演进的一个预告。话虽如此,如果我不亲自审查代码,或者完全依赖自动化循环去修复,我的产品质量就会下降。我大概会陷入恶性循环,不断把自己挖进更深的坑。

话虽如此,尽管去搭你的循环,但别忘了,直接给智能体下 Prompt(提示词)同样有效。关键在于找到恰当的平衡。

循环也会因你而不同。两个人可以搭出完全相同的循环,却得到完全相反的结果。一个用它,是在自己深有理解的工作上跑得更快。另一个用它,是为了完全避免去理解那项工作。循环分辨不出这差别。你辨得出。

这正是让循环设计比 Prompt 工程更难、而非更易的原因。Cherny 的意思不是工作变容易了。而是杠杆点移动了。

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