这不是一篇概念介绍,而是一套可以直接照着做的 Loop Engineering 教程。
我们会把一句普通指令:
修复登录接口的并发问题。
逐步改造成一个真正可运行的 Loop:AI 自己读取代码、修改实现、运行测试、根据失败继续修复;验证通过后停止,连续无进展时交还给人。
最终要得到的不是“让 AI 一直跑”,而是下面这套受控闭环:
目标 → 执行 → 获取证据 → 独立验证 → 继续 / 停止 / 人工接管
▲ │
└──────── 反馈与状态 ──────┘
一、先判断任务是否适合做成 Loop
并不是所有任务都应该循环执行。开始前先问四个问题:
- 目标是否明确?
- 过程是否需要根据反馈动态调整?
- 结果是否可以被独立验证?
- 失败是否可回滚,或者能在隔离环境中执行?
适合 Loop 的任务:
- 修复 bug,直到指定测试通过;
- 补充测试,直到覆盖率达到要求;
- 批量迁移代码,并逐批运行回归测试;
- 调研多个来源,直到关键结论完成交叉验证;
- 生成结构化数据,直到 schema 校验通过;
- 反复优化页面,直到视觉、性能和可访问性检查达标。
不适合 Loop 的任务:
- 解释一段代码、改写一段文案等单轮任务;
- 完全依赖个人审美、没有验收标准的任务;
- 路径固定、普通脚本就能稳定完成的重复操作;
- 无法隔离且错误代价很高的生产操作。
一个简单判断方法是:
目标明确、路径不确定、结果可验证,适合 Loop。
路径完全确定,优先写普通脚本。
二、第一步:把需求改写成“任务契约”
普通 Prompt 往往只描述“做什么”,Loop 还必须明确“怎样算完成”和“什么时候必须停”。
不要这样写:
修复登录接口的并发问题,修好为止。
改成下面这种任务契约:
目标:
修复登录接口在并发刷新令牌时偶发创建两个有效会话的问题。
允许范围:
- 可以修改 src/auth/ 和 tests/auth/。
- 可以运行测试、类型检查和 lint。
- 可以创建临时文件,但结束前必须清理。
禁止范围:
- 不修改公开 API 的请求和响应结构。
- 不修改数据库表结构。
- 不连接生产环境。
- 不提交代码、不推送远程仓库。
完成标准:
1. 新增一个能够稳定复现该问题的并发测试。
2. 修复前该测试失败,修复后通过。
3. auth 模块现有测试全部通过。
4. 类型检查和 lint 通过。
5. 最终 diff 只包含与该问题直接相关的改动。
停止规则:
- 最多执行 8 轮。
- 连续 3 轮没有新增有效证据或测试结果改善时停止。
- 需要修改数据库结构或公开 API 时停止并询问。
- 发现疑似凭据、生产数据或高风险操作时立即停止。
任务契约是整个 Loop 的控制面。后面的 Agent、验证器和停止逻辑都围绕它运行。
可复制的任务契约模板
【目标】
要解决什么问题,最终交付什么。
【已知上下文】
现象、相关文件、错误信息、已有结论。
【允许操作】
可以读取、修改、执行和调用哪些工具。
【禁止操作】
不能触碰的目录、接口、环境和高风险动作。
【完成标准】
列出可被测试、检查或复核的客观条件。
【每轮要求】
读取状态 → 选择一个最小动作 → 执行 → 验证 → 更新状态。
【停止规则】
最大轮数、预算、无进展阈值、高风险边界、人工接管条件。
【最终输出】
修改内容、验证结果、遗留问题、证据位置。
三、第二步:为 Loop 准备外部状态
长任务不能只依赖聊天上下文。上下文会变长、被压缩,也可能把早期错误带进后续每一轮。
最小实现只需要一份状态记录:
LOOP_STATE
├── goal 当前目标
├── acceptance 完成标准
├── current_status 当前处于哪一步
├── confirmed_facts 已由工具或测试确认的事实
├── attempts 已尝试方案及结果
├── blockers 当前阻塞
├── next_action 下一轮建议动作
├── budget 已用轮数 / 最大轮数
└── last_evidence 最近一次验证证据
在代码项目中,可以把它放进任务系统、Agent 内置 todo,或者临时状态文件。重点不是文件名,而是每轮都必须遵守同一套读写顺序:
每轮开始:读取目标、完成标准、上轮证据和剩余预算
每轮结束:记录做了什么、得到什么证据、下一步是什么
推荐的状态内容:
当前轮次:3 / 8
当前假设:会话创建缺少同一 refresh token 维度的互斥控制
本轮动作:新增 20 个并发请求的回归测试
工具结果:修复前 10 次运行中有 7 次产生两个有效会话
已确认事实:问题可以在本地测试环境稳定复现
失败尝试:仅增加事务隔离级别,问题仍存在
下一步:检查会话创建前的 token 消费是否为原子操作
是否有进展:是
不要把模型的猜测写成“已确认事实”。只有测试输出、代码、日志、接口响应等外部证据才能进入 confirmed facts。
四、第三步:把执行者和验证者分开
Loop 最常见的错误,是让同一个 Agent 一边产出,一边宣布自己已经完成。
正确做法是把职责拆成 Maker 和 Checker:
┌─────────────────────────────┐
│ 任务契约 │
└──────────────┬──────────────┘
▼
┌──────────────┐ ┌──────────────┐ ┌──────────────┐
│ Maker │ ─────► │ 客观验证工具 │ ─────► │ Checker │
│ 分析与修改 │ │ 测试/lint/type│ │ 独立验收 │
└──────┬───────┘ └──────────────┘ └──────┬───────┘
▲ │
└────────── 不通过:返回证据和差距 ───────────────┘
│
通过:输出结果并停止
Maker 的职责
- 阅读目标和当前状态;
- 每轮选择一个最小、可验证的动作;
- 调用工具获取真实反馈;
- 根据反馈修改方案;
- 不自行宣布最终完成。
Checker 的职责
- 只依据任务契约和验证证据验收;
- 不因为 Maker 说“已完成”就通过;
- 明确指出未满足的标准;
- 输出
PASS、RETRY或ESCALATE。
验证优先级
验证器不一定是另一个大模型。优先级应该是:
确定性程序验证 > 结构化规则 > 独立模型评审 > Maker 自我评价
代码任务优先使用:
- 单元测试、集成测试、端到端测试;
- 类型检查;
- lint 和格式检查;
- schema 校验;
- 安全扫描;
- diff 范围检查;
- 覆盖率报告。
只有“可读性是否足够”“解释是否清晰”这类难以程序化的部分,再交给独立 Checker 模型。
可复制的 Checker 模板
你是独立验证者,不参与修改。
请只根据任务契约、当前 diff 和工具输出判断结果。
逐项检查每一条完成标准,不接受执行者的自我陈述作为证据。
输出只能是以下三种状态之一:
- PASS:所有完成标准都有充分证据。
- RETRY:仍可继续修复;列出未通过项、证据和建议验证方式。
- ESCALATE:需要越过权限边界、目标存在歧义或继续执行风险过高。
禁止为了让任务结束而降低标准。
五、第四步:设置每轮只做一个“最小可验证动作”
Loop 不是让 Agent 一口气做完全部工作。每轮动作越大,失败后越难判断是哪一步出了问题。
推荐的单轮结构:
Observe → Choose → Act → Verify → Record
观察现状 → 选择动作 → 执行 → 验证 → 记录
在登录并发问题中,合理的轮次可能是:
- 找到会话创建和 refresh token 消费路径;
- 编写稳定复现问题的并发测试;
- 运行测试,确认测试在修复前会失败;
- 修改原子性控制;
- 运行定向测试;
- 运行 auth 模块回归测试;
- 执行类型检查和 lint;
- Checker 对照任务契约审查最终 diff。
不合理的单轮动作是:
阅读全部代码、重构认证架构、修复所有问题、补齐测试并发布。
这会扩大修改范围,也会让验证结果失去定位能力。
六、第五步:配置停止条件和人工接管
一个 Loop 至少要有四类出口:
┌─► PASS:全部标准达成
│
本轮执行 ─► 验证结果 ──────┼─► RETRY:未达标但仍有进展
│
├─► ESCALATE:需要人做决策或授权
│
└─► ABORT:超出轮数、预算或安全边界
必须设置的停止条件
- 最大轮数:防止无限循环;
- 无进展阈值:连续多轮没有新证据或指标改善;
- 成本预算:限制 Token、工具调用或外部 API 成本;
- 权限边界:触碰生产环境、删除、发布、支付等动作时停止;
- 范围漂移:需要修改任务契约之外的模块时停止;
- 目标冲突:完成标准互相矛盾时停止;
- 不可验证:缺少环境、依赖或数据,无法证明结果时停止。
“无进展”不能只看 Agent 有没有输出新文字。更可靠的判断是:
- 测试失败数是否减少;
- 是否出现新的、可验证的事实;
- 是否排除了一个假设;
- 是否完成一个任务契约中的检查项;
- 是否只是重复相同工具调用和相同修改。
七、第六步:限制工具和运行环境
Loop 会放大能力,也会放大错误。运行前要先缩小它能够造成的影响。
代码任务建议使用:
代码仓库
└── 独立分支或 Git Worktree
└── Agent 可写目录
├── 允许:读取代码、修改指定模块、运行本地测试
├── 需确认:安装依赖、修改配置、访问外部服务
└── 禁止:推送主分支、生产部署、读取真实凭据
最低限度的安全配置:
- 在独立分支、Worktree、容器或沙箱中执行;
- 工具使用白名单,而不是默认开放全部权限;
- 凭据只通过受控引用使用,不写入上下文和日志;
- 删除、发送、发布、合并、部署等操作保留人工确认;
- 每次工具调用都记录参数、结果和退出状态;
- 支持中断和回滚。
如果任务不能安全地失败,就不要让它无人值守地循环。
八、在积木中启动一个 Loop
在积木中,可以直接用“启动循环”“深度任务”“持续执行”等表达触发 Loop 工作流。不要只说“持续做直到完成”,而要把前面的任务契约一起提供。
可直接复制下面这段,再替换其中内容:
启动循环完成以下任务。
目标:
修复登录接口并发刷新令牌时偶发创建两个有效会话的问题。
完成标准:
1. 新增可稳定复现问题的并发回归测试。
2. 修复前测试失败,修复后通过。
3. auth 模块全部测试通过。
4. 类型检查和 lint 通过。
5. 最终修改不超出 src/auth/ 和 tests/auth/。
循环规则:
1. 每轮开始先读取任务状态和上一轮证据。
2. 每轮只选择一个最小可验证动作。
3. 执行后必须运行对应验证,不能依据自我描述判断成功。
4. 每轮结束更新:已确认事实、失败尝试、验证结果、下一步。
5. 由独立 Checker 对照完成标准验收。
权限:
- 允许读取和修改指定目录、运行本地测试和静态检查。
- 禁止提交、推送、部署、连接生产环境或修改数据库结构。
停止规则:
- 最大 8 轮。
- 连续 3 轮没有有效进展时停止并报告阻塞。
- 需要超出权限或修改公开 API 时先询问。
- 所有标准有客观证据后才允许结束。
最终输出:
- 根因;
- 修改文件;
- 每项完成标准对应的验证证据;
- 未解决问题和风险。
启动后,人不需要每轮都告诉 Agent“继续”,但仍然应该关注三个节点:
- 第一次计划:确认它没有误解任务;
- 触及边界时:决定是否扩大权限或修改契约;
- 最终验收时:查看 Checker 的证据,而不是只看结论。
九、完整 Loop 的控制逻辑
下面的伪代码展示了一个工具无关的最小实现:
state = load_state()
for step in range(MAX_STEPS):
if budget_exceeded(state):
return abort("预算已耗尽", state)
action = maker.choose_minimal_action(
goal=state.goal,
acceptance=state.acceptance,
evidence=state.confirmed_evidence,
failed_attempts=state.failed_attempts,
allowed_tools=state.allowed_tools,
)
observation = sandbox.execute(action)
deterministic_checks = run_required_checks()
verdict = checker.verify(
acceptance=state.acceptance,
observation=observation,
checks=deterministic_checks,
diff=current_diff(),
)
state.record(action, observation, deterministic_checks, verdict)
save_state(state)
if verdict.status == "PASS":
return build_final_report(state)
if verdict.status == "ESCALATE":
return ask_human(verdict.reason, state)
if state.no_progress_rounds >= 3:
return ask_human("连续三轮无进展", state)
return abort("达到最大轮数", state)
实现时不必照抄代码,但下面几个结构不能缺:
- 循环开始前读取状态;
- 工具在受控环境中执行;
- 验证与生成分离;
- 每轮保存证据;
- 成功、升级、超限都有明确出口。
十、怎样判断 Loop 真的在工作
不要用“Agent 看起来很忙”作为判断标准。观察下面这些信号。
健康信号
- 每一轮都有新的工具证据;
- 失败范围逐步缩小;
- 已确认事实与模型假设明确分开;
- 下一步动作与上轮结果直接相关;
- 修改范围保持在任务契约内;
- Checker 能明确指出通过或不通过的依据;
- 达到停止条件时系统真的会停。
失控信号
- 反复读取同一批文件却没有新结论;
- 多轮执行相同命令并得到相同失败;
- 没有测试结果,却声称问题已经修复;
- 为绕过失败而删除测试、降低阈值或扩大范围;
- 状态中充满推测,缺少工具输出;
- 子 Agent 越开越多,但没有清晰分工;
- 已超出预算或权限,仍然继续运行。
发现失控信号后,不要简单追加一句“请认真完成”。应该中止当前循环,检查任务契约、验证器和权限设计哪里出了问题。
十一、从最小 Loop 开始,不要一上来堆多 Agent
第一次实践建议只保留四个组件:
1 个 Maker
1 组确定性检查
1 个 Checker
1 份外部状态
先让这个最小闭环稳定运行,再考虑增加:
- 定时器或事件触发;
- 多个并行 Worker;
- 专项安全审查 Agent;
- 跨任务长期记忆;
- 根据历史 Trace 自动优化 Prompt 和工具。
复杂度应该来自真实需求,而不是为了让系统看起来更“Agentic”。
十二、开始前的最终检查清单
- 任务满足“目标明确、路径不确定、结果可验证”;
- 已写出任务契约,而不只是普通 Prompt;
- 每一条完成标准都有对应证据来源;
- Maker 不负责最终判定完成;
- 优先使用测试和规则进行确定性验证;
- 每轮只执行一个最小可验证动作;
- 状态保存在聊天上下文之外;
- 设置了最大轮数、预算和无进展阈值;
- 运行环境隔离,工具遵循最小权限;
- 高风险和不可逆操作保留人工确认;
- 有明确的 PASS、RETRY、ESCALATE、ABORT 出口;
- 最终报告能把每项结论对应到真实证据。
Loop Engineering 的关键不是让 AI “永远继续”,而是把下面这句话真正落到系统里:
有证据就推进,未达标就带着反馈重试,触及边界就停下,无法可靠判断就把控制权交还给人。
当任务契约、外部状态、独立验证、权限边界和停止条件都被明确设计出来时,Agent 才从“需要人不断催促的聊天助手”,变成一个可以持续工作、可以验收、也可以安全停止的工程系统。