循环工程:别再给智能体写提示词,去设计驱动它们的循环

循环工程(Loop Engineering)是指不再亲自给智能体写提示词,而是去设计那个替你写提示词的系统。它由五块积木加一份外部记忆组成,Claude Code 和 Codex 如今都已凑齐这五块。本文逐块讲清自动化、worktree、技能、插件与连接器、子智能体各自的作用,一个真实循环长什么样,以及循环替代不了你的那三件事。

阅读时长: 11 分钟
共 5484字
作者: eimoon.com

循环工程,就是把"那个给智能体写提示词的人"——也就是你自己——替换掉。你转而去设计那个替你写提示词的系统。 这里说的「循环」可以理解成一个递归的目标:你定义一个目的,AI 就一直迭代,直到完成。它大致由五块积木构成,而 Claude Code 和 Codex 现在都把这五块凑齐了。

我相信这可能就是我们和编程智能体协作方式的未来。不过现在还很早期,我自己也持怀疑态度,而且你绝对得当心 token 成本(取决于你 token 是富还是穷,用量差异可以大得离谱)。你也仍然需要某种手段保证质量别掉下去,关于"流水线产出垃圾(slop)“的担忧是站得住脚的。话虽如此,咱们还是来聊聊这到底是怎么回事。

@steipete 最近说:“你不该再给编程智能体写提示词了,你该去设计那些替你给智能体写提示词的循环。” 类似地,Anthropic 那边主管 Claude Code 的 @bcherny 也说:“我已经不再给 Claude 写提示词了。我让一堆循环跑着,由它们去给 Claude 写提示词、去想清楚该干什么。我的工作是写循环。”

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

过去差不多两年里,你想从编程智能体那儿拿到点东西,做法是写一段好提示词、给够上下文。你打一段字,读读返回的内容,再打下一段。智能体是个工具,而你全程都得握着它,一轮接一轮。这种模式如今某种程度上结束了——至少有些人认为它快结束了。

现在你要搭一个小系统:它去活儿、把活儿出去、检查结果、记下已完成的部分,然后决定下一件事——你让这个系统去戳智能体,而不是你亲自戳。我之前写过它的近亲,叫"智能体框架工程(agent harness engineering)",那讲的是单个智能体运行所在的那个环境,以及"工厂模型”——也就是真正构建软件的那套系统。循环工程则坐在框架的上面一层:它就是那个框架,但它跑在定时器上,它会派生出小帮手,它自己喂自己。

让我意外的是,这件事如今已经基本不再是"工具"的事了。一年前你想要一个循环,得写一大坨 bash,永远自己维护那坨东西,它是你的、也只是你一个人的。现在这些零件直接随产品出厂了。Steinberger 列的那张清单几乎严丝合缝地对应到 Codex 应用上,又几乎一模一样地对应到 Claude Code 上。一旦你注意到形状是同一个,你就不再争论该用哪个工具了——你只管设计一个不管坐在哪个工具里都还能跑的循环。

五块积木,外加一处备忘

一个循环需要五样东西,再加一个用来记事的地方。我先把它们列出来,再逐一对应。

  1. 自动化(Automations):按计划自己触发,自己做发现和分诊(triage)。
  2. Worktree:让两个并行干活的智能体不会互相踩脚。
  3. 技能(Skills):把项目知识写下来,否则智能体只能瞎猜。
  4. 插件与连接器(Plugins / Connectors):把智能体接进你本来就在用的工具。
  5. 子智能体(Sub-agents):让其中一个出主意,另一个去检查。

然后是第六样,记忆。一个 markdown 文件,或者一块 Linear 看板,任何活在"单次对话之外"、保存着"已完成什么、接下来做什么"的东西。听起来蠢得不像能管用。但这正是每个长时间运行的智能体都依赖的同一个把戏,我在写"长时运行智能体(long-running agents)“那篇里展开讲过:模型在两次运行之间会把什么都忘光,所以记忆必须落在磁盘上,而不是待在上下文里。智能体会忘,仓库不会。

两个产品现在都凑齐了这五样。

名字这儿那儿略有不同,但能力是同一回事。让我一个一个过,因为说实话,细节才是一个循环"能撑住"还是"悄悄到处漏水"的分水岭。

自动化:这是循环的心跳

自动化是让循环成为一个真正的循环、而不只是你跑过一次的某次运行的东西。在 Codex 应用里,你在 Automations 标签页里建一个,挑好项目、要跑的提示词、跑的频率,以及它是跑在你本地的检出上还是某个后台 worktree 上。找到问题的那些运行会进一个 Triage 收件箱,什么都没找到的运行就自己归档,挺省心。OpenAI 内部就拿它干些无聊活儿:每天的 issue 分诊、汇总 CI 失败、写提交简报、揪出上周某人埋下的 bug。而且一个自动化可以调用一个技能,这样你那件重复的事就好维护——你触发 $skill-name,而不是把一大墙指令糊进一个永远没人会去更新的定时任务里。

