Claude Code 卡在循环里:6 种 loop 签名 + 各自的一句话破解

Claude Code 反复同样 edit、来回切换两个文件、永远追 flaky 测试——6 种 loop 签名各有诊断和一句话破法,外加 Esc / rewind / clear / Stop hook 的确切恢复命令。2026 年 6 月。

Claude Code 第 8 次跑 pnpm test。每次:改同一行 expect(...).toBe(...)、重跑、又挂、回退。或者它在「修 auth bug」的两种解读间反复横跳——修 OAuth 挂 magic-link、修 magic-link 挂 OAuth。Token 烧着、进度条不动。Agent 进了循环。

绝大多数 loop 都不是「模型修不了」,而是反馈环坏了:flaky 测试、prompt 没约束住、context 被污染、工具失败没被察觉。修法不是换更强的模型,而是 30 秒内识别 loop 签名,用一句话约束或一个按键打破它。下面是 6 种 loop 形态、各自的破解约束,以及恢复时要用到的确切 Claude Code 命令(Ctrl+C、双击 Esc / /rewind/clear/compact)。本文以 2026 年 6 月的 Claude Code 为准,模型为 Claude Opus 4.7 / Sonnet 4.6。

TL;DR——60 秒打破一个 loop

  1. 立刻中断。Esc 停掉当前动作;命令卡死就按 Ctrl+C。别等 loop「跑完」——它不会停。
  2. 读 trace。 让 Claude 把最近 10 个动作列成表格(文件 + edit + 命令 + exit code)。规律几乎都是两个文件交替、或同一行被反复改。
  3. 套上对应签名的一句话约束(见下表)。
  4. 如果 context 被污染,双击 Esc(或跑 /rewind)回滚到干净的 checkpoint,或 /clear 后用一句话目标重启。
  5. 预防下一次:在 CLAUDE.md 里设迭代上限,再配一个 Stop hook。

常见原因

按命中率从高到低:

1. flaky 测试——过 / 挂 / 过 / 挂

最常见触发。测试用了 Date.now()、网络调用、随机数、snapshot 时间戳——同一份代码一次过一次挂。Agent 看到红 → 改 → 绿 → 重跑又红 → 回退 → 绿 → 改 → 红,没完没了。

如何判断:停掉 agent(Esc)。你自己不改代码连跑 3 次同一命令。能复现绿红绿——是测试的问题,不是模型那次 edit 的问题。

2. 模糊 prompt——agent 在两种解读间漂

「修 login bug」——但你有 OAuth 和 magic-link。Agent 修 OAuth,magic-link 测挂;切 magic-link,OAuth 测挂——在互斥的两种解读间反复跳。

如何判断:看最近 5 个 diff——动了两个不同 feature 的两个不同文件、每个新 edit 撤上一个——prompt 没约束住。

3. Plan 错了 agent 拒绝 replan

agent 锁定「改 schema → 改 API → 改 UI」。Step 1 不可能(表有数据,列删不掉)——agent 死磕 step 1 反复重写 migration,而不是 replan。

如何判断:问「你当前 plan 是什么?现在第几步?」——5+ 轮都说”还在 step 1”,强制 replan。

4. context 被旧 error 塞满

长 session 里,context 窗口大半都是过期的「上次失败」日志——agent 在拟合一堆不再反映现状的旧 error。一个明显信号是你看到 Autocompact is thrashing: the context refilled to the limit...——这是 Claude Code 在自动 compact 成功后、context 又被某个大文件或工具输出立刻填满时给出的提示。按 Anthropic 的 troubleshooting 文档,当 compact 后 context 连续三次被重新填满到上限,Claude Code 就会停止重试,正是为了避免在毫无进展的 loop 上白烧 API 调用。罪魁通常是 agent 每一轮都重读同一个超大文件、或一段巨大的工具输出。

如何判断:跑 /context 看窗口占用百分比(拆解里会显示 system prompt、tools、CLAUDE.md、消息历史各自吃了多少 token)。超过 ~70% 还卡着,多半就是 context 的问题。再用 /clear(或开新 session)贴当前代码、重述目标确认一下——第一次就成,就是被污染了。

5. Agent 在 mock 和实 implementation 间漂

写 mock 让测试过,下轮觉得 mock 不真实改实 impl,原测试挂,回 mock——loop。

如何判断:跨次 diff 里搜 jest.mock / vi.mock / MagicMock 被加被删。

6. 工具失败 agent 没察觉

