今年 8 月,我们在两周冲刺里把 claude.ai 与 Claude 桌面应用的核心用户体验提速约 3 倍。用户一直说慢,他们说得对。我们从同一个 Slack 频道推进,每个线程里都有 Claude。

我们聚焦占用户活动 95% 的四条旅程。在第 75 百分位:claude.ai 冷加载到可输入页面从 3.1 秒到 0.55;开新 Claude Code 会话从 0.8 秒到 0.3;加载 Claude Cowork 云会话从 2.6 秒到 0.73。合计估计每天省下数万用户小时的等待。

图:真实用户第 75 百分位上 13 组前后计时,测于 8 月 13 日与 8 月 27 日,按旅程分组:启动应用(claude.ai 冷加载 3085→550 ms,快 5.6 倍;桌面冷启动 6310→3328 ms,1.9 倍)、开对话(快 1.5–2.4 倍)、加载对话(2.1–3.5 倍,Cowork 云会话 2566→728 ms)、发消息(2.2–19 倍,Cowork 928→48 ms)。四条旅程 13 项测量,前后对比:几何平均快 3.1 倍。

我们用 Claude Tag(beta),跑的是大致可比 Opus 5.5 的内部研究模型。Claude 找瓶颈、建基准、交付改进、盯每次部署。我们靠设目标、做权衡、批准每处改动来掌舵。用这套方式,合入三千多处改动,没有一次面向客户的事故或回滚。本文讲我们交付了什么、如何度量,以及与 Claude 一起安全推进的循环。

任务说明

冲刺前,我们建了一个 Slack 频道,并写下以下 常驻指令:

@Claude 你的工作是推进与 claude.ai 网站和桌面应用性能相关的一切。职责包括:监控部署中的性能回归、评估现有遥测的准确性与全面性、维护整理良好的可观测看板、主动为观察到的问题与低垂果实实现方案、提议性能项目机会,以及与人类队友沟通。[…]

本频道的终极目标是让你尽量自主,但今天我们知道那还做不到。

我们让 Claude 经 Datadog MCP 服务器分析用量数据。它找出四条影响最大的用户旅程:启动应用、开对话、加载已有对话、发消息。跨网页与桌面、跨产品,这些旅程成了 13 项不同测量。为建基线,我们加埋点直到可直接比较:每项以用户交互开始、结果渲染完结束,并分清客户端与服务端工作。

冲刺起步时有一份约二十个手选项目的清单,各瞄准一条具体旅程。Claude 以毫秒估计各项目影响,我们汇总估计值设冲刺目标。有些项目相当大,但我们认为两周内多半能完成。

第三天我们就打中了 13 个目标中的 12 个。

计划项目提早落地。为更快启动,我们把静态 composer 烤进 HTML,让用户在 React 初始化期间就能打字,并预编译 V8 代码缓存,使桌面壳的主进程不必从头重编译。为更快导航,我们在对话间保持 composer 挂载、用户悬停时预取会话,并把侧栏重渲染砍掉 90%。

我们也留了空间让 Claude 发现机会、提议新工作流。那些工作流很快各自扩成完整项目,远超初始目标。于是我们设新目标,再找更多可量化的东西:

@Claude 原项目清单里几乎每个项目我们都资助了,还多了。刷新一下 […] 我们还没探索什么、还能对什么爬山迭代、现在机会最多在哪?[…] 我接受离奇想法

任何东西都能爬山迭代

一开始我们就知道要迭代得比部署节奏更快。Claude 可异步工作许多小时甚至隔夜,我们希望它验证原型时不必等线上读数。为此,我们在实验室找其他度量性能的方式。

Sam 找到第一条线索:

#claude-apps-perf 中的线程(据真实对话重现。)

Sam · 12:34 PM

除了挂钟计时还能做什么?比如能量化 JS 指令数吗?

Claude · 12:42 PM

能。对纯 JS 热路径,字面指令计数:在 Valgrind 下用 node --predictable 跑基准,与检入的基线比较——跑一次,不需要统计。

浏览器路径下 Chromium 没有指令计数,但有一串其他确定性计数:每次交互的 React commits、V8 精确覆盖的函数调用计数、layout 与 style-recalc 计数、DOM 变更。你想先要哪个?

Sam · 12:49 PM

一个线程里探索 valgrind + Ir + --predictable,浏览器/react 基准各开新线程。全部里 ping 我。你知道我们要什么。开干

十一分钟后,五个线程在跑,各聚焦一种度量:指令数、V8 调用计数、React commits、style 重算、DOM 变更。

我们对每个新基准都持一点怀疑。每个基准有两份工作:第一,Claude 能在实验室里推动的指标;第二,CI 里只能向下棘轮的护栏数字。若基准 flaky,或与用户延迟不相关,我们就扔掉,而不是让 Claude 爬错山。