Claude Code 走到同一个地方,但路径是"调度 + 钩子(hooks)"。你可以用 /loop 按间隔重复跑一段提示词或命令,可以排一个 cron 任务,可以用钩子在智能体生命周期的某些时点触发 shell 命令,或者把整件事推到 GitHub Actions 上,让它在你合上笔记本之后还接着跑。思路一模一样:你定义一个自主任务,给它一个节奏,然后结果自己送上门,省得你到处去查。

还有个值得知道的"会话内原语”,它离这整篇文章想说的事最近。/loop 是按节奏重复跑。/goal 则是一直跑到你写的某个条件真的为真,而且每一轮之后会有一个独立的小模型来判断你是否完成了——这样写代码的那个智能体就不是给自己打分的那个。你给它类似"test/auth 下所有测试通过且 lint 干净"这样的目标,然后走人。Codex 有同样的东西,也叫 /goal,它跨多轮一直干,直到一个可验证的停止条件成立,还支持暂停、恢复和清空。同一个原语,两个工具都有——这差不多就是整篇文章的套路。

所以这部分是把"活儿"浮出水面的环节。循环剩下的部分,是去处理它。

Worktree:别让"并行"变成"混乱"

你一旦同时跑超过一个智能体,文件就开始打架,这会成为失败点。两个智能体写同一个文件,跟两个工程师都往同几行提交、事先谁也没打招呼,是一模一样的头疼。一个 git worktree 能解决它:它是一个独立的工作目录,跑在自己的分支上,共享同一份仓库历史,所以一个智能体的改动根本碰不到另一个智能体的检出。

Codex 把 worktree 支持直接内建进去,于是好几个线程同时怼同一个仓库也不会撞车。Claude Code 用 git worktree 给你同样的隔离:一个 --worktree 标志能在独立检出里开一个会话,还有一个挂在子智能体上的 isolation: worktree 设置,让每个小帮手拿到一份干净的检出、用完自己清理掉。我在"编排税(the orchestration tax)“里写过这一切里属于人的那一面:worktree 拿掉了机械层面的碰撞,但仍然是天花板——你能真正跑几个,取决于你的评审带宽,而不是工具。

技能:别每一次都把项目从头讲一遍

技能(skill)是让你不必每个会话都像金鱼一样重新解释同一套项目上下文的办法。两个工具用同一种格式:一个文件夹,里面放一个 SKILL.md 装着指令和元数据,然后可选地配脚本、参考资料、素材。Codex 在你用 $/skills 调它时运行一个技能,或者当你的任务匹配上技能描述时它自己触发——这正是为什么一段又紧又"无聊"的描述比一段聪明的更好用。Claude Code 做法相同,我把这套模式写在"智能体技能(agent skills)“里了。

技能也是让"意图"不再反复向你收费的地方。我在"意图债(intent debt)“里论证过:智能体每个会话都是冷启动的,你意图里的任何窟窿,它都会用一个自信的猜测填上。一个技能就是把那份意图写在外面——那些约定、构建步骤、“我们不这么干是因为出过那一次事故”——只写一次,然后智能体每次运行都去读它。没有技能,循环每一圈都从零把你整个项目重新推导一遍;有了技能,它就有点像在复利累积了。

有一点要理清:技能是创作格式,插件是分发方式。当你想把一个技能跨仓库共享、或把几个打包到一起时,你就把它们封成一个插件。Codex 如此,Claude Code 也如此。

插件与连接器:让循环碰到你真实的工具

一个只能看见文件系统的循环,是个很小的循环。连接器(connectors,建立在 MCP 之上)让智能体能读你的 issue 跟踪器、查数据库、打你的预发(staging)API、往 Slack 里丢条消息。Codex 和 Claude Code 都讲 MCP,所以你给其中一个写的连接器,通常拿到另一个上就直接能用。而插件把连接器和技能打包在一起,于是你的队友一步就能装上你的整套配置,而不用凭记忆把整套东西重搭一遍。

这就是"一个会说『这是修复方案』的智能体"和"一个会自己开 PR、关联 Linear 工单、等 CI 变绿后往频道里发消息的循环"之间的差别。连接器正是循环之所以能在你真实环境里动手、而不只是告诉你"它要是能干的话会怎么干"的原因。

子智能体:让"造的人"离"检的人"远点

循环里在结构上最有用的一件事,没有之一,就是把"写的那个"和"检查的那个"分开。写出这段代码的模型,给自己批改作业时实在太宽容了。一个带着不同指令、有时还是不同模型的第二个智能体,能逮住第一个智能体把自己说服了的那些东西。

