你让 Claude Computer Use 填一份表单、点提交、读确认信息。Claude 点了提交按钮。页面看起来没变化。Claude 又截图一次,发现表单还在,于是再点一次。然后再一次,再一次。十几二十轮过去,任务还在跑,聊天记录里全是”我将点击提交按钮”。模型并不蠢 —— 它只是在根据看到的画面做反应,而它看到的画面前后没有差异。这种死循环几乎只来自五种原因:截图捕捉到了错误帧、Claude 看不到的焦点状态、确认弹窗渲染到了画面外、视口尺寸变化后坐标漂移,或者点击落在了被覆盖 / disabled / z-index 错误的元素上,页面真的什么都没发生。
常见原因
按典型 Computer Use 死循环出现的概率排序。
1. 点击落在了覆盖层上(modal 遮罩、tooltip、透明 overlay)
Computer Use 是按像素坐标点击的。如果点击瞬间,目标按钮上方刚好盖着一个 tooltip、modal 背景或者 pointer-events: auto 的 overlay,那这一击就打在了覆盖层上,按钮根本没触发。下一张截图看起来一模一样,Claude 又点一次。
如何识别:手动打开页面,在按钮位置悬停,DevTools 的 Inspect 工具看那个坐标的最顶层元素。如果不是按钮本身,就是这种情况。
2. 按钮”看着可点”,其实在等异步校验
很多表单的提交按钮在视觉上看起来是 enabled 的,但点击处理函数被一个 debounce 的校验逻辑拦住,要等校验跑完才生效。Claude 点得太早,点击被静默吞掉,页面纹丝不动。
如何识别:你自己手动在输入完后立刻点按钮 —— 如果要等 500-1500ms 才有反应,就是这个原因。
3. 截图在 DOM 稳定之前就抓了
Claude 的截图工具是有一个固定延时的(通常 800-1500ms)。如果页面在做客户端路由切换,中间有一个 2 秒的 loading 转圈,Claude 截到的就是转圈那一帧,然后判断”还在加载,再点一次” —— 但此时点击早就成了误操作。
如何识别:看截图里有 spinner / skeleton 占在内容应该出现的位置,而 Claude 还在反复点那个其实已经失效的 CTA。
4. 视口 / 缩放变化后坐标漂移
如果浏览器缩放级别、devicePixelRatio 或者窗口大小在两轮之间发生了变化(自动 resize、侧边栏收起、移动端模拟时弹出虚拟键盘),Claude 之前算好的像素坐标就不再对应同一个 DOM 元素了。
如何识别:对比两张连续截图 —— 如果按钮挪了几像素,但 Claude 还在点老位置,就是坐标漂移。
5. 确认弹窗渲染在画面外或者在 Claude 看不到的 portal 里
有些 UI 把 modal portal 到 document.body 的某个位置,而 Claude 截图区域刚好没包含那里(比如挂在页面顶部,但当前滚动位置在中间)。Claude 看到的还是没变化的表单,而 modal 正在屏幕外等用户输入。
如何识别:手动把页面滚到最顶部 —— 如果那里真的有一个 modal 挡着,那 Claude 需要先被告知滚动到顶部。
6. 操作其实成功了,但成功提示太微弱
一个 200ms 淡入、停 1.5 秒再淡出的 toast。一个 800ms 就消失的绿色边框。等 Claude 下一轮截图触发的时候,成功信号已经没了,所以 Claude 判定操作失败。
如何识别:手动操作一遍,看成功提示能在画面上停留多久。如果不到 2 秒,Claude 大概率会错过。
排查前的准备
- 把死循环里所有的截图保存下来。每轮的截图是判断 Claude 看到了什么的唯一证据。
- 把触发这次运行的原始 prompt 记录下来 —— 像”请一直尝试直到成功”这种措辞,会让死循环更严重。
- 留意死循环是不是确定性的(每次同一个网站都循环)还是偶发的(有时能跑通)。偶发指向时序问题,确定性指向结构问题。
需要收集的信息
- 死循环的连续截图(至少 3 轮)。
- 目标网站 URL 和让 Claude 做的具体操作。
- 你用的是 API、Console 还是某个桌面端壳子接入 Computer Use —— 不同入口的默认截图延时不一样。
- 运行时的浏览器缩放级别、视口大小、devicePixelRatio。
- 你自定义的 system prompt 或 tool-use 指令。
一步步修复
按 ROI 排序,便宜的检查在前。
第 1 步:在 prompt 里加上明确的”等待并验证”指令
最有效的一招:
每次点击之后,等待 3 秒,截一张图,确认预期的变化出现了。
如果新截图和点击之前的截图看起来完全一样,绝对不要再点同一个元素。
改为滚动页面、扩大截图范围,或者去页面其他位置找错误信息。
这条规则能在大多数情况下打破第 1、2、3、6 类死循环 —— 因为 Claude 不再盲目重试了。
第 2 步:在判定状态前先强制滚到顶部
如果你怀疑确认信息渲染在当前滚动位置之上:
在判断操作是否成功之前,先把页面滚到最顶,等 1 秒,再截图。
modal 和 toast 经常 portal 到 document.body 的顶部。
第 3 步:能用文字标签定位的就别用坐标
Computer Use 可以通过 prompt 引导用”按标签点击”的模式。在 prompt 里加:
点击按钮时优先用按钮上可见的文字标签来识别,而不是像素坐标。
如果同一坐标连续两次点击失败,说明按钮可能已经挪了位置 ——
请重新按标签定位。
这可以基本消除视口变化后的坐标漂移问题。
第 4 步:固定运行期间的视口尺寸
如果你能控制浏览器会话,在启动前把视口尺寸钉死:
# Computer Use 环境启动时
export COMPUTER_USE_VIEWPORT_WIDTH=1280
export COMPUTER_USE_VIEWPORT_HEIGHT=800
export COMPUTER_USE_DEVICE_PIXEL_RATIO=1
或者在 API 调用里通过 tool config 显式传入,避免运行中途被动 resize。
第 5 步:在 wrapper 里加一道硬性 loop-breaker
用代码包一层,检测连续相同的截图:
import hashlib
last_hash = None
identical_count = 0
def on_screenshot(image_bytes):
global last_hash, identical_count
h = hashlib.sha256(image_bytes).hexdigest()
if h == last_hash:
identical_count += 1
if identical_count >= 3:
raise StopIteration("3 张截图完全一致 —— 中止循环")
else:
identical_count = 0
last_hash = h
连续 3 张截图哈希完全一致,基本可以判定卡死。直接 abort 抛给用户处理。
第 6 步:对”惯犯网站”,尴尬的那一步用脚本预编排
有些网站(银行、老旧企业系统)对 Computer Use 特别不友好。对这种站,把点击 + 等待那一步交给 Playwright / Selenium 之类的确定性脚本,只把需要推理的部分留给 Claude。
验证
- 用新 prompt 重跑一遍原任务,确认 Claude 不再连续三次点同一个元素。
- 看截图序列:连续两次操作之间,截图应当肉眼可见地不同(弹窗打开了、页面变了、toast 出现了)。
- 任务的总轮数比原来的死循环跑法至少降低 40%。
长期预防
- 把每一次 Computer Use prompt 都当作一个状态机:“点 X,然后验证 Y 出现,再做下一步。“把验证步骤显式写进去。
- 在 system prompt 模板里固化一条”不允许在状态没有变化的情况下重复点击同一元素”的规则。
- Computer Use 会话一定要锁定视口尺寸和 devicePixelRatio,绝不留给宿主环境去自动调整。
- 对高价值的网站,提前录一组”成功态截图”,当作 Claude 判断”完成”的参照。
- 把截图都落到文件系统,这样失败的运行可以离线复盘,不必再烧 API 重跑一次。
常见坑
- 在 prompt 里写”请更努力一点”或”持续尝试” —— 这就是死循环的助燃剂。
- 完全信任按钮的视觉 enabled 状态,不去检查它背后是否还有异步校验在拦截。
- 跑 Computer Use 不设最大轮数预算 —— 一个死循环可以烧掉几百轮、几十美金。
- 把已经被限流 / 被验证码挡住的页面当作”只是慢一点”,Claude 会一直点下去。
- wrapper 日志里不区分”坐标点击”和”标签点击” —— 不区分就没法定位坐标漂移问题。
FAQ
Q:Claude 点对了按钮,但页面突然变白了,怎么办?
很可能点击触发了一个被沙箱拦掉的外发请求 —— CSP 或网络策略问题。手动重做一遍,看 Network 面板是不是有 CORS / CSP 报错。如果是,沙箱需要加白对应域名。也可参考 Claude 文件连接器陷入重新授权死循环。
Q:为什么死循环只发生在某些网站上,别的网站没事?
客户端路由重度、portal 渲染 modal、异步校验多的站,最容易循环。纯静态 HTML 表单几乎不会。修复手段是针对单站调 prompt,而不是一刀切全局参数。
Q:能不能把 max-turns 调大,赌它最后能成功?
不行。一旦开始循环就会一直循环 —— 输入没变,Claude 的推理也不会变。要么打破输入(滚动、等待、重新定位),要么直接 abort。
Q:用长上下文模型版本能解决吗?
略有帮助 —— 至少能让 Claude 记住”这个按钮我已经点过两次了”。但截图本身的同质化问题不是上下文问题,所以收益有限。prompt 上的修复才是关键。