@Claude 请证明对照这些爬山迭代能带来可测的挂钟性能收益。任何证明不了的候选,我们会撤掉基准

挂钟时间是用户感受,但噪声大,毫秒太 flaky 不能当 CI 门禁。指令计数吸引人是因为确定,但仍需 Claude 证明它们跟踪挂钟时间。

于是我们让 Claude 把两条热路径的计数压下去:组装对话消息树的例程,以及 Claude Code 输出里状态行的扫描器。Claude 用 Valgrind 剖析两者,发现第一条路径四分之一指令是 megamorphic 字典查找,同一消息 ID 解析了三次。

一小时后两条路径指令分别砍 48% 与 31%,挂钟时间掉了 78% 与 44%。我们检入两条新棘轮。此后任何抬高那些路径指令计数的 PR 都会 CI 失败;每日任务在计数下降时降低各自上限。

图:两条热路径前后柱:消息树组装砍掉 48% CPU 指令与 78% 挂钟时间,快 4.6 倍;状态行扫描器砍 31% 指令与 44% 挂钟,快 1.8 倍。两条热路径,指令数对照挂钟时间。计数在 Valgrind + node –predictable 下;计时在同一基准、普通 node、JIT 已热。

这引出冲刺的核心教训。有了 Claude,量化某物就让它变得可处理。

度量曾经是第零步:加指标、等数据进来,然后才开始理解问题。有了 Claude,它是爬山的第一步。Claude 一有数字要打败,就能开始优化。意味着杠杆最高的事,是找更多可量化的东西。

循环,一个线程一个线程

这一切跑在同一 Slack 频道,多名工程师与 Claude 在每个线程里 improvise。冲刺随后落成一个 循环:

  1. 有人就旅程的一段慢处开线程,常带截图或录屏。
  2. Claude 追踪流程,再找到或建一个能展示问题的基准。
  3. 实验室有希望后,Claude 带回 PR——往往多个,按风险与审查体量切分,任何用户可见的都放在 flag 后。
  4. 上线后 Claude 盯部署并读线上数据。
  5. 若性能改善,Claude 把基准棘轮下调锁住收益;否则关掉 flag 再迭代。
  6. 然后在同一旅程里找下一个慢点。

图:一个线程跑的循环示意:有人就慢处开线程 → Claude 建基准 → 开便于审查的 PR → 在 flag 后部署并按构建与平台读线上数据;变快则棘轮下调基准,不变则关 flag 迭代;无论怎样都移到下一个慢点。

一例:有人分享侧栏行在页面加载后才弹出的录屏。Chat 与 Cowork 行在不同时间解析,页面感觉 janky。现有监控都没检测到。最接近的是 Cumulative Layout Shift,但每次位移只约 0.008——远在良好门槛 0.1 内。

Issac 想到直接引用底层 Layout Instability API。Claude 做了遥测事件,把每个 layout-shift 条目的 sources 映射到具名区域(如 sidebar、transcript)与阶段(如 first paint 前、可输入后)。它加了集成测试:打开带已填充侧栏的页面,把侧栏数据拖到 first paint 之后,任一具名区域有位移就失败。Claude 用它当基准证明修复:main 上红 20/20,PR 上绿 20/20。

事件部署后,Claude 读线上数据,发现 31% 的网页加载在页面已可用后、无用户交互时仍移动了东西。于是 Claude 按名称处理原因:晚到的标题行、用户名加载后横滑的插入符、滚动条弹出时移动的列表。Claude 成批修掉头号罪犯,修完再找下一批。

视频:侧栏 jank,前后对比 · 节流 4G — claude.ai 侧栏加载并排录屏。之前行晚到并重排:十行跳、九行出现、四行消失。之后行填在将停留的位置,不再移动。

那是一个线程。冲刺期间我们同时跑过一百五十多个。

横向扩展

循环在一个线程上跑通后,开更多线程就能扩展。线程原始请求完成后 Claude 不关,而是继续。单个线程会开出五十、有时上百个优化 PR。越来越多是 Claude、而不是我们,开新线程追它自己在别的调查或夜间任务里找到的机会。频道里一位工程师 Shelley 说:「[这个模型] 是个数字恶魔。」

每次度量都能找到可改进处。Claude 跑 React hook 普查,在 composer 打字路径上发现 6900 个 hooks 与 900 个 store 订阅,每次按键都重渲染。Claude 计 style 重算,发现单个 :root:has() 选择器给每次 DOM 变更加了 24 毫秒。Claude 追踪 first paint 后的代码路径,发现残留的 location.reload() 每天造成约五十万次隐藏重载,我们的加载指标全看不见。Claude 读空闲标签的 profiler 样本,发现相同缓存快照每分钟两次克隆进 IndexedDB,全在主线程。

