Ralph:18K+ Star 的 AI 自主编程循环引擎——让 Agent 持续交付

8327 字
42 分钟
Ralph:18K+ Star 的 AI 自主编程循环引擎——让 Agent 持续交付

Ralph:18K+ Star 的 AI 自主编程循环引擎——让 AI Agent 像工人一样持续交付#

一个只有几百行 Bash 脚本的开源项目,如何撬动 AI 编程的无限可能?


1. 引子:什么是 Ralph?为什么值得写?#

2025 年,AI 编程工具迎来了爆发式增长。从 Claude Code、Cursor 到 GitHub Copilot,每一个工具都在试图回答一个问题:AI 能帮我们写多少代码?

但大多数工具的使用模式是相同的:开发者打开终端,输入需求,AI 执行一次,然后停下来等下一个指令。这种”单次对话”模式固然方便,但在面对复杂功能时,往往需要开发者反复介入、反复补充上下文、反复修正方向。

直到 snarktank/ralph 在 GitHub 上出现——短短时间内狂揽 18,071+ Star,成为 AI Agent 工程领域最受关注的项目之一。

Ralph 是什么?#

Ralph is an autonomous AI agent loop that runs AI coding tools (Amp or Claude Code) repeatedly until all PRD items are complete. Each iteration is a fresh instance with clean context. Memory persists via git history, progress.txt, and prd.json.

简单来说,Ralph 是一个 AI 编程的”循环引擎”。它基于 Geoffrey Huntley 首创的 Ralph pattern,由 Ryan Carson 在 snarktank 组织下开源。它的核心思想极其简单却极其有力:

给 AI 一份需求文档 → 它自动循环执行 → 每次检查完成度 → 直到全部完成。

没有复杂的编排框架,没有微服务架构,没有消息队列——只有一个几百行的 Bash 脚本,加上几个精心设计的数据文件。

为什么值得深入分析?#

  1. 极简主义的力量:在 AI Agent 框架动辄上万行代码的今天,Ralph 证明了”循环 + 状态文件”的朴素模式可以解决实际问题。
  2. Fresh Context 范式:每次迭代使用全新上下文,彻底规避了长上下文导致的注意力稀释和幻觉累积。
  3. 需求驱动开发:以 User Story 为最小执行单元,将敏捷开发理念与 AI 编程深度融合。
  4. 可审计、可复现:所有状态通过 Git、prd.json、progress.txt 持久化,每一步都可追溯。

接下来,我们深入拆解 Ralph 的架构、设计决策和底层哲学。


2. 核心哲学:循环做一件事做到极致#

Ralph 的哲学可以浓缩为一句话:

AI 不擅长一次性完成复杂任务,但擅长重复执行简单任务。

这看似矛盾,实则道出了当前大语言模型的核心局限与优势:

能力现状
一次理解完整需求❌ 容易遗漏、容易偏离
保持长时间注意力❌ 上下文越长,注意力越分散
执行单一明确的任务✅ 在清晰指令下表现优秀
遵循结构化流程✅ 模板化指令执行准确

基于这个认知,Ralph 设计了一套**“循环执行 + 状态持久化”**的工作模式:

┌─────────────────────────────────────────────────────┐
│ Ralph 循环引擎 │
│ │
│ PRD (需求文档) │
│ │ │
│ ▼ │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │ 第 1 次迭代 │───▶│ 第 2 次迭代 │───▶│ 第 N 次迭代 │ │
│ │ Fresh │ │ Fresh │ │ Fresh │ │
│ │ Context │ │ Context │ │ Context │ │
│ └────┬─────┘ └────┬─────┘ └────┬─────┘ │
│ │ │ │ │
│ ▼ ▼ ▼ │
│ 完成 Story A 完成 Story B 完成 Story C ... │
│ │ │ │ │
│ └───────────────┴───────────────┘ │
│ │ │
│ ▼ │
│ progress.txt (追加记录) │
│ prd.json (状态更新) │
│ Git (版本快照) │
└─────────────────────────────────────────────────────┘

这个循环的每一步都遵循相同的模式:

  1. 读取当前状态(prd.json、progress.txt)
  2. 选择最高优先级、未完成的 User Story
  3. 执行:在干净上下文中实现这个 Story
  4. 验证:运行 typecheck、tests、必要时浏览器验证
  5. 提交:检查通过则 commit,更新 prd.json
  6. 沉淀:将本轮 learnings 追加到 progress.txt
  7. 判断:是否全部完成?是 → 输出 <promise>COMPLETE</promise>;否 → 进入下一轮

这种设计的精妙之处在于——AI 不需要”记住”之前做了什么,因为它可以从 prd.json 和 progress.txt 中读取所有必要信息。每次迭代都是一个”干净的大脑”,带着”完整的记忆”开始工作。


