Agent 工程 - 长时运行之 Ralph Agent
最近 AI 圈子有点疯,一个叫 Ralph Wiggum 的东西突然就火了,火到什么程度呢?有人说它是 “最接近 AGI 的玩意儿”,有人用它通宵干活,第二天早上醒来发现几个代码仓库都妥妥地建好了。甚至还有人专门为它发了个加密货币 $RALPH。
这名字听着是不是有点耳熟?没错,就是《辛普森一家》里那个脑子不太灵光,但总是蜜汁自信,坚持不懈的小胖子 Ralph Wiggum。

一个动画里的憨憨角色,怎么就成了 AI 圈的当红炸子鸡?
一、 Ralph Wiggum 是个啥?
简单来说,Ralph Wiggum 不是一个具体的模型或软件,而是一种工作方法、一种技术理念。它的核心思想就一个字:循环。
具体点说,就是用一个脚本把 AI 编程助手(比如 Anthropic 的 Claude Code)框在一个循环里,给它一个任务,让它不停地尝试、失败、再尝试,直到任务完成为止。它不会因为一次失败就停下来等你,而是会把失败的日志、错误信息作为下一次尝试的“养料”,自己琢磨怎么解决。
这个看似简单的想法,在社区的演化中,其实分裂成了两个版本,我称之为“两个拉尔夫的故事”。
1.1 野生 Ralph
故事的起点,在 2025 年的澳洲乡下。一位名叫 Geoffrey Huntley 的老哥,他是个资深开源开发者,后来跑去养山羊了。在用 AI 助手写代码的时候,他被一个问题搞得不胜其烦——“人在环路中”(human-in-the-loop)的瓶颈。
当时的 AI 助手,更像个听话的实习生。你让它干活,它干砸了,就会停下来,把一堆错误甩给你,等你分析完,再给它新的指令。这个过程极其打断心流,效率很低。
Huntley 老哥一琢磨,能不能让 AI 自己“死磕”呢?于是,他写了一个极其简单粗暴的 5 行 Bash 脚本,并用他最喜欢的《辛普森一家》角色 Ralph Wiggum 来命名。这个脚本的核心长这样:
while :; do cat PROMPT.md | claude-code ; done这行代码的意思就是:
while :; do ... done:创建一个无限循环,也就是俗称的“死循环”。cat PROMPT.md:读取一个叫做PROMPT.md的文件,这个文件里写着要 AI 干的活儿。|:这是管道符,把前面命令的输出,作为后面命令的输入。claude-code:调用 AI 编码助手。
连起来就是:不断地把任务指令喂给 AI,让它执行,执行完了再把指令喂给它,周而复始,永不停止。

