从 while True 到 Loop Engineering:AI Agent 的古罗马副官
Claude Code 明明已经有两层循环,为什么还不等于 Loop Engineering?沿着开源项目 Optio 走完一条任务从生成、提交 PR 到 CI 失败后再次唤醒 Agent 的完整生命周期。
TL;DR
这是我学 Loop Engineering 时最被绕晕的问题:query_loop 里已经有内外两层 while 了,那它算不算 Loop Engineering? 沿着开源项目 Optio 走一遍才看清——两层循环解决的是「一次 Agent 运行内部如何推进」, Loop Engineering 要往外再包一层,解决「多次运行之间工作如何持续推进」。 判断标准不是嵌套了几个 while,而是:那个负责发现工作、检查结果、记录进度、启动下一轮的人,有没有被系统替代。 文章拆了 Automation / Worktree / Skill / Connector / Sub-agent / State 六个组件, 以及真正让循环闭合的 Reconciler,和防止它自己失控的 CAS、Resync、预算三道护栏。
目录
之前的文章拆解了 Claude Code 收到一个任务后,内部到底发生了什么。当时是把它的核心 query_loop 拆成了两层循环:
- 内层是工具执行循环:模型发出 tool_use,Python 程序执行工具,再把 tool_result 塞回消息列表
- 外层是回合循环:模型拿到工具结果后继续思考,直到输出
stop_reason == "end_turn"
既然这里都有两层 Loop 了,那它是不是就是 Loop Engineering 呢?这是我最近学习 Loop Engineering 时最把我绕晕的问题。
- 如果它不是,为什么不呢?难道代码里的
while True还不算循环吗? - 如果它是,Automation、Worktree、Skill、Connector、Sub-agent 和 State 又是在解决什么呢?
带着这些疑问,我找到了一个开源项目 Optio,沿着一个任务从产生、执行、提交 PR,到 CI 失败后再次唤醒 Agent 的完整生命周期走了一遍,终于看清楚:
- Claude Code 里的两层循环自然是真正的 Loop,但它们解决的是:一次 Agent 运行内部如何推进
- Loop Engineering 还要再向外包一层,解决:多次 Agent 运行之间,工作如何持续推进
这不是否定 while True,而是在追问一个更外层的问题:当这次循环退出以后,下一次由谁启动?
这篇文章从 Optio 的源码出发,拆开以下四个问题:
- Claude Code 明明已经有两层循环,为什么还不等于完整的 Loop Engineering?
- Automation、Worktree、Skill、Connector、Sub-agent、State 分别解决什么问题?
- 为什么有了这六个组件,仍然不一定形成真正的 Loop?
- 一个可以长期运行的 Loop,还需要哪些工程化护栏?
补充一句题外话:Optio,是古罗马军队中协助百夫长维持队伍运转的副手。而这个项目做的也是类似的事:它不亲自写代码,而是负责叫醒 Agent、分配任务、检查结果,再决定下一轮行动。
明明已经有两层循环,为什么还不够?
先回到之前文章中的 query_loop。把那些流式事件、消息类型和容错逻辑暂时去掉,它大致可以压缩成一个很短的循环。
这个 Loop 发生在一次 Agent 运行内部:模型规划,程序执行,结果重新放回上下文,模型再判断要不要继续。这当然是循环,而且还是两层嵌套循环。内层让模型和工具来回协作,外层让 Agent 可以连续推进多个回合。它们共同回答的是:
人给 Claude Code 一个任务后,它内部如何把这个任务做完?
但问题恰恰出现在 end_turn 以后。
假设 Coding Agent 提交了 PR,然后结束运行。半小时后 CI 才失败。这时 query_loop 已经退出,原来的 Agent 进程可能也不存在了。这时谁去读取 CI 日志?谁来重新唤醒 Agent?谁告诉它只修复这次失败?如果连续失败十次,又由谁来叫停呢?
这些都不是增加一层工具调用循环能够解决的。
之前的 Claude Code 文章拆解的是里面两层,Loop Engineering 重点关注的是最外面一层。
还有一个容易混淆的地方:Claude Code 的 Runtime 外面确实有 Supporting Systems,包括权限、Hooks、Memory、Session 和 MCP。但架构上的外层,不一定等于循环上的外层。这些模块在支撑 query_loop 运行,却不一定会在 CI 失败后主动生成下一次 Agent 任务。
判断是不是 Loop Engineering,关键不是代码里嵌套了几个 while,而是看:最外层那个负责发现工作、检查结果、记录进度和启动下一轮的人,有没有被系统替代?
把传统的使用方式画出来后,这个区别就更明显了:在这里,Agent 只负责其中一段,真正的循环控制器一直是人。
所以「不要再亲自 Prompt Agent,而要设计 Prompt Agent 的 Loop」,并不是说以后不需要写 Prompt,也不是说 Agent 内部的循环不重要。它真正想替代的,是人反复复制错误、重新运行命令、追问 Agent、记录进度这些机械操作。
小结一下:Agent Loop 负责的是一次运行内部如何行动;而 Loop Engineering 负责的则是多次运行之间如何持续推进工作。
Loop Engineering 的六个组件
带着这个问题我们来到 Optio 这个项目。这里不按文件夹来读源码,而是追踪一条具体链路:
每天自动生成一个代码维护任务,Agent 在独立目录中修改代码并提交 PR;CI 失败就重新修,CI 通过后启动另一个 Agent 审查;Review 通过才允许结束。
这时,Loop Engineering 的六个组件就从抽象名词变成了六个具体的问题。它们把原来散落在人脑和手工操作里的东西,逐一搬到系统外部。
Automation:并不是「定时调用一次模型」
Optio 中的 Automation 是由几样东西配合完成:Task Config 保存「每次做什么」,Trigger 保存「什么时候做」,Trigger Worker 定期检查有没有到期任务。
源码里,workflow-trigger-worker.ts 默认每隔一段时间查询到期的 Trigger。当目标类型是 task_config 时,它调用 instantiateTask()。后者会渲染 Prompt 参数、创建一条真实 Task,把状态从 pending 变成 queued,最后放进 BullMQ 队列。
原来可能会把 Automation 理解成「每天早上八点调用一次模型」。但从这里会发现,一个可靠的 Automation 不是定时器本身,而是**「触发条件 + 任务蓝图 + 实例化 + 入队」的完整链路**。
因为闹钟只负责响,它不能直接代替一张工作单。
Worktree:给每个 Agent 一张不会串台的办公桌
任务进入队列后,Optio 不会让所有 Agent 在同一个仓库目录里修改文件。它为每个 Task 创建独立的 Git Worktree。
这一步决定了多个 Agent 能不能真正并行。如果没有 Worktree,就像让三位程序员共用一台电脑、同时编辑同一份文件。Agent 数量越多,冲突反而越快。
并行不是多开几个对话框,而是先隔离它们会修改的环境。
Skill 与 Connector:一个管「会不会」,一个管「能不能」
在 Agent 启动前,Optio 会向 Worktree 注入两类不同的信息。
第一类是 Skill:源码中的 buildSkillSetupFiles() 会把技能写成文件,告诉 Agent:这个项目怎么测试、代码规范是什么、哪些目录不能碰、出现某类问题应该按什么步骤处理。
第二类是 Connector:Optio 会根据当前仓库、Agent 类型和权限找到可用 Connection,再生成 .mcp.json。Agent 因此可以访问 GitHub、Slack、Linear、数据库等外部系统。
Skill 决定 Agent「应该怎样工作」,Connector 决定 Agent「被允许去哪里工作」。
Sub-agent:不是多叫一个模型,而是把「检查」变成独立任务
这部分是我感受最深的地方。我原来以为 Review Agent 就和普通的 Sub-agent 一样,是由主 Agent 在对话中临时喊来一个小助手。但 Optio 的 Review Agent 不是一次临时调用,而是一条真正写入数据库、可以排队、失败和重试的子任务。
这相当于把开发和验收完全交给两个人。写代码的 Agent 不能自己说一句「测试通过,完成了」,系统就当真。另一个 Agent 会拿到原始需求、PR 内容、已有评论和测试命令,独立给出审查结果。
真正让 Loop 闭合的,是那位不写代码的「副官」
有了队伍,不等于队伍会自己持续向前走。仔细看会发现,这条链路仍然可能只是一条直线:
- 如果 CI 失败,谁来决定「要不要继续」?
- 如果 Review 要求修改,谁把反馈交回 Coding Agent?
- 如果进程中途崩溃,谁知道应该从哪里恢复?
上面的组件提供的是循环所需的执行能力,而真正把首尾接起来的,是 State + Feedback + Decision。
1、Reconciler:谁来下达下一道命令
在 Optio 中,负责把这些能力连接起来的角色叫 Reconciler。也是到这里,我才突然意识到这个项目的名字很有意思:在古罗马军队中,Optio 是协助百夫长维持队伍运转的副手,它会观察队伍、传递命令,并在情况变化时及时补位。
那么是不是可以这么比喻:如果说 Coding Agent 是在前线执行任务的士兵,那么源码中的 Reconciler 就很像站在队伍后方的 Optio——它不亲自修改代码,只负责观察现场、传递命令,再决定下一步行动。
它反复做三件事。buildWorldSnapshot() 像是重新巡视现场:任务现在处于什么状态?PR 有没有合并?CI 是通过还是失败?Review 有没有要求修改?reconcileRepo() 则根据这些事实,生成下一道命令。源码中的判断很具体:
- PR 已合并:把 Task 变成 completed
- CI 第一次变为失败:重新唤醒 Coding Agent
- CI 通过且开启自动审查:创建 Review Task
- Review 要求修改:把评论重新交给 Coding Agent
- 自动恢复次数达到上限:进入 needs_attention,等待人处理
最后,executeAction() 才会真正执行唤醒 Agent、创建 Review Task、自动合并或者结束任务。
但这里还有一个问题:Reconciler 每次被唤醒时,原来的 Agent 进程可能早已退出。它怎么知道任务上一次进行到哪里了呢?
答案不是 Reconciler 自己拥有记忆,而是系统把现场写在了外部 State 中。
2、State:这位副官靠什么记住现场
Optio 把任务状态写入 Postgres,并通过状态机限制它如何变化。
这里不只保存了一个简单的完成 / 未完成:
tasks.state记录任务现在进行到哪里task_events记录任务为什么从一个状态进入另一个状态- PR、CI 和 Review 状态记录外部世界发生了什么
- Git 分支和 Worktree 保留 Agent 已经完成的代码修改
每一次 transitionTask() 也不只是修改一个字段。它还会校验状态迁移是否合法、记录事件,并唤醒下一轮 Reconcile。
3、CAS、Resync 与预算:如何防止「副官」自己失控
如果同时有两个 Worker 下达命令,或者某次唤醒消息丢了,这该怎么办呢?
顺着这个问题继续读源码,这才明白那些一开始让我觉得很繁琐的代码,几乎都在处理这个问题:如果 Loop 在无人盯着时出错怎么办?Optio 加了至少三道护栏。
第一道是 CAS:更新任务状态时,SQL 会附带「当前状态仍然等于我刚才看到的状态」这个条件。两个 Worker 同时处理同一任务时,只有一个能成功,另一个会重新读取最新事实。
第二道是 Resync:即使某次消息丢了,系统仍会周期性扫描未完成任务,再次放入 Reconcile 队列。这个很像夜班交接时重新点一遍未结工单,避免某个任务永远躺在角落里。
第三道是预算和停止条件:自动恢复不是无限的,源码会比较 recentAutoResumeCount 与 maxAutoResumes。超过上限,就不再继续烧 Token,而是把任务交回人类。
能重复运行的脚本,不等于可靠的 Loop。可靠的 Loop 必须知道何时继续、何时重试、何时恢复,以及何时承认自己做不到。
最后
再回到开篇的那个问题:Claude Code 明明已经有两层循环,为什么还需要 Loop Engineering?
现在可以这样回答:Claude Code 的 query_loop 解决了一个 Agent 被叫醒之后,如何调用模型、执行工具,再一轮轮把任务做下去;而 Optio 继续追问的是,当这次运行结束以后,谁检查结果,谁记住现场,谁决定要不要再次叫醒它。
前者让 Agent 能够行动,后者让行动可以跨越一次会话,持续地向一个目标收敛。
Agent 负责向前走,而人负责决定方向,以及哪里才是终点。
核心结论
标注「判断」「假设」的是我的看法而非事实;标注「已推翻」的保留在这里,不删除。
Agent Loop 负责的是一次运行内部如何行动,Loop Engineering 负责的是多次运行之间如何持续推进工作。判断是不是 Loop Engineering,关键不是代码里嵌套了几个 while,而是看那个负责发现工作、检查结果、记录进度、启动下一轮的人,有没有被系统替代。#
判断 · 把握较大
架构上的外层不等于循环上的外层。Claude Code 的 Supporting Systems(权限、Hooks、Memory、Session、MCP)确实包在 Runtime 外面,但它们只是在支撑 query_loop 运行,不会在 CI 失败后主动生成下一次 Agent 任务。#
判断 · 把握较大
可靠的 Automation 不是定时器本身,而是「触发条件 + 任务蓝图 + 实例化 + 入队」的完整链路。闹钟只负责响,它不能直接代替一张工作单。#
判断 · 把握较大
并行不是多开几个对话框,而是先隔离它们会修改的环境。没有 Worktree,就像让三位程序员共用一台电脑同时编辑同一份文件,Agent 数量越多冲突反而越快。#
判断 · 把握较大
能重复运行的脚本不等于可靠的 Loop。可靠的 Loop 必须知道何时继续、何时重试、何时恢复,以及何时承认自己做不到——对应 CAS 乐观锁、周期性 Resync 扫描和自动恢复次数上限三道护栏。#
判断 · 把握较大
引用本文
晨旭,《从 while True 到 Loop Engineering:AI Agent 的古罗马副官》,晨光里的AI,2026-06-29
[晨旭:《从 while True 到 Loop Engineering:AI Agent 的古罗马副官》](https://chenxu.xin/writing/loop-engineering-optio)带进你的 AI 继续追问
这篇文章有一份干净的 Markdown 原文,可以直接交给任何模型读,不用复制粘贴。