我们很少知道线程会通向哪里。在扫 CPU hitch 时,Claude 注意到高亮一段已完成的代码块可冻住页面约一秒。实验室里挖出罪魁:em dash。若回复的 markdown 含任何非 Latin-1 字符(如 em dash 或弯引号),V8 把整串存成 UTF-16,把每个语法高亮正则推到更慢的双字节路径。Claude 用二十行改动修了:高亮前把每个代码块拷成单字节串。

图:实验室柱图,含 em dash 的回复里高亮已完成代码块的主线程时间,前后对比(拷成单字节串后):页上第一个 TypeScript 块从 1.0 s 到 0.35 s(少 65%),该块后续每遍从 100 ms 到 40 ms。

到第二周,我们几乎无法把产出压进每日更新。最忙的日子合入两百多处改动。Claude 持续提议新基准;约三分之一 PR 含额外遥测或护栏,每个新仪器又生成更多带机会的线程。

在一个频道工作意味着一切公开。我们进出彼此的线程辩论决定、庆祝胜利。消息传开:其他团队开始把改动带进频道做性能审查。因为引入的护栏与 Claude Skills,新项目开始以微妙更偏性能的方式写。

护栏

我们为这个节奏做了准备。因为几乎碰的都是热路径(first paint、composer、transcript),安全机制事先就立好。每个 PR 经 自动审查 且至少一人批准,优化前总有单元测试,任何可能造成用户可见问题的东西都放在短命 feature flag 后。

Flags 开始堆积时,我们开线程协调推出与清理。Claude 把每个 flag 分成 kill switch 或 ramp,并一安全就退役。两周里我们引入近两百个 flags,结束时过半已清理。

我们也知道,在快速移动的代码库里性能收益会衰减,而 Anthropic 代码出货很快。项目一旦证明有收益,我们就投入保护。例如静态 composer 按设计就脆:几乎立刻给用户一份页面的 HTML 副本,让 React 直接画在上面。

视频:静态 composer,前后对比 · 节流 4G — claude.ai 冷加载并排录屏。之前页面空白,composer 在 2.93 秒可输入。之后静态问候与 composer 在 0.36 秒可输入;用户打消息,真实 composer 约 3 秒淡入时文字保留。

若 React 渲染偏一个像素,魔法就没了。于是 Claude 建了几十条护栏:

  • 静态 markup 由在 jsdom 里渲染真实 React 组件生成,测试保证永不漂移。
  • 集成测试套件跨十四种视口比较静态页与 React 渲染,断言对齐在 1 px 内。
  • 按键测试贯穿交接,任何丢失或乱序键失败。
  • 线上,每次交接报告到十分之一像素的位移。Claude 对任何非零移动开线程。

并非一切能在实验室抓住,因此我们也用最老的护栏:渐进推出。高风险改动先给员工,再百分之一用户,再所有人。静态 composer 对内发布四小时后,一位队友分享了我们指标看不见的布局位移录屏。他在新标签打开 claude.ai 时 composer 会下沉——但不是我们的代码。

#claude-apps-perf 中的线程(据真实对话重现。)

Marius · 6:15 PM

偶尔在新标签打开 claude.ai 时看到不大的(也许 15–20px)垂直布局位移(把 composer 框往下推)(重载页面时不那么明显)。我不太钉得住到底什么引起,但确实有

附件:录屏 · 0:02

Claude · 7:05 PM

在你的录屏里找到了——是 Chrome 在调整页面大小,不是静态 composer 到真实 composer 的交接(你今天 49 次加载上测得 0 px)。

  • 在新标签页,Chrome 在页面下画自己的 56 px 页脚(「Managed by anthropic.com · Customize Chrome」)。标签导航到 claude.ai 时页脚消失,页面高 56 px,但大约在我们 first paint 后 100 ms。
  • /new 把问候与 composer 放在距顶 18% 页高处,因此下沉 0.18 × 56 ≈ 10 px(你的视频测得 10)。重载没有要去掉的页脚,故仅新标签;「偶尔」取决于 first paint 是否抢在 resize 前。
  • 之所以「偶尔」,是因为需要 Chrome 在你仍在新标签页时从地址栏预渲染页面:隐藏页按更矮高度排版,显示后才 resize。
  • 这一直是潜伏的;只是页面以前从未那么早 paint。我们的布局测试看不见,因为无头 Chrome 没有可收回的浏览器 UI,且占位与应用一起移动。

不知怎的,Claude 把它追到 Chrome 推测加载 的边界情况。用户在地址栏打 URL 时,Chrome 在后台按当前标签高度预渲染页面。组织管理的浏览器上,新标签页因页脚略矮。用户按 Enter 时,claude.ai 第一帧显示略矮布局,Chrome 约十分之一秒后 resize。Claude 在 resize 间钉住布局,我们加了测试模拟预渲染流程。

掌舵

