快速摘要
Ralph Loop 是一种让 AI 编程助手在同一个任务上持续迭代、直到真正完成目标的自动化技术。 它的核心思想极其简单——用一个 Bash 循环反复把同一份提示词喂给 AI 代理,而 AI 每次迭代时都能看到上一轮修改过的文件和 Git 提交记录,从而实现"自我纠错、持续改进"的闭环。这项技术由独立开发者 Geoffrey Huntley 于 2024 年初发现并命名,如今已被 Anthropic 纳入 Claude Code 官方插件体系,并衍生出多个社区版本。它特别适合有明确完成标准的任务,比如单元测试编写、代码重构、依赖迁移和批量文档生成。 如果你正在使用 Claude Code 或其他命令行 AI 编程工具,Ralph Loop 几乎是你必须掌握的一项"挂机编程"技能。往下看,莫潇羽@源码七号站 会带你从原理到实操,完整拆解这项技术的每一个细节。
一、到底什么是 Ralph Loop?
如果你用过 Claude Code、Cursor、Copilot 这类 AI 编程助手,大概率遇到过一个共同的挫败体验:AI 帮你写了一段代码,完成了大约百分之八十的工作,然后它就停了。你不得不反复对话、手动纠正、来回拉扯,才能把剩下的百分之二十补完。这种"最后一公里"的磨损感,是当前 AI 辅助编程最大的效率瓶颈之一。
Ralph Loop 就是为了解决这个问题而诞生的。
从技术角度看,Ralph Loop 的本质就是一个 Bash 无限循环脚本:
while :; do
cat PROMPT.md | claude-code
done
这三行代码做的事情非常直接:它会反复读取你事先写好的提示词文件(PROMPT.md),然后把内容传给 Claude Code 的命令行工具执行。每次 AI 完成一轮工作尝试退出后,脚本会立刻再次启动新一轮,把同样的提示词重新喂给 AI。
关键在于——虽然提示词没变,但 AI 每次重新启动时,看到的是上一轮修改之后的代码文件和 Git 提交历史。这意味着 AI 不是在做无意义的重复劳动,而是在每次迭代中基于上一轮的成果继续推进。它会检查自己之前写的代码,发现其中的问题,然后尝试修复。如果测试没通过,它会分析失败原因并重新实现。如此循环往复,直到任务真正完成。
这个技术的名字来源于美国动画片《辛普森一家》中的角色 Ralph Wiggum。这个角色以"迷迷糊糊、总是犯错但永远不放弃"著称,一些观众对他那句经典台词"Me fail English? That's unpossible!"印象深刻。Geoffrey Huntley 觉得这种"执拗地一直干下去"的气质,恰好就是这个循环迭代技术的精髓,于是用 Ralph 来命名。而且"Ralph"在英语俚语中还有"呕吐"的意思——Huntley 表示,当他在 2024 年 2 月首次发现这个技术时,意识到它对软件行业意味着什么,那种冲击感"让人想吐"。
从概念上理解 Ralph Loop 并不难,但它背后隐含的设计哲学却相当深刻。接下来莫潇羽@源码七号站 会逐层拆解它的工作原理、使用方法以及各种进阶技巧。
二、Ralph Loop 解决了什么核心痛点?
要理解 Ralph Loop 为什么有效,先得搞清楚当前 AI 编程助手存在的几个关键瓶颈。
上下文窗口的"腐烂"问题
所有基于大语言模型(LLM)的编程工具,都受到"上下文窗口"(Context Window)的限制。以 Claude Code 为例,它的上下文窗口大约为 200,000 个 Token。听起来很大,但在实际使用中,这个空间会被迅速填满——MCP 服务器的配置信息可能就占去将近一半,再加上你的代码文件、对话历史、错误日志、测试输出,上下文窗口很快就到达极限。
当上下文窗口满了以后,AI 工具会触发一种叫做"压缩"(Compaction)的机制,自动对之前的对话内容做摘要,丢弃一些它认为不重要的信息,腾出空间来处理新的内容。问题在于,这个压缩过程是有损的。被丢弃的信息中,可能包含对当前任务至关重要的需求说明、之前的修复尝试记录,甚至是你明确给出的约束条件。
一旦关键上下文被压缩掉了,AI 就开始"跑偏"——它可能会重复犯已经修复过的错误,忘记你之前的特定要求,或者在完全错误的方向上越走越远。这个现象被形象地称为"上下文腐烂"(Context Rot)。
开发者 Dex Horthy 提出过一个"笨区与聪明区"(Dumb Zone vs. Smart Zone)的概念来描述这个问题:当上下文窗口的使用率超过百分之六十到七十时,LLM 的表现会明显下降,进入所谓的"笨区"。Ralph Loop 的设计哲学就是让 AI 始终工作在"聪明区"——通过每次迭代都使用全新的上下文窗口,从根本上避免上下文腐烂的发生。
AI "半途而废"的问题
另一个常见问题是 AI 编程助手的"半途而废"倾向。当任务复杂度超过一定阈值后,AI 往往会在完成了主要功能后自行停下来,给你一个"基本可用但细节粗糙"的结果。这不是因为 AI 偷懒,而是因为在一次性的对话交互中,AI 很难同时兼顾全局把控和细节打磨。
Ralph Loop 通过"不让 AI 停下来"的方式解决了这个问题。每次 AI 试图退出时,循环会把它拉回来,让它重新审视自己的工作成果。第一次迭代可能只完成了框架搭建,第二次迭代会发现测试没通过并尝试修复,第三次迭代可能会优化代码结构、补充边界情况处理……就这样一轮一轮地打磨,直到达到你预设的完成标准。
为什么简单循环比复杂编排更有效?
你可能会想:既然问题出在上下文管理上,为什么不设计一个更复杂的多代理协作系统来解决呢?Ralph Loop 的回答是——简单才是力量。
Geoffrey Huntley 在多个场合反复强调一个观点:Ralph Loop 是"在不确定的世界中确定性地差"(deterministically bad in an undeterministic world)。这句话的意思是,与其追求每次都成功的复杂系统,不如接受每次可能失败、但失败模式可预测可修复的简单系统。每次失败都会以文件变更和 Git 提交的形式被记录下来,下一次迭代可以直接基于这些"失败痕迹"做改进。
这种思路与分布式系统设计中的很多经典理念不谋而合:无状态工作进程加持久化状态存储,优于复杂的内存状态管理方案。Unix 哲学几十年前就验证了这一点,Ralph Loop 不过是在 LLM 时代重新发现了这个道理。
三、Ralph Loop 的核心原理深度拆解
理解了 Ralph Loop 要解决什么问题,接下来我们深入看看它到底是怎么工作的。莫潇羽@源码七号站 会从底层机制开始,逐步讲清楚每一个环节。
文件系统作为"记忆层"
这是 Ralph Loop 最核心的设计理念:AI 的"记忆"不存在于对话历史中,而存在于文件系统和 Git 仓库中。
传统的 AI 编程交互中,所有的上下文信息——你说的话、AI 的回复、代码修改记录——都存在于一次连续的对话会话中。这意味着信息的留存完全依赖于上下文窗口的容量。一旦窗口满了被压缩,信息就会丢失。
Ralph Loop 反转了这个逻辑。每次迭代结束时,AI 所做的一切修改都已经写入了实际的代码文件,并且通过 Git 提交保存了下来。当下一次迭代开始时,AI 拿到的是一个全新的、干净的上下文窗口,但它面对的代码库已经是上一轮迭代之后的最新状态。AI 通过阅读当前的代码文件来了解"之前做了什么",而不是通过回顾对话历史。
这种设计带来了一个巨大的优势——每次迭代都有完整的上下文窗口可用。不会有上下文腐烂,不会有压缩导致的信息丢失,AI 始终在"聪明区"工作。代价是每次迭代都需要重新读取文件、重新理解代码结构,会消耗更多的 Token,但这种"看似浪费"的做法换来的是远高的可靠性。从长期来看,因为每次迭代都能产出高质量的有效工作,总体消耗的 Token 反而可能比在一个日益"腐烂"的上下文中反复纠错要少。这就好比修房子——与其在一个歪了的地基上不断打补丁,不如每次都在平整的地面上重新砌一层砖,虽然每次都要重新铺地基看起来浪费功夫,但最终盖出来的房子一定更结实。
Stop Hook 拦截机制
在 Claude Code 的官方插件实现中,Ralph Loop 使用的是一种叫做"Stop Hook"(停止钩子)的机制。这是 Claude Code 提供的一个扩展点,允许开发者编写脚本来拦截 AI 的退出行为。
工作流程大致是这样的:
当你执行 /ralph-loop "你的任务描述" 命令后,插件会在项目目录下的 .claude/ralph-loop.local.md 文件中记录循环的状态信息,包括当前迭代次数、最大迭代限制、完成承诺关键词以及当前会话的 ID。每次 Claude Code 试图结束会话退出时,Stop Hook 脚本会被触发,执行以下检查流程:
首先,脚本会确认状态文件是否存在,以及当前会话 ID 是否匹配。这一步是为了确保只有启动了 Ralph Loop 的那个会话会被拦截,其他正常的 Claude Code 会话不会受到影响。
接着,脚本检查当前迭代次数是否已经达到预设的最大限制。如果是,循环正常终止,状态文件被删除。
然后,脚本会读取当前会话的对话记录(JSONL 格式的转录文件),提取 AI 最后一次输出的内容,检查其中是否包含预设的"完成承诺"标签。例如,如果你设定的完成承诺是 COMPLETE,脚本会用 Perl 正则表达式在 AI 的输出中查找 <promise>COMPLETE</promise> 标签。如果找到并且完全匹配,说明 AI 认为任务已经完成,循环终止。
如果以上停止条件都不满足,Stop Hook 会执行最关键的动作:返回退出码 2(表示阻止退出),同时将原始的任务提示词重新注入到会话中,递增迭代计数器,并更新状态文件。Claude Code 收到退出码 2 后,会取消退出并继续执行,开始新一轮的工作。
用一段伪代码来表示这个过程:
你执行一次: /ralph-loop "你的任务描述" --completion-promise "DONE"
Claude Code 自动执行以下循环:
1. 接收任务,开始工作
2. 修改文件、运行测试、提交代码
3. 尝试退出
4. Stop Hook 拦截退出
5. Stop Hook 检查: 完成承诺? → 没有 → 重新注入原始提示词
6. Claude Code 继续工作,基于已修改的文件
7. 重复步骤 2-6
...
直到: AI 输出 <promise>DONE</promise> 或达到最大迭代次数
原生 Bash 循环 vs. 官方插件:两种实现的关键区别
这里有一个技术社区中争议比较大的问题,理解它对于正确使用 Ralph Loop 非常重要。
原生 Bash 循环(也就是 Huntley 最初提出的方式)和 Claude Code 官方插件(Stop Hook 方式)虽然都叫 Ralph Loop,但在实现机制上有一个本质区别:
原生 Bash 循环的做法是:每次迭代启动一个全新的 Claude Code 进程,带着全新的上下文窗口。上一轮的对话历史完全不会带到下一轮,AI 只通过读取文件系统来获取之前的工作成果。这是最"纯粹"的 Ralph Loop。
#!/bin/bash
MAX_ITERATIONS=20
ITERATION=0
while [ $ITERATION -lt $MAX_ITERATIONS ]; do
ITERATION=$((ITERATION + 1))
echo "=== 迭代 $ITERATION / $MAX_ITERATIONS ==="
# 每次都是全新的 Claude Code 进程和上下文
claude -p "$(cat PROMPT.md)"
# 检查完成标志(比如某个文件是否存在)
if [ -f ".ralph-complete" ]; then
echo "任务完成!"
rm .ralph-complete
break
fi
done
官方插件的做法则不同:它在同一个 Claude Code 会话内通过 Stop Hook 实现循环。这意味着所有迭代共享同一个上下文窗口。好处是保持了会话的连续性,AI 可以"记住"之前做了什么;坏处是随着迭代次数增加,上下文窗口会逐渐填满,最终还是可能触发压缩机制。
Huntley 本人以及社区中的很多资深用户更倾向于使用原生 Bash 循环的方式。Huntley 甚至在 Anthropic 发布官方插件后专门录了一期视频来说明两者的区别,提醒开发者不要把插件当作 Ralph Loop 的全部。他的核心论点是:Ralph 应该在外层控制 AI 代理的生命周期,而不是让 AI 代理在内部控制 Ralph。 当 AI 代理自己控制循环的生命周期时,你失去了最核心的优势——每次迭代都从干净的上下文开始。
不过,官方插件也有它的使用场景。对于迭代次数不多的简单任务(比如十轮以内),上下文窗口通常不会溢出,插件的便利性反而是优势。对于需要长时间运行、大量迭代的复杂任务,原生 Bash 循环是更稳妥的选择。
四、从零开始上手 Ralph Loop
聊了这么多原理,是时候动手操作了。莫潇羽@源码七号站 会按照从简到繁的顺序,介绍三种使用 Ralph Loop 的方式。
前置条件
在开始之前,你需要确保以下工具已经安装并配置好:
- Claude Code 命令行工具:这是 Anthropic 推出的终端 AI 编程工具,安装命令为
npm install -g @anthropic-ai/claude-code。你需要 Node.js 环境的支持。 - Git:Ralph Loop 依赖 Git 来持久化每次迭代的工作成果。
- 一个初始化好的 Git 仓库:你的项目目录需要已经执行过
git init,并且有至少一个初始提交。
如果你使用的是 Windows 系统,需要特别注意:官方插件的 Stop Hook 脚本需要 Bash 环境来运行,建议安装 Git for Windows 并确保系统 PATH 中指向的是 Git/bin/bash.exe,而不是 WSL 中可能配置不当的 Bash。
方式一:使用官方插件(最简单)
这是入门门槛最低的方式,适合初次尝试 Ralph Loop 的开发者。
第一步,安装插件。 在 Claude Code 的终端中执行:
/plugin install ralph-loop@claude-plugins-official
安装完成后,你会获得两个新的斜杠命令:/ralph-loop 和 /cancel-ralph。
第二步,启动循环。 进入你的项目目录,执行:
/ralph-loop "为 src/ 目录下所有没有测试的函数添加单元测试。测试覆盖率达到 80% 以上后,输出 <promise>TESTS_DONE</promise>" --completion-promise "TESTS_DONE" --max-iterations 15
这条命令做了三件事:用引号包裹的文本定义了任务内容和完成标准;--completion-promise 参数指定了 AI 需要输出什么关键词来表示任务完成;--max-iterations 参数设定了最大迭代次数作为安全兜底。
第三步,等待或监控。 启动后你可以去做别的事情。如果想实时查看进度,可以打开另一个终端窗口。
第四步,停止循环。 如果需要手动停止,有几种方式:执行 /cancel-ralph 命令;连按两次 ESC 键;或者直接关闭终端窗口。
方式二:使用原生 Bash 循环(更可靠)
对于复杂任务或需要长时间运行的场景,原生 Bash 循环是更好的选择。
第一步,编写提示词文件。 在项目根目录创建一个 PROMPT.md 文件:
# 任务说明
你是一个专注于代码质量的工程师。请完成以下工作:
## 目标
为本项目的 src/ 目录下所有公开函数添加单元测试。
## 具体要求
- 使用 Jest 作为测试框架
- 每个函数至少包含正常路径和异常路径的测试
- 测试文件命名遵循 `*.test.ts` 的约定
- 运行 `npm test` 确认所有测试通过
## 工作流程
1. 先检查当前的测试覆盖率(运行 `npm test -- --coverage`)
2. 找到尚未覆盖的函数
3. 为它们编写测试
4. 运行测试确认通过
5. 用 `git add -A && git commit -m "添加单元测试"` 提交更改
## 完成标志
当测试覆盖率达到 80% 以上时,创建一个名为 `.ralph-complete` 的空文件。
第二步,编写循环脚本。 创建 ralph.sh:
#!/bin/bash
# Ralph Loop 脚本 - 莫潇羽@源码七号站
# 基于 Geoffrey Huntley 的 Ralph Wiggum 技术
MAX_ITERATIONS=${1:-20} # 第一个参数为最大迭代次数,默认 20
ITERATION=0
START_TIME=$(date +%s)
echo "=========================================="
echo " Ralph Loop 已启动"
echo " 最大迭代次数: $MAX_ITERATIONS"
echo " 开始时间: $(date)"
echo "=========================================="
while [ $ITERATION -lt $MAX_ITERATIONS ]; do
ITERATION=$((ITERATION + 1))
echo ""
echo "--- 迭代 $ITERATION / $MAX_ITERATIONS ---"
echo " 时间: $(date)"
# 使用 -p 参数以非交互模式运行 Claude Code
# 每次都是一个全新的进程,全新的上下文窗口
claude -p "$(cat PROMPT.md)"
# 检查完成标志
if [ -f ".ralph-complete" ]; then
END_TIME=$(date +%s)
DURATION=$((END_TIME - START_TIME))
echo ""
echo "=========================================="
echo " 任务完成!"
echo " 总迭代次数: $ITERATION"
echo " 总耗时: $((DURATION / 60)) 分 $((DURATION % 60)) 秒"
echo "=========================================="
rm .ralph-complete
exit 0
fi
echo " 迭代 $ITERATION 完成,继续下一轮..."
done
echo ""
echo "=========================================="
echo " 已达到最大迭代次数 ($MAX_ITERATIONS),循环终止"
echo " 请检查当前工作状态并决定后续操作"
echo "=========================================="
第三步,启动循环:
chmod +x ralph.sh
./ralph.sh 20
这种方式的优势在于:每次迭代都是全新的 Claude Code 进程,拥有完整的上下文窗口,不会出现上下文腐烂的问题。你还可以在脚本中加入更多的自定义逻辑,比如在迭代之间运行 Lint 检查、自动格式化代码、或者发送通知。
方式三:社区增强版(功能最全)
社区中有多个 Ralph Loop 的增强实现,其中比较成熟的是 frankbria 开发的 ralph-claude-code 项目。它在原生 Bash 循环的基础上增加了很多实用功能:
- 智能退出检测:使用双重条件退出门控,需要同时满足"完成指标"和"明确的退出信号"才会终止循环
- 速率限制:内置 API 调用频率管理,默认每小时 100 次调用,防止过度消耗
- 断路器机制:高级错误检测,防止在持续出错的情况下无意义地消耗资源
- 语义分析器:对 AI 的输出进行语义理解,而不是简单的文本匹配
- 五小时 API 限制处理:三层检测机制,在无人值守模式下遇到 API 限制时自动等待
安装方式:
git clone https://github.com/frankbria/ralph-claude-code.git
cd ralph-claude-code
./install.sh
安装完成后,ralph 会成为一个全局命令,你可以在任何目录中使用它。
五、提示词工程:Ralph Loop 成败的关键
Geoffrey Huntley 反复强调过一个观点:Ralph Loop 的成功取决于提示词的质量,而不仅仅是模型的能力。LLM 是操作者技能的放大器。 如果提示词写得模糊、缺乏结构、没有明确的完成标准,即使跑上一百次迭代也不会收敛到理想的结果。
差的提示词 vs. 好的提示词
我们用一个实际例子来对比。假设你想用 Ralph Loop 来为项目添加 API 接口。
一个差的提示词可能是这样的:
帮我写一个 API
这个提示词的问题太多了——什么 API?用什么框架?要实现哪些接口?完成的标准是什么?AI 每次迭代都在猜你想要什么,结果就是在不同方向上反复横跳。
一个好的提示词应该是这样的:
# 任务:构建 Todo REST API
## 技术栈
- 语言: TypeScript
- 框架: Express.js
- 数据库: SQLite(使用 better-sqlite3)
- 测试: Jest + supertest
## 功能需求
- GET /api/todos — 获取所有待办事项
- POST /api/todos — 创建新的待办事项(必填字段: title)
- PUT /api/todos/:id — 更新待办事项状态
- DELETE /api/todos/:id — 删除待办事项
## 验收标准
- 所有接口都有输入验证
- 错误情况返回合适的 HTTP 状态码
- 每个接口都有对应的集成测试
- 测试覆盖率 > 80%
- 项目根目录有 README.md,包含 API 文档
## 工作方式
1. 先检查当前项目结构和已有代码
2. 每完成一个接口就运行测试确认
3. 所有工作完成后执行 git commit
4. 确认所有测试通过后,输出 <promise>COMPLETE</promise>
两者的差距一目了然。好的 Ralph 提示词有几个共同特征:
明确的技术栈声明,避免 AI 在不同技术方案之间摇摆不定。比如你不说用什么测试框架,第一次迭代 AI 可能用 Mocha,第二次改用 Jest,第三次又切回 Mocha——每次迭代不是在推进任务,而是在推翻上一次的技术选择。
可量化的完成标准,让 AI 能够自己判断"做完了没有"。"代码质量好"是不可量化的,"测试覆盖率 > 80%"是可量化的。"性能优化"是不可量化的,"首页加载时间 < 2 秒"是可量化的。
明确的工作流程,告诉 AI 应该按什么顺序做事。没有工作流程指引的话,AI 可能会跳来跳去——先写了一半测试,又去改了一下接口设计,再回来补另一半测试——这种随机的工作方式在多次迭代中会造成大量的无效劳动。
清晰的完成信号,即完成承诺标签的使用。关于这一点,下一节会详细展开。
提示词模板推荐
经过社区的大量实践,目前公认效果最好的 Ralph 提示词遵循一种叫做"三阶段两提示词一循环"(3 Phases, 2 Prompts, 1 Loop)的结构。这个结构的核心思想是:把整个开发过程分为需求定义、计划制定、和构建实施三个阶段,只有最后一个阶段放进 Ralph Loop 中自动执行,前两个阶段由人工参与完成。
一个典型的项目目录结构如下:
my-project/
├── ralph.sh # Ralph 循环脚本
├── PROMPT_build.md # 构建阶段的提示词(这个会被喂进循环)
├── PROMPT_plan.md # 计划阶段的提示词(手动使用)
├── AGENTS.md # AI 的操作手册(约 60 行以内)
├── IMPLEMENTATION_PLAN.md # 由计划阶段生成的任务列表
└── specs/ # 需求规格文档目录
└── feature-auth.md
这种结构的好处是职责清晰:specs/ 目录存放的是人工审核过的需求文档,IMPLEMENTATION_PLAN.md 是由 AI 在计划模式下生成但经人工确认的实施方案,PROMPT_build.md 是喂给 Ralph 循环的指令文件,它会引导 AI 读取计划文件、找到下一个待完成的任务、实施、测试、提交。
六、完成承诺(Completion Promise)机制详解
完成承诺是 Ralph Loop 中一个非常巧妙的设计。它本质上是一种"信号约定"——你预先定义一个特殊的标签格式,只有当 AI 认为任务真正完成时才被允许输出这个标签,Ralph Loop 检测到这个标签后就会自动终止循环。
基本用法
在启动 Ralph Loop 时通过 --completion-promise 参数指定完成承诺的关键词:
/ralph-loop "你的任务描述……完成后输出 <promise>ALL_DONE</promise>" \
--completion-promise "ALL_DONE" \
--max-iterations 20
AI 在提示词中会被告知:只有当你确信任务已经完全完成时,才可以输出 <promise>ALL_DONE</promise> 标签。系统会明确指示 AI "不要为了退出循环而撒谎"。
Stop Hook 脚本在每次拦截退出时,会用 Perl 正则表达式解析 AI 最后一次输出中的 <promise> 标签内容。匹配是精确的字符串比较,所以你不能用一个承诺来表示多种完成状态(比如同时用 SUCCESS 和 BLOCKED)。
实际使用建议
关于完成承诺,莫潇羽@源码七号站 有几个经过实践验证的建议:
始终搭配 --max-iterations 使用。 完成承诺是"正常退出"的机制,--max-iterations 是"安全兜底"的机制,两者缺一不可。如果你只设了完成承诺但没设迭代上限,万一 AI 始终无法满足完成条件(比如任务本身就不可能完成),循环就会无限运行下去,持续消耗 API 额度。
在提示词中包含"卡住时怎么办"的指引。 比如:
如果在 15 次迭代后仍然无法完成任务:
- 停止尝试
- 在 BLOCKERS.md 文件中记录遇到的障碍
- 列出已经尝试过的方案
- 提出可能的替代方案
- 输出 <promise>BLOCKED</promise>
不过要注意的是,--completion-promise 参数只能匹配一个关键词。如果你想区分"成功完成"和"被阻塞"两种退出状态,需要用 --max-iterations 作为超时兜底,然后在脚本中检查 AI 是否创建了 BLOCKERS.md 文件来判断是哪种情况。
让完成条件可以被程序化验证。 最理想的完成条件是那些可以被自动化工具验证的:测试通过、构建成功、Lint 检查无错误。如果完成条件只能靠人工判断(比如"代码风格优雅"),Ralph Loop 的效果就会大打折扣,因为 AI 很难准确自我评估这类主观标准。
七、上下文管理:Ralph Loop 的隐藏技能树
前面提到,上下文窗口管理是 Ralph Loop 的核心设计考量。这一节深入聊聊在实际使用中,怎么做好上下文管理来最大化 Ralph Loop 的效果。
每次迭代的上下文构成
在原生 Bash 循环模式下,每次迭代 AI 获得的上下文大致包含以下内容:
- 提示词文件内容(PROMPT.md),通常几百到几千个 Token
- AGENTS.md 或 CLAUDE.md 配置文件,包含 AI 的角色设定和操作规范
- AI 在读取代码文件时产生的内容,这部分会随着项目规模增大而增大
关键原则是:把需要 AI 参考的信息写进文件中让 AI 主动读取,而不是塞进提示词里。提示词应该尽量短小精悍,只包含"做什么"和"怎么做"的指引。具体的代码、测试结果、错误日志等信息,让 AI 自己通过执行命令和读取文件来获取。这样可以最大限度地节省宝贵的上下文空间。
子代理的运用
Huntley 在实践中发现了一个重要技巧:主上下文窗口应该扮演"调度器"的角色,把耗费大量 Token 的操作交给子代理去做。
比如,如果 AI 需要检查整个项目的测试覆盖率报告,这个报告可能有上千行。如果直接在主上下文中读取这个报告,会占用大量空间。更好的做法是让 AI 启动一个子代理来读取报告、提取关键信息、生成一份简要摘要,然后把摘要传回主上下文。主上下文只需要处理几十行的摘要信息就够了。
在 Claude Code 中,你可以通过在提示词中加入这样的指引来实现这个模式:
## 上下文管理规则
- 不要在主会话中直接读取超过 200 行的文件
- 对于大型文件的分析,使用子代理(subagent)来处理
- 将子代理的分析结果写入摘要文件,然后从主会话读取摘要
"意向性压缩"技巧
HumanLayer 团队的 Dex Horthy 提出了一个叫做"意向性压缩"(Intentional Compaction)的技巧,核心思想是:与其等到上下文窗口被迫自动压缩,不如在每次迭代之间主动做一次结构化的信息整理。
具体做法是在提示词中加入这样的指引:
每次提交代码后,请更新 progress.md 文件,包含以下信息:
- 最终目标是什么
- 目前采取的技术方案
- 已完成的步骤清单
- 当前正在处理的问题
- 下一步计划
这样,即使使用官方插件(同一会话内循环),AI 在每次新迭代开始时都可以先读取 progress.md 来快速恢复上下文,而不需要依赖可能已经被压缩过的对话历史。
八、Ralph Loop 的适用场景与不适用场景
任何技术都有它的适用边界。Ralph Loop 也不例外。莫潇羽@源码七号站 根据社区经验和多方资料整理了以下使用建议。
非常适合的场景
单元测试批量编写。 这可能是 Ralph Loop 目前最经典的用例。测试有天然的"可量化完成标准"——覆盖率达到某个百分比,所有测试通过。你只需要在提示词中描述清楚测试范围和质量要求,Ralph 就能一轮一轮地添加测试,每次迭代都基于上一轮未覆盖的代码继续补充。具体来说,你可以在提示词中要求 AI 先运行覆盖率工具,找到没有被测试覆盖的函数列表,然后从列表中选择一个来编写测试,运行通过后提交代码,进入下一次迭代再处理列表中的下一个。这种"每次迭代啃掉一个"的模式,在实际使用中的收敛速度非常理想。有开发者反馈,一个拥有上百个函数的项目,Ralph Loop 用大约三十次迭代就把测试覆盖率从不到百分之二十提升到了百分之八十五。
大规模代码重构。 比如从旧版本框架迁移到新版本、统一代码风格、替换已废弃的 API 调用。这类任务的特点是工作量大、重复性高、每个修改点的模式相似。Ralph Loop 可以反复执行"查找 → 修改 → 测试"的循环,持续推进直到所有需要修改的地方都被处理完。在实际的依赖迁移案例中,AI 第一次迭代可能修复了二十个编译错误,但同时引入了五个新错误。第二次迭代修复了这五个新错误,可能又冒出两个。第三次迭代修复这两个……以此类推,每次迭代都在缩小问题范围,最终收敛到零错误。这种"错误数量逐步递减"的模式是 Ralph Loop 最擅长处理的场景之一。
绿地项目的脚手架搭建。 当你有一份清晰的需求文档时,Ralph Loop 可以通宵帮你把项目的基本骨架搭建起来。第二天醒来时,你拿到的不是一个空壳,而是一个可以运行的、有基本功能的项目原型。在