3. 架构深度解析#

3.1 ralph.sh:循环引擎——Bash 如何驱动 AI 编码工具反复执行#

Ralph 的核心是一个 Bash 脚本 ralph.sh。这看似”原始”的选择,实际上蕴含了深刻的设计考量。

为什么选择 Bash?#

  • 零依赖:不需要 Python、Node.js 运行时,任何 Unix 环境都能跑
  • 透明:没有隐藏逻辑,开发者可以逐行理解、逐行修改
  • 可靠:Bash 的行为是确定性的,不会因为包版本变化而出问题
  • 轻量:几百行代码,没有框架负担

脚本的核心执行流程#

#!/bin/bash
# Ralph Wiggum - Long-running AI agent loop
# Usage: ./ralph.sh [--tool amp|claude] [max_iterations]

脚本支持两种 AI 工具:Amp(默认)和 Claude Code。通过 --tool 参数指定:

Terminal window
./ralph.sh --tool amp 10
./ralph.sh --tool claude 15

max_iterations 默认为 10,防止无限循环。

脚本的核心循环结构如下:

Terminal window
for (( i=1; i<=max_iterations; i++ )); do
echo "=== Iteration $i / $max_iterations ==="
# 调用 AI 工具执行 prompt
if [ "$TOOL" = "amp" ]; then
amp --dangerously-allow-all --print < prompt.md
else
claude --dangerously-skip-permissions --print < prompt.md
fi
# 检测完成信号
if grep -q "<promise>COMPLETE</promise>" output.log; then
echo "✅ All stories completed!"
exit 0
fi
done
echo "❌ Reached max iterations ($max_iterations) without completing all stories"
exit 1

--dangerously-allow-all--dangerously-skip-permissions 是关键参数——它们让 AI 工具在无人工确认的情况下自由执行文件操作、终端命令等。这在自主循环中是必须的,因为人工介入会打破自动化流程。

--print 参数则确保 AI 的完整输出被打印到日志中,供循环引擎检测完成信号。

分支管理与自动归档#

Ralph 的一个重要设计是:每次运行自动创建/切换到 feature branch,并在切换分支时归档上次的运行产物

这意味着:

  • 每次 Ralph 运行都在独立的分支上工作,不会污染主分支
  • 如果开发者中途切换分支查看代码,Ralph 会自动将上次的中间状态归档保存
  • 归档机制防止了多次运行之间的文件冲突

这种设计体现了 Ralph 对开发者工作流的尊重——它不会独占你的项目,你可以在 Ralph 运行的同时自由切换分支、查看进度。

3.2 prompt.md / CLAUDE.md:Agent 指令模板#

如果说 ralph.sh 是 Ralph 的心脏,那么 prompt.md(或其等效的 CLAUDE.md)就是 Ralph 的大脑。

Agent 指令的核心内容#

prompt.md 是每一轮迭代中发送给 AI 工具的指令模板。它的核心逻辑可以用以下伪代码表示:

=== 第 N 次迭代指令 ===
## 1. 读取状态
- 读取 prd.json,获取所有 User Story 及其完成状态
- 读取 progress.txt,获取历史 learnings
## 2. 选择任务
- 找到 priority 最高且 passes: false 的 User Story
- 一次只选一个!
## 3. 实现任务
- 切换到 prd.json 中指定的 branchName 分支
- 根据 Story 的 description 和 acceptanceCriteria 编写代码
- 如果是前端 Story,必须通过 dev-browser 验证
## 4. 质量检查
- 运行 typecheck
- 运行 tests
- 确保全部绿色
## 5. 知识沉淀
- 如果本轮发现了新的代码模式或最佳实践,更新 AGENTS.md / CLAUDE.md
- 这些模式会在后续迭代中被 AI 自动读取和遵循
## 6. 提交代码
- 检查通过后,git commit
- 更新 prd.json,将该 Story 标记为 passes: true
- 将本轮 learnings 追加到 progress.txt
## 7. 完成判断
- 如果所有 Story 都 passes: true → 输出 <promise>COMPLETE</promise>
- 否则 → 结束本轮,等待下一轮循环

指令模板的精妙之处#

  1. 严格的单任务原则:“一次只选一个!“——强制 AI 专注,避免多任务导致的注意力分散。

  2. 浏览器验证要求:对于前端 Story,必须通过 dev-browser 验证。这意味着 AI 不仅要写代码,还要亲自”看”效果。这是 Ralph 对前端开发特殊性的深刻理解——代码正确 ≠ 视觉正确。

  3. 知识沉淀机制:AGENTS.md 是一个动态进化的文件。随着迭代进行,AI 会不断发现项目中的代码模式,并将其写入 AGENTS.md。后续的迭代会自动读取这些模式,确保代码风格一致性。这实际上是一种**“元学习”**机制。

  4. XML 标签标记<promise>COMPLETE</promise> 是一个精心设计的完成信号。XML 标签的使用避免了与自然语言输出混淆,确保循环引擎能准确检测。