Codex 只在你要求时才派生子智能体,让它们同时跑,然后把结果叠回成一个答案。你把自己的智能体定义成 .codex/agents/ 里的 TOML 文件,每个有名字、描述、指令,以及可选的模型和推理努力——这样你的安全审查员可以是一个开高努力的强模型,而你的探索者是个又快又只读的小东西。Claude Code 用 .claude/agents/ 里的子智能体、以及在彼此之间传递工作的"智能体团队(agent teams)“做同样的事。两边常见的分工都是:一个探索,一个实现,一个对照规格做验证。

这个观点我已经讲过两遍了,一次叫"代码智能体交响乐团(the code agent orchestra)",一次叫"对抗式代码评审(adversarial code review)"。它在循环里之所以尤其重要,是因为循环跑的时候你没在看——一个你真正信得过的验证者,是你之所以敢走人的唯一理由。子智能体确实更烧 token,因为每个都跑自己的模型和工具,所以把它们花在"第二意见值得这个钱"的地方。这其实也基本就是 Claude Code 的 /goal 底下在干的事:一个全新的模型来判断循环是否完成,而不是干活的那个——把"造与检"的分工,应用到停止条件本身上。

一个循环长什么样

把它们拼起来,一个单独的线程就变成了一个小小的控制面板。这是我反复在用的一种形状。

一个自动化每天早上在仓库上跑。它的提示词调用一个分诊技能,去读昨天的 CI 失败、打开着的 issue、最近的提交,把发现写进一个 markdown 文件或一块 Linear 看板。对每一条值得做的发现,这个线程开一个隔离的 worktree,派一个子智能体去起草修复,再派第二个子智能体对照项目技能和现有测试去评审那份草稿。

连接器让循环去开 PR、更新工单。任何循环搞不定的,落进分诊收件箱给我。那个状态文件是整件事的脊梁:它记着试过什么、过了什么、还有什么开着,于是明天早上那次运行从今天停下的地方接着干。

再看看你实际干了啥。你只设计了它一次。那些步骤你一个都没去写提示词。这就是 Steinberger 那个观点的真正落地——而且在 Codex 里还是在 Claude Code 里,它是同一个循环,因为零件就是那同一批零件。

循环仍然替你做不了的事

循环改变了工作,但它没把你从工作里删掉。而且有三个问题,随着循环变得更好,是变得更尖锐了,而不是更省事了。

验证仍然落在你头上。 一个无人看管地跑着的循环,也是一个无人看管地犯着错的循环。你之所以要把验证者子智能体和制造者分开,整个目的就是让循环说的那句"它好了"有点分量——可即便如此,“好了"是一个声称,不是一个证明。我老是重复"AI 时代的代码评审"里那句话:你的工作是交付你确认过能跑的代码。

你的理解力如果你放任不管,仍然会烂掉。 循环交付你没写过的代码越快,“实际存在的东西"和"你真正理解的东西"之间的鸿沟就越大。这就是"理解债(comprehension debt)",而一个顺滑的循环只会让它长得更快——除非你去读循环造出来的东西。

而且,是的,那个最舒服的姿势,大概率就是那个最危险的。 当循环自己跑起来,你会非常容易就懒得再有自己的看法,直接收下它给回来的任何东西。我把那个叫"认知投降(cognitive surrender)"。带着判断力去设计循环,它是解药;为了逃避思考去设计循环,它是催化剂——同一个动作,相反的结果。

把循环搭起来,但你得继续当那个工程师

我认为这是我们工作演化方向的一个预览。话虽如此,假如我不亲自评审代码、或者完全依赖自动化循环去修,我产品的质量会受损。我多半会卡进一个向下的螺旋,不停地把自己往更深的坑里挖。

所以,去把你的循环搭起来吧,但别忘了——直接给你的智能体写提示词仍然有效。一切都关乎找到那个对的平衡。

循环还会因为你是谁而导向截然不同的结果。两个人可以搭出一模一样的循环,得到完全相反的结果。一个人用它在自己深刻理解的工作上跑得更快;另一个人用它来彻底回避去理解那份工作。循环不知道这两者的区别。你知道。

这正是为什么循环设计比提示词工程更难,而不是更简单。Cherny 的观点不是工作变容易了。他的观点是,那个杠杆的支点移动了

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


关于

关注我获取更多资讯

月球基地博客公众号二维码,扫码关注获取更多 AI 与编程资讯
📢 公众号
月球基地博客作者个人微信二维码,扫码交流 AI 与编程话题
💬 个人号
使用 Hugo 构建
主题 StackJimmy 设计