跳转至

循环工程

概述

循环工程(Loop Engineering)是一种系统设计实践:由系统代替人工,自动向编程智能体发出提示,而非逐轮手动输入。运行框架工程关注的是单次智能体运行所依赖的引导机制与传感器,循环工程则处于其上一层——这是一种按计时器自动运行、自行派生辅助智能体、自我供给任务的运行框架(harness),无需人工逐步输入指令。

这一理念来自两位深度参与主流编程智能体产品的从业者。Peter Steinberger 指出:"你不应该再手动提示编程智能体,而应该设计那些能自动提示智能体的循环。"Anthropic Claude Code 负责人 Boris Cherny 也说:"我不再手动提示 Claude 了。我有运行中的循环来提示 Claude 并决定下一步行动。我的工作就是编写循环。"

在过去大约两年里,想从编程智能体中获得价值,意味着人工必须全程持续操控——写提示词、读输出、再写下一条提示词,每次只走一轮。循环工程用一套小型系统取代了这种工作模式:系统自动发现任务、交给智能体执行、检验结果、记录过程,并决定下一步动作——人工只需审查系统的产出,而非驱动每一轮操作。

值得关注的一个转变:一年前,构建一个循环还意味着要编写和维护大量自定义 bash 脚本。而在撰写本文时,循环所需的基础原语已内置于智能体产品自身(OpenAI 的 Codex 应用与 Claude Code 开放了几乎相同的能力集),因此设计问题已不再是"选哪个工具",而是"如何组合出一个无论使用哪款工具都能正常运转的循环"。

循环的六大构件

一个循环需要五种能力原语,加上一个记录状态的存储位置:

# 原语 在循环中的职责
1 自动化(Automations) 按计划自动执行发现与分类工作,无需人工在场
2 工作树(Worktrees) 隔离并行智能体,避免操作同一文件时产生冲突
3 技能(Skills) 将项目知识固化,避免智能体每次都靠猜测
4 插件 / 连接器(Plugins / connectors) 将智能体接入团队现有工具(任务追踪、API、聊天等)
5 子智能体(Sub-agents) 将提出方案的智能体与验证方案的智能体分离
6 状态 / 记忆(State / memory) 对话上下文之外的持久化存储——Markdown 文件、Linear 看板等——记录已完成内容与待处理任务

第六个构件是让其余五个构件得以持续运转的关键:模型在两次运行之间会彻底遗忘,因此记忆必须存在磁盘上,而非留在上下文中——"智能体会遗忘,代码仓库不会"。这一约束同样适用于所有长期运行的智能体设计:状态必须外部化,因为上下文窗口并非持久化存储。

原语对照:Codex 应用 vs. Claude Code

原语 在循环中的职责 Codex 应用 Claude Code
自动化 按计划执行发现与分类 Automations 标签页:选择项目、提示词、频率、运行环境;结果进入 Triage 收件箱;/goal 实现运行直至完成 计划任务与 cron、/loop/goal、hooks、GitHub Actions
工作树 隔离并行特性分支 每个线程内置工作树 git worktree--worktree 标志、子智能体的 isolation: worktree 设置
技能 固化项目知识 Agent Skills(SKILL.md),通过 $name 调用或按描述自动匹配 Agent Skills(SKILL.md),相同约定
插件 / 连接器 将智能体接入真实工具 连接器(MCP)加插件分发 MCP 服务器加插件
子智能体 构思与验证 子智能体以 TOML 格式定义于 .codex/agents/ 任务子智能体位于 .claude/agents/,支持智能体团队
状态 追踪已完成内容 Markdown 或通过连接器接入 Linear Markdown(AGENTS.md、进度文件)或通过 MCP 接入 Linear

各产品的命名略有差异,但每一行所对应的底层能力是相同的——这正是为什么针对原语形态而非特定工具 API 设计的循环,能够在工具切换后依然有效。

自动化——循环的心跳

自动化是将一次性运行变成真正意义上"循环"的关键所在。

