goose Ralph Loop 实战指南:以“全新上下文 + 双模型交叉评审”把 Agent 迭代任务自动推进到可交付
【免费下载链接】goosean open source, extensible AI agent that goes beyond code suggestions - install, execute, edit, and test with any LLM项目地址: https://gitcode.com/GitHub_Trending/goose3/goose
Ralph Loop 是 goose 生态中一种面向复杂开发任务的迭代式执行模式:它让 goose 在每一轮迭代都从零开始新建会话,只通过文件在轮次之间传递任务、总结与评审反馈,从而彻底规避标准 Agent 循环中“历史噪声累积”导致的质量衰减问题。本文以 Ralph Loop 官方教程 为骨架,结合仓库中真实可用的 ralph-loop.sh、ralph-work.yaml 与 ralph-review.yaml 三个文件,讲解它的设计动机、搭建步骤、状态文件协议与 recipe 文件逐段语义,读完即可在你的终端里跑通“干活模型 + 评审模型”协同完成任务的完整闭环。
为什么要引入 Ralph Loop:标准 Agent 循环的上下文累积问题
单次 goose 会话里,Agent 会反复执行“思考 → 调用工具 → 得到结果”的循环。如果任务一次没有做完,常见的做法是让它在同一个会话里继续改,但这会带来一个隐蔽而严重的问题:每一次失败的尝试都会留在对话历史里。
- 模型每次发起请求都必须重新处理整段历史,token 消耗随迭代次数线性甚至超线性增长;
- 会话越长,早期有用信息越容易被后期的大量噪音淹没,模型的注意力被稀释;
- 多次失败的历史还会“传染”后续决策——模型倾向于沿用旧思路反复修补,而不是重新审视问题。
Ralph Loop 化解这个问题的核心思想只有一个:每一轮迭代都从全新上下文开始。这一思路源自 Geoffrey Huntley 提出的 Ralph Wiggum 技术,而本项目教程在此基础上进一步扩展出了“跨模型评审”(cross-model review)机制——一个模型负责干活,另一个模型负责把关,循环往复直到任务达到可交付(SHIP)标准。
核心机制一览:文件传状态,会话不延续
Ralph Loop 的两个阶段分工如下:
Iteration 1: WORK PHASE → Model A does work, writes to files REVIEW PHASE → Model B reviews the work → SHIP? Exit successfully ✓ → REVISE? Write feedback, continue to iteration 2 Iteration 2: WORK PHASE → Model A reads feedback, fixes things (fresh context!) REVIEW PHASE → Model B reviews again → SHIP? Exit successfully ✓ → REVISE? Continue... ... repeats until SHIP or max iterations关键点在于:迭代结束后,只有工作总结与评审反馈落在磁盘文件上,会话历史不会保留。下一轮开始后,新会话里的模型只需读取.goose/ralph/目录下的状态文件,就能精确地从上一轮结束的位置继续。工作产物(代码、配置等)天然留在工作目录里,跨轮次共享;而“意图类”信息(做了什么、还缺什么)则通过状态文件显式交接,二者互不干扰。
前置准备
动手前需要满足两个条件:
- 安装 goose CLI:Ralph Loop 全程在终端里驱动,参考 安装指南 完成 goose 命令行工具安装。
- 配置两个模型:分别扮演 worker(干活)与 reviewer(评审)角色。参考 Providers 配置。官方教程建议使用两个不同模型以获得更高质量的评审视角,但同一模型同时承担两角色时循环依然可以工作(脚本只会给出警告)。
获取 Ralph Loop 的 Recipe 文件
Ralph Loop 由三个文件组成,它们在当前仓库中的真实位置如下(教程正文即引用自这些文件):
- ralph-loop.sh:Bash 编排脚本,驱动 work/review 循环;
- ralph-work.yaml:Work 阶段 recipe,告诉 worker 模型如何推进任务;
- ralph-review.yaml:Review 阶段 recipe,告诉 reviewer 模型如何评判与给出反馈。
下载到 goose 的 recipe 默认目录后赋予执行权限:
mkdir -p ~/.config/goose/recipes # 将仓库 documentation/src/pages/recipes/data/recipes/ 下的三个文件复制到该目录 cp documentation/src/pages/recipes/data/recipes/ralph-loop.sh ~/.config/goose/recipes/ cp documentation/src/pages/recipes/data/recipes/ralph-work.yaml ~/.config/goose/recipes/ cp documentation/src/pages/recipes/data/recipes/ralph-review.yaml ~/.config/goose/recipes/ chmod +x ~/.config/goose/recipes/ralph-loop.sh说明:脚本本身内置了
RALPH_RECIPE_DIR环境变量用于覆盖 recipe 目录,其默认值正是$HOME/.config/goose/recipes(见下文脚本源码第 23 行),所以复制到上述位置后无需任何额外参数。你也可以选择不下载,直接从 Recipe Files 章节 复制文件内容。
仓库的 recipe 加载逻辑也与该约定一致:goose 会扫描全局配置目录下的recipes子目录、当前工作目录下的.goose/recipes,以及.agents/recipes等位置(见 local_recipes.rs),并支持通过GOOSE_RECIPE_PATH环境变量追加自定义搜索路径。
三步跑通 Ralph Loop
Step 1:启动循环
打开终端,进入你要 goose 开发的项目目录(注意 Ralph Loop 会把.goose/ralph/状态目录创建在当前工作目录下),把任务描述放在引号里传给脚本:
~/.config/goose/recipes/ralph-loop.sh "Create a simple browser using Electron and React"教程用它演示的正是这个场景:从零构建一个基于 Electron + React 的简易浏览器,观察迭代循环如何在交付前拦截缺失功能(如非法 URL 缺少错误处理、缺少前进/后退导航按钮)。
针对复杂任务的小技巧:字符串参数并不总是够用。当任务是 PRD、详细规格说明书或任何适合迭代式开发的多步骤需求时,直接传入文件路径:
~/.config/goose/recipes/ralph-loop.sh ./prd.md脚本会检测到参数是一个存在的文件,将其内容复制为任务描述(cp "$INPUT" "$STATE_DIR/task.md")。
Step 2:交互式配置模型
首次运行且未通过环境变量预设模型时,脚本会引导你逐步填写配置,随后显示成本警告并要求确认:
Worker model [gpt-4o]: Worker provider [openai]: Reviewer model (should be different from worker): claude-sonnet-4-20250514 Reviewer provider: anthropic Max iterations [10]: ⚠️ Cost Warning: This will run up to 10 iterations, each using both models. Estimated token usage could be significant depending on your task. Continue? [y/N]: y各配置项含义如下:
| 变量 | 描述 |
|---|---|
| Worker model | 真正执行编码工作的模型。若已设置GOOSE_MODEL环境变量,则作为默认值出现在方括号中 |
| Worker provider | Worker 模型所属的 provider(如openai、anthropic),默认取自GOOSE_PROVIDER |
| Reviewer model | 负责评审工作的模型。为获得最佳效果应区别于 worker 模型 |
| Reviewer provider | Reviewer 模型所属的 provider |
| Max iterations | 放弃前最多执行多少轮 work/review 循环,默认 10 |
值得注意的两处内置校验(见 ralph-loop.sh 第 39-103 行的prompt_for_settings函数):
- 必要项缺失直接退出:worker/reviewer 的模型与 provider 均不允许为空;
- 同模型降级警告:当 worker 与 reviewer 的
(model, provider)完全一致时,脚本会明确提示“为获得最佳交叉评审效果请使用不同模型”,并要求输入y才继续——这印证了同模型也能跑、但质量打折扣的设计取舍。
跳过交互式提示:如果你希望循环完全无人值守(例如接入 CI),可以预先设置环境变量,脚本检测到四项配置齐全后会直接跳过所有问答:
RALPH_WORKER_MODEL="gpt-4o" \ RALPH_WORKER_PROVIDER="openai" \ RALPH_REVIEWER_MODEL="claude-sonnet-4-20250514" \ RALPH_REVIEWER_PROVIDER="anthropic" \ ~/.config/goose/recipes/ralph-loop.sh "Create a simple browser using Electron and React"Step 3:观察循环运行
终端会交替显示 WORK PHASE 与 REVIEW PHASE。成功的一次运行大致长这样:
═══════════════════════════════════════════════════════════════ Ralph Loop - Multi-Model Edition ═══════════════════════════════════════════════════════════════ Task: Create a simple browser using Electron and React Worker: gpt-4o (openai) Reviewer: claude-sonnet-4-20250514 (anthropic) Max Iterations: 10 ─────────────────────────────────────────────────────────────── Iteration 1 / 10 ─────────────────────────────────────────────────────────────── ▶ WORK PHASE ... (goose creates initial implementation) ... ▶ REVIEW PHASE ... (goose reviews the work) ... ↻ REVISE - Feedback for next iteration: Missing error handling for invalid URLs. Also needs back/forward navigation buttons. ─────────────────────────────────────────────────────────────── Iteration 2 / 10 ─────────────────────────────────────────────────────────────── ▶ WORK PHASE ... (goose addresses feedback) ... ▶ REVIEW PHASE ... (goose reviews again) ... ═══════════════════════════════════════════════════════════════ ✓ SHIPPED after 2 iteration(s) ═══════════════════════════════════════════════════════════════注意“REVISE - Feedback for next iteration”后面的文字并非人为输入,而是 reviewer 模型在评审阶段写进review-feedback.txt的内容,由脚本原样打印——这也是下一次 WORK PHASE 的修改依据。示例里 reviewer 在第 1 轮拦截到“缺少非法 URL 错误处理”和“缺少前进/后退导航按钮”,第 2 轮 worker 修复后即通过评审。
成本警告
:::warning 成本提示 Ralph Loop 会在循环中多次运行 Agent(默认最多 10 轮迭代),每轮都会同时消耗 worker 与 reviewer 两个模型的 token。请密切关注用量,必要时通过RALPH_MAX_ITERATIONS调低上限。 :::
状态文件协议:模型间的“文件级 API”
.goose/ralph/是循环状态的唯一事实来源。worker 与 reviewer 两个模型不共享任何记忆,它们之间通过以下文件“对话”:
| 文件 | 用途 |
|---|---|
task.md | 任务描述(脚本在启动时写入) |
iteration.txt | 当前迭代序号 |
work-summary.txt | 本轮 worker 做了什么(无论完成与否都会写) |
work-complete.txt | 当 worker 声明任务完成时创建 |
review-result.txt | 评审结论:SHIP或REVISE |
review-feedback.txt | 给下一轮的改进反馈 |
.ralph-complete | 成功完成时创建(内容含时间戳) |
RALPH-BLOCKED.md | 若 worker 判定任务被阻塞则创建 |
从 ralph-loop.sh 的编排逻辑可以看到这些文件的读写顺序:
- 每次启动先把
INPUT(字符串或文件)写入task.md,并清空上一轮的review-result.txt、review-feedback.txt、work-complete.txt、work-summary.txt(第 137-149 行); - 每轮迭代开始把轮次号写入
iteration.txt(第 166 行); - WORK PHASE 结束后检查
RALPH-BLOCKED.md,存在即打印内容并退出(第 176-181 行); - REVIEW PHASE 结束后读取
review-result.txt并去除所有空白字符后与SHIP比较(第 192 行)——这一细节保证了即使模型写出了带换行或空格的SHIP也能正确匹配; - 结果为
SHIP:写入.ralph-complete、打印成功横幅并以退出码 0 结束;结果为REVISE:打印反馈文件内容,清理work-complete.txt与review-result.txt后进入下一轮(第 194-215 行); - 循环正常耗尽时打印“Max iterations reached”并以退出码 1 结束(第 218-219 行)。
由于脚本头部开启了set -e(第 20 行),WORK 或 REVIEW 阶段任何一次goose run失败(goose 自身报错)都会导致整个循环立即中止,避免带病继续。
Recipe 文件逐段解析
Ralph Loop 的“智能”全部浓缩在三个文件里。在逐一拆解前,先看一下 goose 是如何解析 recipe 的,这能帮我们理解每个字段的真实含义。
从源码看 Recipe 结构
goose 的 recipe 是一份 YAML(也支持 JSON)格式的 Agent 配置,其数据模型定义在 crates/goose/src/recipe/mod.rs。核心字段包括:
version:文件格式版本,采用 semver,缺省值为1.0.0;title/description:recipe 的标题与描述,均为必填;instructions:注入会话的系统级指令;prompt:启动会话时使用的初始提示词。prompt与instructions至少需要一个(见同一文件第 413-415 行的RecipeBuilder::build校验);extensions:recipe 启用的一组扩展(extension)配置;settings/activities/author/parameters/sub_recipes/response等可选字段。
CLI 侧,goose run通过--recipe参数接受“recipe 名称或 recipe 文件的完整路径”(cli.rs)。真正运行时,extract_from_cli.rs 会把prompt映射为会话初始内容、把instructions映射为额外的系统提示词——这解释了为什么两份 recipe 都同时提供instructions(长期约束)和prompt(阶段性行动清单)两个字段。
Bash 编排脚本(ralph-loop.sh)
这是整个循环的“指挥中枢”,从参数校验、模型提示、状态目录初始化到阶段切换全部由它完成。完整内容如下:
#!/bin/bash # # Ralph Loop - Multi-Model Edition # # Fresh context per iteration + cross-model review # Based on Geoffrey Huntley's technique # # Usage: ./ralph-loop.sh "your task description here" # or: ./ralph-loop.sh /path/to/task.md # # Environment variables: # RALPH_WORKER_MODEL - Model for work phase (prompts if not set) # RALPH_WORKER_PROVIDER - Provider for work phase (prompts if not set) # RALPH_REVIEWER_MODEL - Model for review phase (prompts if not set) # RALPH_REVIEWER_PROVIDER - Provider for review phase (prompts if not set) # RALPH_MAX_ITERATIONS - Max iterations (default: 10) # RALPH_RECIPE_DIR - Recipe directory (default: ~/.config/goose/recipes) # set -e INPUT="$1" RECIPE_DIR="${RALPH_RECIPE_DIR:-$HOME/.config/goose/recipes}" RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' BLUE='\033[0;34m' NC='\033[0m' if [ -z "$INPUT" ]; then echo -e "${RED}Error: No task provided${NC}" echo "Usage: $0 \"your task description\"" echo " or: $0 /path/to/task.md" exit 1 fi # Function to prompt for settings prompt_for_settings() { local default_model="${GOOSE_MODEL:-}" local default_provider="${GOOSE_PROVIDER:-}" # Worker model if [ -n "$default_model" ]; then echo -ne "${BLUE}Worker model${NC} [${default_model}]: " read -r user_input WORKER_MODEL="${user_input:-$default_model}" else echo -ne "${BLUE}Worker model${NC}: " read -r WORKER_MODEL if [ -z "$WORKER_MODEL" ]; then echo -e "${RED}Error: Worker model is required${NC}" exit 1 fi fi # Worker provider if [ -n "$default_provider" ]; then echo -ne "${BLUE}Worker provider${NC} [${default_provider}]: " read -r user_input WORKER_PROVIDER="${user_input:-$default_provider}" else echo -ne "${BLUE}Worker provider${NC}: " read -r WORKER_PROVIDER if [ -z "$WORKER_PROVIDER" ]; then echo -e "${RED}Error: Worker provider is required${NC}" exit 1 fi fi # Reviewer model echo -ne "${BLUE}Reviewer model${NC} (should be different from worker): " read -r REVIEWER_MODEL if [ -z "$REVIEWER_MODEL" ]; then echo -e "${RED}Error: Reviewer model is required${NC}" echo "The reviewer should be a different model to provide fresh perspective." exit 1 fi # Reviewer provider echo -ne "${BLUE}Reviewer provider${NC}: " read -r REVIEWER_PROVIDER if [ -z "$REVIEWER_PROVIDER" ]; then echo -e "${RED}Error: Reviewer provider is required${NC}" exit 1 fi # Same model warning if [ "$WORKER_MODEL" = "$REVIEWER_MODEL" ] && [ "$WORKER_PROVIDER" = "$REVIEWER_PROVIDER" ]; then echo -e "${YELLOW}Warning: Worker and reviewer are the same model.${NC}" echo "For best results, use different models for cross-model review." echo -ne "Continue anyway? [y/N]: " read -r confirm if [ "$confirm" != "y" ] && [ "$confirm" != "Y" ]; then exit 1 fi fi # Max iterations echo -ne "${BLUE}Max iterations${NC} [10]: " read -r user_input MAX_ITERATIONS="${user_input:-10}" } # Initialize from environment variables WORKER_MODEL="${RALPH_WORKER_MODEL:-}" WORKER_PROVIDER="${RALPH_WORKER_PROVIDER:-}" REVIEWER_MODEL="${RALPH_REVIEWER_MODEL:-}" REVIEWER_PROVIDER="${RALPH_REVIEWER_PROVIDER:-}" MAX_ITERATIONS="${RALPH_MAX_ITERATIONS:-10}" # If any required setting is missing, prompt for all settings if [ -z "$WORKER_MODEL" ] || [ -z "$WORKER_PROVIDER" ] || [ -z "$REVIEWER_MODEL" ] || [ -z "$REVIEWER_PROVIDER" ]; then prompt_for_settings fi # Cost warning and confirmation loop while true; do echo "" echo -e "${YELLOW}⚠️ Cost Warning:${NC} This will run up to ${MAX_ITERATIONS} iterations, each using both models." echo " Estimated token usage could be significant depending on your task." echo "" echo -ne "Continue? [y/N]: " read -r confirm if [ "$confirm" = "y" ] || [ "$confirm" = "Y" ]; then break else echo "" prompt_for_settings fi done STATE_DIR=".goose/ralph" mkdir -p "$STATE_DIR" if [ -f "$INPUT" ]; then cp "$INPUT" "$STATE_DIR/task.md" echo -e "${BLUE}Reading task from file: $INPUT${NC}" else echo "$INPUT" > "$STATE_DIR/task.md" fi TASK=$(cat "$STATE_DIR/task.md") rm -f "$STATE_DIR/review-result.txt" rm -f "$STATE_DIR/review-feedback.txt" rm -f "$STATE_DIR/work-complete.txt" rm -f "$STATE_DIR/work-summary.txt" echo -e "${BLUE}═══════════════════════════════════════════════════════════════${NC}" echo -e "${BLUE} Ralph Loop - Multi-Model Edition${NC}" echo -e "${BLUE}═══════════════════════════════════════════════════════════════${NC}" echo "" echo -e " Task: ${YELLOW}$TASK${NC}" echo -e " Worker: ${WORKER_MODEL} (${WORKER_PROVIDER})" echo -e " Reviewer: ${REVIEWER_MODEL} (${REVIEWER_PROVIDER})" echo -e " Max Iterations: $MAX_ITERATIONS" echo "" for i in $(seq 1 "$MAX_ITERATIONS"); do echo -e "${BLUE}───────────────────────────────────────────────────────────────${NC}" echo -e "${BLUE} Iteration $i / $MAX_ITERATIONS${NC}" echo -e "${BLUE}───────────────────────────────────────────────────────────────${NC}" echo "$i" > "$STATE_DIR/iteration.txt" echo "" echo -e "${YELLOW}▶ WORK PHASE${NC}" GOOSE_PROVIDER="$WORKER_PROVIDER" GOOSE_MODEL="$WORKER_MODEL" goose run --recipe "$RECIPE_DIR/ralph-work.yaml" || { echo -e "${RED}✗ WORK PHASE FAILED${NC}" exit 1 } if [ -f "$STATE_DIR/RALPH-BLOCKED.md" ]; then echo "" echo -e "${RED}✗ BLOCKED${NC}" cat "$STATE_DIR/RALPH-BLOCKED.md" exit 1 fi echo "" echo -e "${YELLOW}▶ REVIEW PHASE${NC}" GOOSE_PROVIDER="$REVIEWER_PROVIDER" GOOSE_MODEL="$REVIEWER_MODEL" goose run --recipe "$RECIPE_DIR/ralph-review.yaml" || { echo -e "${RED}✗ REVIEW PHASE FAILED${NC}" exit 1 } if [ -f "$STATE_DIR/review-result.txt" ]; then RESULT=$(cat "$STATE_DIR/review-result.txt" | tr -d '[:space:]') if [ "$RESULT" = "SHIP" ]; then echo "" echo -e "${GREEN}═══════════════════════════════════════════════════════════════${NC}" echo -e "${GREEN} ✓ SHIPPED after $i iteration(s)${NC}" echo -e "${GREEN}═══════════════════════════════════════════════════════════════${NC}" echo "COMPLETE: $(date)" > "$STATE_DIR/.ralph-complete" exit 0 else echo "" echo -e "${YELLOW}↻ REVISE - Feedback for next iteration:${NC}" if [ -f "$STATE_DIR/review-feedback.txt" ]; then cat "$STATE_DIR/review-feedback.txt" fi fi else echo -e "${RED}✗ No review result found${NC}" exit 1 fi rm -f "$STATE_DIR/work-complete.txt" rm -f "$STATE_DIR/review-result.txt" echo "" done echo -e "${RED}✗ Max iterations ($MAX_ITERATIONS) reached${NC}" exit 1(同文件同时保留于 documentation/src/pages/recipes/data/recipes/ralph-loop.sh。)
脚本中最值得关注的两处设计:
- 两阶段模型切换:脚本用内联环境变量方式调用 goose(第 171 行与 186 行)——
GOOSE_PROVIDER="$WORKER_PROVIDER" GOOSE_MODEL="$WORKER_MODEL" goose run --recipe ...。这意味着 goose 会话的实际模型由环境变量在每次调用前被覆盖,而无需修改任何 goose 全局配置; - 失败即终止:无论是 goose 命令本身出错、模型声明 BLOCKED、还是评审结束却没有产出
review-result.txt,脚本都会立即退出并给出明确的失败原因,不会在错误状态上空转。
Work 阶段 Recipe(ralph-work.yaml)
这份 recipe 决定 worker 模型每一轮的行为,其完整内容与仓库文件 ralph-work.yaml 一致:
version: 1.0.0 title: Ralph Work Phase description: Single iteration of work - fresh context each time instructions: | You are in a RALPH LOOP - one iteration of work. Your work persists through FILES ONLY. You will NOT remember previous iterations. STATE FILES (in .goose/ralph/): - task.md = The task you need to accomplish (READ THIS FIRST) - iteration.txt = Current iteration number - review-feedback.txt = Feedback from last review (if any) - work-complete.txt = Create when task is DONE (reviewer will verify) FIRST: Check your state 1. cat .goose/ralph/task.md (YOUR TASK) 2. cat .goose/ralph/iteration.txt 2>/dev/null || echo "1" 3. cat .goose/ralph/review-feedback.txt 2>/dev/null 4. ls -la to see existing work THEN: Make progress - If review-feedback.txt exists, ADDRESS THAT FEEDBACK FIRST - Read existing code/files before modifying - Make meaningful incremental progress - Run tests/verification if applicable FINALLY: Signal status - If task is complete: echo "done" > .goose/ralph/work-complete.txt - Always write a summary: echo "what I did" > .goose/ralph/work-summary.txt prompt: | ## Ralph Work Phase Read your task from: .goose/ralph/task.md 1. Read the task: `cat .goose/ralph/task.md` 2. Check iteration: `cat .goose/ralph/iteration.txt 2>/dev/null || echo "1"` 3. Check for review feedback: `cat .goose/ralph/review-feedback.txt 2>/dev/null` 4. List existing files: `ls -la` 5. Do the work (address feedback if any, otherwise make progress) 6. Write summary: `echo "summary" > .goose/ralph/work-summary.txt` 7. If complete: `echo "done" > .goose/ralph/work-complete.txt` extensions: - type: builtin name: developer timeout: 600逐段拆解其语义:
- instructions 是“世界观”:它用最高优先级告知模型“你处于 Ralph Loop 的单轮工作中;你的成果只通过文件持久化,你不会记得上一轮”。这句话是整套机制能运转的心理基础——模型一旦误以为自己在长会话里,就可能跳过读取反馈,破坏循环;
- 状态读取的确定性:
cat task.md、cat iteration.txt 2>/dev/null || echo "1"、cat review-feedback.txt 2>/dev/null的组合确保了三件事——任务永远被读到、迭代号缺失时回退为 1、首次运行时“没有反馈”不会报错而是被当作正常状态处理; - 推进优先级:有评审反馈就先解决反馈(ADDRESS THAT FEEDBACK FIRST),其次才是新增功能,并且要求动手前先读已有代码、尽量做“有意义的增量”、条件允许就跑测试验证——这些约束把“修补”和“新开发”的顺序固定下来;
- 收尾信号:完成时写
work-complete.txt(供 reviewer 验证),无论完成与否都必须写work-summary.txt(供 reviewer 了解工作内容)。两个文件职责分离:一个是“完成声明”,一个是“工作摘要”; - extensions:
type: builtin+name: developer表示加载 goose 内置的 developer 扩展(提供文件操作、命令执行等开发工具),timeout: 600把该扩展的调用超时放宽到 600 秒,避免大型构建或长测试被过早中断。
Review 阶段 Recipe(ralph-review.yaml)
评审是 Ralph Loop 相对原始 Ralph Wiggum 技术的增量所在。完整内容与仓库文件 ralph-review.yaml 一致:
version: 1.0.0 title: Ralph Review Phase description: Cross-model review of work - returns SHIP or REVISE instructions: | You are a CODE REVIEWER in a Ralph Loop. Your job: Review the work done and decide SHIP or REVISE. You are a DIFFERENT MODEL than the worker. Your fresh perspective catches mistakes. STATE FILES (in .goose/ralph/): - task.md = The original task (READ THIS FIRST) - work-summary.txt = What the worker claims to have done - work-complete.txt = Exists if worker claims task is complete REVIEW CRITERIA: 1. Does the code/work actually accomplish the task? 2. Does it run without errors? 3. Is it reasonably complete, not half-done? 4. Are there obvious bugs or issues? BE STRICT but FAIR: - Don't nitpick style if functionality is correct - DO reject incomplete work - DO reject code that doesn't run - DO reject if tests fail OUTPUT: If approved: echo "SHIP" > .goose/ralph/review-result.txt If needs work: echo "REVISE" > .goose/ralph/review-result.txt echo "specific feedback" > .goose/ralph/review-feedback.txt prompt: | ## Ralph Review Phase 1. Read the task: `cat .goose/ralph/task.md` 2. Read work summary: `cat .goose/ralph/work-summary.txt` 3. Check if complete: `cat .goose/ralph/work-complete.txt 2>/dev/null` 4. Examine the actual files created/modified 5. Run verification (tests, build, etc.) 6. Decide: SHIP or REVISE If SHIP: `echo "SHIP" > .goose/ralph/review-result.txt` If REVISE: `echo "REVISE" > .goose/ralph/review-result.txt` `echo "specific feedback" > .goose/ralph/review-feedback.txt` extensions: - type: builtin name: developer timeout: 300要点解读:
- 评审依据不是“摘要”,而是“事实”:prompt 第 4-5 步要求 reviewer 亲自检查实际创建/修改的文件并运行验证(测试、构建等),而不是仅凭
work-summary.txt的自我描述就下结论——这正是“质量闸门”成立的关键; - 评审标准的可操作化:四条判据把“任务是否真正完成、能否无错运行、是否只是半成品、有无明显缺陷”显式列出;再叠加“严格但公平”的边界约束:不抠风格(功能正确时不吹毛求疵),但坚决拒绝不完整的工作、跑不起来的代码和测试失败的结果;
- 两种退出路径:通过则写
SHIP,否则写REVISE并给出具体可执行的反馈(要求“specific feedback”而非泛泛而谈)。反馈质量直接决定下一轮 worker 的修复质量; - timeout 差异:评审阶段同样加载 developer 扩展以运行验证命令,但超时收紧为 300 秒——评审通常比开发更快,较短的超时可避免卡死在评审上。
使用建议与适用边界
何时适合使用 Ralph Loop
- 复杂、多步骤任务:需要多轮迭代才能收敛的任务能从“每轮重来”中获得显著收益;
- 有明确完成判据的任务:例如测试通过、构建成功——这类客观信号能让 reviewer 的
SHIP决策变得可靠; - 希望在交付前设置质量闸门:当你不信任单次一键生成的结果、又不想逐轮人工检查时,用另一个模型把关是一种低成本的替代方案。
何时属于过度设计
- 简单的一次性任务(一轮就能完成,循环纯属浪费 token);
- 交互式 / 探索性工作(需要人工持续介入决策,不适合无人循环);
- 缺乏可验证完成标准、无法让 reviewer 客观判断“是否真的做完了”的任务。
重置与重新开始
如果上一轮运行卡死、或你想在同一个目录里开启一个全新任务,请清空状态目录:
rm -rf .goose/ralph脚本启动时本来就会重建.goose/ralph并清空四个评审相关文件,但手动清理可以同时清除可能残留的RALPH-BLOCKED.md、work-complete.txt等标记,确保从绝对干净的状态开始。
小结
Ralph Loop 用三条简单而有力的工程约定,解决了长任务中 Agent 质量随上下文累积而衰退的痛点:
- 每轮全新会话——噪声不再残留,模型每一轮都以干净上下文面对任务;
- 文件即状态——
.goose/ralph/目录充当 worker 与 reviewer 之间的协议层,用task.md、work-summary.txt、review-feedback.txt、review-result.txt等文件传递信息; - 双模型交叉评审——不同的 reviewer 模型以“严格但公平”的标准执行测试与检查,输出
SHIP/REVISE结论,把质量闸门从人工移到 Agent 侧。
整个模式由三个可复制的文件落地(ralph-loop.sh、ralph-work.yaml、ralph-review.yaml),recipe 的底层结构由 crates/goose/src/recipe/mod.rs 解析、由 crates/goose-cli/src/recipes/extract_from_cli.rs 映射为实际会话。想要进一步钻研的读者,可以从这几处源码入口继续深入,也可以对照 Ralph Loop 教程原文 查看原始排版与上下文。
【免费下载链接】goosean open source, extensible AI agent that goes beyond code suggestions - install, execute, edit, and test with any LLM项目地址: https://gitcode.com/GitHub_Trending/goose3/goose
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考