12. Ralph loop — 从 PRD 到 release,操作者不在场也能走完的路
PRD 与 release gate 之间自主行走的循环。Master Plan = PRD + 关卡,每次迭代交付一项,DECISIONS 队列隔离操作者决策,防止自治变为漂移的纪律。
第 10 篇——PRD说了要造什么。第 11 篇——Release gates说了什么时候造好了。
这一篇讲的是在操作者不在键盘前时,是什么填补了这两者之间的缝隙。
Ralph。它接过带关卡的 PRD,自己走完那条路——一次一个经过验证的 commit。它在后台运行。能 push 时就 push。不能时就把决策放进队列。操作者醒来,跑一个 slash command,做几个决策,然后回去做别的事。工作是系统做的。
这是本系列工作流扩展的第三篇,也是前面所有内容叠加生效的那一篇。人格收窄决策空间。记忆保留为什么。Skills 压缩动词。Hooks 触发可能被遗忘的事。多智能体分摊负载。验证锁定「完成」。令牌经济保护信号。PRD 持有意图。Release gate 强制到达。Ralph 把整套编排放在时钟上跑起来。
0. 出发前提 — 自治不是「更信任智能体」
自治的坏版本是「让智能体爱怎么干就怎么干,并祈祷顺利」。它崩塌的理由和第 10 篇里没有 PRD 的工作流崩塌的理由一样——操作者的心智无处耐久存放,智能体只好临场发挥。
能跑的版本正好相反。操作者写 PRD。操作者写关卡。智能体的自由裁量被锐利地界定——凡是不改变系统是什么的事,它都能做;凡是会改变的事,它都不能做。在那个边界内,智能体不受监督地运转。在边界外,智能体停下来等。
自治在心智被固定在代码里、而劳动才是被委托的那部分时奏效。
Ralph 就是让这个区分在运行上变得真实的套件。
1. Ralph 实际上是什么
Ralph 是两个脚本加一个文件夹。
ralph-code.sh— 一次跑一个 phase。读 PRD-N。挑下一个[ ]项。实现它。跑 verify。verify 通过就 commit。重复。ralph-orchestrator.sh— 连续跑多个 phase。读 Master Plan。每个 phase 调用ralph-code.sh。phase 之间检查关卡。要么通过关卡 (Auto),要么停下来把决策入队 (Manual)。ralph-loop/— 每个项目一个文件夹,里面装 PRD、master plan、进度日志、blocker 列表,最重要的是——DECISIONS 队列。
子进程不是长生命周期的智能体。它是每次迭代一个新会话。每次迭代是一项:实现、验证、commit。下一次迭代从干净的状态开始,重新读 PRD 找下一个 [ ]。迭代之间没有共享上下文可以漂移,所以漂移无法累积。
父进程——orchestrator——什么都不实现。它唯一的工作是关卡强制。每个 phase 之后它问「关卡通过了吗?」如果是,前进。如果否,停下并写入队列。
2. Master Plan — PRD 和关卡的融合
Master Plan 是 Ralph 读的文档。形状像 PRD,每个 phase 内联了关卡:
Approved-By: lead, 2026-05-18
Phase P1 — Privacy 与合规清理
PRD: ralph-loop/PRD-P1.md
Auto-Gate: pnpm verify:privacy && pnpm build && pnpm lint
Manual-Gate: 负责人批准 privacy policy 文本
Items: 12
Phase P2 — 资源 SHA-256 强制
PRD: ralph-loop/PRD-P2.md
Auto-Gate: pnpm verify:assets && pnpm build
Manual-Gate: —
Items: 7
Phase P3 — i18n locale 扩展 (4 个新 locale)
PRD: ralph-loop/PRD-P3.md
Auto-Gate: pnpm build && pnpm verify:i18n
Manual-Gate: 负责人批准每个 locale 的机器翻译内容
Items: 24
...
三条属性重要。
Approved-By: 是必需行。 orchestrator 没有它就拒绝启动。如果负责人没在 Master Plan 上签字,Ralph 不跑。
每个 phase 的 PRD 都已预先生成。 不是「orchestrator 到 P3 时再生成 PRD-P3」——启动时 PRD-P3.md 就已经存在,由 Alice 从 Master Plan 写成。预先生成是漂移安全网:正在飞行中生成的 PRD-P3 没有经过操作者审阅。
Auto-Gate 与 Manual-Gate 在每个 phase 命名。 Auto 是 shell 命令。Manual 是具名批准人加上他批准的对象。没有任何 phase 在关卡未通过的情况下推进。
3. 循环实际上怎么跑
ralph-code.sh 一次迭代的简化轨迹:
1. cd 到 worktree
2. 读 PRD-N.md
3. 找到第一个标记为 [ ] 的项
4. 如果没有 [ ] 项了 → 退出 (ALL DONE)
5. 启动一个新的 Claude Code 会话
6. system prompt: "只实现这一项,然后停"
7. 子进程写代码
8. 子进程跑 verify (PRD 里命名的脚本)
9. verify 通过:
- 子进程用包含项 ID 的消息 commit
- 父进程重跑 verify (纵深防御)
- 父进程 verify 也通过 → 把 [ ] 标记为 [x],继续
- 父进程 verify 失败 → revert,写入 BLOCKERS,跳到下一项
10. verify 失败:
- 记入 BLOCKERS
- 重试一次
- 还是失败 → 标记为 blocked,跳到下一项
11. 如果 BLOCKERS 达到阈值 (默认每 phase 3 个) → abort
12. 回到第 2 步
这个循环的关键属性,以及每一条为什么是这个形状。
每次迭代一项。 子进程不能「既然进来了,那就顺手修一下」。system prompt 明确把它限制在一行 PRD 上。这就把范围漂移当场掐死。
每次迭代新会话。 项与项之间不带上下文。下一项重新读 PRD。如果上一项留下了微妙的坏假设,它们不会传播。
父进程重新验证。 子进程的 verify 是一次检查。父进程的 verify 是同一个脚本,在子进程会话之外、在 commit 后的状态上重跑。两边对不上,子进程的声明就错了,commit 被 revert。这是系统在「verify passed」是幻觉时仍能存活的方法。
Blocker 上限。 一个 phase 累积了 N 个 blocker 后,phase 中止。操作者检查是什么一直在挡,然后要么修根因要么改写 PRD。Ralph 不会永远撞同一堵墙。
4. Orchestrator — phase 边界是人住的地方
ralph-code.sh 处理 phase 内的项。ralph-orchestrator.sh 处理 phase 之间的过渡。
一个 phase 的 ralph-code.sh 以 ALL DONE 退出后:
1. 父进程跑该 phase 的 Auto-Gate 命令
2. Auto-Gate 失败:
- 在 DECISIONS 记入「Auto-Gate failed, see verify output」
- 停止 orchestrator
3. Auto-Gate 通过且无 Manual-Gate:
- 在 ORCHESTRATOR-STATE.md 把 phase 标为 [x]
- 前进到下一个 phase
4. Auto-Gate 通过且有 Manual-Gate:
- 在 DECISIONS 记入「Manual-Gate awaits: <approver> approves <thing>」
- 停止 orchestrator
5. 每 5 个 phase (无论状态):
- 强制 DECISIONS 检查点
- 停止 orchestrator
- 操作者跑 /btw 确认方向
三个有意为之的停顿,每一个对应一种不同的只有人能做的责任。
Auto-Gate 失败。 这是技术事件,但解读归人。verify 脚本错了?spec 错了?世界变了?操作者来决定。orchestrator 不无限重试。
Manual-Gate 到达。 这是明确的交接。负责人批准 privacy policy、或种子内容、或 OAuth scope 选择。这一行无法自动化,所以 orchestrator 在门口停下来。
强制检查点。 每五个 phase,即使没出任何问题,orchestrator 也停下来询问方向。这是漂移安全网。长周期自治最难的失败模式是「一切都跑通了但方向错了」,唯一已知的对策是在固定节奏上做人工复审。
5. DECISIONS 队列 — 把「我需要人」隔离开
三个文件在 ralph-loop/ 里累积:
| 文件 | 装什么 | 触发 | 如何处理 |
|---|---|---|---|
PROGRESS.md | 每次迭代一行,成功或失败 | 每次迭代 | append-only, 仅审计 |
BLOCKERS.md | 智能体无法解决的技术失败 | verify 两次失败等 | 计入 abort 阈值 |
DECISIONS.md | 只有人能决定的事 | 选项选择、安全/DB、依赖新增 | 操作者用 /btw 处理 |
让这个机制奏效的纪律,在于子进程如何分类它无法解决的情形。
子进程遇到一个不知道如何处理的情形:
├── "我大概知道该做什么,但 spec 没说" → BLOCKER
├── "有两个合理选择,只有负责人能挑" → DECISION
└── "需要新依赖 / 安全审查 / public API 变更" → DECISION
不确定时,归为 DECISION 而不是 BLOCKER。把决策错分为 blocker 只是浪费迭代。把 blocker 错分为决策会不必要地把操作者叫醒,但不会破坏代码库。这种不对称就是重点。
PRD 里状态为 [?] 的项(决策待定)被 Ralph 跳过。循环继续在 [ ] 项上跑。能做的都做完后,只剩 [?] 项——循环自然退出,发出「轮到操作者了」的信号。
6. /btw — 操作者那一边的循环
操作者那一边,整个交互就一个 slash command。
/btw
它做的事:
- 读取每个已知项目里的
ralph-loop/DECISIONS.md - 按优先级排序待定决策 (安全/DB +10 权重,等待时间权重)
- 作为带选项的批量问题呈现给操作者
- 对每个回答:
- 把决策从「待定」移到「已解决」,附上答案和时间戳
- 在 PRD 里把
[?]翻回[ ],按照决策更新该行内容 - 用
[Decision] D-NNN R0N: <summary>消息 commit
- 询问操作者是否在受影响的 phase 上重启 Ralph
操作者的心理模型是——我在回答问题,而不是在跑工作。orchestrator 做了实际工作。orchestrator 碰到了只有我能决定的事。我决定。orchestrator 继续。
一段真实形状的交互:
操作者 (早上): /btw
Alice: 待定决策 3 件,跨 2 个项目。
Project A (等待 14 h):
D-007 Phase P5 — 事务邮件用 Resend 还是 Postmark?
spec 沉默。价格 Resend 占优,送达率 Postmark 占优。
Project A (等待 14 h):
D-008 Phase P6 — 加 `zod` 依赖做运行时校验?
spec 未预料到运行时校验器。两个备选:
(a) zod (~14 kB)
(b) 手写校验器
Project B (等待 2 h):
D-002 Phase P2 — Manual-Gate: 负责人批准机器翻译内容?
24 个文件, 4 个 locale × 6 个分类。附样例 diff。
操作者: D-007: Resend. D-008: zod. D-002: 批准.
Alice: 三件已记录。Project A Phase P5 恢复。
Project B Phase P2 推进到 P3。Project B 继续。
那段对话就是全部交互。操作者没写代码。操作者没跑构建。操作者在一分钟内做了三个决策。Ralph 在对话之前做了其余的事,对话之后继续做其余的事。
7. Ralph 不合适的时候
Ralph 不是万能锤。它对一种形状的工作很在行,对另一种形状不行。
好的契合。
- 大量相似的项,每项可验证。(对 36 个 MDX 文件做一次润色。为 48 个 lens 变体生成样板。重构改名函数的 24 个调用点。)
- verify 脚本能检查的生成测试或文档。
- 把大表面朝一个方向移动的 lint、format 或类型严格化批次。
坏的契合。
- 架构决策。(重点是决策走 DECISIONS,但如果每一项都是决策,Ralph 不干活只产生队列噪声。)
- 安全或 DB schema 变更。两者都触及 Ralph 无法完全验证的不变量,而且两者都有「通过」错得很危险的失败模式。
- public API 变更。verify 脚本能确认本地变更工作,但确认不了下游消费者是否仍然工作。
- 任何带新依赖的事。永远是决策。
不确定时的启发式:我睡觉时这个 commit 落地,我会放心吗?放心,用 Ralph。不放心,在有操作者在场的普通会话里做。
8. 安全护栏 — 让自治不变成火灾
几条护栏叠加起来让 Ralph 能放着跑也安全。
Worktree 隔离。 Ralph 在 git worktree 里跑,不在 main 上跑。worktree 在专用分支上 (ralph/master-plan 或 ralph/{phase})。操作者随时可以检查并丢掉整个分支。
Approved-By 行。 orchestrator 没有 Approved-By: lead, <date> 拒绝启动 Master Plan。操作者的签字被机械地强制——不是「负责人在聊天里说 OK」,而是 orchestrator 解析的文件里的一个字符串。
Verify 是 commit 的唯一通道。 子进程在 verify 脚本不以 0 退出时无法 commit。父进程在 commit 后的状态上重跑 verify。同一道关卡的两次独立通过。
每次迭代有边界的范围。 子进程的 system prompt 写着「只实现这一行 PRD,然后停」。迭代级的范围蔓延被机械地阻断。
Phase abort 阈值。 一个 phase 累积 N 个 blocker 后 phase 中止。整个计划累积 M 个 blocker 后 orchestrator 中止。系统在路变得无法识别时退出,而不是硬闯。
强制人工检查点。 每 5 个 phase,orchestrator 停下来问。即使没有明显出错的迹象,操作者也确认方向。没有人工复审的长周期无监督运行是最危险的模式,这条护栏把它堵上。
决策隔离。 只有操作者能决定的事被路由到 DECISIONS 并被 Ralph 跳过。智能体绝不在属于人的问题上猜。
成本上限。 成本监控是操作者的责任(如 ccusage 等外部工具)。比预期昂贵的 phase 也是某处漂移的信号,值得检查。
9. 一条原则
Ralph 的整个形状收敛为一句话。
「凡是操作者的心智会当成日常的,让系统自己走。凡是操作者的心智会当成决策的,入队等待。」
而那一句也是这三篇扩展的终点——也是本系列本身的归处。
第 1 篇——为何是 Alice 问的是:我如何积累我的心智,让 AI 不会把它丢失?
前九篇回答:构建一个划定心智边界的人格、一份跨会话保有它的记忆、压缩它动词的 skills、触发可被遗忘事项的 hooks、不让一个上下文承载一切的多智能体、锁定「完成」的验证、保护信号槽位的令牌经济,以及让每天在同一处亮起和同一处关闭的会话协议。
后三篇回答:写一份 PRD 让意图活过会话。写下 release gates 让「完成」成为事实。跑一个循环让意图和到达之间的路自己走,操作者只处理那些属于自己的决策。
当十二块都到位,操作者就不再是做工作的人,而是决定什么工作值得做的人。心智——第 1 篇里那个原本的、不可还原的东西——终于到了它该在的地方:在栈的顶端,做决策,而下面的一切承载劳动。
这就是我过去几个月一直在构建的与 AI 协作的版本。工具可能是 Claude,可能是 Codex,可能是接下来出现的任何东西。上面那十二个决定不依赖于工具。它们等待任何决定去构建自己的协作者而不是仅仅去使用一个协作者的人。
如果这个系列哪怕稍稍缩短了到达那些决定所需的时间——操作者的意图就落到了它本该落到的地方。