Codex 应用:Automations 标签页允许选择项目、执行提示词、设置频率,以及选择在本地检出还是后台工作树中运行。有所发现的运行结果进入 Triage 收件箱;没有发现的运行则自动归档。OpenAI 报告在内部将自动化用于每日问题分类、汇总 CI 失败、生成提交简报,以及追踪前一周引入的缺陷。自动化可调用技能,让定期任务保持可维护性——在计划定义中执行 $skill-name,而非粘贴一大段没人会更新的指令。

Claude Code:通过调度与 hooks 实现相同效果,而非专用的自动化标签页。/loop 按固定频率重复执行提示词或命令;通过 cron 计划的任务独立运行;hooks 在智能体生命周期的特定节点触发 shell 命令;GitHub Actions 则在本地会话结束后继续保持循环运转。

/loop vs. /goal

两款产品都提供了一个会话内的第二原语,它比单纯的调度更接近循环工程的核心理念:

  • /loop 按固定频率重复执行。
  • /goal 让智能体跨轮次持续工作,直到用户设定的条件真正满足为止。每轮结束后,由一个独立的、更小的模型来检验停止条件是否成立——负责完成工作的智能体不负责对结果打分。典型目标如:"test/auth 中所有测试通过且 lint 无报错",达成后人工即可离开。Codex 的 /goal 功能上完全相同:跨轮次持续运行直至可验证的停止条件成立,并提供暂停、恢复和清除控制。

这种将"制作者/检验者"分离的模式应用于停止条件本身,与子智能体验证(见下文)采用的是相同的结构模式——正是这一机制让"循环宣告完成"的意义超越了智能体的自我评估。

工作树——并行而不混乱

一旦有多个智能体同时操作同一代码仓库,文件冲突就成为最主要的失败模式——这与两个工程师在未协调的情况下提交同一行代码时面临的问题如出一辙。git 工作树从结构上解决了这个问题:它是一个独立的工作目录,拥有自己的分支,但共享相同的仓库历史,因此一个智能体的修改在物理上无法触及另一个智能体的检出内容。

  • Codex 原生内置了工作树支持——多个线程可并发操作同一仓库而不发生冲突。
  • Claude Code 通过 git worktree--worktree 标志(在独立检出中打开会话)和 isolation: worktree 设置(为子智能体提供全新的、可自清理的检出)提供相同的隔离能力。

工作树消除了机械层面的冲突问题,但并不能提高团队可以有效并行运行的智能体数量上限——人工审查带宽仍是制约因素("编排税")。并行化智能体并不等同于并行化安全合并其产出所需的审查能力。

技能——停止重复解释项目背景

技能是避免每次会话都重新解释相同项目上下文的机制。两款产品使用相同的编写格式:一个包含 SKILL.md(含说明与元数据)的文件夹,以及可选的脚本、参考资料和资源。Codex 在收到 $name/skills 调用时执行技能,或在任务与技能描述匹配时自动触发——这正是为什么简洁、直白的描述比巧妙的描述更有效。Claude Code 遵循完全相同的模式。

技能是防止"未表达意图的代价"逐会话积累的地方。智能体每次会话都从零开始,对任何未明确表述的意图,都会用有信心的猜测来填补;而技能就是将这些意图写下来并外部化——约定、构建步骤、某种做法被规避的原因——在每次运行时被智能体读取,而不是每次从头推导。没有技能,循环每次都要从零重建整个项目上下文;有了技能,这些知识便能在各个循环周期中不断积累。

技能 vs. 插件:技能是编写格式,插件是分发机制。要跨仓库共享某个技能,或将多个技能打包在一起,就将它们封装为插件。这一区别在 Codex 和 Claude Code 中均成立。

插件与连接器——触达真实工具

只能看到文件系统的循环,是一个能力受限的循环。基于 MCP 构建的连接器,让智能体能够读取问题追踪系统、查询数据库、调用预发布 API,或向聊天频道发送消息。Codex 和 Claude Code 均支持 MCP,因此为其中一款产品构建的连接器,通常在另一款中无需修改即可使用。插件将连接器与技能捆绑在一起,让团队成员能够一键安装完整配置,而无需凭记忆重新搭建。

连接器是"智能体汇报修复方案"与"循环自动开 Pull Request、关联追踪工单、并在 CI 通过后通知团队频道"之间的本质差异。没有连接器,循环只能描述它将要做什么;有了连接器,它便能在团队的真实环境中直接行动。

