本文系统梳理了 Ralph 范式的核心机制与标准实施 SOP,并结合实际业务场景探讨灵活的自定义扩展方案,以应对多仓库工程治理等挑战。
在传统的 AI 辅助编程中,开发者通常采用“单次对话”模式:向 AI 描述需求,获取代码,复制粘贴,手动测试。这种模式在面对复杂功能重构或跨文件修改时,易因上下文超载、AI 幻觉或遗漏细节而导致逻辑错乱。
Ralph 范式的核心在于:将 AI 交互从“单次问答”转变为由外部持久化状态驱动的、可重复执行的 Agent Loop。
每一轮 Agent 在相对独立的上下文中读取当前状态,识别并执行可验证的任务,完成测试与状态更新后退出;外部循环随后重新启动 Agent,继续推进剩余任务,直至满足预设的完成条件。
┌──────────────────────────────────────────────────────────┐
│ Agent 自动化 Loop │
▼ │
┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
│ 读取外部状态 │ ──► │ Agent 执行 │ ──► │ 测试校验 & │ ───────┘
│ & 选择 Task │ │ 单个原子 Task │ │ 持久化 Commit │ (直到输出 COMPLETE)
└──────────────┘ └──────────────┘ └──────────────┘
在一种典型的 Coding Agent 实现中,可以将 Ralph 的工程实践归纳为以下四项:
ONE ATOMIC TASK PER ITERATION):建议强约束 Agent 每次循环只处理一个可验证的原子任务,防止 Agent 在单次循环中过度扩展修改范围。PRD.md / progress.txt):PRD.md 负责描述目标状态和任务清单,作为任务规划层面的单一事实来源 (Single Source of Truth);progress.txt 跨循环记录增量履约细节,确保后续循环平滑衔接。[注] 关于运行沙箱 (Sandbox):
在无人值守模式下,由于 Agent 可能连续自主执行 Shell 命令,建议通过 Docker、Dev Container、虚拟机或其他 Sandbox 机制限制文件系统、网络和凭据访问范围。需要注意的是,容器并不天然等于绝对安全,实际隔离能力取决于权限、挂载、网络和凭据配置。
落地 Ralph 范式需要构建从“人机协同 (Human-in-the-Loop)” 到 “无人值守模式 (AFK Loop)” 的标准化流程。
[注] 本章的 SOP 实施脚本参考了 Matt Pocock 的教程 Getting Started With Ralph。
可以使用 Plan 模式(快捷键 Shift+Tab)交互生成计划并保存至 PRD.md,同时创建一个空文件 progress.txt:
PRD.md:定义终态需求与 Checklists。progress.txt:记录 Agent 跨循环已完成的工作细节。每次循环 Agent 都会读取两者,提取首个未勾选的任务并履约。ralph-once.sh在开启全自动循环前,先通过单次触发脚本观察 Agent 行为,校准 Prompt 效力:
#!/bin/bash
# ralph-once.sh - 单步人工监护脚本
claude --permission-mode acceptEdits "@PRD.md @progress.txt \
1. 读取 PRD 和 progress 文件。 \
2. 找到下一个未完成的任务并实现它。 \
3. 提交你的修改。 \
4. 将你完成的操作更新至 progress.txt。 \
单次只能处理一个任务。"
设置可执行权限并运行:
chmod +x ralph-once.sh
./ralph-once.sh
观察终端输出,确认代码改动与 Git Commit 正确后,再次手动运行。
afk-ralph.sh单步验证稳定后,即可使用 Bash 循环实现离席自动运行。脚本通过引入完成标志 (Completion Sigil,如 <promise>COMPLETE</promise>),当 PRD 所有 Task 履约完成后自动退出循环。
#!/bin/bash
# afk-ralph.sh - 离席全自动循环脚本
set -e
if [ -z "$1" ]; then
echo "Usage: $0 <iterations>"
exit 1
fi
for ((i=1; i<=$1; i++)); do
result=$(claude --permission-mode acceptEdits -p "@PRD.md @progress.txt \
1. 查找优先级最高的任务并实现它。 \
2. 运行测试与类型检查。 \
3. 将完成的工作更新至 PRD。 \
4. 将进度追加至 progress.txt。 \
5. 提交你的修改。 \
单次仅处理单个任务。 \
如果 PRD 已全部完成,输出 <promise>COMPLETE</promise>。")
echo "$result"
if [[ "$result" == *"<promise>COMPLETE</promise>"* ]]; then
echo "PRD complete after $i iterations."
exit 0
fi
done
运行脚本并指定最大迭代次数(例如 20 次):
./afk-ralph.sh 20
参数说明:
set -e:遇到命令错误时立即退出。-p(Print Mode):以非交互模式运行 Claude Code 并将输出捕获到变量中,用于检索 Completion Sigil。<promise>COMPLETE</promise>:当需求完全履约时由 Agent 在末尾打印的收敛信号。
在企业级工程实践中,常面临跨数十个仓库/微前端/微服务的全局数据盘点与治理需求:
直接在大模型中打开包含数十个子项目的根目录并指令 AI “提取所有子目录中的路由并写入 Excel”,这种做法在工程上容易失效,对比分析如下:
| 评估维度 | 最外层直接投喂 (Outer Single Prompt) | Ralph 目录控制链 (Python Master-Worker) |
|---|---|---|
| 搜索空间与定位 | 搜索空间过大。跨多个项目搜索,信息匹配与定位成本高。 | 空间聚焦。每个 Worker 将当前子项目作为主要代码上下文,避免多个项目的代码状态混杂。 |
| 状态复杂度与覆盖率 | 容易漏检。全局任务状态集中在单 Agent,易遗漏子目录节点。 | 程序化保证。Master 程序化遍历目录,保障覆盖率。 |
| Token 成本 | 随规模快速增长。单次携带所有仓库信息,难于控制。 | 单项目可控。避免 Token 成本随整体工作区规模盲目增长,使单轮消耗主要取决于当前项目复杂度。 |
| 失败恢复与断点 | 难以恢复。中途中断后需重新全量扫描。 | 支持断点重试。可按项目独立重试与跳过已完成项。 |
| 结果可靠性 | 格式易漂移。Agent 直接拼接并追加文本结果。 | 格式收敛。Structured Artifact + Schema Validation。 |
借鉴 Ralph 的“独立上下文与原子循环”机制,引入 Python Master 控制脚本:
cwd)让 Worker 以当前子项目作为工作上下文,实现项目级的 Context Isolation。./routes.json。采用 “产物即凭证 (Artifact-driven)” 模式,无需在目标仓库写入临时 PRD.md 文件。routes.json,由程序统一清洗、校验 Schema 结构并导出为标准 all_routes.csv。若项目已存在合法 routes.json 则直接跳过,支持基本的断点续传。 ┌──────────────────────────────┐
│ Python 控制链 (Master) │
│ 遍历目录 / 汇总 JSON 到 CSV │
└──────────────┬───────────────┘
│
┌──────────────────────────┼──────────────────────────┐
▼ ▼ ▼
┌─────────────────────┐ ┌─────────────────────┐ ┌─────────────────────┐
│ Project 01 (Worker) │ │ Project 02 (Worker) │ │ Project 03 (Worker) │
│ 生成 routes.json │ │ 生成 routes.json │ │ 生成 routes.json │
│ Context Isolation │ │ Context Isolation │ │ Context Isolation │
└─────────────────────┘ └─────────────────────┘ └─────────────────────┘
[架构延伸] 任务收敛的信号层级 (Signal Hierarchy):
在 Agent 工程实践中,确认任务是否完成存在不同层级的校验强度:
- 弱信号:Agent 口头文本输出“处理完成”。
- 中信号:输出特定的收敛 Tag(如
<promise>COMPLETE</promise>)。- 强信号:结构化文件产物 (Structured Artifact) 成功生成。
- 更强信号:产物通过 Schema Validation 结构校验。
- 最强信号:通过与任务目标对应的独立验证机制(如代码修改对应单元测试与构建,数据提取对应 Schema 格式与字段完整性校验)。
import csv
import json
import subprocess
from pathlib import Path
# 1. 定义工作区目录、全局路由标准字段元数据与统一 Prompt
WORKSPACE = Path("./projects")
if not WORKSPACE.exists():
WORKSPACE = Path(".")
OUTPUT_CSV = Path("./all_routes.csv")
# 统一规范路由导出的核心字段列表(仅包含 3 个目标字段)
FIELDNAMES = ["project", "path", "title"]
PROMPT = """你现在正在处理子项目。
1. 只分析提取当前项目的前端页面路由(无需提取后端 API 接口)。
2. 将提取到的页面路由定义输出为结构化 JSON 文件 ./routes.json。
3. routes.json 为 JSON 数组,每个对象包含以下字段:
- path: 页面路由路径(字符串,必填,例如 "/diary/list")
- title: 页面标题/说明(字符串,可选,无标题则填 "")"""
def is_valid_routes_json(path: Path) -> bool:
"""校验 routes.json 是否存在且符合结构契约"""
if not path.exists():
return False
try:
data = json.loads(path.read_text(encoding="utf-8"))
if not isinstance(data, list):
return False
return all(
isinstance(item, dict)
and isinstance(item.get("path"), str)
and bool(item.get("path").strip())
for item in data
)
except (json.JSONDecodeError, UnicodeDecodeError):
return False
# 2. 遍历子项目仓库运行微型 Ralph 循环
failed_projects = []
for project in WORKSPACE.iterdir():
if not project.is_dir() or project.name.startswith(".") or not (project / "package.json").exists():
continue
print(f"\n[日志] 开始处理项目: {project.name}")
route_json = project / "routes.json"
# 产物与 Schema 双重校验:若存在合法 routes.json 则直接跳过(支持断点续传)
if is_valid_routes_json(route_json):
print(f"[日志] 项目 {project.name} 已存在合法 routes.json,自动跳过。")
continue
completed = False
# 运行微型 Ralph 循环(限制单项目最多尝试 3 次)
for iteration in range(1, 4):
print(f" └─ 正在执行微循环 Iteration {iteration}")
try:
result = subprocess.run(
["claude", "--dangerously-skip-permissions", "-p", PROMPT],
cwd=str(project),
stdin=subprocess.DEVNULL,
capture_output=True,
text=True,
timeout=90
)
# 校验 Exit Code 与产物 Schema,符合契约即算收敛
if result.returncode == 0 and is_valid_routes_json(route_json):
completed = True
print(f"[日志] 项目 {project.name} 处理收敛!")
break
except subprocess.TimeoutExpired:
print(f" └─ [警告] Iteration {iteration} 执行超时 (90秒),准备下一次重试...")
if not completed:
failed_projects.append(project.name)
print(f"[错误] 项目 {project.name} 处理失败,已达到最大重试次数。")
# 3. Master 统一汇总各项目的 routes.json 并导出为标准 CSV
all_routes = []
for project in WORKSPACE.iterdir():
if not project.is_dir() or project.name.startswith(".") or not (project / "package.json").exists():
continue
route_json = project / "routes.json"
if is_valid_routes_json(route_json):
routes = json.loads(route_json.read_text(encoding="utf-8"))
for r in routes:
record = {"project": project.name}
for field in FIELDNAMES:
if field != "project":
record[field] = r.get(field, "")
all_routes.append(record)
# 写入 CSV(由 Python 显式控制 Header 与字段顺序,防止数据漂移)
with OUTPUT_CSV.open("w", newline="", encoding="utf-8") as f:
writer = csv.DictWriter(f, fieldnames=FIELDNAMES)
writer.writeheader()
writer.writerows(all_routes)
print(f"\n[日志] 全局路由导出完成!共汇总 {len(all_routes)} 条路由记录 -> {OUTPUT_CSV}")
# 4. 输出失败项目报告,保障批处理可观测性
if failed_projects:
print(f"\n[警告] 以下 {len(failed_projects)} 个项目处理失败,请排查:")
for p in failed_projects:
print(f" - {p}")
[注] 关于 Schema Validation 扩展:
示例代码实现了最小结构契约校验;在生产实践中,可进一步结合 JSON Schema、Pydantic 或 Zod 等定义强类型数据契约,进行自动化验证。
[注] 关于 Worker 中的 Git Commit:
在本例的数据提取场景中,生成routes.json属于只读分析任务而非业务代码重构,因此示例省略了子仓库 Commit。若产物属于仓库日常维护资产,可在 Prompt 中引导 Agent 提交 Commit;若属于临时分析产物,建议将结果写入独立的结果目录,避免污染业务仓库历史。
在掌握 Ralph 的基础 Loop 与 Master-Worker 控制链后,可根据质量治理要求构建不同类型的专职 Ralph 循环:
Vitest / Jest 覆盖率报告,引导 Agent 识别未覆盖代码行,每次循环补全特定模块的单元测试,逐步提升覆盖率。ESLint 或 Biome 报错日志作为任务输入,每次循环修复单个文件或单一类型的报错并单独 Commit,避免大范围变更引入破坏性修改。jscpd 等代码重复率检测工具,引导 Agent 提取重复逻辑为公共组件或工具函数。pnpm tsc 或 npm test),由测试结果指导后续变更。MAX_ITERATIONS 上限,配合 <promise>COMPLETE</promise> 终止标示,保证运行可控。