随笔 / AI 工程

循环的灵魂在循环之外

· AI Coding Agent 架构

Codex /goal 和 Ralph Loop 功能描述几乎一样,使用体感天差地别。深入之后发现,差异不在谁更强,在于它们解决的根本不是同一个问题。一个是验收型完成器,一个是持续搜索器。而你觉得哪个好用,暴露的是你真实任务的性质。

这两天试了 Codex 新上线的 /goal 命令。道理上,它想做的事跟 Ralph Loop 一样:给 agent 设一个目标,让它自己循环干到完成。

用了几轮之后,我的体感是:很容易一两轮就停。而同样的任务交给 Ralph Loop,至少能主动优化三五轮。不是 Codex 不努力,是它停下来的时候真诚地认为自己完成了。

这让我很好奇:两个功能描述几乎一样的东西,为什么体验差这么多?

调研之后我的判断是:体感大概率是对的,但原因不是"Codex 的 /goal 比 Ralph Loop 弱"。而是这两个东西的目标函数根本不同。

它们不是同一种产品

先说 /goal 在技术上做了什么。4 月 30 日发布的 Codex CLI 0.128.0 加入了这个 experimental 命令。Simon Willison 第一时间分析了它,指出核心实现是两个模板文件:continuation.md 在每个 turn 结束后自动注入,提醒 agent "继续朝目标推进";budget_limit.md 在预算快用完时提醒 agent "收尾,别开新坑"。

Ralph Loop 呢?Geoffrey Huntley 的原始设计只有一行 bash:

while :; do cat PROMPT.md | claude-code ; done

一个外部循环,每次迭代启动一个全新的 Claude 进程。

表面上看,两者都是"循环做事直到完成"。但把它们的核心循环拆开看,差异是结构性的:

/goal 的循环是:持久目标 → idle 检查 → 注入 continuation prompt → 模型执行下一步 → 模型自己 audit → 模型标记 complete(或 runtime 预算到期强停)。

Ralph Loop 的循环是:外部脚本启动 agent → agent 做一轮 → 外部检测 completion signal → 如果不满足,丢弃上下文、保留文件状态、重新启动 agent。

前者更像"单 agent 的持久任务生命周期"。后者更像"多次独立审查的蒙特卡洛式工程搜索"。

为什么 /goal 容易一两轮就停

GitHub 上有一个精准定位了 /goal 核心问题的 Issue #19910。一位深度用户报告:密集使用 /goal 几天,在 ambitious work 上没有一次真正跑到完成。根因是 compaction:session 对话太长时系统会压缩历史,而压缩过程可能把 goal continuation prompt 丢掉。新一轮的 agent 只看到"刚才在跑测试,快完事了",不知道这只是子步骤。于是验证完局部任务就标记 goal achieved。

但 compaction 只是表层原因。更深层的是 /goal 的续跑规则本身带有收敛倾向。

从 Codex 的 runtime PR 可以看到一个关键设计:如果某一轮模型用自然语言总结"我检查过了,目标已达成"而没有进一步调用工具,运行时不会触发下一轮 continuation。这意味着 agent 只要输出一段"总结性文字"而非动手操作,循环就自然停了。这大概率就是我体验到"一两轮就停"的直接技术原因。

再看 continuation.md 模板本身。它要求 agent 在决定完成前把目标重述成 deliverables/success criteria,建立 prompt-to-artifact checklist,检查文件、命令输出、测试结果等真实证据,只有 audit 显示"no required work remains"时才调用 update_goal complete

这套设计对"验收型任务"很合理。但对"持续优化型任务"有天然收敛倾向:它问的是"显式要求是否都覆盖了",而不是"还有没有高价值的非显式改进机会"。

Ralph Loop 的主动性从哪来

理解了 /goal 的收敛设计,Ralph Loop 的优势就不只是"架构更好"那么简单了。它的主动性来自一个反直觉机制:不是让同一个 agent 更聪明,而是不断制造新的、不完全一致的审查视角。

每次 bash loop 迭代启动的新 Claude 进程:没有上一轮的对话历史,没有自我确认偏误,通过 git diff 和文件系统状态来了解"上一轮做了什么"。它会自然产生新的 framing:刚才那轮完成了什么?测试能过吗?结构还能更好吗?有没有边界情况没覆盖?

LLM 在同一上下文里容易产生承诺一致性,就是"我已经做得差不多了"的路径依赖。Fresh run 会降低这种依赖。对于架构优化、质量提升、测试补洞这类开放任务,重新采样通常比继续同一条思路更有效。