3.3 prd.json:需求驱动机制#

prd.json 是 Ralph 的”需求数据库”,也是整个循环的状态中枢。

结构示例#

{
"project": "My Web App",
"branchName": "feature/user-auth",
"description": "实现用户认证系统,包括登录、注册、密码重置",
"userStories": [
{
"id": "US-001",
"title": "用户注册页面",
"description": "创建一个注册表单,包含邮箱、密码、确认密码字段",
"acceptanceCriteria": [
"表单包含邮箱、密码、确认密码输入框",
"密码强度验证(至少8字符,包含大小写和数字)",
"邮箱格式验证",
"提交后显示成功消息",
"重复邮箱注册时显示错误提示"
],
"priority": 1,
"passes": false,
"notes": ""
},
{
"id": "US-002",
"title": "用户登录页面",
"description": "创建登录表单,支持邮箱密码登录",
"acceptanceCriteria": [
"表单包含邮箱和密码输入框",
"登录失败时显示错误提示",
"登录成功后跳转到首页",
"支持'记住我'功能"
],
"priority": 2,
"passes": false,
"notes": ""
}
]
}

prd.json 的设计精髓#

User Story 作为最小执行单元

每个 User Story 包含:

  • id:唯一标识符
  • title:简短描述
  • description:详细说明
  • acceptanceCriteria[]:验收标准列表——这是 AI 判断”是否完成”的依据
  • priority:优先级(数字越小越优先)
  • passes:布尔值,标记是否完成
  • notes:备注,用于记录特殊情况

这种结构的意义在于:

  1. 可量化:每个 Story 都有明确的验收标准,AI 可以逐条检查
  2. 可排序:通过 priority 字段控制执行顺序
  3. 可追踪:passes 字段提供实时进度
  4. 可扩展:notes 字段允许记录人工干预或特殊情况

与敏捷开发的深度契合

prd.json 的设计与敏捷开发中的 User Story 概念高度一致。在敏捷开发中,User Story 的标准格式是:

As a [角色], I want to [目标], so that [价值]。

Ralph 的 prd.json 虽然没有强制使用这种格式,但其设计哲学完全一致:以用户价值为导向,以可验证的标准为边界

3.4 progress.txt:记忆持久化#

progress.txt 是 Ralph 的”工作日志”。每一次迭代的 learnings 都会被追加到这个文件中。

作用机制#

# Iteration 1 Learnings (2025-04-15 10:30)
- 发现项目使用 Tailwind CSS 进行样式管理
- 组件文件应放在 src/components/ 目录下
- TypeScript 配置要求严格模式
# Iteration 2 Learnings (2025-04-15 10:45)
- 注册表单需要使用 react-hook-form 进行表单管理
- 密码验证使用 zod schema
- API 调用使用 axios,基础 URL 从环境变量读取
# Iteration 3 Learnings (2025-04-15 11:00)
- 登录成功后 token 存储在 localStorage
- 路由保护使用 Higher-Order Component 模式
- 错误消息使用统一的 ErrorBanner 组件

这种追加式记录有几个关键好处:

  1. 增量知识积累:AI 每次迭代只写当轮的发现,不会覆盖历史
  2. 上下文无关:新的 Ralph 实例不需要从之前的对话中恢复状态,只需读取 progress.txt
  3. 人类可读:开发者可以随时查看 progress.txt 了解 Ralph 做了什么、发现了什么
  4. Git 友好:progress.txt 的变更可以 diff,可以回滚

3.5 AGENTS.md:知识沉淀#

AGENTS.md(或 CLAUDE.md)是 Ralph 的”知识库”。它记录了项目在开发过程中发现的代码模式、最佳实践和约定。

内容示例#

# AGENTS.md - Project Knowledge Base
## Code Patterns
- 所有组件使用 TypeScript 函数组件
- 使用 Tailwind CSS 的 className 进行样式管理
- API 调用统一使用 src/api/ 目录下的函数
- 错误处理使用 try/catch + toast 通知
## Conventions
- 组件文件名使用 PascalCase
- 工具函数文件名使用 camelCase
- 环境变量前缀为 VITE_
- Git commit message 遵循 Conventional Commits
## Learned from Iterations
- Iteration 3: 表单验证使用 zod + react-hook-form 组合
- Iteration 5: 日期格式化使用 date-fns 而非原生方法
- Iteration 7: 列表组件需要实现虚拟滚动以避免性能问题

AGENTS.md 与 progress.txt 的区别#

维度progress.txtAGENTS.md
内容性质每次迭代的原始记录提炼后的知识沉淀
更新方式追加式追加 + 更新
用途记录”做了什么”指导”怎么做”
生命周期随项目持续增长持续精炼,保留有效模式