Bash exit code 非 0。Agent 把 stdout 当成功,又跑同命令——loop 因为”失败信号”它看不见。

如何判断:看最近 3 个工具调用的 exit code——非 0 但 Claude 没说”命令失败”——它漏了。

最短修复路径

按收益从高到低。Step 1 + 2 在一分钟内打破大多数 loop。

Step 1:停 agent,让它列最近 10 个动作

先中断。Esc 停掉当前动作、回到提示符;Ctrl+C 取消卡死的命令。一次按不下来就再按——第一次是温和请求,连按会升级到强制结束。要是终端彻底没反应,关掉它,在同一目录下跑 claude --resume 把 session 接回来;重启不会丢对话。

停下来后问它:

列最近 10 个动作(文件路径 + edit 总结 + 命令 + exit code)。
不要评论,只表格。

大多数时候你会看到两个文件交替、同一行反复改、或测试反复跑却没代码进展——这个 pattern 就揭示了 loop 签名。

Step 2:按签名套约束句

匹配 loop 类型和约束 prompt:

Loop 类型约束 prompt
反复改测试期望「不要动测试。测试是对的——改 implementation 匹配它。」
反复加/删 mock「保留真实现,删所有 mock,跑集成测试。」
反复改 migration「schema 冻结,重新 plan 只动 UI 层。」
来回两个文件「只允许动 src/auth/login.ts,其他全只读。」
同一 flaky 测试反复挂「停跑这个测试,mock 时间依赖,继续。」
重跑失败命令「上条命令 exit 非 0。读 error,不要盲重跑。」

Step 3:flaky 测试先稳

不要让 agent 在 flaky 信号上 loop——先稳:

# 跑 5 次看稳不稳
for i in {1..5}; do pnpm test -- --testNamePattern="login flow"; done

2+ 次挂就 mock 不确定性源:

// vitest setup
vi.useFakeTimers();
vi.setSystemTime(new Date('2026-01-01'));

然后让 agent 在稳定的测试上继续。

Step 4:重置 context——rewind、clear 还是 compact

当 trace 被一堆过期失败日志占满时,你有三档递进的杠杆,按想保留多少状态来选:

命令作用何时用
双击 Esc/rewind打开 rewind 菜单。每个 prompt 都是 checkpoint,可单独恢复对话、代码或两者。想撤掉 loop 的 edit、从一个已知正常点重试。
/compact [focus]把历史总结后替换,保留要点。可带 focus,如 /compact keep only the plan and the diffcontext 很大,但目标/plan 仍然正确。
/clear彻底清空对话历史。你的代码改动会保留——/clear 不会回退文件。整个 session 都被污染了,想要一张白纸。

依赖 /rewind 前有两点要先知道(据 Anthropic 的 checkpointing 文档,2026 年 6 月)。第一,只有在输入框为空时,双击 Esc 才会打开 rewind 菜单;如果你已经打了字,第一下 Esc 是清空文字、第二下才打开菜单。第二,checkpoint 只追踪 Claude 自己的 edit 工具改过的文件——被 Bash 命令改动的文件(rmmv、某个脚本、一条往磁盘写的 migration)不会被记录,rewind 也撤不回来。这类改动只能靠 Git 兜底。checkpoint 会跨 session 保留,30 天后自动清理。

/clear 之后(或在全新 session 里),用一段自包含的紧凑 prompt 重启:

目标:[一句话]
当前代码:[贴整个文件,不是 diff]
失败测试/错误:[原样贴]
约束:不动测试,只动 src/X.ts。
先打出 plan,等批准再 edit。

干净的 context 不会被旧失败日志牵着走,通常一次就过。另外,/rewind 里选「只恢复代码」会回退文件改动但保留对话——讨论有用、但 edit 跑偏时很顺手。

Step 5:设迭代上限

预防下一个 loop。软约束是在 CLAUDE.md 里写一条规则:

## Agent 行为约束

- 每个任务最多 5 次 build/test 迭代
- 3 次失败后停下汇报
- 同一文件的同一块不要 edit 超过 3 次
- 任何工具调用重试 3 次后停下来问

Cursor 用 Project Rules / .cursor/rules、Codex 用 AGENTS.md——同理。不过 CLAUDE.md 里的规则只是建议性的,agent 能给自己找借口绕过去。要硬停就加一个 Stop hook:Stop 事件在 Claude 回完一轮时触发。

