SSD Nodes Learn Hosting plans →
指南 Matt Connor作者: Matt Connor · 更新于 2026-08-24

什么是循环工程?定义与四个核心组成部分

循环工程不是编写一个巧妙提示词,而是设计 AI 代理反复运行的流程:触发器、边界、验证和预算。本文给出清晰定义,并解释其与提示词工程的区别。

循环工程的含义

循环工程是指设计 AI 代理运行的重复周期:由什么事件唤醒它、它可以访问什么、如何检查其输出,以及什么条件会停止它。提示词工程塑造的是发送给模型的一条消息。循环工程塑造的是一个在您休眠期间发送数千条消息的流程。工作单元从提示词转变为循环。

简而言之:您不再只是编写指令,而是开始编写控制系统。代理仍然需要高质量的指令,但指令只是循环中的一个组件。该循环按计划运行,在代码的隔离副本中执行,通过测试验证自身结果,并在预算耗尽时停止。

该术语为何在 2026 年出现

这个名称目前正在公开传播并逐渐固定下来。GitHub 仓库 cobusgreyling/loop-engineering 首次出现后不到两个月就获得了 9,600 个 star(截至 2026 年 7 月),其口号是“停止编写提示词。设计循环。获得评分。”它将这种转变归纳为 6 个构建模块:调度、worktree、技能、插件和连接器、子代理,以及保存在对话之外的持久化记忆。

其中引用了 Anthropic 的 Claude Code 负责人 Boris Cherny:

我不再为 Claude 编写提示词。我让一些循环持续运行,并由它们向 Claude 发送提示词。

另一个仓库 AI-Builder-Club/skills 拥有约 1,100 个 star(截至 2026 年 7 月),并直接定义了这两个角色:“代码库 harness”负责让代理能够安全地在代码库中运行测试和执行部署;“循环工程师”负责构建工作流,使其在触发器发生时启动、完成任务,并将所学内容写入共享文件,以便下一次循环读取。

这两个仓库都不是这种实践的发明者。运行过 nightly build、持续集成中的 linter,或能自动创建工单的 cron job 的人,都熟悉这种结构。新变化在于,循环中的工作器现在具有非确定性,因此外围机制需要承担不同的职责。

循环的四个部分

每个正常运行的循环都包含这四个部分。缺少其中任何一个部分的循环,最终都会在凌晨 3 点把您叫醒。

  • 触发器。 启动一次运行的事件:定时器、webhook、新的 pull request 或告警。
  • 边界。 代理在本次运行期间可以访问的文件、凭据和网络。
  • 验证。 通过退出码进行检查,以决定保留还是丢弃本次运行的输出。
  • 预算。 限制 token、时间和费用的上限。无论运行是否成功,达到上限后都会终止运行。

将这四项重新读成问题,就可以对任何准备让其持续运行的代理进行设计评审。

触发方式:什么会唤醒代理

定时器是最简单的触发方式。在 Linux 服务器上,systemd 定时器通常优于 cron,因为它会记录日志,可以按您的设置重试,而且不会启动仍在运行的单元的第二个实例。最后这一点可以避免代理循环中最常见的重叠问题:两个运行实例同时修改同一个分支。

/etc/systemd/system/agent-loop.service 中编写单元:

[Unit]
Description=Agent loop: triage open issues
After=network-online.target
Wants=network-online.target

[Service]
Type=oneshot
User=agent
WorkingDirectory=/srv/agent/repo
ExecStart=/srv/agent/bin/loop.sh
TimeoutStartSec=1800

然后在 /etc/systemd/system/agent-loop.timer 中编写定时器:

[Unit]
Description=Run the triage loop every 30 minutes

[Timer]
OnBootSec=5min
OnUnitActiveSec=30min
Unit=agent-loop.service

[Install]
WantedBy=timers.target
sudo systemctl daemon-reload
sudo systemctl enable --now agent-loop.timer
systemctl list-timers agent-loop.timer

systemctl list-timers 应显示一个包含未来时间的 NEXT 列,以及一个显示倒计时的 LEFT 列。结果为空表示定时器未启用,因为在没有 --now 的情况下使用 enable,只会将其安排在下一次启动时运行。TimeoutStartSec=1800 的重要性常被低估:如果代理因等待输入而挂起,它会一直使单元保持活动状态,定时器也就不会再次触发。使用 journalctl -u agent-loop.service -n 50 查看一次运行。

如果改用 cron 驱动循环,请自行添加重叠保护,因为 cron 会直接启动第二个实例:

*/30 * * * * /usr/bin/flock -n /tmp/agent-loop.lock /srv/agent/bin/loop.sh