AGENTS.md 是 Ralph 实现**“自我进化”**的关键。随着迭代进行,AI 不断将有效的代码模式写入 AGENTS.md,后续迭代会自动遵循这些模式,从而确保整个项目的代码一致性。

这种机制类似于人类的”经验积累”——第一次做某件事时可能会犯错,但把经验记录下来后,下次就会做得更好。


4. 完整工作流:从 PRD 到自动交付#

Ralph 的完整工作流程分为四个阶段:

阶段一:创建 PRD(Product Requirements Document)#

开发者首先需要编写一份 PRD 文档,存放在 tasks/prd-[feature-name].md 中。

PRD 的内容通常包括:

  • 功能描述
  • 用户故事列表
  • 技术要求
  • 验收标准

PRD 的格式是自由的 Markdown,没有强制模板。这是因为 Ralph 认为需求表达应该是人类友好的,而不是机器友好的

阶段二:转换 PRD 为 prd.json#

Ralph 提供了一个转换脚本(或手动操作),将 PRD 中的 User Story 提取出来,生成结构化的 prd.json。

转换过程包括:

  1. 解析 Markdown 中的 User Story
  2. 为每个 Story 分配唯一 ID 和优先级
  3. 提取验收标准
  4. 生成 feature branch 名称

这个步骤是**“人类需求 → 机器可执行格式”**的关键转换点。Ralph 没有要求开发者直接编写 JSON,而是允许用自然的 Markdown 表达需求,然后自动转换。这体现了 Ralph 对开发者体验的重视。

阶段三:运行 Ralph#

Terminal window
./scripts/ralph/ralph.sh --tool amp 10

或者使用 Claude Code:

Terminal window
./scripts/ralph/ralph.sh --tool claude 15

运行后,Ralph 会:

  1. 读取 prd.json
  2. 创建/切换到 feature branch
  3. 开始循环执行

阶段四:监控与交付#

在 Ralph 运行期间,开发者可以:

  • 实时查看 progress.txt 了解进度
  • 检查 prd.json 查看哪些 Story 已完成
  • 切换到 feature branch 查看代码变更
  • 必要时手动干预(编辑 prd.json、补充 acceptanceCriteria)

当所有 Story 完成或达到 max_iterations 时,Ralph 停止运行。此时 feature branch 上已经有了完整的代码变更,等待开发者 code review 和合并。


5. 关键设计决策#

5.1 每次迭代 = 全新上下文(Fresh Context)#

这是 Ralph 最核心的设计决策,也是它与其他 AI 编程工具的最大区别。

问题背景:

当前的 AI 编程工具(Claude Code、Cursor 等)大多依赖上下文积累——随着对话的进行,AI 会记住之前说过的话、做过的修改。这种模式在短期对话中表现良好,但在长时间、多轮次的任务中存在严重问题:

  1. 注意力稀释:上下文越长,AI 对早期信息的注意力越弱
  2. 幻觉累积:早期的错误理解会被后续迭代不断放大
  3. Token 成本爆炸:长上下文意味着每次调用都需要传输大量历史数据
  4. 不可复现:相同的需求,在不同对话上下文中可能得到不同的结果

Ralph 的解决方案:

┌──────────────────────────────────────────────┐
│ 传统模式 vs Fresh Context │
│ │
│ 传统模式: │
│ Iteration 1: 上下文 = [] │
│ Iteration 2: 上下文 = [Iteration 1 的全部对话] │
│ Iteration 3: 上下文 = [Iteration 1 + 2] │
│ ... │
│ Iteration 10: 上下文 = [1+2+3+...+9] ← 💥 │
│ │
│ Ralph 模式: │
│ Iteration 1: 上下文 = [prompt.md] │
│ Iteration 2: 上下文 = [prompt.md] │
│ Iteration 3: 上下文 = [prompt.md] │
│ ... │
│ Iteration 10: 上下文 = [prompt.md] ← ✅ 干净 │
└──────────────────────────────────────────────┘

每次迭代,AI 工具被作为一个全新的进程启动,没有任何历史对话。它需要的”记忆”全部来自:

  • prd.json:当前需求和进度
  • progress.txt:历史 learnings
  • AGENTS.md:代码模式和约定
  • Git 仓库:当前代码状态

这种设计带来了一个深刻的洞见:AI 的记忆不应该是对话历史,而应该是结构化的状态文件。

5.2 小故事拆分原则#

Ralph 要求每个 User Story 必须足够小——能在一个 context window 内完成

为什么?

如果一个 Story 太大,AI 在一次迭代中无法完成,就会出现:

  • 代码写了一半但没有 commit
  • 质量检查无法通过
  • progress.txt 记录不完整
  • 下一轮迭代不知道从哪里继续

