2025 年 7 月,Geoffrey Huntley 在博客里介绍了一个他叫 Ralph 的做法,核心只有一行 Bash。
while :; do cat PROMPT.md | claude-code ; done一个死循环,把同一个提示词文件一遍遍喂给编程智能体。每一轮都是全新的会话,智能体读提示词,读规格文档和一份按优先级排好的待办清单,挑一件最重要的事做完,跑测试,提交,退出。下一轮从头再来。Ralph 是《辛普森一家》里那个有点傻的小孩,这个名字多少带点自嘲。
文章里有几条讲究。每轮只做一件事,Huntley 专门强调了只做一件。规格按功能拆成一个个文件,放在 specs 目录里,和待办清单一样,每轮都用同样的方式加载,因为每轮的上下文都是空的。测试、类型检查和静态分析负责把不合格的产出挡回去,他管这叫背压。Ralph 跑出问题时,他的态度是去调提示词和规格,别怪工具。
一年后,2026 年 6 月 7 日,Addy Osmani 写了《Loop Engineering》,给这类做法起了名字。他引了两句话。OpenClaw 的作者 Peter Steinberger 说,你应该设计替你给智能体写提示词的循环。Claude Code 的负责人 Boris Cherny 说,他已经不再给 Claude 写提示词了。
两层循环
循环这个词在这里有两层意思,容易混。
里面一层是智能体自己的执行循环,模型思考,调工具,看结果,再思考,直到它觉得这一轮做完了。每个智能体产品都有,属于 harness。
外面一层是驱动智能体的循环,谁给它派活,做完谁检查,没通过怎么办,下一件事从哪来。Loop 工程说的是外面这层。
外层循环(Loop 工程)
┌──────────────────────────────────────────────────┐
│ 发现任务 → 交给智能体 → 检查结果 → 记下进度 → 下一轮 │
│ │ │
│ ▼ │
│ 内层循环(智能体自己,属于 harness) │
│ ┌─────────────────────────────────┐ │
│ │ 思考 → 调用工具 → 看结果 → 思考… │ │
│ └─────────────────────────────────┘ │
└──────────────────────────────────────────────────┘只用提示词的时候,外层循环的每一步都是人在做。Loop 工程就是把这些步骤一件件交给系统。
一个循环由什么组成
Osmani 在文章里列了几样东西,自动化调度、隔离的 git worktree、Skill、MCP 连接、子智能体,再加一层保存状态的地方。他还指出 Codex 和 Claude Code 在往同一个形状靠,两边都有定时任务、子智能体和 Skill。我按循环里的先后顺序把它们重新排一下。
任务得有个来源。最简单的是一份待办清单,每轮取一项。也可以拿规格去对代码,找出还没实现的部分。外部事件同样能当来源,比如新的报错、失败的 CI、新开的 issue。还有定时巡检,每天看看依赖有没有安全更新。从固定清单取任务的循环有终点,清单空了就结束。由外部事件触发的循环一直在跑,更像一个后台服务。
交给智能体的任务描述必须自己就能看懂。对话里可以随时补充,循环里没人补充。Ralph 的办法有代表性,提示词本身不变,变化的信息都放在文件里,每轮从同一个入口读起,上下文干净,也不会因为前面几十轮的历史越来越乱。范围也要小。Anthropic 在讲长时间运行的智能体时观察到,一次给太多,智能体会做到一半上下文就满了,留下没写说明的半成品,他们的解法同样是每个会话只做一个功能。
最要紧的是检查。Osmani 认为循环里最有用的设计,是让干活的和检查的分开,写代码的模型给自己打分不靠谱。另派一个子智能体,给它不同的指令,有时干脆换个模型来查,循环报告的完成才比较可信。他也提醒,完成始终只是一个说法,算不上证明。
检查有两类。一类是测试、类型检查、lint、构建,结果非过即不过,不会被说服,也不会看走眼,这就是 Huntley 说的背压。另一类是让模型来判断,适合很难写成测试的标准,比如是否符合需求的本意。条件要写成能被证明的形式。代码质量好这种话没法检查,测试退出码为 0、没有改动 test 目录以外的测试文件,这样才能检查。
状态得存在窗口外面,因为每一轮的上下文都是空的。最可靠的是代码和 git 历史,每轮做完就提交,出了问题能回滚。Osmani 的说法是智能体会忘,仓库不会。还可以用一份进度文件,或者 Linear 这类看板。Anthropic 那篇文章里用的是 JSON 格式的功能清单,每项有描述、测试步骤和一个是否通过的字段,智能体只能改这个字段,不许删改条目。他们选 JSON,是因为发现模型不太会随手改写 JSON 文件。Ralph 还会把每轮学到的构建技巧写回 AGENT.md,下一轮就用得上,循环在顺手改进自己的 harness。
调度决定下一轮什么时候开始,可以是上一轮一结束就开始,可以按时间,也可以由事件触发。停止条件比调度更重要。完成条件要有,比如清单清空或者目标验证通过;轮数和花费都要有上限;连续几轮没有进展,或者在两个状态之间来回打转,就该停;停下来之后通知谁、给什么信息,也要事先定好。
现成工具里的循环
Claude Code 有几种让会话持续跑下去的方式。/loop 按时间间隔重复运行一条提示词。/goal 设一个完成条件,每个回合结束后由另一个小模型判断条件达成没有,没达成就自动开始下一回合。Stop Hook 写在设置文件里,回合结束时运行你自己的脚本或提示词,决定要不要继续。官方文档建议给 /goal 写条件时写清可度量的终点和检查方式,再加上回合数或时长的上限。
这几样都在你本机的会话里跑。想在笔记本关机时也照常运行,可以用 Claude Code 的例程,它在云端按计划、API 调用或 GitHub 事件触发。Osmani 也提到 GitHub Actions、cron 和 Codex 的自动化功能都能承担调度这一块。
| 形态 | 下一轮何时开始 | 适合 |
|---|---|---|
| 目标循环 | 上一回合结束 | 有明确验收条件的一件大活,比如让某个目录的测试全部通过 |
| 清单循环 | 上一轮结束 | 能拆成很多独立小块的工作,比如大规模迁移、补测试 |
| 定时循环 | 到了固定时间 | 巡检、依赖更新、文档链接检查 |
| 事件循环 | 外部事件发生 | 修报错、处理 issue、CI 失败后尝试修复 |
还有一种更外层的循环,用来改进让智能体干活的那套系统。比如定期翻最近的失败记录,归纳常见错误,提出修改项目说明、Skill 或 lint 规则的建议。这相当于把 harness 工程里每个错误只犯一次的习惯也自动化了。
容易出的问题
循环出问题往往没有声响,你不在旁边,发现时可能已经跑了几十轮。
最常见的是来回打转。修 A 弄坏了 B,修 B 又弄坏了 A,没有进展检测的话会一直跑下去,每一轮都在花钱。
目标会悄悄漂移。任务是修好测试,测试很难修,它就把测试改简单了,测试通过了,测的已经不是原来那件事。所以检查条件里要写清不许改测试本身。
后来的会话容易提前收工。Anthropic 观察到,新会话看到前面已经做了很多,就直接宣布整个项目完成了。让完成与否由结构化清单的状态决定,可以避免这个问题。
质量会一点点往下掉。每一轮单独看都能通过检查,合起来却多了重复代码、不一致的命名和临时方案。要靠定期整理,或者在检查里加一些更高层的质量要求。
Osmani 还提到两个跟人有关的风险。循环跑得越快,存在的代码和你真正理解的代码之间差距越大,他叫这个理解债。把判断全交给循环,人会慢慢放弃思考。循环能帮人,也能让这些问题恶化得更快,看人怎么用。
什么时候先别用
需求还没想清楚的时候。循环擅长执行,不擅长探索。先在对话里和智能体一起把方案想明白,写成规格,再交给循环。
没有可靠检查手段的时候。做得对不对只能靠人看,那每一轮都得人看,循环就没意义了。先去补测试、加 lint、写验证脚本。
牵涉到不可逆操作的时候。发布、删数据、对外发消息、花钱,在循环里都应该停下来等人确认,或者干脆不给这个权限。
只做一次的小事也不值得。搭循环本身有成本,直接在对话里做更快。
人还做什么
人从循环的每一步,挪到了循环的设计和边界上。想清楚要做什么,写成规格和验收标准;设计检查,定好什么算对;划出权限、预算和停止条件;看关键的决定和最终产出;从失败里找该改的地方。
Osmani 文章的最后一句是 Build the loop. Stay the engineer. 他对 Cherny 那句话的理解是,用力的地方变了,活并没有变轻松。
四层工程到这里就讲完了,总览见从提示词到 Loop,AI 编程的四层工程。想从概念上把智能体本身理解得更透,可以接着读智能体是什么。
参考资料