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

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

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

循环工程的含义

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

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

为什么这个术语在 2026 年出现

这个名称目前正在公开确定下来。GitHub 仓库 cobusgreyling/loop-engineering 在首次出现后的两个月内获得了 9,600 个 star(截至 2026 年 7 月),并在 2026-10-27 显示约 11,600 个 star,其标语是“停止编写提示。设计循环。获得评分。”2026 年 7 月,该仓库的 README 将这种转变归纳为 6 个构建模块:调度、worktree、技能、插件和连接器、子代理,以及保存在对话之外的持久记忆。当前 README 已不再保留这份列表(检查于 2026-10-27),但仍将循环的状态保存在对话之外的文件中。

该仓库将 Anthropic Claude Code 负责人 Boris Cherny 列为其灵感来源之一。他广为报道的一句话是:

我不再为 Claude 编写提示。我让循环持续运行,由循环为 Claude 编写提示。

第二个仓库 AI-Builder-Club/skills 目前接近 1,300 个 star(截至 2026-10-27),并直接说明了两种角色:“代码库 harness”负责让仓库能够安全地供代理运行测试和执行部署;“循环工程师”负责构建工作流,使其在触发条件满足时唤醒、执行任务,并将所得信息写入共享文件,以便下一个循环读取。

这两个仓库都不是这种实践的发明者。任何运行过 nightly build、持续集成中的 linter,或能创建工单的 cron job 的人,都已经了解这种结构。新的变化在于,循环内部的工作进程现在具有非确定性,这改变了外围机制必须承担的职责。

循环的四个部分

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

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

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

触发器:唤醒代理的机制

定时器是最直接的触发方式。在 Linux 服务器上,systemd 定时器优于 cron,因为它具备日志记录功能,支持按需重试,且不会在单元仍在运行时启动第二个副本。最后这一特性消除了代理循环中最常见的重叠错误:即两个进程同时编辑同一个分支。

首先为代理创建一个专用用户。该用户是安全边界的一部分,因此它仅拥有 /srv/agent,除此之外别无他物:

sudo useradd --system --home-dir /srv/agent --shell /usr/sbin/nologin agent
sudo chown -R agent:agent /srv/agent

然后在 /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 列。如果结果为空,说明定时器未启用,因为仅执行 enable 而不执行 --now 只会将其调度到下次启动时运行。TimeoutStartSec=1800 的重要性超乎想象。Type=oneshot 服务在脚本退出前会被视为“正在启动”状态,而 systemd 默认会关闭 oneshot 单元的启动超时限制。因此,若没有这一行,等待输入的代理一旦挂起,单元将永远卡在激活状态,后续的定时器触发也会因发现服务仍在运行而不再启动新任务。加上这一行后,systemd 会在 30 分钟后终止运行并将其标记为失败。如果将单元更改为默认的 Type=simple,TimeoutStartSec 将不再覆盖运行本身,此时需使用 RuntimeMaxSec= 进行限制。使用 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 服务与定时器设置 适用于服务器上任何长期运行的任务,无论是否为代理。

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

编辑工作树的 agent 可能会丢失尚未提交的工作。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 会拒绝操作,除非添加 --force。因此,下面的门控脚本只会在该路径会被运行删除时强制移除工作树。git worktree prune 会清理目录已经消失的条目。此时,并行循环就变得安全了,因为两个目录中的两个 agent 分别位于两个分支上,不会相互覆盖文件。

边界也涉及凭据。无人值守运行的循环会持有长期有效的令牌,而每次运行都可能将令牌泄露到日志、提交或模型上下文中。将令牌权限限制为循环实际访问的单个仓库;在可行的情况下,不要将令牌放入 agent 自己的 shell 可以看到的环境中。在授予循环生产环境访问权限前,请阅读 如何避免将机密泄露给 AI agent。如需更严格的隔离,可以将整个循环放入 每次运行后都可以销毁的一次性 VM 中。你运行的工具也会在编写循环之前决定部分隔离边界,因此在决定需要自行构建多少隔离之前,值得阅读 Cowork 的托管沙箱与在自己的计算机上运行 Claude Code 的比较。

验证:让循环安全运行的门控

这一部分决定了它是循环,而不是只会执行命令的 cron 任务。agent 的输出只是提案。门控负责决定是否继续。