Blake Crosley 的实践报告证实了这一点:他用 Ralph Loop 架构跑了多个通宵 session,交付了 3,455 行 Python 代码和 141 个测试。HN 上也有人总结:Ralph 这类东西的核心价值是"在长期任务中纠正 drift",通过 fresh context 打破 agent 的自我满足叙事。

公平地说:/goal 的早停不全是 bug

写到这里需要补一个视角。如果只从"谁循环得更久"来评判,对 /goal 不公平。

/goal 是 OpenAI 官方运行时的一部分。它必须考虑预算控制、用户可暂停恢复、误触发防护、安全边界。PR 里明确说不让模型从普通 task request 推断 goal,不给模型 broad control over user/runtime-owned state。这些产品约束是有意为之的。

Ralph Loop 是社区脚本。它的哲学是粗暴但有效:不断跑,直到外部条件满足或 max iterations 停止。有些实现加了 rate limiting、circuit breaker,但本质仍然是"外部循环优先"。它更浪费,但更不容易满足于第一轮的局部最优。

所以 /goal 的早停有三层原因:

它不是一个"做坏了的 Ralph Loop"。它是一个不同目标函数的产品,碰巧被社区拿来跟 Ralph Loop 对比。

真正的判断:你的任务是哪一种

两种工具做的事用人话说:

/goal 是一个合规的工程员工:拿到需求、执行、验收通过、汇报、停止。它擅长"把一个明确的 goal 可控地做完"。

Ralph Loop 是一个偏执的外部审稿流程:你说完成了,我换个脑子再看一遍。你还是说完成了,我再换个人来看。它擅长"不断发现下一个改进点"。

我之前觉得 /goal "不好用",本质上是因为我给它的任务不是"做完一个有明确验收标准的需求",而是"持续优化,帮我发现还能更好的地方"。前者 /goal 理论上可以做(如果 compaction 问题修好的话),后者它的设计基因就不支持。

换句话说:你觉得 Ralph 更好用,暴露的是你的真实任务性质。你不是在"达成一个 goal",你是在"持续发现下一个更高价值的 goal"。这两者不是同一个产品形态。

架构差异的本质:自检 vs 外审

抽象到更一般的层面,这里有一个工程管理中的经典问题。

让同一个 agent 在同一个 session 内自我评估是否完成,本质上就是"自检"。让一个全新的 agent 来审视上一轮的产物,是"外审"。

自检不如外审可靠,这是组织管理、软件工程、质量体系都验证过的普遍规律。代码要别人 review,审计要独立第三方。不是因为你不诚实,是因为你不可能客观审视自己持续投入的工作。agent 也一样,在同一 context 里积累的"我在认真工作"叙事会形成路径依赖。

Ralph Loop 通过进程级隔离实现了"外审"。每次迭代是一个独立的 code review + continue 决策。/goal 通过 prompt 注入试图在"自检"框架内提高审计质量。前者结构上更可靠,后者产品上更可控。

实操建议:混合架构

如果你跟我一样,日常任务里"持续优化"比"验收完成"更多,有一个比较务实的混合做法:

用 /goal 做单轮长任务的内层执行器(它对有明确 deliverables 的单次任务确实比反复手动"继续"好用)。在外层套一个 Ralph 式的循环做"反满意"外壳。外层不需要一直让它写代码,可以交替执行三种 prompt:builder、reviewer、regression-finder。只有 reviewer 连续两轮找不到 material issue,外层才停。

这正好补上 /goal 的弱点:/goal 擅长沿着目标推进,外层 loop 擅长"不相信它已经完成"。

如果非要只选一个,我的判断是:对于"做完一个有验收标准的需求",等 /goal 修好 compaction 问题后值得一试;对于"持续优化、不断发现改进点"这类开放任务,Ralph Loop 的架构基因更匹配。它的"浪费"(每轮丢弃上下文)恰恰是它的优势(破坏 agent 对自己已完成的叙事)。

带走一个判断框架

评估 AI coding 工具的自主循环能力时,不要看功能描述,看三个设计选择:

更关键的是:先想清楚你的任务属于哪种。

如果是"把这个明确的需求做完",你需要的是一个可预算、可审计的完成器。/goal 的方向是对的。

如果是"帮我持续发现还能更好的地方",你需要的是一个不断重新采样的搜索器。Ralph Loop 的架构更匹配。

工具不分好坏,但目标函数要对齐。你觉得一个工具"不好用",很多时候不是工具有问题,是你在用验收型工具做搜索型任务。