# 让 Claude Code 在你睡觉时自己写代码?

> 拉尔夫循环——给 Claude Code 一个目标和验证标准,让它在闭环里跑'执行→测试→改→重来',睡觉时自己改完代码。哪些活能交出去,哪些坑要避开。

- 原文链接: https://laojin.blog/blog/20260514_claude_code_ralph_loop
- 作者: 老金
- 发布日期: 2026-05-14
- 标签: Claude Code, AI 工作流, Agent, 拉尔夫循环

---

![让 Claude Code 在你睡觉时自己写代码?](https://pic-1258874139.cos.ap-hongkong.myqcloud.com/laojinblog/posts/20260514/00_cover.png)

如果你用 Claude Code 还停留在"打开终端、敲一句问题、等 diff、看一眼说不对、再让它改",那其实就是把它当嵌在 IDE 里的 ChatGPT 在用。

社区里最近聊得比较多的另一种玩法叫**拉尔夫循环**:给它定一个目标和验证标准,让它在闭环里跑"执行 → 测试 → 看错 → 改 → 再来",整个过程不需要你介入。配合 `--dangerously-skip-permissions`,理论上你可以挂着它去睡觉,醒来代码就在那。

我用自己手上的 PWA 项目 TinyPA 跑过几轮。下面是怎么搭起来的,以及哪些地方最容易翻车。

## 一个反复修了十几次的功能

TinyPA 的核心逻辑之一,是把用户碎碎念的消息拆成「待办 / 笔记 / 心情 / 待跟进」四类卡片。

`git log --grep="llm"` 出来一长串:

```
fix(llm): hard timeout on NIM calls; always stamp processedAt
feat(llm): stream Gemma output and insert items incrementally
fix(llm): full-content fallback + log raw Gemma output
perf(llm): use llama-3.1-8b for extract; keep gemma-4-31b for digest
fix(llm): force IPv4-first DNS to avoid 50s cold-start stall
...
perf(llm): switch extract default to llama-3.3-70b-instruct
fix(extract): local time + '只输出 reply' rule for questions
```

同一个抽取功能反反复复修了十几次。每次都是:发一条消息试试 → 看输出对不对 → 不对就翻日志、改 prompt、换模型、调超时 → 部署 → 再发一条。一周时间,每天熬一会儿。

这种活根本不该人来跑。任务可拆、每步有明确完成标志(JSON 解析过没?四类卡片对不对?延迟够不够低?),也不需要任何审美判断。

## 怎么把"我"从循环里摘出去

要让 CC 自己跑这个循环,需要三样东西。

**一个机器化的验证入口。** 我之前在 `/settings/llm-test` 做了个浏览器测试页,输入 prompt 直接看结构化输出。把这个剥成命令行能跑的脚本之后,CC 自己就能验证一轮跑得对不对,不用每次部署到 prod 再发消息。

**沉淀过的上下文。** memory 目录里有一条 `project_extract_model.md`,记的是"extract 为什么用 llama-3.3-70b 而不是 gemma/llama-8b,之前换过又换回来了"。这是给下一轮 CC 留的线索——它如果想随手把模型换掉,会先看到这条历史。没有这种线索,它会原地踏步。

**能机器断言的成功条件。** 比如发"明天下午3点开会要准备财报;老婆说晚上吃火锅;最近睡眠不太好",预期是 1 个 todo + 1 个 followup + 1 个 mood,且 `due_at` 带正确时区偏移。只要这种判断能写成代码,CC 就能自己循环到过为止。

![拉尔夫循环示意](https://pic-1258874139.cos.ap-hongkong.myqcloud.com/laojinblog/posts/20260514/01_ralph_loop.png)

最后给它一个 loop 入口,大致这样:

```
任务:把 lib/jobs/extract.ts 的成功率调到 95% 以上。

loop:
  1. 跑测试集,记录每条用例的实际输出/延迟/错误
  2. 通过率 ≥ 95% 且 p95 ≤ 3s 就停
  3. 否则:归因(模型?prompt?schema?网络?),改一处,commit,回到 1

约束:每轮一个 commit,写清楚改动假设;切模型前先看 memory 里的历史。
```

加上 `--dangerously-skip-permissions`,启动,关电脑。

## 但有几个坑得提前知道

听起来丝滑,跑起来不是。

**它不会心疼你的账单。** 如果 bug 卡在某个偶发问题上——比如 cold start 偶尔超时、某个 region 网络抽风——CC 会反复 retry,每次都把完整的失败日志、相关代码、之前的 commit 一起再塞进 prompt。有一晚我被 NIM 冷启动问题坑了,CC 在那 loop 里转了一两个小时,第二天看账单不太舒服。

**它会为了让测试过而写出你不会写的代码。** 它的目标是"测试通过",不是"代码合理"。某个边界条件死活过不了,它下一步往往不是去改逻辑,而是往函数顶上加一段特判,把这条用例 hardcode 进去。我醒来看 diff,里面经常有几个"看起来确实绿了,但你绝对不会自己这么写"的分支。

**它会把绿测误当成完成。** 这件事的代价取决于你的测试有多严。早期我想让 CC 自己调通 Resend 的邮件发送,结果它在我邮箱里塞了二十几封测试邮件才说"看起来 OK"——因为我设的成功标志只是 API 返回 200。带不可逆副作用的活(发邮件、写生产库、付款)都不要往这种循环里塞,`--dangerously-skip-permissions` 也不该出现在这种场景。

**测试本身的成本经常被低估。** 循环跑得动的前提是有一套能精确判断结果的自动化测试。测试本身有漏洞,CC 就会顺着漏洞钻,本质上不是在修 bug,是在帮你绕过你自己写的检查。但写一套能覆盖时区、异常 schema、各种边界的测试脚本,可能要花一整天。半天能改完的功能,先花一天写测试再让 AI 自己跑——账有时候算不过来。

## 那到底什么时候用

判断标准其实挺朴素的:**这个 loop 我能不能不在里面。**

![能交出去 vs 不能交出去](https://pic-1258874139.cos.ap-hongkong.myqcloud.com/laojinblog/posts/20260514/02_delegate_or_not.png)

输入输出明确、验证完全机器化、最坏结果就是 commit 一坨垃圾然后 `git reset` 的活,可以放心交出去。TinyPA 的 extract 调优完全是这一类。

不适合交出去的:要看审美的(UI、文案、产品取舍),有不可逆副作用的(生产 DB、外发通信),以及"看一眼对不对"比"我自己改一遍"还累的——这种情况一旦发生,loop 就退化回了人机交互,CC 反而是累赘。

那十几个 `fix(llm)` 提交里,下次我大概会让 CC 自己闭环掉一半。剩下的还是得我盯着——网络层那种事,光看测试看不出来。

下次你要修一个"反复试就行"的 bug,先停下来问一句:**这个循环我能不能不在里面?**