#!/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,变量名中的拼写错误会展开为空字符串,随后清理操作会针对错误路径执行,而不是明确报错。最后一行故意没有 --force:如果本次运行在工作树中留下未跟踪或未提交的文件,git 会拒绝删除该工作树,-e 会在推送完成后以错误结束运行,而不会静默删除任何人都尚未提交的工作。

if ! npm test 代码块体现了整个思路。使用你已经信任的检查的退出码,例如测试套件或类型检查器的退出码,来决定是推送还是删除分支。没有门控的循环会产生没人有时间审查的工作,这比不产生工作更糟。带门控的循环会生成一个分支,并且该分支已经通过了人工贡献者分支必须通过的同一标准。门控通过并不能说明 agent 为此修改了多少代码,因此最好将该检查与一条长期有效的指令配合使用,例如让 agent 采用能够正常工作的最小改动的规则,以保持差异足够小,从而降低审查成本。

选择一个能够如实失败的门控。在空差异上也能通过的测试套件会让循环认为不做任何事也是成功。测试薄弱的代码仓库会产生薄弱的循环,这也是热门代码仓库先强调“让代码库适合 agent”再强调“编写循环”的原因。如果你想知道测试套件是否真的能捕获回归,而不只是执行相关代码行,应使用变异测试进行检查;而由 agent 返回可重新运行的证据报告,而不是要求你阅读其差异,则可以将这个结果转化为你能够自行确认的证据。

预算:如何防止运行失控

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

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

热门仓库总结的模式

截至 2026-10-27,循环工程仓库列出了 8 种生产模式。与其把它们看作宣言,不如把它们看作可选清单。每日分诊。作为 GitHub Action 运行且不保留状态文件的轻量循环。监控评审评论并回复的 pull request 处理程序。自动处理失败构建的持续集成清理器。依赖项清理器。变更日志起草器。合并后的清理任务。问题分诊。

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

它们也都保留书面记录。两个仓库都将状态从对话移到仓库中的文件里:运行了什么、发现了什么、作出了什么决定。该文件就是循环的记忆,也是第二个循环能够基于第一个循环的工作继续执行,而不必重新发现已有信息的原因。它还支持事后审计代理,因为运行退出后,模型的上下文就会消失。实时协调通过独立的通道进行;一个 Claude Code 会话可以在同一台主机上将工作交给另一个会话,即使两个会话仍在运行也是如此。但这种交接不会在任一会话结束后继续存在,因此文件仍然是之后可以读取的部分。

循环为何会失败

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

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

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

无需先掌握术语即可入门

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

FAQ

循环工程与提示词工程有何不同?

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

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

不需要。systemd 定时器、每个运行任务对应的 git worktree、以测试命令结尾的 shell 脚本,以及服务商账户的支出上限,涵盖了定义中的所有要素。框架增加了调度接口、共享内存格式和多代理路由,这些在运行多个循环时很有用,但并非构建第一个循环的门槛。

什么是代码库工具链(harness)?

这是一套让代理能够在无人值守的情况下在仓库中工作的工具集合:一键式设置、非交互式且失败时会报错的测试、代码检查器(linter),以及部署或预览变更的方法。该术语源自 2026 年与循环工程同期出现的仓库实践。其实际测试标准很简单:如果新加入的人类贡献者无法通过一条命令从克隆代码到通过测试,那么代理也无法做到。

如何防止代理循环产生高额账单?

从三个方面设置上限。在上述 Type=oneshot systemd 单元中设置 TimeoutStartSec,以便在运行挂起时将其终止(对于 Type=simple 服务,等效设置为 RuntimeMaxSec)。在脚本内部限制重试次数,而不是无限循环直到成功。在 API 账户上设置硬性支出限额,这是代理无法绕过的唯一天花板。此外,记录每次运行的成本,因为成本翻倍的循环通常意味着其作用域在悄悄扩大。

哪些任务最值得优先转化为循环?

选择具备机器可读通过条件且影响范围较小的任务。修复失败的构建、更新依赖项和重新生成变更日志都符合条件,因为测试套件或差异对比(diff)可以验证结果。重构或设计等开放式工作尚不适合,因为没有可供门控检查的依据,而没有门控的循环只会产生昂贵的审查债务。

这篇文章对您有帮助吗?