在我还没从 Thoughtworks 离职的时候(现在在 Qoder 团队),我就想写一篇文章,把一张图里 Loop 那一栏补完整。那张图其实很直白:不是让 AI 生成更多代码,而是让 AI 在工程体系中稳定完成交付。

唯独 Loop 这一块,我一直没找到特别好的写法。
它当然可以写成一个原则:把一次性生成,变成带反馈、自修正、可持续推进的执行闭环。可这个说法太干净了,也太容易写成一段正确废话。后来我看过 Ralph Loop,它给了一个很朴素的参照:任务表、进度文件、测试、提交、下一轮 fresh context。
只是呢,我还是觉得少了一点真实工程里的手感。
引子 0:三个 /goal 的试验
直到这个月试了 Codex 的 /goal,睡觉前给一个任务,起床看结果。我拿 Office、IDA、Contra 这几个目标做了一些尝试,才觉得 Loop 这块终于有东西可以写了。效果不能说神奇,但至少它把一个问题压到了工程现实里:当任务大到一次对话装不下时,Agent 应该怎么继续工作。
所以这篇文章某种程度上也是一个有点绕的产物:先用 /goal 做了几组试验,再让 AI 帮我起草,最后我反过来修它。写到这里,文章本身也成了一个小 Loop。

这个月我拿三个任务试了一下 /goal。它们的共同点不是"AI 写了多少代码",而是最后都留下了一个可继续接班的状态。

IDA 的截图对齐报告最能说明这种状态。 RtlVirtualUnwind 的参数、14 行 normalized instructions、32 个可见函数名、右侧五个视图都能对上,但截图层仍然有红色差异区。它不是简单的"失败",也不是可以放心宣布"完成";它告诉下一轮 Agent:数据层已经接住了,像素层还没有。

这三件事单独看都不轻。放在一起之后,我开始更确定一件事:复杂任务交给 Agent 时,不能期待它"想一次就想明白"。任务得被做成一个可以接班、验证、修正的工作系统。
所以 /goal 的价值,不只是"让 Codex 跑更久"。它把一个松散的聊天请求,变成了一个可继续接班的运行对象。OpenAI 的文档把它描述成实验性能力:适合长时间编码、迁移、重构、实验、游戏和 side project;关键是目标要清楚、验证循环要清楚、停止条件要清楚。
Loop:如何从确定性中恢复控制
过去两年,大家谈 Agent 时,脑子里最容易浮现的还是聊天窗口。你给它一个目标,它读文件、改代码、跑命令、解释结果。这个模式已经很有用,但它有一个很硬的上限:一次对话很难承载一个真正长任务的全部上下文。
Addy Osmani 在《Long-running Agents》里对这个问题的定义很准确:长时间运行的 AI Agent 可以在数小时、数天,甚至数周里持续推进,跨多个上下文窗口和沙盒恢复工作,并留下结构化产物。这个定义里最重要的词落在"恢复"和"结构化产物"上。因为模型会忘,session 会断,沙盒会重建,命令会失败。
模型本身可以短暂,工作区不能短暂。只要任务、计划、验证结果、失败记录和 Git 历史还在,下一轮 Agent 就不必从一团聊天记录里重新猜项目现在到哪了。

Ralph Loop 是这个思想最小的版本:读 PRD,选下一个未完成任务,调用 coding agent,跑测试,更新进度文件,提交,再进入下一轮。它看起来像一个土办法,却抓住了核心:Agent 本体不必永远在线,工作状态必须能被下一轮接住。
回到代码里,它对应的就是那些很普通的交接物。

这张图里最容易被低估的是 Memory。很多人讨论 Agent 时盯着模型能力,真正让长任务能跑下去的,反而是那些很普通的东西:README、PLAN、progress、artifact、test report、git log。
/goal 的任务:如何设计长期可执行的目标
把这几个实现当成 /goal 任务来拆,差异首先出现在验收方式上。
第一类是模仿 Codex 编写 Office 能力。Routa 里的 packages/office 现在是一个 Node.js wrapper,底层通过 .NET 9 browser-wasm 读取 DOCX、PPTX、XLSX,外部 API 暴露函数。

另一边的 packages/office-render 是 React runtime layer,负责把 payload 渲染成 WordPreview、 SpreadsheetPreview、 PresentationPreview。
而 "让 Agent 写一个 Office 预览器" 这句话太大了,几乎没有执行边界。能落地的目标得先拆成这些层:

如果把这个目标交给一次普通聊天,我很容易得到一个"看起来能渲染"的大组件。长任务需要反着来:先把边界固定下来,再让 Agent 在边界内一点点补能力。比如 office-render 的 README 里已经把目标层次写出来:

第二类任务是用 Next.js 一比一复刻 IDA 项目。 ida-demo 里最有价值的部分,是它把"像 IDA"拆成了一组可验证目标。API 层用 lib/pe.ts 分析真实的 samples/kernel32.dll, /api/analyze 支持 GET 样例和 POST 上传;UI 层用 IdaWorkbench.tsx 组织函数列表、Hex View、Imports、Exports、Strings、SegmentMap 和 Output;验证层有一组脚本专门比较结果:
go
npm run test:detail:comparenpm run test:text:comparenpm run test:functions:comparenpm run test:right-views:comparenpm run test:functions:coveragenpm run test:ui:compare
第三类任务是《魂斗罗》。这个目标一开始听起来更像一句玩笑:从零编写 NES 模拟器,然后跑《魂斗罗》。

名字越大,停止条件越要具体。
Artifacts:Git、报告和失败记录,是 Agent 的黑匣子
长时间运行 Agent 一定会失败。它会走错路,会误判完成,会为了修一个错误引入另一个错误。关键是失败之后有没有东西留下来。
Git 在这里承担了版本控制之外的黑匣子角色:什么时候改了什么,哪一轮引入了风险,哪一次验证通过,哪一次回滚,哪一个 commit 可以作为恢复点。Anthropic 的 harness 文章也强调,让 Agent 做增量工作、写 progress、提交 git,可以减少下一轮重新猜状态的成本。
报告也是同一类东西。IDA demo 的 README 把通过项和失败项放在一起,读起来一点也不"漂亮",但它很可用。它告诉下一轮 Agent:不要再证明 RtlVirtualUnwind 的 14 行指令已经对齐,那里过了;也不要假装 pixel parity 已经完成,那里还没过。
这就是 /insights 这类能力真正该去的地方。它不一定非得是某个工具里的固定命令。它更应该成为 long-running agent 的复盘层:每轮结束之后,提炼失败路径、验证证据、隐含规则和下一步,让项目记忆变厚一点。
如果一轮 Agent 做完之后,只留下"完成了"的一句话,那下一轮其实没有得到任何东西。它只得到了一次信任请求。
繁杂任务:长时间运行需要人能插手
长时间运行不能变成 Agent 在仓库里随便跑几个小时。它要在一个有约束的 loop 里持续推进。这个 loop 里必须有计划,有验证,有权限边界,有日志,有 checkpoint,有人类可以中途插手的位置。
OpenAI 的 long-horizon Codex 文章把 Codex loop 写成:plan、edit code、run tools/tests/build/lint、observe、repair、update docs/status、repeat。 这套循环有效,是因为每一步都能产生外部证据。模型的自信不重要,命令输出、diff、测试报告、浏览器截图、README 状态更重要。
所以当我们开始设计复杂、繁杂任务时,会先问几个很土的问题:
-
• 这个目标能不能拆成 3 到 7 个 checkpoint?
-
• 每个 checkpoint 有没有一条验证命令或一个可检查 artifact?
-
• 哪些文件是公共边界,不能为了局部通过而破坏?
少一条,下一轮 Agent 就会多花一段时间重新找入口,或者更糟,重新证明一件已经证明过的事。
未来:管理一支异步工程队
如果把 Ralph Loop、Claude Code、Codex 放在一起看,会发现它们的方向并不神秘。
Ralph Loop 先证明最小循环成立:任务表、进度文件、Git、fresh context。Claude Code 把 loop、hooks、skills、insights 放进开发者日常工具。Codex 的 /goal 则把一个 durable objective 挂到 thread 上,让 Agent 可以跨 turns 持续推进,并用 /goal pause、 resume、 clear 控制运行状态。
这三条路最后会碰到同一个管理问题:如何让多个异步执行者在同一套工程证据上协作。
围绕这几个目标,最后最重要的事反而不是盯着模型怎么写代码,而是写 spec,设边界,设计验证,拆 checkpoint,看报告,决定哪些状态要写回 README,哪些失败要留给下一轮。
这不轻松,甚至比写一个普通提问麻烦得多。只是呢,它更接近真实软件工程。
我现在对 Agent 复杂任务的判断可以压成一句话:不要让 Agent 记住一切,要让工作区接得住下一轮。