拆分原则:

  1. 一个 Story = 一个可交付的功能点

    • ❌ “实现用户管理系统”
    • ✅ “实现用户注册页面”
    • ✅ “实现用户登录页面”
    • ✅ “实现密码重置功能”
  2. 每个 Story 有明确的验收标准

    • 验收标准应该是可验证的、具体的
    • 避免模糊的描述
  3. Story 之间尽量独立

    • 减少跨 Story 的依赖
    • 如果必须依赖,通过 priority 控制顺序

拆分示例:

// ❌ 不好的拆分
{
"id": "US-001",
"title": "实现完整的用户系统",
"description": "包括注册、登录、个人中心、密码修改等所有功能",
"acceptanceCriteria": ["..."]
}
// ✅ 好的拆分
{
"id": "US-001",
"title": "用户注册",
"description": "创建注册表单,支持邮箱注册",
"acceptanceCriteria": [
"表单包含邮箱和密码输入",
"密码强度验证",
"注册成功显示提示"
],
"priority": 1
},
{
"id": "US-002",
"title": "用户登录",
"description": "创建登录表单,支持邮箱密码登录",
"acceptanceCriteria": [
"表单包含邮箱和密码输入",
"登录成功跳转首页",
"登录失败显示错误"
],
"priority": 2
}

5.3 反馈闭环:Typecheck/Test/CI 必须保持绿色#

Ralph 强制要求每次迭代后运行质量检查:

实现 Story
运行 typecheck
运行 tests
全部绿色? ──── 是 ────▶ 提交代码
修复问题(在同一迭代内完成)

这个闭环有几个关键意义:

  1. 即时反馈:问题在当前迭代内就被发现和修复,不会累积
  2. 质量保证:即使 AI 写的代码有 bug,也会被 typecheck 和 tests 捕获
  3. 可合并:每次提交的代码都通过了基本检查,降低了 review 成本

Ralph 没有依赖外部的 CI 系统(如 GitHub Actions),而是在每个迭代内部完成质量检查。这意味着:

  • 不需要等待 CI 流水线
  • 反馈是即时的
  • AI 可以在发现问题后立即修复

5.4 浏览器自动验证:前端 Story 必须通过 dev-browser 验证#

对于前端相关的 User Story,Ralph 要求通过 dev-browser 进行自动验证。

这意味着 AI 不仅要确保代码能通过 typecheck 和 tests,还要确保在浏览器中的表现符合预期

这个设计解决了 AI 编程中的一个经典问题:代码正确 ≠ 视觉正确

  • TypeScript 类型检查通过?✅
  • 单元测试通过?✅
  • 但按钮的颜色不对、布局错位、交互不流畅?❌

dev-browser 验证确保了 AI 能够”亲眼看到”自己的代码效果,从而及时调整。这是 Ralph 对前端开发特殊性的深刻理解。


6. 代码分析:逐段解读 ralph.sh 核心逻辑#

让我们逐段分析 ralph.sh 的核心逻辑。

6.1 参数解析#

#!/bin/bash
# Ralph Wiggum - Long-running AI agent loop
# Usage: ./ralph.sh [--tool amp|claude] [max_iterations]
TOOL="amp"
MAX_ITERATIONS=10
# 解析 --tool 参数
while [[ $# -gt 0 ]]; do
case "$1" in
--tool)
TOOL="$2"
shift 2
;;
*)
MAX_ITERATIONS="$1"
shift
;;
esac
done
# 验证工具选择
if [[ "$TOOL" != "amp" && "$TOOL" != "claude" ]]; then
echo "❌ Invalid tool: $TOOL. Use 'amp' or 'claude'."
exit 1
fi

这段代码展示了 Ralph 的参数解析逻辑:

  • 支持 --tool 参数指定 AI 工具
  • 支持位置参数指定最大迭代次数
  • 默认使用 Amp 工具,最大迭代 10 次
  • 参数验证确保工具名称合法

6.2 分支管理与自动归档#

Terminal window
# 读取 prd.json 中的 branchName
BRANCH_NAME=$(jq -r '.branchName' prd.json)
# 检查是否需要归档上次运行
if git rev-parse --verify "$BRANCH_NAME" >/dev/null 2>&1; then
echo "📦 Archiving previous run on $BRANCH_NAME"
# 创建归档分支,保留上次运行的中间状态
ARCHIVE_BRANCH="archive/${BRANCH_NAME}-$(date +%Y%m%d%H%M%S)"
git branch -m "$BRANCH_NAME" "$ARCHIVE_BRANCH"
fi
# 创建新的 feature branch
git checkout -b "$BRANCH_NAME"