子智能体——分离制作者与检验者

循环中最有价值的结构性选择,是将负责完成工作的智能体与负责检验工作的智能体分开。让模型自己给自己的输出打分,宽容度会过高;而一个拥有不同指令、有时还使用不同模型的第二智能体,能捕捉到第一个智能体自我说服而产生的失误。

  • Codex 仅在请求时才派生子智能体,并发运行后将结果合并为一个答案。子智能体以 TOML 文件形式定义于 .codex/agents/ 中,每个文件包含名称、描述、指令,以及可选的模型与推理力度覆盖——这样,安全审查子智能体可使用高推理力度的强模型,而探索子智能体则使用快速的只读模型。
  • Claude Code 通过 .claude/agents/ 中的子智能体以及在会话间传递工作的智能体团队实现相同模式。

常见的拆分方式是:一个智能体负责探索,一个负责实现,一个负责对照规格验证。这在循环中尤为重要,因为循环无人看管——运营者信任的验证者,是让循环可以放心运行的根本保障。子智能体会消耗更多 Token,因为每个子智能体都会产生自己的模型调用和工具调用,因此这种拆分只在第二意见具有可量化价值的地方值得付出,而非统一应用。/goal 的独立评分模型(见上文)正是将这一模式应用于停止条件,而非具体的交付物。

组合示例

以下是一个综合所有六个构件的典型循环:

  1. 每天早晨,一个自动化任务对代码仓库执行一次运行。
  2. 其提示词调用一个分类技能,读取前一天的 CI 失败、未解决的问题和近期提交,并将发现写入 Markdown 文件或 Linear 看板。
  3. 对于每个值得处理的发现,循环打开一个隔离的工作树,并派发一个子智能体草拟修复方案。
  4. 第二个子智能体对照项目技能与现有测试审查该草案。
  5. 连接器开 Pull Request 并更新追踪工单。
  6. 循环无法解决的问题进入人工分类收件箱。
  7. 状态文件是整个系统的脊梁:它记录了尝试过什么、哪些通过、哪些仍未解决,以便第二天早晨的运行从上次中断处继续。

运营者只需设计这套系统一次,无需对任何单个步骤逐一下发提示——这正是"设计能提示你的智能体的循环"的实际体现。由于底层原语相同,同一套循环设计可在 Codex 和 Claude Code 之间无缝迁移。

flowchart TD SCHED(["⏰ 自动化<br/>定时节奏<br/>/loop · cron · hooks · GitHub Actions"]) --> TRIAGE TRIAGE["📋 分诊技能<br/>读取 CI 失败、issue、提交"] --> STATE1[("🗂️ 状态 / 记忆<br/>markdown 文件或 Linear 看板")] STATE1 --> DECIDE{"该发现值得<br/>处理吗?"} DECIDE -->|否| ARCHIVE["自动归档<br/>(无需人工)"] DECIDE -->|是| WT["🌳 Worktree<br/>每个智能体独立检出"] WT --> MAKER["🤖 子智能体:执行者<br/>起草修复方案"] MAKER --> CHECKER["🕵️ 子智能体:检查者<br/>对照技能与测试审查"] CHECKER -->|"/goal:停止条件<br/>由独立模型验证"| PASS{"已验证?"} PASS -->|否| MAKER PASS -->|是| CONNECT["🔌 连接器 (MCP)<br/>开 PR · 更新工单 · 通知频道"] CHECKER -->|无法解决| INBOX["📥 人工分诊收件箱"] CONNECT --> STATE2[("🗂️ 状态 / 记忆<br/>记录完成 / 下一步")] INBOX --> STATE2 STATE2 -.->|明天的运行从此处继续| SCHED classDef mem fill:#fef3c7,stroke:#b45309,color:#000 classDef human fill:#fee2e2,stroke:#b91c1c,color:#000 class STATE1,STATE2 mem class INBOX human

该图直观呈现了本文的核心结构观点:人工必然出现的地方只有两处——Triage Inbox(无法自动解决的发现)和循环本身的设计者——其余每一个箭头都是系统在自我提示。状态 / 记忆存储(琥珀色)是让循环跨天持续运转的关键;没有它,每次计划运行都会从零重新发现同样的问题。

