教程Claude Code系列第 6 / 8 篇

两周把 claude.ai 提速 3 倍:和 Claude 一起做性能优化的方法

根据 Anthropic 工程师的文章整理:他们在一个 Slack 频道里和 Claude 协作,两周合并三千多个改动,把 claude.ai 的核心体验提速约 3 倍,没有出过事故。讲清“先找到能数的指标”的思路、每个线程的循环、护栏和人的分工。

发布 · 约 11 分钟读完 · 经人工审核()· 本站的内容怎么来的

本文根据公开分享整理,本站尚未实测。操作前请对照文末的原始来源。

本页目录(9 节)
  1. 结果
  2. 起点:一个频道,一段常驻的说明
  3. 核心经验:能数出来的,就能优化
  4. 每个线程里的循环
  5. 铺开之后
  6. 护栏:为什么三千多个改动没出事
  7. 人做什么
  8. 一个支线:8 毫秒的预算
  9. 对你有什么用

这是“Claude Code 开发系列”的第六篇。

这一篇解决的问题是:想让 Claude 长时间、大规模地替你优化一样东西,该怎么组织这件事,才能又快又不出事。 原文是一次真实冲刺的复盘:今年 8 月,Anthropic 的一个小组用两周把 claude.ai 网页和桌面应用的核心体验提速到原来的约 3 倍,合并了三千多个改动,没有一次影响用户的事故或回滚。

先说明一点:他们用的是 Claude Tag(测试版,在 Slack 里工作的 Claude),跑的是一个内部研究模型,原文说能力大致相当于 Opus 5.5。你手上的工具不一定一样,但方法是通用的。

结果

他们盯的是占用户活动 95% 的四条路径:启动应用、开始对话、打开已有对话、发送消息。按第 75 百分位算:

指标 之前 之后
全新打开 claude.ai 到可以打字 3.1 秒 0.55 秒
开始一个新的 Claude Code 会话 0.8 秒 0.3 秒
加载一个 Claude Cowork 云端会话 2.6 秒 0.73 秒

数据来自真实用户监控,对比的是 8 月 13 日和 8 月 27 日。

起点:一个频道,一段常驻的说明

冲刺开始前,他们建了一个 Slack 频道,写了一段常驻的指示。大意(译自原文,有删节):

@Claude 你的工作是推动和 claude.ai 网站、桌面应用性能有关的一切。
职责包括:盯每次发布有没有性能退步,评估现有监测数据是否准确和全面,
维护好观测面板,对观察到的问题和容易摘的果子主动动手解决,
提出性能项目的机会,并和人类同事沟通。

这个频道的最终目标是让你尽可能自主,但我们知道今天还做不到。

接着做了三件事:

  1. 找出最值得优化的路径。 让 Claude 通过 Datadog 的 MCP 服务器分析使用数据,得出上面那四条路径。算上网页和桌面、不同产品,一共是 13 个测量点。
  2. 把基线量准。 补埋点,直到这些测量可以直接比较:每一个都从用户的操作开始,到结果渲染出来结束,并且分得清客户端和服务端各花了多少。
  3. 定目标。 人工挑了大约 20 个项目,每个对应一条路径。Claude 估算每个项目能省多少毫秒,加起来就是冲刺的目标。

结果第三天就达成了 13 个目标里的 12 个。于是重新定了目标,并且让 Claude 自己提新方向。原文里的那条消息(译自原文,有删节):

@Claude 原来清单上的项目我们几乎都做了,还多做了不少。来刷新一下:
还有什么没探索过,哪些可以继续爬坡,现在机会最大的在哪里?
我愿意听离谱的点子

核心经验:能数出来的,就能优化

这是全文最值得带走的一点。

他们想比发布的节奏迭代得更快。Claude 可以连续工作很多小时,甚至一整夜,不能每个原型都等线上数据。所以要找能在实验环境里测的指标。

真实耗时是用户感受到的,但它有噪声,毫秒级的数字拿来当 CI 的关卡太不稳定。工程师 Sam 问了一句:能不能不测耗时,改成数 JS 的指令数?Claude 给出了一串确定性的计数方式:

  • 纯 JS 的热点路径:在 Valgrind 下用 node --predictable 跑基准,直接数 CPU 指令数,和仓库里存的基线比。跑一次就行,不需要做统计。
  • 浏览器里的路径:数每次交互的 React 提交次数、V8 精确覆盖率给出的函数调用次数、布局和样式重算的次数、DOM 变动的次数。

