如果你最近开始把 Claude Code 当常规编程工具用,大概率遇过这种画面:光标旁边的 Spinner 转了半天,屏幕上一行新内容都没出现,整个人瞬间怀疑是网络断了、官方服务挂了,还是自己把它用坏了。这个问题的出现频率远比想象中高,尤其当你处理大项目、长会话,或者把 Claude Code 接到非官方 API 网关时,“Spinner 卡住”几乎成了必经之路。
先直接说结论:大部分情况不是 Claude 真的不工作了,而是它卡在了某一环,比如等待云端响应、等待一个迟迟不结束的终端命令,或者是终端自己渲染大量输出时拖垮了界面。Spinner 只是它的事件循环还在跑的一个指示,并不代表任务一定在推进。这篇文章不搞玄学,我按自己实际排障的思路,把 Spinner 状态标识、卡顿根源、以及一套可复现的排查方案完整梳理一遍。看完之后,再遇到这种情况你至少知道该从哪里先下手。
1. Spinner 状态标识:它到底是不是“忙”
1.1 Spinner 的真相:不是进度条而是事件循环指示灯
Claude Code 是一个终端里的 Agent 式 AI 编程助手,它的工作流程可以简单理解成:用户下达任务后,它把任务拆解成一系列步骤,每个步骤都可能触发一次大模型 API 请求,也可能触发一次本地工具调用,比如读文件、执行 Bash、修改代码。在等待当前步骤完成的时候,终端界面上就会出现一个不断刷新的动画,也就是我们常说的 Spinner。
关键认知要纠正一下:这个 Spinner 不是进度条,它只代表“事件循环还活着”。也就是说,Claude Code 的进程没有崩溃,程序还在等待某个异步任务的 Promise 被 resolve。网络请求如果一直不返回,Spinner 照样转;某条命令卡在前台不退出,Spinner 也照样转。所以我的经验是:不要用 Spinner 是否转动来判断“它是否在工作”,而要看它是否有实际输出、有日志流动、有 CPU 占用。把 Spinner 理解成“心跳”而不是“进度”,排障思路就清晰了。
1.2 几种常见 Spinner 状态对照
我把 Claude Code 运行中比较典型的状态做了个归类,方便你遇到时快速对照:
| 表面现象 | 可能的真实状态 | 说明 |
|---|---|---|
| Spinner 快速转动,屏幕持续刷新 | 大模型响应正在流式返回 | 通常伴随代码 diff 或文字一段段出现,这是最健康的状态 |
| Spinner 转,但几秒到十几秒没动静 | 等待服务端首包返回 | 网络延迟高、网关排队,或请求体过大导致上游处理慢 |
| Spinner 转,屏幕上停在某条命令之后 | 工具调用尚未结束 | 比如 Bash 命令还没退出,或脚本在等待输入 |
| Spinner 几乎不动,移动一下光标又恢复动画 | 终端渲染性能问题 | 大量文本堆积在终端缓冲区,重绘开销很高 |
| Spinner 长时间转,然后断线 | 连接被远端关闭 | 常见于鉴权失败、请求被网关熔断,或网络链路中断 |
| Spinner 突然消失,界面退回提示符 | 当前步骤已结束 | 可能正常完成,也可能被用户中断或异常终止 |
这里要特别提醒一句:Spinner 的快慢并不能精确反映“任务进行到什么程度”。有时候你以为转得快就离成功近,其实只是服务端在发小片数据;有时候慢吞吞的 Spinner 可能是在做一次很重的文件索引,之后突然给出一大段结果。所以对照表的价值更多在于帮你判断“下一步该看哪里”,而不是告诉你“还要等多久”。
1.3 判断“真卡”与“假卡”的关键信号
判断一个卡顿是真是假,我一般看三个信号。第一个是输出有没有推进:等 10 秒左右,如果连一个字符都不出,同时进程 CPU 占用很低,那大概率不是正常推理,而是卡在等待网络或者工具返回。第二个是日志有没有变化:Claude Code 会把完整的会话流程写到本地日志里,日志一直在追加,就不用太慌;日志也停住,那才是真的僵住了。第三个是界面交互是否还能响应:按一下回车或者 Esc,如果终端本身没反应,可能连终端假死都搭进去了,这种情况要优先处理终端。
真实线上踩过的坑是这样的:有一次我让它修一个 Go 项目的并发 bug,它连续跑了三四个工具,Modify 文件也做了,但 Spinner 还在转。我当时以为卡了,直接 Ctrl+C 中断,结果把已经改了一半的文件状态弄乱了。后来看日志才发现,它是在等一个 shell 命令执行完,那个命令因为网络下载依赖包太慢,一直没返回。这件事给我的教训是:中断前一定要先确认工具调用日志,最好让它自己超时,而不是急着手动刹车。
2. 卡顿根源:网络、上下文与终端渲染
2.1 网络层导致的无限等待
网络是最常见的挂起原因,它又分好几种情况。你直接使用官方服务时,请求走的是流式接口,正常情况下首包几百毫秒内就会到达。但如果本地到云端的链路不稳定、代理规则配置异常、或者中间某个网关把连接挂住,客户端就会一直等。这类问题在外层表现就是:Spinner 频繁出现,有时等几分钟突然又出结果,有时干脆等到超时。
另一个很容易踩的坑是自定义 API 网关。Claude Code 可以通过环境变量或配置文件把请求路由到第三方兼容接口,比如很多朋友会用 cc-switch 这类工具把 Claude Code 切换到其他大模型接入方式。第三方网关如果对 SSE 流式协议兼容得不好,数据是一个包一个包缓慢吐出来的,Claude Code 这边就会呈现出“Spinner 长转、输出按段蹦”的特征。还有的网关会在模型推理完成后才一次性返回,这就更让界面显得像卡死。
针对网络层,我的建议是:遇到 Spinner 长时间不动时,先到另一个终端窗口里用ping或curl简单测一下对应 API 地址的响应时间。如果域名解析或连通性都有问题,那问题就不在 Claude Code 这边,而是网络环境或 API 配置有问题。
2.2 上下文膨胀和工具调用阻塞
第二个让人误以为是“卡死”的根源来自上下文本身。Claude Code 在处理长会话时,会把历史消息、工具调用列表、文件内容和命令结果都拼进请求里。你让它连续干几小时活,会话上下文可能膨胀到几十万 token。每次生成新内容,服务端都要把整套上下文重新处理一遍,响应速度自然会断崖式下降。这时候 Spinner 并不会消失,它只是把“等待请求完成”的时间拉得很长。
还有一类情况是工具调用本身堵住了链路。Claude Code 允许 Agent 动态执行 Bash 命令,但命令如果进入交互模式,比如执行了ssh远程登录、启动了某个需要密码的脚本、或者运行了watch这类持续刷新的命令,它可能永远不会正常退出。Claude Code 在等待这个命令的 stdout 结束后才能继续下一步,于是整个流程就被“焊死”在这条命令上。典型现象是:Spinner 转着,终端里还能看到光标在闪,但无论你怎么按都得不到回应。
2.3 终端渲染是容易被忽略的瓶颈
这一层很多人没意识到,但它造成的体感非常明显。Claude Code 经常会把工具执行结果直接打印到终端上,比如读取一个几千行的日志文件、跑一次全仓库搜索、或者把 diff 一次性铺满屏幕。终端模拟器在处理超长文本时,需要逐行计算排版、绘制颜色、处理高亮,数据量大的时候 CPU 占用会飙升,界面就会卡到连 Spinner 动画都不流畅。
我自己做过桌面工具,对这个问题印象特别深。用 Qt 的QTableWidget塞几万行数据,不做任何优化,一滚动就卡得不行;改成QTableView + 自定义模型,只加载可见区域需要的行,性能立刻提上来。终端渲染其实也是同一个道理:屏幕要显示的海量文本就是一种“大数据表”,如果终端模拟器没有足够好的虚拟化渲染能力,输出的行数一多,UI 就会拖不动。所以当你发现 Claude Code 在打印大段内容时变慢,不要怀疑模型,先怀疑终端。
这种情况下,可以试试把输出重定向到文件而不是直接打印到终端,或者在命令里加head -n 100控制显示行数。效果立竿见影,Spinner 会明显变得更加流畅。
3. 排查方案:从“猜”到“看”
3.1 先确认是不是真死锁
遇到 Spinner 卡住,先别急着重启。我会按下面几步确认:
- 观察 10 到 20 秒,看是否有字符增量输出。
- 打开另一个终端窗口,用
top或htop查一下 Claude Code 进程的 CPU 占用。如果 CPU 一直有波动,说明它大概率还在处理数据;如果 CPU 变成 0,多半是卡在网络等待上,或者某个子进程阻塞了。 - 看网络流量。在系统监控里看对应进程的收包速率,持续有收包就说明请求在进行,只是慢。
这套动作做完,再决定要不要干预,避免误杀一个本可以正常完成的任务。我见过太多人因为急躁,在工具正写文件时按 Ctrl+C,最后留下一堆半成品代码,收拾起来更费劲。
3.2 /status 与 debug 日志
Claude Code 提供了状态相关的命令,最常用的就是/status。它可以显示当前连接状态、模型、会话上下文统计等信息。当你怀疑 Spinner 是网络问题的时候,先跑/status看看能不能正常获取服务端状态,这比瞎猜直观得多。
如果常规命令还看不出端倪,就开启 debug 模式。启动时加一个参数,比如:
claude --debug或者在启动之前设置 verbose 环境变量,让 Claude Code 把每一步内部事件都打印到终端。调试模式下你会看到请求发出去的状态、工具调用的事件流、响应接收的进度,这样就能很清楚地分辨它到底卡在哪个环节。看到密密麻麻的调试信息不要慌,只在排障时开就好,平时不用开。
3.3 session 日志怎么读
Claude Code 的日志体系非常完整,对排障帮助很大。它通常会把每次会话记录成 JSONL 文件,位置一般在:
~/.claude/projects/<项目目录名>/<会话id>.jsonl这个文件每一行是一个完整的事件对象,包括用户消息、助手消息、工具调用、工具执行结果等。你可以直接搜索关键字排查,比如:
# 找到最近记录中包含 error 的行 grep -i "error" ~/.claude/projects/你的项目目录/*.jsonl | tail -n 20我个人排障最关注三类字段:一是is_error,看工具执行是否报错;二是tool_use_result的体积,如果单条结果大到几万字符,说明上下文正在被撑爆;三是请求之间的时间间隔,如果相邻两条请求间隔特别长,那基本可以锁定是网络等待或网关超时。
这里说一个共性问题:很多人问“日志里什么都没有,为什么 Spinner 还是卡?”实际上绝大多数卡顿都会在日志中留下痕迹,只是事件类型比较隐蔽。比如连接重试不会标注成错误,它会表现为多次api_request事件之间夹杂了很长的间隔。看到这类模式,就直接检查网络和上游服务即可。
3.4 本地版本与全局环境检查
排查到最后,如果日志还没发现明显问题,我会检查本地环境。Claude Code 的安装和升级链路如果出现问题,也会导致莫名的卡顿。比如用 npm 全局安装的用户,可能由于多个版本并存、缓存残留等原因,实际跑起来的是一个旧版本或半新半旧的包。
建议按下面顺序操作:
# 查看当前版本 claude --version # 更新到最新版本 npm install -g @anthropic-ai/claude-code@latest # 如果问题依旧,卸载后重装 npm uninstall -g @anthropic-ai/claude-code npm install -g @anthropic-ai/claude-code重装之前最好看一下全局 node_modules 里是否残留旧的 claude 相关目录。有时候 npm 的缓存会导致新版没有被正确覆盖,装完还是老行为。换版本之后,再跑一遍同样的任务,如果卡顿依旧,基本可以排除版本因素。
4. 防卡顿思路:给工作流“加护栏”
4.1 限制输出量和读取范围
很多卡顿是“人为制造”出来的。比如你让 Claude Code 读取一个大文件,或者让它搜索整个项目后把结果一股脑打印出来,处理时间和终端渲染压力都会成倍增长。比较好的习惯是在提示词里给输出加边界,比如“只列出文件路径,不要展示文件内容”“输出结果最多 50 行”“grep 时限制匹配数量”等。
还可以在 Agent 的执行命令里主动加限制。比如它需要查看日志,我会更建议它在命令中带tail -n 200而不是直接cat整个文件;搜索代码时用grep -r --max-count=50而不是无约束地全量扫描。这相当于给工具调用装上“限流阀”,让它别把大体积数据运回上下文。
我自己的经验是:输出量减少之后,不仅卡顿少,回答质量也会提升。因为模型不会被一堆无关内容淹没,它更清楚该关注哪些信息。
4.2 慎用交互式命令
Claude Code 执行 Bash 命令时,最怕遇到交互式程序。如果你知道某个命令可能进入等待输入的状态,最好从源头规避。方法有两个:一是给命令套上一层超时保护,比如:
timeout 60 npm install这个命令可以确保即使进程没结束,60 秒后也会被强制终止,Claude Code 拿到退出结果后就能继续往前走。二是明确要求它使用非交互式参数,比如各种 CLI 工具常见的-y、--no-input、-f选项。
还要注意,有些命令虽然不会显示交互提示,但会持续产生日志输出,比如tail -f或npm run dev。这类命令天然不适合让 Agent 在会话里直接跑到结束,因为永远等不到结束。我一般会让它把这一类长驻进程放到后台,或者直接禁止它执行这类命令。
4.3 及时压缩或重建会话
长会话是卡顿的最大催化剂之一。上下文窗口虽然能装下很多内容,但装得越多,单次请求处理得就越慢。这里有几个很实用的控制手段:
- 在对话中执行
/compact,让 Claude Code 把历史摘要压缩后再继续。 - 如果任务边界很清晰,直接
/clear清空上下文,新开一个会话做下一件事。 - 不要让 Claude Code 在同一个会话里同时处理太多无关任务,比如既要修 A 模块,又要重构 B 模块,分开会话更稳。
我个人习惯是一天中把工作按任务切成多个短会话,每个会话目标单一,防止上下文无意义膨胀。短期看好像多开了几个会话,长期看效率反而高,因为每次请求的响应速度都能保持在一个比较低的延迟区间。
4.4 更新、重装与终端调优
Claude Code 更新频率不低,官方修 bug 和优化性能的速度还是可以的。如果长时间没更新,建议每隔一段时间主动 upgrade 一次。更新后如果发现某些旧会话无法恢复,也不用慌,直接重开新会话即可。
另外,终端本身也值得调优。Windows 上比较推荐用 Windows Terminal 而不是老旧的 ConHost,Windows Terminal 对 ANSI 渲染和滚动性能更好。如果你在 Windows 上跑虚拟机或使用蓝牙外设时遇到系统级卡顿,那更应该先解决系统层面的资源占用,否则任何终端工具都跑不利索。就好比我以前在 Win11 里同时开着虚拟机、浏览器和 VS Code,系统整体响应变慢,Claude Code 的 Spinner 也跟着半天没反馈,那不是 Claude Code 的问题,是系统资源被吃光了。
5. 高热度卡顿问题速查
5.1 我几乎天天被问的几个场景
结合大家在各种社区和群里问得最多的问题,我把高频卡顿场景整理成下面这份速查:
| 问题现象 | 首选排查动作 | 可行的处理办法 |
|---|---|---|
| Spinner 一直转,屏幕长时间无输出 | 看网络流量和 CPU 占用 | 用/status查连接状态,必要时 Ctrl+C 中断后重试 |
| 按了回车也没反应 | 检查终端是否卡死 | 最小化/恢复窗口一次,或切换终端模拟器 |
| 大文件输出后开始卡 | 看终端渲染压力 | 让命令输出重定向到文件,或限制行数 |
| 长时间运行后越来越慢 | 检查上下文大小 | 执行/compact或/clear,重建会话 |
| 工具调用停在某条命令后 | 看命令是否交互式 | 给命令加timeout,避免交互程序 |
| 频繁断线,日志里有连接错误 | 检查 API 网关和鉴权 | 核对密钥、模型名、接口地址,重新登录 |
其中中断操作要谨慎:一次 Ctrl+C 通常是中断当前生成,但如果在工具执行关键步骤时中断,可能留下不完整的文件状态。优先按 Esc 尝试停止当前操作,如果还不行再考虑 Ctrl+C。
5.2 接入非官方模型的额外注意点
现在不少人会把 Claude Code 接到其他第三方兼容接口上,比如 deepseek、qwen、glm 这类模型。这个玩法很实用,但也需要额外留心两个问题。第一,不是每个后端都完整实现了工具调用协议,如果模型本身对函数调用支持不完善,Agent 就可能反复重试某个工具,表现出 Spinner 长时间停顿。第二,第三方网关的流式传输质量和超时设定差距很大,有些网关要在模型完整生成后一次性返回全部内容,肉眼看起来就是长时间没反应。
我的建议是:切换这些模型接入方式后,先做一个小任务验证,比如让它读一个文件并修改一行。如果这个小场景都能顺畅走完,再让它跑复杂任务。一旦发现某个模型在多个小任务中都表现不稳定,哪怕它是 API 网关里有而 Claude Code 里用着也难受,就果断换回更稳的模型或官方接口。工具是用来提效的,没必要为了适配把自己心态熬崩。
6. 一点个人使用习惯
最后说点我自己的实操体会。现在我用 Claude Code 干活,已经不纠结 Spinner 是不是一直在转了。只要它还有输出流动、日志还追加、CPU 有占用,我就当它在忙;只有确认这三个信号都停住,我才会介入。介入也不是直接重启,而是先/status看连接、再开 debug 看事件、最后看 session 日志。
有一个细节我反复跟同事强调:大任务一定要拆开。连续干几个小时的超长会话,除了越跑越慢,还会让 Claude 在后续步骤里出现“自我感动式改代码”的情况,把本不该动的地方也动了。每天开工新开一个会话,每完成一个子任务就/clear一次,这个习惯帮我避免掉大量无意义的卡顿和返工。Spinner 卡住不可怕,方法不对才真的浪费时间。