循环仍无法解决的问题

循环改变的是工作的形态,而非将人工从中移除。随着循环能力的提升,以下三个问题不是变得更容易,而是变得更加尖锐:

问题 为何依然存在
验证责任仍在运营者 无人值守的循环,同样是在无人值守地犯错。制作者/检验者的分离旨在让循环的"完成"声明更有意义,但"完成"终究只是一个声明而非证明——运营者的职责仍然是交付经过确认可以运行的代码。
理解腐化 循环交付代码的速度越快,运营者实际理解的内容与代码仓库中存在的内容之间的差距就越大——循环运行得越顺畅,这种差距就以越快的速度扩大,除非产出被切实阅读。
认知放弃 无人值守、运转良好的循环,容易让人不再对工作形成独立判断,直接接受循环返回的任何结果。以判断力来设计循环,是一种力量倍增器;以逃避思考来使用同一个循环,则是朝着同一种失败加速——动作相同,结果相反。

两个运营者可以构建结构上完全相同的循环,却得到截然相反的结果:一个用它加速处理自己深入理解的工作,另一个用它回避对工作的理解。循环本身无法区分这两种情况——只有运营者自己能做到。这正是为什么循环设计比提示词工程更难,而非更容易:工作并没有变简单,杠杆支点从单条提示词移到了生成提示词的系统,而用好这一杠杆所需的判断力并没有消失。

示例实现

Cobus Greyling 的 loop-engineering 示例仓库 提供了具体的 Claude Code 循环定义,将六大原语模型付诸实践,以开箱即用的自动化提示词呈现:

示例 循环用途
changelog-drafter 根据近期合并的提交/PR 生成变更日志草稿
ci-sweeper 扫描近期 CI 运行失败,提出修复方案或标记不稳定测试
daily-triage 每日定时扫描新增 issue 与 CI 失败,将发现写入分诊状态文件
dependency-sweeper 检查过期或存在漏洞的依赖,起草更新 PR
issue-triage 按项目约定对新增 issue 进行分类与打标签
post-merge-cleanup PR 合并后执行清理任务(清除过期分支、跟进 TODO)
pr-babysitter 监视开放中的 PR,回复审查评论,并持续重跑 CI 直至通过

每个示例都是一个自包含的提示词/技能,映射到上文所述的"自动化 + 状态"原语——尤其是 daily-triagepr-babysitter,与组合示例中"自动化运行、写入状态、无法自动解决时交人工收件箱"的模式高度吻合。它们是团队设计自己的循环时的实用起点,无需从空白文件开始构建自动化提示词。

最佳实践

挑战 / 领域 说明 解决方案 / 建议
将循环设计绑定到特定工具 构建与某款产品 API 深度耦合的定制化 bash 自动化 针对六大原语(自动化、工作树、技能、连接器、子智能体、状态)进行设计,而非针对特定产品的接口——同一结构可在 Codex 和 Claude Code 之间迁移
并行智能体产生文件冲突 两个智能体在未协调的情况下编辑同一文件 始终将并行智能体工作隔离在工作树中,每个智能体独占一个分支/检出
每轮重新推导项目上下文 由于智能体每次都在猜测约定,循环质量停滞不前 将项目知识编码为技能,让意图跨周期积累而非重置
智能体自我评判输出 循环将自身的工作认定为"完成",缺乏独立检验 引入制作者/检验者分离——对验证环节使用独立的子智能体或模型,包括停止条件本身(/goal
循环只能描述而无法行动 智能体汇报将要做什么,却无法实际执行 添加连接器(MCP),让循环能够直接开 PR、更新追踪系统、通知频道
无人值守的规模化超出审查能力 并行循环数量超过团队可审查的上限 认识到人工审查带宽(而非工具)才是安全并行的上限(编排税)
将"循环运行成功"等同于正确性证明 一旦循环报告成功,运营者便停止审查 验证仍是人工责任;循环的"完成"是声明,不是保证
快速交付的循环导致理解脱节 代码量的增长速度超过运营者的理解速度 阅读循环产出的内容;不要让交付速度超过理解速度

参见

参考资料