这里方向特别容易搞反,要看清楚(据 hooks 文档,2026 年 6 月):对 Stop hook 来说,exit code 2{"decision": "block"}阻止 Claude 停下、强迫它继续——和你想要的 loop 护栏正好相反。要在上限处真正停掉 session,得往 stdout 输出 {"continue": false, "stopReason": "iteration cap reached"}(exit code 是几都行)。写个小脚本读迭代计数、超过上限就打印 {"continue": false, ...},你就有了一个模型无法绕过的护栏。千万别用 exit 2 去停 loop——它的效果是反的,会让 agent 继续跑。

Step 6:卡 plan 时强制 replan

agent 永远 step 1:

停。当前 plan 不行。不要继续。
打印:
1. 为什么 step 1 不行
2. 两个替代方案
3. 推荐一个

等我批准再继续。

强制 agent 跳出失败 plan,不是在上面磨。

怎么确认 loop 真的断了

loop 可能这一轮看着好了、下一轮又接上。走人之前,先查三件事:

  1. trace 在往前走。 再让它列一遍最近 10 个动作的表格。你该看到新文件、新行,而不是同一个 edit 反复。同一行被改了 3 次以上——还在 loop。
  2. 信号是确定的。 你自己手动把目标检查连跑 3 次。如果不是稳定绿或稳定红,那你什么都没稳住——flaky 测试还在给 agent 喂噪声。
  3. 完成标准被字面满足。 不是「看起来好了」——你当初给的那条确切命令 exit 0。自己跑一遍 pnpm test -- auth(或你指定的那条),亲自确认 exit code。

三条都成立,loop 才算断。任何一条没过,你离下一个 loop 只差一个 prompt。

预防建议

  • CLAUDE.md 设迭代上限,再用 Stop hook 兜底——给 loop 一个内建、模型无法绕过的出口。
  • 把 flaky 测试隔离到 flaky.test.ts——agent 永远不会在不稳定信号上迭代。
  • 同一步骤连续失败 3 次就强制 replan。
  • 给出显式完成标准——不要「修 login」,而是「pnpm test -- auth exit 0」。
  • 看 agent 的动作 trace,不只看最终输出——loop 在结果暴露之前,早就显形在 trace 里了。
  • loop 一出现,就双击 Esc 回到干净 checkpoint、或 /clear 重启,别去救污染的 session。
  • 盯着 /context;超过 ~70% 就主动 /compact,免得任务中途撞上 auto-compact thrashing 那堵墙。
  • 如果 thrashing 是某个巨大文件引起的,让 agent 按行号区间读、别整个读,或者把这部分活儿交给一个跑在独立 context 窗口里的 subagent。

FAQ

Claude Code 卡在循环里,怎么停下来?

Esc 停掉当前动作,或按 Ctrl+C 取消卡死的命令。一次不行就再按——连按会升级到强制结束。终端彻底卡住的话,关掉它,在同一目录下跑 claude --resume 接回同一 session。

/clear/compact/rewind 有什么区别?

/clear 清空对话历史,但保留你的代码改动。/compact 把历史总结后替换(可带 focus,如 /compact keep only the plan and the diff)。/rewind(或双击 Esc)打开 checkpoint 菜单,可把对话、代码、或两者恢复到更早的某个 prompt。撤坏 edit 用 /rewind,给仍然有效的 session 瘦身用 /compact,想不丢文件地重新开始用 /clear

Claude Code 会自动建 checkpoint 吗?

会。截至 2026 年 6 月,你发的每个 prompt 都会生成一个 checkpoint,双击 Esc(或 /rewind)就能回滚到其中任意一个——只恢复对话、只恢复代码、或两者都恢复。

为什么同一个 flaky 测试会让 agent 反复 loop?

flaky 测试给 agent 一个不确定的过/挂信号,于是它改、看到绿、下一轮又红、回退——没完没了。先把测试稳住(mock 掉时间/网络/随机,比如 vi.useFakeTimers()),再让它继续。绝不要让 agent 在一个会自己变的信号上迭代。

能不能硬性限制迭代次数,让 loop 根本发不出来?

能。CLAUDE.md 里的规则只是建议,但 Stop hook 由 Claude Code 强制执行:迭代计数超过上限时输出 {"continue": false, "stopReason": "..."},agent 就无法再往下走。这里别用 exit code 2——对 Stop hook 来说,exit 2(以及 {"decision": "block"})会强迫 Claude 继续,正是你想停掉的那个 loop。能停掉 session 的只有 {"continue": false}

相关阅读

外部参考:

标签: #排查 #Claude Code #排查 #Agent 死循环