持有锁时,flock -n 会立即以状态码 1 退出。因此,第二次运行会静默结束,不会与第一次运行发生竞争。同样的 systemd 服务和定时器配置 也适用于服务器上的任何长时间运行任务,无论是否为代理。

边界:为每次运行提供独立副本

编辑工作树的代理可能会覆盖尚未提交的工作。Git worktree 可以低成本地解决这个问题:每次运行使用自己的目录和分支,同时共享同一个对象存储。

cd /srv/agent/repo
git worktree add -b loop/triage-01 /srv/agent/work/triage-01 origin/main
git worktree list

git worktree list 为每棵工作树输出一行,其中包含路径、提交和分支。运行结束后,git worktree remove /srv/agent/work/triage-01 删除该目录,git worktree prune 清理目录已经消失的条目。此时并行循环变得安全,因为两个目录中的两个代理分别操作两个分支,不会互相覆盖。

边界也涉及凭据。无人值守运行的循环会持有长期有效的令牌,每次运行都可能将令牌泄露到日志、提交或模型上下文中。将令牌权限限制到循环实际操作的单个仓库。在可行的情况下,不要让代理自身 shell 可以看到该令牌所在的环境。向循环授予生产环境访问权限前,请阅读 如何避免向 AI 代理泄露机密。如果需要更严格的隔离,可以将整个循环放在 每次运行后都能销毁的一次性 VM 中。运行哪种工具也会在编写循环前决定部分隔离边界,因此在决定需要自行构建多少隔离措施前,建议阅读 Cowork 的托管沙箱与本机上的 Claude Code 有何区别

验证:让循环保持安全的门禁

这部分决定了循环与只会输入命令的 cron 任务之间的区别。代理的输出只是提案。门禁负责裁决。

#!/usr/bin/env bash
set -euo pipefail

repo=/srv/agent/repo
branch="loop/$(date -u +%Y%m%dT%H%M%SZ)"
tree="/srv/agent/work/$(basename "$branch")"

cd "$repo"
git fetch --quiet origin
git worktree add -b "$branch" "$tree" origin/main
cd "$tree"

# the agent's own command runs here, in non-interactive mode

if ! npm test; then
  echo "gate failed: discarding $branch" >&2
  cd "$repo"
  git worktree remove --force "$tree"
  exit 1
fi

git push origin "$branch"
cd "$repo"
git worktree remove "$tree"

set -euo pipefail 在该脚本中发挥着实际作用。没有 -e 时,失败的 git fetch 会被忽略,运行会继续处理过期的 origin/main。没有 -u 时,变量名中的拼写错误会展开为空字符串,随后清理操作会针对错误路径执行,而不是立即明确失败。

if ! npm test 代码块体现了整个思路。使用你已经信任的检查的退出码来决定是推送还是销毁该分支。这个检查可以是测试套件,也可以是类型检查器。没有门禁的循环会产生没人有时间审查的工作,这比不产生任何工作更糟。带门禁的循环会生成一个已经通过与人工贡献者分支相同标准的分支。绿色门禁无法说明代理为达到该结果修改了多少代码,因此最好将该检查与一条持续生效的指令配合使用,例如要求代理采用可行的最小变更的规则。这样可以保持差异较小,使审查成本保持在较低水平。

请选择一个能够如实失败的门禁。在空差异上也能通过的测试套件,会让循环认为不做任何修改就是成功。测试薄弱的仓库会产生薄弱的循环。因此,热门仓库会先要求“让代码库适合代理处理”,再要求“编写循环”。如果你想确认测试套件是否确实能捕获回归,而不只是执行相关代码行,应使用变异测试。让代理返回可重复运行的证据报告,而不是要求你阅读其差异的代理,可以将该结果转化为你能够自行确认的证据。

预算:如何防止运行失控

无限重试的 agent 会产生无限账单。为每个循环设置 wall-clock 时间上限,并由上面的 TimeoutStartSec 强制执行;在脚本中设置重试次数;再由 provider 账户设置支出上限。然后记录每次运行的成本,这样可以在账单出现之前发现循环是否逐渐失控。持续运行的 agent VPS 成本控制介绍账务管理,管理 agent 在不同轮次之间携带的上下文介绍如何控制单次运行成本中最重要的因素。因为如果循环每 30 分钟重新读取同一个 repository,就会每 30 分钟为此付费。

成本是循环通常优于长时间会话的原因。每次从全新状态开始、完成一个范围明确的任务后退出,可以保持上下文较小。持续打开 8 小时的会话会在历史记录中携带此前的所有错误,并在每一轮都为完整 transcript 付费。