这套打法的精髓,Huntley 称之为“上下文压力锅”(contextual pressure cooker)。它不做任何花里胡哨的处理,直接把 AI 的所有输出——无论是成功的代码、失败的日志、还是胡言乱语(hallucinations)——全部通过命令行历史再次塞回给 AI。AI 在下一次迭代中,就能“看到”自己上次干的好事,包括完整的错误堆栈。
这种感觉,就像你把一个犯了错的人关进小黑屋,屋里只有他自己和一堆他搞砸的烂摊子,不收拾干净就不准出来。AI 被迫直面自己的失败,没有任何“保护措施”。Huntley 和其他人认为,这种“天真的坚持”(naive persistence)和未经过滤的反馈,会给模型施加巨大的压力,逼着它在绝望中“悟”出正确的解决方案,只为了能跳出这个该死的循环。
这就是最初的、野生的 Ralph,它的哲学是:大力出奇迹,用坚持和蛮力压倒一切困难。
1.2 Anthropic Ralph
Huntley 的这个“骚操作”很快就在开发者社区传开了。到了 2025 年末,Anthropic 公司(Claude 的开发商)的 Claude Code 负责人 Boris Cherny,将这个黑客方法正式化,做成了一个官方插件 ralph-wiggum。
然而,官方的实现和 Huntley 的野生版在哲学上有了微妙但关键的区别。如果说 Huntley 的版本是混乱、野蛮生长的,那 Anthropic 的版本就是“无菌化”、可控的企业级方案。
官方版的核心理念,从“大力出奇迹”转变成了“失败即数据”(Failures Are Data)。它不再是简单粗暴地把所有东西都怼回去,而是引入了一个更精巧的机制——“停止挂钩”(Stop Hook)。
这个官方插件的工作流程是这样的:
拦截退出(Intercept the Exit):当 Claude Code 认为自己已经完成了任务,尝试退出命令行时,
ralph-wiggum插件会像个门卫一样把它拦住。验证承诺(Verify Promise):插件会检查 Claude 的输出里,是否包含一个特定的、预先定义好的“完成承诺”(Completion Promise),比如一个 XML 标签
<promise>COMPLETE</promise>。这个承诺就像是任务完成的“接头暗号”。注入反馈(Feedback Injection):
如果找到了“完成承诺”,门卫放行,循环结束,任务成功。
如果没找到,说明任务还没搞定(比如,单元测试没通过)。这时,插件会把失败的结果(比如测试报告)格式化成一个结构化的数据对象,然后连同最初的提示,一起重新提交给 Claude,开始新一轮的迭代。
你看,区别就出来了:
野生版:反馈是原始、混乱、无差别的。AI 看到的是一整个终端的输出历史。
官方版:反馈是结构化、干净、有针对性的。AI 看到的是明确的失败原因。
这就引出了“两个拉尔夫”的关键选择:
亨特利版 Ralph(Bash 脚本/社区 Forks):更适合混乱的、创造性的探索。你想让 AI 通过纯粹的、不受约束的“死磕”来解决问题,可能会有意外之喜。
官方版 Ralph(Anthropic 插件):更适合企业级工作流。它被严格的 Token 限制和安全钩子约束,目标是可靠地修复一个构建失败的问题,而不用担心 AI 陷入无限的幻觉循环中。
一句话总结:Huntley 证明了循环是可行的;Anthropic 证明了循环可以是安全的。
二、 Ralph 如何实现「无人值守」?
光说理念有点虚,咱们直接上干货,看看一个典型的、社区驱动的 Ralph Wiggum 工作流到底是怎么搭建的。这套系统设计得相当精巧,充满了后端开发的智慧:通过简单的工具和约定,构建一个强大的自动化系统。
下面我们以 Ryan Carson 等社区贡献者完善的方案为例,来拆解它的核心组件和工作流程。
2.1 Ralph 的工具箱
要让 Ralph 跑起来,你需要在你的项目里准备一个专门的文件夹,通常是 scripts/ralph/,里面装着它全部的“作案工具”:
scripts/ralph/
├── ralph.sh # 核心驱动脚本,那个无情的循环就在这里
├── prompt.md # AI 的行动指南,每次循环都要读一遍的“圣经”
├── prd.json # 任务清单 (PRD),AI 的 "Jira Board"
└── progress.txt # 进度与学习日志,AI 的短期记忆这四个文件各司其职,构成了一个最小但完整的自动化闭环:
ralph.sh:引擎。负责启动和维持循环,调用 AI,检查结果,决定是继续还是收工。prompt.md:大脑。定义了 AI 在每一次迭代中的思考模式和行为准则,是整个系统里最重要的“提示工程”产物。prd.json:待办事项。以结构化的 JSON 格式定义了所有需要完成的子任务(User Stories),包括优先级和完成状态。progress.txt:记忆。记录了 AI 在之前迭代中都干了什么、学到了什么,避免重复犯错,并实现知识的“复利”增长。
接下来,我们把每个文件都拆开,仔细看看里面的门道。
2.2 ralph.sh 脚本详解
这是驱动一切的发动机。我们来看一个典型的 ralph.sh 实现:
#!/bin/bash
set -e
# 接收一个可选参数作为最大迭代次数,默认为 10 次
MAX_ITERATIONS=${1:-10}
# 获取脚本所在的目录,方便引用其他文件
SCRIPT_DIR="$(cd "$(dirname \
"${BASH_SOURCE[0]}")" && pwd)"
echo "🚀 Starting Ralph"
# 启动一个从 1 到 MAX_ITERATIONS 的循环
for i in $(seq 1 $MAX_ITERATIONS); do
echo "═══ Iteration $i ═══"
# 这是整个脚本最核心的一行
OUTPUT=$(cat "$SCRIPT_DIR/prompt.md" \
| amp --dangerously-allow-all 2>&1 \
| tee /dev/stderr) || true
# 检查输出中是否包含“完成承诺”
if echo "$OUTPUT" | \
grep -q "<promise>COMPLETE</promise>"
then
echo "✅ Done!"
exit 0 # 成功退出
fi
# 短暂休眠,避免 API 调用过于频繁
sleep 2
done
echo "⚠️ Max iterations reached"
exit 1 # 达到最大迭代次数,异常退出这段脚本虽然不长,但对于后端同学来说,里面有很多熟悉的味道。我们来逐行分析一下:
set -e:这是一个非常重要的安全设置。它告诉 Bash,如果脚本中任何一个命令执行失败(返回非零退出码),就立即终止整个脚本。这可以防止在某个环节出错后,后续的命令继续执行,造成更大的混乱。MAX_ITERATIONS=${1:-10}:这是 Ralph 的“保险丝”。它设置了一个最大迭代次数,防止 AI 陷入死循环,把你的 API 账单烧穿。你可以通过命令行参数传入这个值,比如./scripts/ralph/ralph.sh 25。SCRIPT_DIR="...":一个健壮的脚本必备的写法,确保无论你在哪个目录下执行这个脚本,它总能正确地找到prompt.md等同级文件。for i in $(seq 1 $MAX_ITERATIONS):主循环体,控制 Ralph 的工作轮次。
下面是最关键的一行命令,我们把它拆解开:
OUTPUT=$(cat "$SCRIPT_DIR/prompt.md" | amp --dangerously-allow-all 2>&1 | tee /dev/stderr) || true这是一个经典的 Unix/Linux 管道链,数据像流水一样从左向右处理:
cat "$SCRIPT_DIR/prompt.md":读取prompt.md文件的内容,并将其输出到标准输出(stdout)。|:管道符,将左边命令的 stdout 连接到右边命令的标准输入(stdin)。amp --dangerously-allow-all:这是调用 AI 助手的地方(amp是一个流行的 Claude Code 命令行工具)。它从 stdin 读取prompt.md的内容作为指令。--dangerously-allow-all参数授予 AI 执行任意终端命令的权限,这是 Ralph 能够修改文件、运行测试、提交代码的前提,但也是巨大的安全风险,我们后面会详细说。2>&1:这是一个重定向操作。它把标准错误(stderr,文件描述符为 2)合并到标准输出(stdout,文件描述符为 1)。这意味着,无论 AI 在执行过程中是正常输出还是报错,所有的信息都会被送到同一个输出流里。这对于“上下文压力锅”至关重要,因为我们希望 AI 看到所有的结果,尤其是错误结果。| tee /dev/stderr:tee命令像一个三通管。它从 stdin 读取数据,然后做两件事:一份数据写到指定的文件(这里是/dev/stderr,也就是标准错误流,所以你能在屏幕上实时看到 AI 的输出),另一份数据再原样输出到 stdout。OUTPUT=$(...):$(...)是命令替换语法,它会捕获整个管道链最终的 stdout 输出,并将其赋值给变量OUTPUT。|| true:这是一个容错处理。||表示如果前面的命令失败(返回非零退出码),则执行后面的命令。true命令永远成功返回 0。这里加它的原因是,如果 AI 执行的某个命令(比如npm test)失败了,会导致amp工具退出并返回一个错误码,如果没有|| true,set -e就会让整个脚本立即中止。我们不希望这样,我们希望即使单次迭代失败,循环也能继续下去,所以用|| true来“欺骗”set -e,让脚本总能继续执行。
循环的最后,通过 grep -q "<promise>COMPLETE</promise>" 来判断 AI 是否已经发出了“任务完成”的信号。如果找到了,就正常退出;如果循环次数用尽还没找到,就异常退出,提醒你去检查问题。
2.3 prompt.md 设计
如果说 ralph.sh 是骨架和肌肉,那么 prompt.md 就是灵魂和大脑。这个文件定义了 AI 在每一轮迭代中应该遵循的思维框架和行为准则。它的好坏,直接决定了 Ralph 的工作效率和质量。
这是一个精心设计的 prompt.md 示例:
# Ralph Agent Instructions
## Your Task
You are an autonomous AI software engineer. Your goal is to complete user stories by writing and modifying code. Follow these steps precisely in each iteration.
1. **Read Context**:
* Read the task list in `scripts/ralph/prd.json`.
* Read the progress log in `scripts/ralph/progress.txt`. Pay close attention to the "Codebase Patterns" section at the top.
2. **Select Task**:
* Check you are on the correct git branch defined in `prd.json`.
* Pick the ONE story from `userStories` with the highest priority (lowest `priority` number) where `passes: false`.
3. **Implement**:
* Implement the changes required for that single story.
* Focus only on fulfilling the acceptance criteria for that story.
4. **Verify**:
* Run the type checker (e.g., `npm run typecheck`).
* Run the unit tests (e.g., `npm test`).
* If both pass, proceed. If not, analyze the errors and fix them in the next attempt. This entire loop is one attempt.
5. **Document Learnings**:
* If you discovered any reusable patterns, gotchas, or important conventions, update the `AGENTS.md` file in the relevant directories.
* Append a summary of your work and key learnings to `scripts/ralph/progress.txt`.
6. **Commit & Update Status**:
* Commit your changes with a clear message, like: `feat: [Story ID] - [Story Title]`.
* Update `prd.json` to set the `passes` field for the completed story to `true`.
## Progress Format
When appending to `progress.txt`, use this format:
---
## [Date] - [Story ID]
- **What was implemented**: A brief description.
- **Files changed**: List of modified files.
- **Learnings**:
- Patterns discovered that might be useful later.
- Gotchas or tricky parts encountered.
---
## Codebase Patterns
Add any reusable patterns you find to the TOP of `progress.txt` under this heading. This is your long-term memory for this session.
## Stop Condition
**If and only if ALL stories in `prd.json` have `passes: true`, you MUST end your response with the following line and nothing else:**
<promise>COMPLETE</promise>
Otherwise, end your response normally without the promise tag.这个 Prompt 的设计堪称典范,它把一个复杂的软件开发流程,拆解成了一个 AI 可以理解和执行的、确定性的算法:
角色设定:开宗明义,告诉 AI 它的身份是“自主 AI 软件工程师”。
指令清晰:用编号列表给出了一个严格、有序的操作流程(SOP)。这对于 LLM 来说至关重要,它减少了 AI 自由发挥导致的不确定性。
上下文感知:指令 1 强制 AI 在每次开始工作前,必须先“阅读”任务清单和历史记录,确保它知道“要做什么”和“已经做了什么”。
任务聚焦:指令 2 和 3 强调一次只做一个任务,避免范围蔓延(scope creep),这与敏捷开发的原则不谋而合。
自我验证:指令 4 把测试和类型检查内化为工作流程的一部分,创建了一个紧密的反馈闭环。
知识沉淀:指令 5 要求 AI 主动记录和总结,这是实现“知识复利”的关键。它不仅要完成任务,还要提炼经验。
状态管理:指令 6 让 AI 负责维护自己的任务状态(更新
prd.json)和代码版本(git commit),形成了一个完整的、可追溯的工作流。明确的终止条件:最后,“Stop Condition”部分用极其明确和强硬的语气,定义了循环的退出信号。这种确定性的信号,是连接自动化脚本和 AI 推理的桥梁。
2.4 prd.json 与 progress.txt 设计
这两个文件是 Ralph 工作流的“数据平面”,它们将状态和记忆外部化,从而解决了 LLM 本身无状态、上下文窗口有限的问题。
prd.json
prd.json 文件本质上是一个简化的产品需求文档(Product Requirements Document)。它把一个大功能,拆分成一个个小的、可执行的“用户故事”(User Stories)。
{
"branchName": "ralph/feature-login",
"userStories": [
{
"id": "US-001",
"title": "Add login form component",
"acceptanceCriteria": [
"Create a React component for the login form.",
"Component should include email and password input fields.",
"Component should include a 'Login' button.",
"typecheck must pass."
],
"priority": 1,
"passes": false,
"notes": "Use the existing UI library for form elements."
},
{
"id": "US-002",
"title": "Implement email validation on front-end",
"acceptanceCriteria": [
"When user types in the email field, validate its format.",
"Display an error message if the email format is invalid.",
"The validation should be triggered on blur."
],
"priority": 2,
"passes": false,
"notes": ""
},
{
"id": "US-003",
"title": "Create server action for authentication",
"acceptanceCriteria": [
"Create a new server action to handle login.",
"It should accept email and password.",
"For now, just log the credentials to the console.",
"Return a success or error message."
],
"priority": 3,
"passes": false,
"notes": ""
}
]
}这个 JSON 文件的设计非常清晰:
branchName:指定了本次系列任务工作的 Git 分支,实现了开发工作的隔离。userStories:一个数组,包含了所有的子任务。id和title:任务的唯一标识和简短描述。acceptanceCriteria:验收标准,这是重中之重。它用自然语言告诉 AI,“完成”这个任务具体意味着什么。标准越明确、越可被机器验证(如 "typecheck must pass"),Ralph 的成功率就越高。priority:决定了任务的执行顺序,AI 会从数字最小的开始做。passes:一个布尔标志,初始为false。AI 每完成一个任务,就会在prompt.md的指导下,把这个值更新为true。这个字段是整个系统的**状态机**,当所有passes都为true时,AI 就知道大功告成,可以发出<promise>COMPLETE</promise>了。
通过把任务状态外部化到这个文件里,即使 AI 在某次迭代中崩溃或者整个循环被中断,下次重启时,它也能准确地知道该从哪里继续,实现了工作的可续传。
progress.txt
如果说 prd.json 是计划,那 progress.txt 就是日志。它在每次循环中,都被 AI 读取和更新,扮演着“会话记忆”的角色。
一个 progress.txt 文件的内容可能长这样:
# Ralph Progress Log
Started: 2026-01-07
## Codebase Patterns
- All server actions should be defined in `app/actions/*.ts`.
- Use `zod` for all data validation.
- React state for timeouts should use `useRef<NodeJS.Timeout | null>(null)`.
## Key Files
- Database schema: `db/schema.ts`
- Authentication logic: `app/auth/actions.ts`
---
## 2026-01-07 - US-001
- **What was implemented**: Created the basic `LoginForm` React component with email/password fields and a button.
- **Files changed**: `components/LoginForm.tsx`, `app/login/page.tsx`
- **Learnings**:
- The project uses Tailwind CSS for styling.
- Discovered a reusable `Button` component in `components/ui/Button.tsx`. Added this pattern to `AGENTS.md`.
---
## 2026-01-07 - US-002
- **What was implemented**: Added client-side email validation using a simple regex.
- **Files changed**: `components/LoginForm.tsx`
- **Learnings**:
- The initial regex was too strict. Found a better one from an online resource.
- Realized form state management is getting complex, might need a library like `react-hook-form` for future stories. This is a gotcha.
---这个文件的作用是双重的:
作为日志:它记录了每次迭代完成的工作,方便人类开发者追溯 AI 的“心路历程”。
作为记忆:
prompt.md指示 AI 在每次开始时都要阅读这个文件。这意味着,在处理US-003时,AI 已经知道了它在US-001和US-002中学到的东西(比如项目使用了 Tailwind CSS,有一个可复用的按钮组件等)。这种机制让知识在迭代中不断累积,形成“知识复利”。AI 解决后面任务的效率和准确性会越来越高,因为它对代码库的“理解”在不断加深。
顶部的 Codebase Patterns 部分尤其关键。AI 会把在实践中摸索出的最佳实践、代码规范、或者“坑”记录在这里,这相当于为当前这个项目动态生成了一份“开发规范”,让后续的所有工作都遵循统一的标准。
三、 怎样才能让 Ralph 好好「上班」?
看了上面的工作流,你可能会觉得这套系统太牛了,简直是程序员的“永动机”。但实际上,Ralph 的表现好坏,极度依赖于操作者——也就是你——为它搭建的工作环境。
想让 Ralph 高效、稳定地“上班”,而不是摸鱼或者搞破坏,你必须做好以下几件事。这几点,与其说是“提示工程”,不如说是“系统工程”。
3.1 小而美的 User Story
这是让 Ralph 工作的第一条,也是最重要的一条军规。你必须把一个大的功能需求,拆解成一系列非常小、非常具体的子任务。
为什么?因为 LLM 的“工作记忆”是有限的,这个“工作记忆”就是它的上下文窗口(Context Window)。如果一个任务太复杂,需要一次性修改十几个文件,思考多层逻辑,那它大概率会中途“失忆”,顾头不顾尾,最后输出一堆乱码。
来看一个对比:
❌ 错误的拆分:
"id": "US-001", "title": "Build entire authentication system"这个任务太庞大了。它包含了数据库 schema 设计、API 路由、前端表单、状态管理、加密、Session/JWT 处理等等。AI 根本不可能在一个迭代里搞定,它会直接懵掉。
✅ 正确的拆分:
"Add user table to database schema""Create login form UI component""Add client-side email validation""Create server action for login""Implement password hashing with bcrypt""Generate and return JWT on successful login"
一个好的 User Story,应该能在一个原子性的 Git Commit 中完成。它的目标单一,验收标准明确。作为开发者,你的核心价值之一,就体现在这种将复杂问题分解为简单、可执行步骤的能力上。
3.2 不可或缺的反馈闭环
Ralph 的工作模式是“试错”。如果没有一个快速、可靠的机制来告诉它“你错了”,那它就会在一个错误的方向上狂奔,导致灾难性的后果。这个机制,就是自动化的反馈闭环。
在软件开发中,我们最常用的反馈闭环就是:
静态类型检查:比如 TypeScript 的
tsc命令 (npm run typecheck)。它能在代码运行前就发现大量的类型错误。单元测试**/集成测试**:比如用 Jest, Vitest, Playwright 等工具编写的测试用例 (
npm test)。它能验证代码的逻辑是否符合预期。
在 Ralph 的工作流中,这些工具不再是“锦上添花”,而是“生死攸关”。prompt.md 中明确要求 AI 在每次实现后都必须运行这些检查。
如果测试通过,说明这步走对了,可以
git commit,然后继续下一个任务。如果测试失败,测试工具输出的错误报告,就成了最宝贵、最精确的反馈。AI 在下一次迭代中读到这个报告,就能知道“哦,原来是这个函数的返回值类型错了”,或者“这个边界条件没考虑到”,从而进行有针对性的修复。
没有**自动化测试的 Ralph,就像一匹脱缰的野马,你根本不知道它会把你带到哪里去。**
3.3 明确的 Acceptance Criteria
AI 不是你肚子里的蛔虫,它无法猜测你的意图。你必须在 prd.json 的 acceptanceCriteria 字段里,用最清晰、最没有歧义的语言,告诉它“完成”的标准是什么。
来看一个对比:
❌ 模糊的标准:
"Users can log in"“可以登录”是什么意思?是通过账号密码?还是手机号?登录成功后会发生什么?失败了又该怎样?AI 完全没法干活。
✅ 清晰的标准:
"Email and password input fields must be present.""The form must validate the email format on blur.""An error message 'Invalid credentials' should be shown on login failure.""On successful login, the user should be redirected to the '/dashboard' page.""Thenpm run typecheckcommand must pass.""The login-related tests inauth.test.tsmust pass."
最好的验收标准,是那些可以被机器自动验证的标准。比如“测试必须通过”、“类型检查必须通过”、“在 localhost:3000/login 页面上能看到某个元素”。你把这些写清楚,AI 就能自己对答案。
3.4 让 AI 持续学习
Ralph 的强大之处,在于它不是一个失忆的金鱼。通过 progress.txt 和 AGENTS.md 这两个文件,它实现了知识的积累和传承。
progress.txt:这是会话级(Session-level)的**短期记忆**。它只在当前这次“上夜班”的任务中有效。AI 通过回顾它,知道自己刚刚踩了什么坑,发现了什么小技巧,从而在后续的几个小时里表现得越来越好。AGENTS.md:这是项目级(Project-level)的长期记忆。这个想法非常酷。prompt.md会指示 AI,如果发现了可以在整个项目中复用的模式、约定或“大坑”,就把它写到被修改文件所在目录下的AGENTS.md文件里。
举个例子,假设 AI 在修改 src/components/ 目录下的文件时,发现所有组件都遵循一个特定的 props 命名规范。它就会被指示在 src/components/AGENTS.md 文件里记上一笔。
# AGENTS.md
This document is for AI agents and humans to understand the conventions of this directory.
- **Props Naming**: All component props should be prefixed with `on` for event handlers (e.g., `onClick`, `onChange`).
- **Dependencies**: Do not introduce new UI libraries without prior approval in the main PRD.这样一来,下一次不管是另一个 Ralph 会话,还是一个新的“人类”开发者加入项目,都可以通过阅读这些分布在代码库中的 AGENTS.md 文件,快速了解各个模块的“潜规则”。这相当于让 AI 参与到了项目文档的建设中,实现了知识的永久沉淀。
3.5 搞定前端 UI 测试
对于后端来说,API 的测试相对直接。但对于前端 UI 呢?AI 修改了一个按钮的样式,怎么知道改对了还是改丑了?
社区也给出了方案,比如集成 dev-browser 这样的工具。它可以让 AI 通过写脚本来控制一个无头浏览器(Headless Browser),执行诸如“打开页面”、“点击按钮”、“填写表单”等操作,最后截一张图。
虽然 AI 目前还不能很好地“审美”,但它至少可以验证:
页面是否成功加载,没有崩溃。
点击按钮后,预期的元素(比如一个弹窗)是否出现。
表单提交后,页面是否跳转到了正确的地方。
通过截图,AI 至少能确保 UI 在功能上是完整的,没有出现明显的布局错乱。这为 Ralph 应用于全栈开发提供了可能。
四、风险与注意事项
看到这里,你可能已经摩拳擦掌,准备让 Ralph 今晚就给你家的祖传代码库来一次“彻夜升级”了。且慢,天底下没有免费的午餐。Ralph Wiggum 这种强大的自动化工具,也伴随着同样巨大的风险。
4.1 失控的 API 调用
Ralph 的核心是循环,而且是一个在成功前永不停止的循环。这意味着,如果你给它的任务定义不清,或者任务本身就是不可能完成的(比如依赖一个不存在的外部服务),它就可能陷入真正的死循环。
LLM 的 API 调用是按 Token 计费的。一个不知疲倦的 AI 在那里通宵达旦地尝试,你的 API 账单可能一夜之间就从“尚可接受”飙升到“需要卖房”。有社区用户就警告说,要小心 Ralph 把你的 Token 预算给干爆了。
解决方案:
永远设置
--max-iterations参数! 这是你的救命稻草,是成本的“熔断器”。根据任务的复杂性,设置一个合理的上限,比如 20 或 50。如果达到上限还没完成,脚本会自动退出,提醒你介入调查。从小的迭代次数开始。先用
--max-iterations=3跑一下,看看它的行为是否符合预期,然后再逐步增加。监控你的 API 使用量。在跑一个长时间的 Ralph 会话时,定期去云服务商的控制台看一眼费用,心里有数。
4.2 终端权限与安全沙箱
这是 Ralph 最大的安全隐患,没有之一。
为了能修改文件、安装依赖、运行测试、提交代码,我们通常需要给 AI 助手完全的终端访问权限,也就是 amp 工具的那个 --dangerously-skip-permissions 或 --dangerously-allow-all 参数。
“dangerously”这个词可不是开玩笑的。它意味着 AI 可以在你的电脑上执行任何命令,包括但不限于 rm -rf /。虽然 LLM 本身没有“恶意”,但它可能会在解决问题的过程中“产生幻觉”,或者错误地理解了某个命令的含义,从而执行破坏性的操作。比如,它为了“清理构建缓存”,可能会把你的整个项目目录给删了。
解决方案:
绝对不要在你的主开发机上直接运行!
使用沙箱环境(Sandbox)。这是最专业、最安全的做法。你可以:
使用 Docker 容器:为每个 Ralph 会话启动一个干净的 Docker 容器,把项目代码挂载进去。AI 在容器里怎么折腾都行,即使搞砸了,也只是毁掉一个容器,你的宿主机安然无恙。
使用一次性的云**虚拟机(VM)**:在 AWS, GCP, Azure 等云平台上,开一个配置最低的虚拟机,把代码 clone 下去跑。跑完任务,直接把虚拟机销毁。成本低,隔离性好。
使用 GitHub Codespaces 或类似服务:这些服务本身就提供了一次性的、基于云的开发环境,是运行 Ralph 的理想场所。
一句话:把 Ralph 当成一个你既不了解也不完全信任的实习生,把它关在安全屋里干活。
五、Warren's take
扒了半天 Ralph Wiggum,从它的野生起源到企业级实现,再到核心工作流和避坑指南,相信大家对它已经有了比较立体的认识。最后,我想聊聊我个人的一些思考。
从「对话式」到「委托式」的范式转移
Ralph 的出现,标志着我们与 AI 协作模式的一次深刻变革。过去,我们使用 Copilot 或其他 AI 助手,更多是“对话式”或“结对编程”模式。AI 像个坐在你旁边的副驾驶,你一句我一句,它提供建议,但最终的决策和执行还是由你来掌控。
而 Ralph 代表的是“委托式”模式。你不再是手把手地教,而是像一个项目经理或架构师,把一个大目标拆解成清晰的子任务(写好 prd.json),定义好验收标准和工作流程(设计好 prompt.md 和测试),然后把整个项目“委托”给 AI 去执行。你从一个执行者,变成了一个系统设计者和任务定义者。这是一种更高维度的抽象,也是对开发者能力提出的新要求。
「失败」不再是 Bug,而是**训练数据**
传统软件开发的理念是尽可能避免失败。我们写代码追求一次写对,Bug 是需要被消灭的敌人。但 Ralph 的哲学完全不同,它拥抱失败,甚至可以说,它依赖失败来学习。
无论是 Huntley 的“上下文压力锅”,还是 Anthropic 的“失败即数据”,核心都是将错误信息、失败日志作为下一轮迭代的关键输入。每一次失败,都为 AI 提供了一次宝贵的学习机会,让它更接近正确答案。这套机制,把“试错”这个成本极高的过程,通过 API 调用变得廉价且高效。它提醒我们,在 AI 时代,构建一个能从失败中自动学习的系统,可能比追求单次交互的完美更重要。
系统的胜利,而非单一模型的胜利
很多人看到 Ralph 的惊人表现,第一反应可能是“哇,Claude Code 这个模型太牛了!”。模型当然是基础,但 Ralph 的成功,更多是系统的胜利。
一个强大的 LLM,就像一颗高性能的 CPU。但你只有 CPU 是没法打游戏的,你需要主板、内存、显卡、操作系统和软件的协同工作。Ralph 就是这样一套精心设计的“主板”和“操作系统”:
ralph.sh循环是主板上的总线,驱动着数据流动。prd.json和progress.txt是内存和硬盘,提供了状态管理和持久化记忆。自动化的测试脚本是显卡,提供了结果的“渲染”和验证。
prompt.md是操作系统内核,调度和指挥着 CPU(LLM)该如何工作。
这个案例完美地诠释了,将软件工程的经典思想(如自动化、模块化、状态管理、反馈闭环)应用于与 LLM 的交互,能爆发出多大的能量。这已经超出了“提示工程”的范畴,进入了“AI 系统工程”的领域。
未来,CRUD boy/girl 的价值可能会被严重稀释,而那些既懂业务,又懂架构,还能为 AI 设计高效工作流的“AI 架构师”或“AI 系统工程师”,将变得炙手可热。
六、工程化
0