跳到主要内容

Ralph Loop

Ralph Loop 基于 Geoffrey Huntley 的 Ralph Wiggum 技巧,是一种迭代开发模式,让 goose 持续处理一项任务,直到它真正完成。

标准智能体循环会受到上下文累积的影响。每一次失败的尝试都留在对话历史中,这意味着几次迭代之后,模型必须先处理一长段噪声历史,才能专注于任务。Ralph Loop 通过每次迭代都从全新上下文开始来解决这个问题,这是 Geoffrey 方法的核心洞察。此实现用跨模型审查扩展了该技巧:一个模型做工作,另一个模型审查它,循环持续到任务可以交付。

每次迭代之后,工作模型和审查模型把摘要和反馈存在文件中。这些文件在迭代之间保留,但对话历史不会。这样新会话可以从上一次迭代停下的地方继续:下一个模型读取这些文件即可接上。

在本教程中,我们将用 Ralph Loop 构建一个简单的基于 Electron 的浏览器,并看看迭代循环如何在交付前发现缺失的功能。

前提条件​

  • 安装 goose CLI,因为 Ralph Loop 通过终端运行。
  • 配置两个模型,分别作为工作者和审查者。建议使用不同模型以获得更高质量的审查,不过两个角色使用同一模型时循环仍然可以工作。
下载 Ralph Loop 配方

把下面的内容复制并粘贴到终端,以下载 Ralph Loop 配方:

mkdir -p ~/.config/goose/recipes

curl -sL https://raw.githubusercontent.com/aaif-goose/goose/main/documentation/src/pages/recipes/data/recipes/ralph-loop.sh -o ~/.config/goose/recipes/ralph-loop.sh
curl -sL https://raw.githubusercontent.com/aaif-goose/goose/main/documentation/src/pages/recipes/data/recipes/ralph-work.yaml -o ~/.config/goose/recipes/ralph-work.yaml
curl -sL https://raw.githubusercontent.com/aaif-goose/goose/main/documentation/src/pages/recipes/data/recipes/ralph-review.yaml -o ~/.config/goose/recipes/ralph-review.yaml

chmod +x ~/.config/goose/recipes/ralph-loop.sh
费用警告

Ralph Loop 会让智能体在循环中多次运行(默认最多 10 次迭代)。请监控用量,并在需要时调整 RALPH_MAX_ITERATIONS。

步骤 1:启动循环​

要开始这个过程,从终端运行脚本,并把提示放在引号中。这条命令会触发工作者和审查者循环的第一次迭代:

~/.config/goose/recipes/ralph-loop.sh "Create a simple browser using Electron and React"
复杂任务

你可以传入文件路径而不是字符串。这对 PRD、详细规格,或任何受益于迭代开发的多步任务都很合适:

~/.config/goose/recipes/ralph-loop.sh ./prd.md

步骤 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工作模型的 provider(例如 openai、anthropic)。如果已设置,默认为 GOOSE_PROVIDER。
Reviewer model审查工作的模型。为获得最佳结果,应与工作者不同。
Reviewer provider审查模型的 provider。
Max iterations放弃之前进行多少次工作/审查循环。默认为 10。
直接设置环境变量

你可以直接设置环境变量,从而跳过交互式提示

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"

步骤 3:看着它运行​

终端会显示 goose 在工作阶段和审查阶段之间推进。每次迭代都从新会话开始,以保持上下文干净。一次成功运行看起来是这样的:

═══════════════════════════════════════════════════════════════
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)
═══════════════════════════════════════════════════════════════

工作原理​

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

状态文件​

Ralph Loop 使用 .goose/ralph/ 中的文件在迭代之间持久化状态。即使每次迭代都从全新上下文开始,工作者也由此知道该做什么,审查者由此知道已经做了什么。

文件用途
task.md任务描述
iteration.txt当前迭代编号
work-summary.txt工作者在本次迭代中做了什么
work-complete.txt工作者声称完成时存在
review-result.txtSHIP 或 REVISE
review-feedback.txt给下一次迭代的反馈
.ralph-complete成功完成时创建
RALPH-BLOCKED.md工作者卡住时创建

配方文件​

Ralph Loop 使用三个文件:编排工作/审查循环的 bash 脚本、告诉工作模型如何取得进展的工作配方,以及告诉审查模型如何评估工作的审查配方。下面是每个文件的内容。你可以下载它们,或直接从这里复制。

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
工作阶段配方(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
审查阶段配方(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

使用提示​

何时使用 Ralph Loop​

Ralph Loop 最适合:

  • 复杂的多步任务,能从迭代中受益
  • 有明确完成标准的任务(测试通过、构建成功)
  • 你希望在交付前有质量门禁的情况

它对以下情况过重:

  • 简单的一次性任务
  • 交互式/探索性工作
  • 没有可验证完成标准的任务

重置​

如果你想开始一个全新的任务,或者上一次运行卡住了、想重新开始,可以清除状态目录:

rm -rf .goose/ralph