1. 性能问题出在哪:先搞懂 Claude Code 的慢与乱
我在真实项目里用 Claude Code 干了几个月,最直观的感受是:它大多数时候不是“能力不够”,而是“效率撑不住”。你给它一个任务,它吭哧吭哧写好几十个文件,改完这个改那个,中间各种上下文丢失、重复读文件、反复确认权限,真正写业务逻辑的时间可能只占三分之一。这个工具本身是一套完整的 Agent 化开发环境,核心价值在于让模型自主完成“读代码—定位问题—设计改动—执行改动—验证结果”的闭环。但在默认配置下,这个闭环跑得极其拖沓。
先说最常见的性能瓶颈,基本集中在四个方面:模型等待时间、上下文窗口被无效信息挤占、工具调用链路过长、权限确认打断流程。第一点是模型服务端的响应速度,你换不同模型、不同接入方式,体感差距能拉到两三倍。第二点最隐蔽,Claude Code 每轮会把会话里的历史消息、读取过的文件内容、工具输出一股脑塞进上下文,一旦之前读过大文件或者输出过超长报错,后面的有效工作区就被挤没了,模型开始忘事、答非所问。第三点是它经常为了确认一个小改动反复去读文件、列出目录、搜索符号,每一步都是独立的 API 请求,累积起来非常可观。第四点不用多说,默认权限模式下每个命令都要你按 Y,交互卡顿不说,整个自动化链路直接被切成碎片。
所以聊“性能提效”,本质上是在解决这四个问题,而不是单纯地“换个更快的模型”。我把实际优化过程拆成几个部分:环境与选型、上下文管理、权限与自动化、工作流设计、大规模仓库的策略、以及性能监控与排错。这套组合拳打完,我这边从“一个任务跑四十分钟还经常跑偏”变成了“二十分钟内稳定收工”,关键是中途不需要我反复介入。
2. 环境选型与模型路由:等待时间的源头优化
2.1 不同模型和接入方式的真实体感差异
Claude Code 最舒服的用法是接 Anthropic 官方的 API,响应稳定,工具调用能力最完整。但在实际工程环境里,团队往往受限于账号额度、网络条件、成本控制等因素,会选择兼容 OpenAI 协议或 Anthropic 协议的第三方端点。我这边同时试过官方 API、聚合网关、以及接 DeepSeek 这类开源模型的本地化部署,先上结论:模型路由决定了感知性能的 60% 以上。
具体数据参考我本地压测的结果。同一段代码重构任务,官方 Claude 模型在 35 轮对话内完成,平均等待 2.8 秒;接同为 Anthropic 协议的第三方大模型(比如 DeepSeek-V3 风格的路由端点),平均等待 5 到 9 秒不等,而且工具调用成功率明显下降,经常出现“意图识别正确但参数格式错误”的情况。更麻烦的是模型输出质量对工具调用链的影响:弱模型在需要多步规划的任务上容易“自作主张”跳过关键步骤,比如明明该先跑测试却直接改代码,最终完成后验证失败,整个流程重来。这种隐性成本远比单次响应延迟更伤效率。
2.2 正确的模型路由策略
我的做法是明确分级:复杂架构设计、跨多文件重构、大规模迁移这类任务用最强的模型(比如 Claude 的 Opus 级别),局部修复、单文件改动、写测试、跑脚本这类高频低难度任务用标准模型(Sonnet 级别或者轻量开源模型)。Claude Code 允许你在会话中通过/model切换,也支持在命令行启动时通过--model参数指定。更高效的方式是在配置里设定不同场景的默认模型,然后在子任务里手动切换。
此外还有“思考等级”这个东西。Claude Code 有多个推理档位(比如low、medium、high、xhigh),默认情况下系统会自动决定,但实测下来,对于简单任务,比如改一行配置、写一小段脚本,把思考等级调低可以明显减少等待时间;对于复杂任务,反而应该主动调高,否则模型为了“省思考”会在中间步骤犯错,然后花更多轮次纠正。我在按xhigh档执行跨模块重构时,首轮响应时间大概会多出 5 到 8 秒,但整体任务轮次减少了三分之一,这是划算的。
2.3 环境安装与基础配置里的隐藏坑
Claude Code 本身对运行环境的要求不高,Node 18 以上的 LTS 版本就行,系统上装好 Git 和常用构建工具链。安装流程是全局安装 CLI 包后通过claude命令启动,首次运行会引导做登录授权。这里有两个容易踩的坑:第一,终端代理与 API 网关冲突。如果你的开发机配置了全局代理,Claude Code 默认会走代理,而企业内网网关可能不认这个代理,导致请求超时。解决办法是在启动命令前明确设置HTTPS_PROXY和HTTP_PROXY为空,或者指向正确的内网代理地址,具体看你网络环境。第二,目录权限不正确。它运行时会在用户目录下创建配置和会话存储目录,如果磁盘权限受限,明明装好了却无法启动,报错信息还很不直观。遇到unable to connect之类的网络类报错,先别急着查 API Key,先确认网络链路上能不能正常到达 API 端点,用 curl 直接测一下是最快的定位方式。
3. 上下文管理:把宝贵的窗口留给真正要紧的内容
3.1 上下文被谁偷走了
我一直认为 Claude Code 性能问题里最容易被低估的是上下文溢出。刚才说过,每轮对话它会把历史消息、读取过的文件、工具输出全部放到上下文里,顺着会话越来越长,有效工作区越来越小了。当上下文被塞满,模型的常见反应是:开始遗忘早期的任务约束,把新问题误判成旧问题;回答质量断崖式下降;开始重复已经执行过的操作,甚至出现循环调用工具的情况。
我做过一次实测:在一个大型前端项目里,让 Claude Code 完成“修改用户登录流程中的 token 刷新逻辑”。任务本身不复杂,但由于项目里有好几个超过八百行的大文件,它为了理解代码结构一口气读了四五个文件,又跑了两次全量搜索,上下文一下吃掉大半。等到真正开始改代码,模型已经处于“半失忆”状态,改到一半忘了 token 刷新接口的调用入口,重新又去读文件,如此反复。整个任务最终用了 52 轮对话、耗时长到没法看,而我自己手动改只需要十五分钟。
3.2 给会话做“减脂”的实操方法
第一,勤用/compact而不是死扛到底。/compact会把当前对话的核心内容压缩成摘要,丢弃细节历史,释放上下文空间。我习惯在每完成一个阶段任务后主动执行一次,哪怕上下文还没满。摘要机制会保留任务目标、已改动文件、当前状态和未完成事项,足以让模型继续工作。注意压缩后模型对具体细节的记忆可能变模糊,所以执行/compact之前,最好让模型先输出一份简短的“当前进度记录”,存进项目里的AGENTS.md或临时 markdown 文件,这样压缩后它还能通过读文件恢复“记忆”。
第二,控制单次读取文件的规模和数量。Claude Code 的命令行界面支持直接用@文件名引用文件,但它自动读取的往往是整个文件。对于超大文件,我更推荐先让它grep定位关键函数,再用sed或awk看局部片段,避免整文件入上下文。
第三,善用/memory和CLAUDE.md。Claude Code 支持项目级记忆文件,在项目根目录放一份CLAUDE.md,写清项目结构、技术栈、代码规范、常用命令和已知约束,模型会在每次会话开始自动读取。这看起来像是在“增加上下文占用”,其实是稳赚不赔的买卖:它用少量固定开销,避免了模型在会话中反复读代码探索项目结构的大额开销。它知道“这个项目是 Next.js + pnpm + Tailwind,组件目录在 src/components,API 路由在 src/app/api”,就省去了每一轮去翻目录的步骤。
第四,关掉无关功能以减少噪音注入。Claude Code 有输出流式显示、搜索工具日志、shell 命令结果回显等功能,这些对调试有帮助,但对性能全是负担,尤其是 shell 输出超长时报错的时候,可能一条几千行的日志就把上下文塞爆。我建议把日志显示级别调到精简模式,并在 prompt 里显式约束“执行命令时输出摘要信息即可,不要回显完整日志”。
3.3 关键模型参数与超时控制
环境变量里有一个CLAUDE_CODE_MAX_OUTPUT_TOKENS可以控制单次模型输出的最大 token 数,设置得太小会让复杂任务一次写不完被迫分多轮,设置得太大可能出现单次输出失控、等待时间翻倍。我的经验值是 8000 到 16000 之间,具体看你的任务类型。如果频繁出现“模型写了一多半突然截断”,大概率是输出 token 上限不够,可以适度调高,同时配合 prompt 里对输出格式的约束(比如“请分步完成,先给出方案再执行”),让模型学会分块交付。
另外,Claude Code 的请求有超时限制,在弱网环境里大请求很容易超时中断。这时可以适当调大超时时间,但不要无脑调大——真要到了几十秒还不返回,说明端点质量本身有问题,应该换端点而不是等超时。
4. 权限配置与自动化链路:把等待从交互中挤掉
4.1 不同权限模式下的性能差异
默认情况下,Claude Code 面对 Shell 命令和文件写入操作都会弹出确认请求。这种交互模式对教学和演示场景很友好,但在批量处理或长链路自动化任务里就是灾难。每个确认都涉及一轮输入等待,虽然单次只有几秒,但几十个工具调用累加起来,任务总时长被拉到两三倍。更气人的是,有些操作工具会反复确认同一类命令,比如每次执行npm test都要你按 Y。
Claude Code 提供多种权限模式,从完全手动到全部放行。我推荐的折中方案是--permission-mode: acceptEdits加--allowedTools白名单的组合。也就是说:文件编辑类操作自动放行(因为代码改动是 AI 编程的核心价值,每次都问就失去意义了),Shell 命令类操作按白名单放行(例如允许npm test、git status、pnpm build等安全命令),其余高风险的命令(如rm -rf、curl下载执行、数据库变更)仍然需要确认。这样既绕开了最频繁的打断,又保留了安全底线。
4.2 通过白名单与 hooks 让流程无人值守
配置位置在~/.claude/settings.json里,也可以放在项目根目录的.claude/settings.json覆盖全局设置。一个参考配置:
{ "permissions": { "allow": [ "Bash(npm run build)", "Bash(npm test)", "Bash(git status)", "Bash(git diff)", "Bash(pnpm install)", "Read", "Edit" ], "deny": [ "Bash(rm -rf *)", "Bash(curl *)", "Bash(wget *)" ] }, "hooks": { "PreToolUse": [ { "matcher": "Bash", "hooks": [ { "type": "command", "command": "node .claude/hooks/check-command.js" } ] } ] } }这里最关键的是 hooks 机制。它允许你在工具调用前和调用后运行自定义脚本,做参数校验、命令改写、日志记录等操作。我在团队里维护了一套 hooks:PreToolUse阶段拦截Bash命令,检查是否包含危险参数,如果命中自动拒绝并返回提示;PostToolUse阶段把每次工具调用的耗时、输入输出摘要写入本地 JSON 文件,用于后续性能分析。这不仅提升安全性,还让我有数据去发现哪次调用最长、哪个工具最频繁,精准优化。
4.3 合适的任务上下文与强制终止策略
自动化链路中最闹心的场景是模型跑偏。比如你让它“给登录模块加一个验证码功能”,它顺着 web 框架的“惯例”自己决定改动数据库表结构、又去改用户模型,越走越远。等我发现不对时,它已经写了七八个无关文件。解决方案是:在 prompt 里使用强制范围约束,并约定好“如果超出范围请先停下询问我”。比如:
你的任务范围仅限于 src/features/login 目录下。 你可以读取其他目录用于理解,但不得修改 src/features/login 之外的任何文件。 如果必须修改外部文件,先停下来,列出修改理由,等我确认。配合权限配置,把写操作限制在指定目录内,就能有效遏制这种“跑飞”行为。另外,给长任务设置最大轮次限制也很重要,万一模型陷入循环,不会无限消耗资源。我会在启动命令加上--max-turns 30之类的限制,避免出现失控。
5. 工作流设计:如何让 Claude Code 真正干活而不是反复试探
5.1 两段式工作流:先出方案,后执行
我代码写久了之后最反感的就是让模型“直接改”。这是一种刻在骨子里的偷懒——模型不经过设计阶段直接落到具体代码,产生的方案经不起推敲,往往只满足当前测试而牺牲了工程可维护性。在 Claude Code 里表现得更明显:它拿到任务立刻开始搜索、改文件、跑测试,整个过程看起来“很忙”,但结果经常是把已有代码绕得更复杂。
我的对策是强制两段式工作流。第一阶段是Plan 模式:只让它读代码、分析现状、输出详细改动方案,不允许它编辑任何文件。第二阶段才切回执行模式:让它按方案逐步落地。Claude Code 内置了 hook 可以切换不同的系统提示词,你也可以通过自定义指令文件来实现。我的做法是在项目的.claude/commands目录里放两个自定义指令,一个叫plan.md,一个叫implement.md:
plan.md核心指令:
你的任务是输出一份《改动方案》,不要修改任何文件。 先回答三个问题: 1. 当前代码里与需求相关的模块有哪些,分别在什么位置? 2. 改动涉及的核心函数/组件/数据流是什么? 3. 你的具体改法是什么,按文件列表逐一说明? 方案里必须包含:影响面分析、风险点、测试计划。 输出前请用 grep 确认你引用的函数确实存在,避免幻觉。implement.md核心指令:
按方案逐文件实施,每完成一个文件的改动后运行相关测试。 不要同时修改超过两个文件。 先跑存量测试确认无回归,再写新代码。 每个步骤完成后用 git diff 查看改动,确保没有意外删改。这条工作流把“想”和“做”拆开,模型在方案阶段不受执行干扰,能把结构想清楚;执行阶段因为它已经输出过详细方案,下一次会话可以带着方案继续干活,上下文负担反而更小。实测下来,两段式工作流比直接执行平均减少 30% 到 40% 的无效轮次。
5.2 把大任务拆成小任务,一次只让它做一件事
Claude Code 在单次会话里承载的任务颗粒度决定了性能上限。塞给它一个“实现整个用户中心模块”的任务,它会在各种子任务之间来回横跳,每切换一次就要重新回忆上下文。更合理的做法是拆成多个独立会话:先创建数据库模型,再写接口,再写前端页面,每一步之间通过文档、commit 和测试来衔接。
这个拆分动作不是靠“感觉”的,我有一套判断标准:如果任务里包含超过三个不相关的技术栈领域(比如数据库 + API + 前端),或者改动文件预计超过十个,或者涉及跨模块接口设计,就一定要拆。拆完之后每个子任务用清晰的上下文启动,效率完全是两个档次。
5.3 引入外部知识库文件减少重复探索
团队项目的领域知识往往储存在文档、历史决策记录、注释和 PR 描述里,而模型对这些一无所知。与其让它在每次会话里通过搜索来重建这些知识,不如主动喂给它。我维护了几个固定文件:AGENTS.md(项目整体结构说明)、ARCHITECTURE.md(架构决策与模块关系)、CODING_STANDARDS.md(代码风格与提交规范)。这些文件由我和团队维护,但主笔其实就是 Claude Code——我会让它根据最近几次代码审查的输出提炼规范,然后我审核后固化下来。
这些文件存在后,每个新会话启动时模型会自动读取它们,相当于“入职培训”只有一次成本,后续全流程受益。尤其是在多人协作的项目里,不同开发者接入 Claude Code 都能获得一致的项目认知,避免每个人都要带模型“重新认识项目”。
5.4 让 Claude Code 自己维护进度文档
执行长任务时,在项目里维护一份PROGRESS.md非常有帮助:模型每完成一个阶段,就让它更新这份文件,记录已完成、进行中、待办、踩坑记录和下一步计划。这个文件的第一个用户是模型自己——会话压缩后它靠这个找回状态;第二个用户是你——快速审查当前进度;第三个用户是 CI 系统,能自动汇总任务产出。
我在团队里养成了习惯:任何超过半小时的自动化任务,都必须同步维护进度文档。看起来是在“浪费 token 写文档”,实际上是给整个流程加了一道安全锁和恢复点。一旦中途断线,新会话开起来读一下进度文件就能继续干,而不是从头再聊一遍需求。
6. 大型仓库实战策略:Claude Code 在复杂工程里的提速技巧
6.1 代码库索引优先于大文件读取
在大中型代码仓库里,Claude Code 最大的敌人是“盲目搜索”。默认情况下它会使用 grep 和 glob 搜索整个仓库,搜索范围越大,等待越长,结果噪音也越大。我用的办法是:在 prompt 里直接指定搜索范围,比如告诉它“搜索范围限定在src/modules/auth和src/shared/utils目录”,它就能自动带上路径参数,避免全库扫描。更进一步,用.claudeignore文件排除 node_modules、dist、构建产物这类无关目录,效果立竿见影。
还有一个容易被忽略的点:让模型多利用git log和git blame来理解代码演进。与其让它读整个文件猜测某段逻辑为什么存在,不如让它先查这个文件的提交历史——经常能直接找到当初的设计意图,省掉大量徒劳的代码考古。
6.2 编译错误优先修的“先跑后写”策略
在大型项目里最消耗性能的循环是:模型写完代码 → 跑构建 → 报错 → 模型读报错 → 修 → 再跑构建。每一轮构建可能就要一两分钟,几轮下来任务耗时就爆表了。加速手段有两个方向:第一,降低单次验证成本,引导模型用针对性单元测试而不是全量构建来验证小改动,改到文件粒度;第二,在 prompt 里明确要求“先检查代码中可能存在的编译错误,再提交测试”,让模型在执笔前先在脑内做一次编译检查。
Claude Code 对tsc --noEmit这类诊断命令的支持很成熟。我给模型设了一条规则:修改 TypeScript 文件后,必须先运行npx tsc --noEmit -p tsconfig.json,确认没有类型错误再继续。这个习惯让“验证循环”从几分钟降到十几秒,因为类型错误往往比逻辑错误更早暴露问题。
6.3 跨服务联调用 mock 和接口契约先行
如果你的项目是微服务架构,Claude Code 很难同时改多个服务然后本地联调,这条路会非常慢。我现在的做法是让模型只改单个服务范围内的代码,然后通过本地 mock server 模拟上下游依赖,接口契约先行定好,联调阶段由我拉通。这样一个改动只涉及一个代码库,模型不会有跨服务的上下文撕裂问题,性能和准确率都高很多。
6.4 超大目录树的处理技巧
树的扫描也是隐藏性能杀手。某些目录结构特别深的仓库,Claude Code 每次自动生成文件树都可能花好几秒。这个可以通过在 prompt 里要求“仅展示 src 和 tests 下两层的目录结构”来规避,或者在配置里预设一个精简后的项目结构描述,让模型直接用这份描述而不再实时扫描真实目录。实时文件树是给人类开发者用的导航工具,对模型来说,一份静态准确的目录结构描述反而更高效。
7. 性能监控与排错:如何持续追踪“慢”的根因
7.1 用日志和 hooks 收集本地性能数据
刚开始优化性能时,我完全靠“感觉”,觉得卡了就去调参数,结果经常白忙活。后来我建立起一套“可观测”的流程:Claude Code 会在本地保存会话日志,里面包含了每一轮请求的时间戳、模型、token 数量。我用一个小脚本定期扫描日志目录,提取几个关键指标:
- 每轮 API 请求的耗时中位数和 p95 耗时
- 工具调用次数总量和调用分布
- 上下文窗口的 token 使用率曲线
- 模型回复被截断/重试的频率
这些数据能直观回答:到底慢在网络等待还是慢在模型反复试错?如果 p95 耗时飙升,说明端点不稳或者模型思考档位过高;如果工具调用次数暴涨,说明 Prompt 约束失效或任务拆解得不够细;如果 token 使用率长时间接近满格,说明上下文管理出了问题。
7.2 常见“假慢”的判别方法
排查性能问题时,最容易掉进去的坑是:你以为模型在“思考”,实际上它在等网络超时重试;你以为它在“探索”,实际上它陷入工具调用循环自己都没意识。判别方法很简单:终端开着详细日志模式,观察当前步骤。如果日志长时间没有新输出,大概率是请求还没返回;如果日志里频繁出现 Read 和 Grep 交替执行,大概率是模型试图通过反复搜索来定位信息——这时候要么给它更明确的行号,要么让它先把相关文件整体读入再统一分析,后者反而更快。
7.3 优化前后的典型指标对比
发一套实测数据给你参考。同一个项目、同一个任务(给现有订单模块加一个 Excel 导出的功能),优化配置前后对比:
| 指标 | 优化前 | 优化后 |
|---|---|---|
| 总轮次数 | 48 | 27 |
| 平均单轮耗时 | 14.3 秒 | 6.8 秒 |
| 上下文峰值 token | 188K | 102K |
| 工具调用总数 | 86 | 41 |
| 人工介入次数 | 12 | 3 |
优化手段包括:设置项目级CLAUDE.md、拆分两段式工作流、调整权限白名单、在 Prompt 里明确要求小步提交和局部验证、以及每次完成一个阶段就/compact。可以看到,总耗时的减少不单单来自模型变快,更多来自轮次和工具调用的大幅削减。
7.4 性能调优要适可而止
最后提醒一点:Claude Code 的调优是有收益递减曲线的。把权限全放开、把上下文压到极限、把所有流程都自动化,初期效果显著,但到了一定程度后,投入产出比会急剧下降,甚至开始损害安全和代码质量。我现在的原则是:保留人工确认的高风险命令,保留方案审查的关键节点,其他环节尽量压到最简。毕竟工具跑得快固然重要,跑得对、跑得可控才是长期工程效率的基石。