这段代码处理分支的生命周期:

  1. 从 prd.json 读取目标分支名
  2. 如果分支已存在,将其重命名为归档分支(带时间戳)
  3. 创建新的 feature branch 开始本次运行

归档机制确保了:

  • 上次运行的中间状态不会丢失
  • 本次运行在干净的分支上开始
  • 开发者可以随时切换到归档分支查看历史

6.3 主循环#

Terminal window
for (( i=1; i<=MAX_ITERATIONS; i++ )); do
echo ""
echo "═══════════════════════════════════════"
echo "🔄 Iteration $i / $MAX_ITERATIONS"
echo "═══════════════════════════════════════"
echo ""
# 执行 AI 工具
echo "🤖 Running $TOOL..."
if [ "$TOOL" = "amp" ]; then
amp --dangerously-allow-all --print < scripts/ralph/prompt.md > "iteration-${i}.log" 2>&1
else
claude --dangerously-skip-permissions --print < scripts/ralph/prompt.md > "iteration-${i}.log" 2>&1
fi
# 显示本轮输出摘要
echo "📋 Iteration $i output:"
tail -20 "iteration-${i}.log"
# 检测完成信号
if grep -q "<promise>COMPLETE</promise>" "iteration-${i}.log"; then
echo ""
echo "🎉 All stories completed successfully!"
echo "✅ Feature branch '$BRANCH_NAME' is ready for review."
exit 0
fi
# 检查是否还有未完成的 Story
REMAINING=$(jq '[.userStories[] | select(.passes == false)] | length' prd.json)
if [ "$REMAINING" -eq 0 ]; then
echo ""
echo "🎉 All stories completed!"
exit 0
fi
echo "📊 Remaining stories: $REMAINING"
done

主循环的逻辑清晰而优雅:

  1. 循环计数器for (( i=1; i<=MAX_ITERATIONS; i++ )) 控制最大迭代次数
  2. AI 工具调用:根据 $TOOL 选择 amp 或 claude,通过管道将 prompt.md 作为输入
  3. 日志记录:每次迭代的输出保存到 iteration-${i}.log
  4. 完成检测:通过 grep 搜索 <promise>COMPLETE</promise> 信号
  5. 备用检测:即使没有 COMPLETE 信号,也检查 prd.json 中是否还有未完成的 Story
  6. 进度显示:每次迭代结束后显示剩余 Story 数量

6.4 退出逻辑#

Terminal window
# 达到最大迭代次数但未完成
echo ""
echo "❌ Reached max iterations ($MAX_ITERATIONS) without completing all stories"
echo ""
REMAINING=$(jq '[.userStories[] | select(.passes == false)] | length' prd.json)
echo "📊 Remaining stories: $REMAINING"
echo ""
echo "💡 Suggestions:"
echo " 1. Review progress.txt for learnings"
echo " 2. Check prd.json for failed stories"
echo " 3. Consider increasing max_iterations"
echo " 4. Manually complete remaining stories"
echo ""
exit 1

当达到最大迭代次数但仍有未完成的 Story 时,Ralph 不会静默退出,而是:

  1. 明确告知用户失败原因
  2. 显示剩余 Story 数量
  3. 提供具体的后续建议
  4. 以 exit code 1 退出,方便 CI 集成

6.5 完整的控制流#

将以上部分整合,Ralph 的完整控制流如下:

开始
解析参数 (--tool, max_iterations)
读取 prd.json (branchName)
分支管理 (归档旧分支 → 创建新分支)
┌─ 主循环 ───────────────────────┐
│ │
│ 显示迭代信息 │
│ │
│ 调用 AI 工具执行 prompt │
│ │
│ 检测 <promise>COMPLETE</promise>│
│ │ │
│ ├─ 是 → 成功退出 (exit 0) │
│ │ │
│ └─ 否 → 继续 │
│ │
│ 检查 prd.json 是否全部完成 │
│ │ │
│ ├─ 是 → 成功退出 (exit 0) │
│ │ │
│ └─ 否 → 继续下一轮 │
│ │
└─ 达到 max_iterations ──────────┘
显示失败信息和建议
失败退出 (exit 1)

7. 与其他 Agent 框架对比#

7.1 vs. Claude Code 单次使用#

维度Claude Code 单次使用Ralph
执行模式一次对话,完成后停止循环执行,直到全部完成
上下文管理依赖对话历史积累每次 Fresh Context
需求表达自由文本结构化的 prd.json
进度追踪无内置机制prd.json + progress.txt
质量保证开发者手动检查每次迭代自动 typecheck/test
适合场景小型任务、快速原型中型功能、多 Story 交付

关键差异:Claude Code 是一个工具,Ralph 是一个流程。Claude Code 解决了”如何让 AI 写代码”的问题,Ralph 解决了”如何让 AI 持续、可靠地交付完整功能”的问题。

7.2 vs. OpenClaw#