十一分钟后,五个线程同时在跑,各盯一种计数。

每个新基准都要先被怀疑。 一个基准有两份工作:先是 Claude 在实验环境里能推动的指标,然后是 CI 里一个只许降、不许升的数字。如果它不稳定,或者和用户感受到的延迟不相关,就扔掉,免得 Claude 爬错了山。他们的原话(译自原文):

@Claude 请证明对这些指标逐个爬坡,都能带来可以测到的真实耗时改善。
证明不了的候选,对应的基准我们会撤掉

验证指令数的那一次:他们让 Claude 压两条热点路径的指令数,一条是组装对话消息树的例程,一条是扫描 Claude Code 输出里状态行的扫描器。Claude 用 Valgrind 分析后发现,第一条路径有四分之一的指令花在字典查找上,同一个消息 ID 被解析了三次。

一小时后的结果:

路径 指令数减少 真实耗时减少
组装消息树 48% 78%
状态行扫描 31% 44%

指令数确实跟得上真实耗时,于是加了两个“棘轮”:之后任何让这两条路径指令数上升的 PR,CI 直接不过;每天有一个任务,在数字下降后把上限跟着调低。

原文对此的总结:以前,测量是“第零步”,加一个指标,等数据进来,然后才开始理解问题。有了 Claude,测量就是爬坡的第一步,一旦有了要打败的数字,它就能开始优化。所以人能做的杠杆最大的事,是找到更多可以测的东西。

每个线程里的循环

所有工作都在同一个频道里,按线程进行。稳定下来之后是这样一个循环:

  1. 有人开一个线程,说某条路径的某一段慢,通常附截图或录屏。
  2. Claude 追踪这段流程,找到或者新建一个能复现问题的基准。
  3. 在实验环境里有了像样的结果后,Claude 提交 PR。往往是好几个,按风险和评审的方便拆开,用户看得见的改动都放在开关后面。
  4. 上线后,Claude 盯着这次发布,读线上数据。
  5. 有改善,就把基准的上限调低,把成果锁住;没有,就关掉开关,再改。
  6. 然后在同一条路径上找下一个慢的地方。

一个例子:侧边栏的跳动

有人发了一段录屏:页面加载后,侧边栏的条目一个个蹦出来,聊天和 Cowork 的条目出现的时间不一样,页面看着发抖。现有的监控都发现不了。最接近的指标是累计布局偏移,但每次偏移只有大约 0.008 分,远低于 0.1 的“良好”线。

Issac 想到直接用底层的 Layout Instability API。Claude 做了这几件事:

  • 新建一个监测事件,把每次布局偏移的来源对应到有名字的区域(侧边栏、对话记录)和阶段(首次绘制之前、可以打字之后)。
  • 写一个集成测试:打开一个侧边栏有内容的页面,把侧边栏的数据扣到首次绘制之后才给,任何有名字的区域发生偏移就失败。
  • 用它来证明修复有效:在主分支上跑 20 次红 20 次,在 PR 上跑 20 次绿 20 次。

事件上线后,Claude 读线上数据,发现 31% 的网页加载在页面可用之后、没有用户操作的情况下有东西在动。然后按名字一个个查原因:迟到的标题行、用户名加载后往旁边滑的光标、滚动条出现时被挤动的列表。先修掉最严重的一批,再找下一批。

这只是一个线程。冲刺期间,同时在跑的线程超过一百五十个。

铺开之后

循环在一个线程上跑通之后,多开几个就行。线程最初的需求完成后,Claude 不会停,单个线程会提出五十个、有时上百个优化 PR。越来越多的新线程是 Claude 自己开的,来自别的调查或夜间任务里的发现。

原文列的一些发现,可以看出“量什么就发现什么”:

  • 数 React hook:输入框的打字路径上有 6,900 个 hook 和 900 个状态订阅,每敲一个键都重新渲染。
  • 数样式重算:一个 :root:has() 选择器让每次 DOM 变化多花 24 毫秒。
  • 追踪首次绘制之后的代码路径:一处遗留的 location.reload(),每天造成 50 万次用户看不见的重新加载,所有加载指标都看不到它。
  • 读空闲标签页的性能采样:同样的缓存快照每分钟被复制进 IndexedDB 两次,全在主线程上。

