引言
你有没有遇到过这样的场景:让 AI 帮你写代码,一开始很顺利,但任务稍微复杂一点,上下文就开始爆炸------AI 忘记了之前的约定、重复犯错、甚至改对了又改回去。最后你花了更多时间在纠错上,还不如自己写。
这不是 AI 不够聪明,而是我们缺少一个工程化的编排方式。
最近,Geoffrey Huntley 提出了一个叫 Ralph 的模式,Ryan Carson 也写了详细的实操指南。
名字的灵感来源于《辛普森一家》中的 Ralph Wiggum------那个天真到有点傻、却异常执着的小学生。他总是搞砸事情,但从不放弃,一遍又一遍地尝试,直到(有时)歪打正着地成功。这个角色恰好隐喻了 Ralph 模式的精髓:单个 AI 实例可能笨拙、可能犯错,但通过反复启动、不断积累经验,最终能把活干完。
它的核心思路异常简洁:不要让 AI 在一个超长对话里做所有事,而是反复启动全新实例,每次只做一件小事。
听起来简单,但背后的工程思考值得深挖。
Ralph 是什么
一句话概括:Ralph 是一个 bash 循环脚本,反复调用 AI 编码工具(Amp 或 Claude Code),每次处理 PRD 里的一个用户故事,直到所有故事完成。
工作流程:
prd.json(任务列表)→ 挑一个未完成的 → AI 实现 → 质量检查 → 提交 → 标记完成 → 下一轮
整个系统只需要四个文件:
| 文件 | 作用 |
|---|---|
ralph.sh |
循环脚本,反复启动 AI 实例 |
prompt.md / CLAUDE.md |
每次迭代的指令模板 |
prd.json |
用户故事列表 + 完成状态 |
progress.txt |
经验积累,跨迭代传递知识 |
就这么简单。没有复杂的框架,没有额外的服务,一个 bash 脚本 + 几个文本文件。
为什么有效:三个关键洞察
洞察一:主动丢弃上下文
这是 Ralph 最反直觉的地方。
传统的思路是:上下文越多越好,让 AI 记住所有东西。但实际情况是,上下文越长,AI 的表现越差------注意力稀释、指令遵循率下降、到后期基本在"自由发挥"。
Ralph 的做法恰恰相反:每次迭代都是全新的 AI 实例,零历史上下文。
那记忆怎么办?用文件系统替代对话历史:
prd.json记录"哪些事做完了"progress.txt记录"做这些事学到了什么"git history记录"之前写了什么代码"
这本质上是一种无状态架构------把状态外置到文件系统,类似 web 应用用数据库替代 session。AI 每次启动时读取这些文件,获得刚好够用的上下文,不多也不少。
洞察二:任务粒度决定成败
Ralph 对故事粒度有一个硬约束:每个故事必须在一个上下文窗口内完成。
这意味着不能写"构建整个认证系统",而是要拆成:
"Add login form"
"Add email validation"
"Add auth server action"
"Add session management"
每个故事就是一个 LLM 调用能搞定的事。这个约束看起来限制了很多,但实际上是释放了 AI 的能力------在一个小而明确的任务范围内,当前的大模型表现非常可靠。
Ryan Carson 分享了他们的实际数据:13 个用户故事,15 次迭代,每次 2-5 分钟,总计约 1 小时完成了一个评估系统。
洞察三:经验复利
Ralph 有一个精巧的双层记忆机制:
第一层:progress.txt(会话记忆)
每次迭代完成后,AI 会把踩过的坑、发现的模式追加到这个文件:
markdown
## 2024-01-15 - US-003
- Added email validation
- Files: src/auth/validate.ts
- **Learnings:**
- This project uses Zod for validation, not Joi
- The UserSchema is in db/schema.ts
---
下一个迭代的 AI 会先读这个文件,避免重复犯错。
第二层:AGENTS.md(永久知识)
更有意思的是,Ralph 还会在修改过的目录下创建/更新 AGENTS.md 文件,记录这个模块的约定和坑。这些文件不仅给未来的 AI 迭代用,也给人看。
Ryan Carson 说了一句很到位的话:"By story 10, Ralph knew our patterns." 到第 10 个故事时,AI 已经从前面 9 个迭代中学到了项目的模式、约定和常见陷阱。这就是经验复利。
实际跑起来是什么样
整个流程分三步:
第一步:准备 PRD
把需求拆成小故事,写成 prd.json:
json
{
"branchName": "ralph/task-priority",
"userStories": [
{
"id": "US-001",
"title": "Add priority field to database",
"acceptanceCriteria": [
"Add priority column: 'high' | 'medium' | 'low'",
"Generate and run migration successfully",
"Typecheck passes"
],
"priority": 1,
"passes": false
}
]
}
注意验收标准要明确且可验证:
❌ "Users can log in"
✅ "Email/password fields present"
"Validates email format"
"Shows error on failure"
"Typecheck passes"
第二步:启动 Ralph
bash
./ralph.sh 25 # 最多跑 25 轮
然后就可以去睡觉了。
第三步:监控
bash
# 看哪些故事完成了
cat prd.json | jq '.userStories[] | {id, passes}'
# 看学到了什么
cat progress.txt
# 看 git 历史
git log --oneline -10
关键成功因素
根据 Ryan Carson 的实操经验和 Ralph 的设计,要跑成功需要四件事:
1. 故事要拆得够小
每个故事 = 一个 LLM 调用能完成的工作量。如果不确定能不能一次搞定,就继续拆。
2. 必须有自动化质量门禁
typecheck + test 是底线。没有反馈循环,坏代码会跨迭代累积,后面的 AI 基于错误代码继续写,雪球越滚越大。
3. 验收标准要明确
AI 无法判断"用户体验好不好",但能判断"typecheck 通过不通过"、"测试跑过不通过"。把主观标准转化成客观标准。
4. 手动初始化 progress.txt
在第一轮之前,花时间把项目的关键信息写进去:
markdown
## Codebase Patterns
- This project uses Drizzle ORM, not Prisma
- Migrations use IF NOT EXISTS
- All server actions are in app/*/actions.ts
- Tests require dev server on PORT 3000
## Key Files
- db/schema.ts - database schema
- app/auth/actions.ts - auth logic
这让第一个迭代的 AI 就有一个好的起点,而不是从零探索。
什么时候不该用
Ralph 不是万能的。Ryan Carson 明确列出了不适合的场景:
- 探索性工作 --- 不确定方案时,需要人和 AI 反复讨论
- 没有明确标准的大规模重构 --- AI 不知道"好的重构"长什么样
- 安全关键代码 --- 需要人工逐行审查
- 需要创意设计的部分 --- UI/UX 设计需要人的审美判断
更深一层的思考
Ralph 的价值不在于这个 bash 脚本本身------它揭示了一个更深层的原则:
复杂任务的可靠执行,不依赖更聪明的 AI,而依赖更好的任务编排。
这和软件工程的很多成熟理念是相通的:
- 和微服务架构的思路类似:不构建一个巨大的单体,而是编排多个小而独立的服务
- 和CI/CD 流水线的思路类似:把复杂流程拆成阶段,每个阶段有明确的通过条件
- 和敏捷开发的思路类似:小批量交付,快速反馈,持续改进
Ralph 本质上是把这些工程原则应用到了 AI 编码代理的编排上。
它的三个核心模式------无状态迭代、小粒度任务、文件系统做记忆------可以推广到任何需要 LLM 处理长链路任务的场景。不只是编码,也包括文档撰写、数据分析、测试生成等。
最后
Ralph 给出的不是一个完美的解决方案,而是一个足够好的工程实践。它用最少的工具(一个 bash 脚本、几个文本文件)解决了一个真实存在的问题。
如果你正在尝试让 AI 代理完成多步骤的复杂任务,Ralph 的模式值得借鉴。不需要照搬整个方案,但它的核心思想------主动丢弃上下文、任务极致拆分、经验跨迭代积累------在任何 AI 编码工作流中都有价值。
参考资料:
- Geoffrey Huntley 的 Ralph 原文
- Ryan Carson 的 Step-by-step Guide
- Ralph GitHub 仓库:snarktank/ralph