OpenClaw 是另一个流行的 AI Agent 框架,它采用了不同的设计哲学:

维度OpenClawRalph
架构复杂的多 Agent 协作系统单一 Agent 循环
状态管理内部状态机外部状态文件(Git + JSON + TXT)
可观测性需要专用 Dashboard直接查看文件
学习曲线高(需要理解框架概念)低(Bash 脚本 + JSON)
定制性通过配置和插件直接修改脚本和模板
适用规模大型项目、复杂编排中小功能、快速迭代

核心差异:OpenClaw 追求的是通用性和扩展性,Ralph 追求的是简单性和实用性。Ralph 的哲学是:如果一个 Bash 脚本能解决问题,就不需要引入一个框架。

7.3 vs. 其他 Agent 框架#

框架核心思路与 Ralph 的差异
MetaGPT多角色协作(产品经理→架构师→工程师)Ralph 是单一角色循环,更简单
AutoGen多 Agent 对话Ralph 没有 Agent 间对话,只有循环
CrewAI角色+任务+流程编排Ralph 的流程是固定的循环
LangGraph图结构的状态机Ralph 是线性循环,无图结构

Ralph 的”反潮流”之处在于:在所有框架都在追求复杂编排的今天,它选择了最朴素的循环模式。但这恰恰是它的优势——简单、可靠、可理解。


8. 实际使用场景#

8.1 适合的项目类型#

Ralph 最适合以下类型的项目:

✅ 前端 Web 应用

  • 有明确的用户界面需求
  • 需要浏览器验证
  • 有 typecheck 和 tests 基础设施

✅ API 服务

  • 有明确的接口定义
  • 有自动化测试
  • 需求可以拆分为独立的 User Story

✅ 内部工具

  • 需求明确,不需要大量用户调研
  • 快速迭代,快速交付
  • 对代码质量有要求但不需要极致优化

8.2 适合的需求类型#

✅ 适合 Ralph 的需求:

  • 功能明确的中等复杂度需求(5-15 个 User Story)
  • 可以清晰拆分为独立 Story 的需求
  • 有现成代码库作为基础的需求(Greenfield 项目也可以,但需要更多 setup Story)

❌ 不适合 Ralph 的需求:

  • 需求不明确、需要大量探索性开发
  • 需要深度架构设计的系统
  • 高度依赖领域知识的需求
  • 需要大量跨系统集成的需求

8.3 最佳实践#

  1. 花时间在 PRD 上:Ralph 的输出质量直接取决于 PRD 的质量。花时间写好 PRD,拆分好 User Story,比任何优化都有效。

  2. 从小故事开始:第一次使用 Ralph 时,选择一个小功能(2-3 个 Story)进行试验,熟悉流程后再尝试更大的需求。

  3. 善用 progress.txt:定期检查 progress.txt,了解 Ralph 学到了什么。这些信息对于改进后续的 PRD 编写非常有价值。

  4. 保持 CI 绿色:确保项目的 typecheck 和 tests 能够快速运行。如果 CI 太慢,Ralph 的每次迭代都会浪费大量时间。

  5. 定期合并:不要等 Ralph 运行完所有 Story 才合并。每完成 2-3 个 Story 就可以创建一个 PR 进行 review,降低集成风险。


9. 局限性与改进空间#

9.1 客观分析不足#

没有任何工具是完美的。Ralph 也不例外。以下是其当前的局限性:

1. 需求拆分依赖人工

Ralph 要求开发者手动将 PRD 拆分为 prd.json 中的 User Story。对于不熟悉敏捷开发的开发者来说,这一步可能比较困难。如果 Story 拆分不合理(太大或太小),Ralph 的执行效率会大打折扣。

改进方向:引入 AI 辅助拆分——让 Claude Code 自动将 PRD 转换为 prd.json,自动拆分 Story。

2. 错误恢复能力有限

当 AI 在某次迭代中写了错误的代码但 typecheck/tests 未能捕获时,Ralph 会在错误的代码基础上继续迭代。错误的累积可能导致后续迭代越来越偏离正确方向。

改进方向:增加代码 diff review 机制,在每次 commit 前对变更进行自动化代码审查。

3. 依赖特定 AI 工具

Ralph 目前只支持 Amp 和 Claude Code。如果这两个工具不可用(网络问题、API 限制等),Ralph 无法运行。

改进方向:支持更多 AI 工具(Cursor CLI、GPT Engineer 等),增加工具降级策略。

4. 缺乏并行执行能力

Ralph 的循环是串行的——每次只处理一个 Story。对于可以并行开发的独立 Story,这导致效率低下。

改进方向:支持并行模式——同时启动多个 Ralph 实例,各自处理不同的 Story,最后合并。

5. 前端验证依赖 dev-browser