热门仓库总结出的模式

loop-engineering 仓库列出了 7 种生产环境模式。将它们视为一份菜单,而不是一份宣言,更值得阅读。每日分诊。监控评审评论并回复的拉取请求处理器。自动处理失败构建的持续集成清理器。依赖项清理器。变更日志起草器。合并后的清理。问题分诊。

这些模式的共同点是任务范围狭窄,并且有明确的门槛。“修复失败的构建”有一个机器可以读取的通过条件。“改进代码库”没有,因此永远不会成为循环。它只会变成一个带有执行计划的混乱任务。

它们还有一个共同点:都有书面记录。这两个仓库都会将状态从对话中移出,写入仓库中的文件:运行了什么、发现了什么、作出了什么决定。该文件就是循环的记忆。这也是第二个循环可以基于第一个循环的工作继续执行,而不是重新发现已有结果的原因。它还支持事后审计 agent,因为运行结束后,模型的上下文就会消失。实时协作使用单独的通道;在两个会话仍在运行时,一个 Claude Code 会话可以在同一台主机上将工作交给另一个会话,但这次交接中的任何内容都不会在两个会话结束后保留,因此文件仍然是你之后回查的依据。

循环为何会失败

这些失败原因并不复杂,而且在不同团队中反复出现。

  • 没有闸门。 输出不断累积,却无人审核;信任随之崩溃,循环最终被关闭。
  • 发生重叠。 同一分支上同时运行两个任务,或两个 agent 在同一个工作树中运行,产生冲突,随后 agent 还要尝试解决这些冲突。
  • 静默漂移。 检查条件过于宽松,即使结果已经偏离预期,循环仍会持续通过。
  • 范围无界。 在繁忙仓库中,每次提交都会触发任务;不到一天,成本就会失控。

每种情况的修复方法都相同:缩小任务范围,明确检查条件,并记录每次运行。如果无法用一句话描述通过条件,就说明该任务还不适合自动化。

无需先掌握术语即可入门

您不需要使用框架。一台持续运行的小型 Linux 服务器、一个在应当失败时会让测试套件失败的 git 代码库、一个 systemd 定时器,以及一个包含 if 的 shell 脚本,就能组成完整的闭环。这确实是大多数人应该采用的起点,因为设计问题应通过实际运行来解决,而不是通过选择工具来解决。一个闭环稳定后,运行第二个闭环通常只需再添加一个定时器和一个 worktree。请参阅如何在 VPS 上运行编码 AI 代理了解基础设置;如果希望让代理本身运行在您控制的硬件上,请参阅当前可自行托管的 AI 代理选项

FAQ

循环工程与提示工程不同吗?

提示工程优化一条消息:措辞、示例和输出格式。循环工程优化消息周围的整个流程:启动一次运行的触发器、运行所处的沙箱、接受或拒绝输出的检查,以及结束运行的预算。循环内部仍然需要高质量的提示。提示不再是你日常调优的重点,因为门控和触发器对结果的影响更大。

构建代理循环需要使用框架吗?

不需要。systemd timer、每次运行使用一个 git worktree、以测试命令结束的 shell 脚本,以及提供商账户上的支出上限,已经涵盖定义中的所有部分。框架会增加调度接口、共享内存格式和多代理路由;运行多个循环后,这些功能会很有用。但它们不是构建第一个循环的必要条件。

什么是代码库 harness?

它是一组让代理能够在无人值守的情况下处理代码库的组件:一条命令完成的初始化、可非交互运行且能明确失败的测试、linter,以及部署或预览变更的方法。这个术语与循环工程一样,源自2026年出现的一批代码库。实际判断很简单:如果新的人工贡献者无法通过一条命令从克隆代码库开始并运行到测试全部通过,代理也无法做到。

如何防止代理循环产生高额费用?

在3个位置设置上限。为 systemd 单元设置 TimeoutStartSec,这样挂起的运行会被终止。在脚本内部限制重试次数,不要一直循环到成功为止。在 API 账户上设置硬性支出上限,因为这是代理无法通过说服方式绕过的唯一上限。然后记录每次运行的费用,因为成本翻倍的循环通常意味着其范围在不知不觉中扩大了。

哪些任务最适合首先改造成循环?

选择具有机器可读通过条件且影响范围较小的任务。修复失败的构建、更新依赖项和重新生成变更日志都符合要求,因为测试套件或差异可以证明结果。重构或设计等开放式工作暂时不适合,因为没有可供门控检查的内容;没有门控的循环,只会以高昂成本积累待审查的变更。