还有一个意外的:给写完的代码块做语法高亮,可能让页面卡住大约一秒。原因是破折号。回复的 Markdown 里只要有一个非 Latin-1 的字符(比如破折号、弯引号),V8 就把整个字符串存成 UTF-16,高亮用的每一条正则都走更慢的双字节路径。Claude 用二十行改动解决:高亮之前把每个代码块复制成单字节字符串。

最忙的时候一天合并两百多个改动。大约三分之一的 PR 带着新的监测或护栏,而每一个新的测量工具又带出更多的线程。

护栏:为什么三千多个改动没出事

他们动的几乎全是最热的路径(首次绘制、输入框、对话记录),所以安全机制是事先定好的:

  • 每个 PR 都过自动评审,并且至少一个人批准。
  • 先有单元测试,再做优化。
  • 可能让用户看到问题的改动,都放在短期的功能开关后面。 两周里新增了将近两百个开关。开关堆起来之后,专门开了一个线程来协调:Claude 把每个开关归为“紧急关停”或“逐步放量”,安全了就马上清理掉,结束时过半已经清理。
  • 成果要保护。 代码库变化快,性能成果会流失,所以一个项目证明有效之后,就投入去守住它。
  • 逐步放量。 高风险的改动先给员工,再给 1% 的用户,然后才是所有人。

“保护成果”的例子是静态输入框:把一份 HTML 版的输入框直接写进页面,用户在 React 初始化期间就能打字,之后 React 直接画在它上面。只要差一个像素,效果就没了。所以 Claude 建了几十道护栏,包括:

  • 静态的 HTML 是用真实的 React 组件在 jsdom 里渲染生成的,有测试保证两者不会走样;
  • 一套集成测试在 14 种视口尺寸下对比静态页面和 React 渲染的结果,要求对齐在 1 像素以内;
  • 一个按键测试在交接的过程中持续打字,丢一个键或者顺序乱了就失败;
  • 线上每次交接都上报偏移量,精确到十分之一像素,只要不是零,Claude 就开一个线程。

逐步放量也确实抓到了实验环境抓不到的问题。静态输入框内部发布四小时后,有同事发来录屏:在新标签页打开 claude.ai 时,输入框偶尔会往下掉一点。Claude 从录屏里查出来,原因是 Chrome 的预渲染:用户在地址栏输入网址时,Chrome 在后台按当前标签页的高度预先渲染页面;由组织管理的浏览器,新标签页底部有一条页脚,所以矮一些;按下回车后,第一帧是矮的布局,约十分之一秒后 Chrome 才调整大小。无头 Chrome 没有浏览器界面,所以布局测试看不到。修复之后,又加了一个模拟预渲染流程的测试。

人做什么

这个循环产出很高,但不是自主运行的。原文把人的工作分成三部分。

给胆量。 Claude 默认对范围很谨慎:把发现记成待办,对可行性留余地,估时间往宽里估。但他们对护栏有信心,所以早期做得很多的一件事,是鼓励 Claude 更大胆。一次对话里,Claude 说这个 PR 这周提,数字要再等几天;工程师 Raymond 的回复是(译自原文):

你现在提,我就把它合并并发布。我们什么都能做。请再勇敢一点

目标达成后,线程会慢下来。Sam 挨个线程发同一句话:“继续往下压,目标不是终点。下一步是什么?要有野心。”

给品味。 每个线程都有一个指名的负责人。凡是用户能察觉的改动,Claude 都附上前后的截图或录屏,由人来定。比如:表格是一格一格填,还是等一整行完成再显示?加载骨架屏是立刻出现,还是等半秒?流式文字逐词淡入的效果,值不值得花掉每帧预算的五分之一?Claude 负责找能省的毫秒,人来权衡。

给方向。 每个线程故意限定得很窄,只盯一个基准或一条路径。人主要判断先后和对用户的影响:先做哪个界面,互相踩到的线程怎么合并,什么时候关掉一个收益已经很小的线程。有一个 900 行的 PR 得到的回复只有一句,大意是:每次发送省 2 毫秒,不值得为此去维护这个构建插件。

一个支线:8 毫秒的预算

Claude 为了展示一个正则优化,附了一段长回答流式输出的录屏,角落里加了帧率读数。Raymond 看到后问:这个基准不错,我们是不是被限制在 60 帧?能不能把滚动和流式输出做到 120?