虽然浏览器自动验证是 Ralph 的亮点,但 dev-browser 的配置和使用可能比较复杂,尤其对于没有前端开发经验的 AI。

改进方向:集成更完善的端到端测试框架(如 Playwright),让 AI 能够编写和运行自动化 UI 测试。

6. 知识沉淀的噪声问题

progress.txt 和 AGENTS.md 会随着迭代不断增长,其中可能包含大量无效或过时的信息。如何让 AI 从海量记录中提取有用信息是一个挑战。

改进方向:引入知识精炼机制——定期清理 progress.txt,保留关键 learnings;AGENTS.md 增加过期标记。

9.2 与理想状态的差距#

理想的 AI 自主编程系统应该具备以下能力:

  • 自动理解模糊需求
  • 自动拆分任务
  • 自动发现架构问题
  • 自动进行代码 review
  • 自动处理冲突和合并
  • 自主学习项目规范和模式

Ralph 在”自动循环执行”方面做得很好,但在其他方面仍然依赖人工。这是当前 AI 编程工具的共性限制,不是 Ralph 独有的问题。


10. 总结与展望#

10.1 Ralph 的核心价值#

回顾全文,Ralph 的核心价值可以总结为三个关键词:

简单(Simple)

  • 几百行 Bash 脚本
  • 几个状态文件(prd.json、progress.txt、AGENTS.md)
  • 没有框架,没有依赖,没有黑盒

可靠(Reliable)

  • Fresh Context 避免了长上下文的幻觉问题
  • 每次迭代的质量检查确保代码可合并
  • Git 版本控制确保每一步可追溯

可扩展(Extensible)

  • 支持多种 AI 工具(Amp、Claude Code)
  • prompt.md 可以根据项目需求定制
  • prd.json 的格式可以根据需要扩展

10.2 Ralph 的启示#

Ralph 给 AI 编程领域带来了几个重要的启示:

1. 简单往往比复杂更有效

在 AI Agent 框架追求越来越复杂的今天,Ralph 证明了:一个设计良好的循环 + 几个状态文件,就能解决实际问题。这不是”简陋”,而是”极简”。

2. 结构化状态优于对话历史

Ralph 用 prd.json、progress.txt、AGENTS.md 替代了传统的对话历史,让 AI 的”记忆”变得结构化、可查询、可编辑。这为 AI 编程的状态管理提供了一种新的范式。

3. Fresh Context 是一个被低估的模式

每次迭代使用全新上下文,虽然看起来”浪费”(AI 需要重新学习项目状态),但实际上避免了长上下文的诸多问题。这种”浪费”是一种刻意的trade-off——用更多的 API 调用换取更高的可靠性和更一致的质量。

10.3 未来展望#

随着 AI 编码工具的不断进化,Ralph 的循环模式可能会演化为:

  • 更智能的需求理解:AI 自动将自然语言需求转换为 prd.json
  • 更好的错误恢复:自动检测偏离方向并回滚
  • 并行执行:多实例同时处理独立 Story
  • 跨项目知识迁移:AGENTS.md 的模式可以跨项目复用
  • 与 CI/CD 深度集成:Ralph 运行完成后自动创建 PR、触发 CI、通知 reviewer

但无论未来如何演变,Ralph 的核心理念——循环执行、Fresh Context、结构化状态、需求驱动——都将继续影响 AI 编程工具的设计方向。

10.4 最后的思考#

Ralph 不是一个完美的工具,但它代表了一种务实的、渐进式的 AI 编程方法论。它不追求”AI 替我写完整个项目”,而是追求”AI 替我完成一个个小故事,每个都质量可靠”。

这种**“化整为零、步步为营”**的思路,或许才是当前 AI 编程最务实的落地路径。

在这个追求 AGI 的时代,Ralph 提醒我们:有时候,最聪明的做法不是让 AI 变得更聪明,而是让任务变得更简单。


本文基于 snarktank/ralph 项目(GitHub)编写,项目 Star 数截至 2025 年。Ralph 基于 Geoffrey Huntley 的 Ralph pattern 开发,由 Ryan Carson 在 snarktank 组织下开源。

文章分享

如果这篇文章对你有帮助,欢迎分享给更多人!

Ralph:18K+ Star 的 AI 自主编程循环引擎——让 Agent 持续交付
https://boke.hackerdream.xyz/posts/ralph-ai-agent-loop-deep-dive/
作者
晴天
发布于
2026-04-29
许可协议
CC BY-NC-SA 4.0
Profile Image of the Author
晴天
Hello, I'm 晴天.
公告
欢迎来到我的博客!这是一则示例公告。
音乐
封面

音乐

暂未播放

0:00 0:00
暂无歌词
分类
标签
站点统计
文章
125
分类
17
标签
287
总字数
257,955
运行时长
0
最后活动
0 天前

目录