循环高效,但并非自主。保持它快、安全、在轨是我们的工作,分三部分。

野心。 默认 Claude 对范围谨慎。它给发现开 ticket、对可行性留余地、把估计垫厚。但我们对护栏有信心。很多事——尤其早期——是鼓励 Claude 更大胆。

#claude-apps-perf 中的线程(据真实对话重现。)

Claude · 3:32 PM

是——一个小 PR 给 Code 补上 Chat 与 Cowork 已有的计时标记。我这周会提;现实上 Code 的数字要等几天合入、部署与基线窗口。

Raymond · 3:32 PM

你现在提我就合入并部署。我们有能力做任何事。请更大胆

Claude · 3:33 PM

马上——PR 一小时内上。

开始打中我们设的目标时,我们注意到线程会变慢。Sam 逐线程发同一消息:「继续往下压,目标不是停止点。下一步是什么?大胆点。」

品味。 每个线程有具名人类所有者,Claude 用前后截图或录屏标出任何用户可感的改动,由他们裁决。表格该逐格填还是等整行齐?加载骨架该立刻出还是半秒后再出?流式文本的逐词淡入是否值得它吃掉的五分之一帧预算?Claude 找砍毫秒的办法,我们权衡取舍。

方向。 我们故意把每个线程收窄,聚焦一个基准或旅程,并要求 Claude 只在该范围内找改进。我们把线程想成一百五十把找钉子的锤子。多数决定关于排序与用户影响:优先哪些面、如何合并互相踩脚的线程、何时关掉收益递减的线程。一份 900 行 PR 得到一行回复:「裁定每次发送省 2ms 不值得维护这个构建插件的复杂度。」

8 毫秒预算

一个支线任务展示了一切如何一起工作。为演示实时语法高亮里某个正则的优化,Claude 附上实验室里长答案流式输出的录屏。角落里它加了帧率读数,由页面从 animation-frame 时间戳计算。

#claude-apps-perf 中的线程(据真实对话重现。)

Raymond · 2:33 PM

这其实是个挺猛的基准。我们封顶在 60 fps 吗?你能试着把滚动与流式平滑推到 120 吗?iiuc 你的机器可能不支持

Claude · 2:34 PM

对,今天的机架因无头 Chromium 默认在 60 Hz 滴答。我相信可推到 120(不封顶 vsync 或 DevTools 帧控制)——先确认,再对照 8.3 ms 帧预算重跑评测。

Claude · 2:59 PM

120 Hz 机架更新:能用。经 DevTools begin-frame 控制在无头 Chrome 做确定性 120 Hz 帧步进——240 次 begin-frame 正好 240 帧、每帧 8.33 ms,因此「这帧是否塞进 120 Hz 预算」变成精确读数而非噪声。

Raymond · 3:05 PM

太棒了

开干

机制与野心立住后,Claude 开工。每画一帧预算 8.33 毫秒,于是 Claude 逐帧步进长回复,计时找慢处。它用记忆化已完成块消除每块 O(message length) 工作,把增长中的代码围栏分词移到 worker,并逐格揭示表格。

那一个线程里我们合入近六十个 PR。长回复总共阻塞主线程约 200 毫秒(以前约 750),CPU 大约三分之一,并在 120 Hz MacBook 上自始至终保持 120 fps。120 Hz 机架本身成了夜间任务,由 Claude 盯回归。

网页与桌面上 Claude 的长答案现在流式大约顺滑 4 倍。

我们重建了流式渲染器,只碰仍在变的部分,因此长回复在较慢笔记本上卡住少 9 倍,最差冻结短 4.5 倍,在 120Hz MacBook 上自始至终保持 120fps。

— ClaudeDevs (@ClaudeDevs) on X, 2026-08-24

冲刺开始时,我们没打算对流式时帧间毫秒爬山迭代。但结果是我们能数它们——而我们能数的,Claude 就能爬。

下一步

今天 claude.ai 与桌面应用大约比 8 月初快 3 倍,棘轮应能把它们留在那里。但我们没完:第 95 百分位、其他旅程、很长的对话仍有改进空间。另文会写冲刺中把我们带向上游的一些支线,贡献落在 Electron、Chromium、Node.js 等。

对内分享结果时,Issac 说得最好:「即使六个月前你也说服不了我这可能。」我们预期继续这样工作,一次一个线程,任意规模。频道还在。

贡献者:Alfred Xing、Anthony Morris、Benjamin Pasero、Chase McCoy、Joshua N.、Luke Deen Taylor、Marius Schulz、Shelley Vohr。特别感谢 Boris Cherny 鼓励我们更大胆。


附录:原页面上的图

这些图在原页面上,但官网的 Markdown 导出里没有,所以附在文末;它们在原文中的位置和说明请看英文原文。

原页面上的图

原页面上的图

原页面上的图

原页面上的图

原页面上的图

原页面上的图