Claude 先确认了可行性:通过 DevTools 的帧控制,在无头 Chrome 里确定性地按 120 Hz 一帧一帧推进,每帧 8.33 毫秒,“这一帧有没有超出预算”就成了一个精确的读数。然后逐帧找慢的地方:缓存已经完成的内容块,去掉每来一段文字就要做一遍的、和消息长度成正比的工作;把还在增长的代码块的分词挪到 worker 里;表格改成逐格显示。

这一个线程合并了将近六十个 PR。长回复阻塞主线程的总时间从约 750 毫秒降到约 200 毫秒,CPU 占用约为原来的三分之一,在 120 Hz 的 MacBook 上全程保持 120 帧。这套 120 Hz 的测试装置后来成了每晚运行的任务。

开始冲刺时并没有计划优化流式输出时帧与帧之间的毫秒数。但它能被数出来,而能数出来的,Claude 就能往上爬。

对你有什么用

只是用 Claude Code 的人:

  • 让 Claude 优化之前,先给它一个能反复跑、结果稳定的数字。没有的话,第一步就让它帮你建一个。
  • 对新指标保持怀疑。先让它证明“这个数字降了,用户感受到的也变好了”,证明不了就不用。
  • 每次有了成果,在 CI 里加一个只许降不许升的检查,否则过几周就退回去了。
  • 一个任务盯一个指标或一条路径,范围窄一点。
  • 给它一个明确的许可。如果你有测试和开关兜底,可以直接告诉它别保守;如果没有,先把兜底的东西建起来。

在团队里推这种做法的人:

  • 护栏先行:评审、测试、功能开关、逐步放量,这四样是他们敢一天合并两百个改动的前提。
  • 人负责三件事:野心、品味、方向。看得见的改动必须由人拍板。
  • 在一个公开的频道里做。原文提到,别的团队后来主动把自己的改动拿来做性能评审。

原文最后说明,还没做完:第 95 百分位、其他路径和很长的对话都还有空间,频道仍在运行。

来源

通过 API 中转站使用这些模型?到 Veridrop 免费检测中转站给你的是不是它声称的模型,或者看看中转站排行榜前 100 名。

相关文章

  • 把代码升级到 Claude 5.5 这一代要改什么:四个模型的不兼容改动和一份检查清单教程 · Claude Code · 约 12 分钟

    把模型名换成 Opus 5.5、Sonnet 5.5、Haiku 5.5 或 Fable 5.1,有几处老写法会直接报 400:强制调用工具、关掉思考、预填回答。还有几处不报错但结果变了:回答的第一块可能是空的 thinking,max_tokens 可能被思考用光。本文按官方迁移指南整理,能试的都通过中转站实测过。

  • 给 Claude 5.5 这一代写提示词:按现象查该改什么,哪些老写法该删教程 · Claude Code · 约 8 分钟

    老提示词在 Opus 5.5、Sonnet 5.5、Haiku 5.5、Fable 5.1 上基本能直接用,但每个模型有几处行为变了。本文把官方四份指南整理成一张“看到什么现象,改什么”的表,列出该删掉的老写法。实测一道要 JSON 答案的推理题:不思考时模型把推理写进回答里,答案是对的,但整段不再是合法的 JSON。

  • Claude 的思考和 effort 怎么调:五档各是什么、什么时候该调高、钱花在哪教程 · Claude Code · 约 11 分钟

    effort 控制 Claude 在一个回答上下多大功夫,思考只是其中一部分。本文整理五档的含义、各模型的默认值、思考怎么计费、怎么让它多想或少想,以及任务预算和快速模式。实测一道排期题:Sonnet 5.5 在 low 和 medium 上十次全错,调到 high 五次全对;再调到 max 要花三倍多的钱,答案一样。

  • Claude 现在有哪些模型、各多少钱、怎么选:价格表、模型 ID、下线时间和省钱的顺序教程 · Claude Code · 约 14 分钟

    Fable 5.1、Opus 5.5、Sonnet 5.5、Haiku 5.5 各管什么、官方价是多少、模型 ID 为什么不带日期、哪些老模型快下线了。本文按官方文档整理,并通过中转站实测了几件事:同一个任务在三个模型上差四倍多的钱;同一段中文在新旧模型上 token 数几乎一样,英文却多出近四成。