# Anthropic 复盘如何让 claude.ai 和桌面应用快 3 倍

- 来源：Hacker News 热门（buzzing.cc 中文翻译）
- 作者：matthieu_bl
- 发布时间：2026-09-24 05:34
- AIHOT 分数：79
- AIHOT 标记：同事件
- AIHOT 链接：https://aihot.news/items/cmuenbkly08n0royn8xzedcew
- 原文链接：https://claude.dev/blog/how-we-made-claude-ai-faster

## AI 摘要

Anthropic 团队在两周冲刺中把 claude.ai 和 Claude 桌面应用的核心体验提速约 3 倍，75 分位下 claude.ai 首次可输入时间从 3.1 秒降到 0.55 秒，Claude Code 新会话启动从 0.8 秒降到 0.3 秒，Claude Cowork 云会话加载从 2.6 秒降到 0.73 秒。

## 正文

今年八月，我们用两周的冲刺让 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 秒。总体来看，我们估计这每天为用户节省了数万小时的等待时间。

我们使用了 Claude Tag（beta），它运行的是一个内部研究模型，大致相当于 Opus 5.5。Claude 找出瓶颈、构建基准测试、交付改进，并盯住每一次部署。我们则通过设定目标、做出取舍、批准每一项变更来掌舵。借助这种方式，我们合并了三千多项变更，没有出现任何一次面向客户的事故或回滚。这篇文章会介绍我们交付了什么、如何衡量，以及我们与 Claude 一起构建的安全闭环。

任务简报

在冲刺开始前，我们创建了一个 Slack 频道，并附上以下 常驻指令：

@Claude 你的职责是促进与 claude.ai 网站和桌面应用性能相关的所有事务。你的职责包括：监控部署中的性能回退，评估现有遥测数据的准确性和全面性，维护精心整理的可观测性仪表盘，主动为已观察到的问题和低垂果实实施解决方案，提出性能项目机会，并与你的人类队友沟通。[…]

这个频道的终极目标是让你尽可能自主，但今天我们清楚这还不可能实现。

我们让 Claude 通过 Datadog MCP server 分析使用数据。它识别出了四条影响最大的用户旅程：启动应用、开始对话、加载已有对话，以及发送消息。在 Web 端和桌面端之间，以及我们的各个产品中，这些旅程共对应十三项不同的测量指标。为了建立基线，我们不断添加埋点，直到它们可以直接比较：每一项都从用户交互开始，在结果渲染完成后结束，并区分客户端和服务端的工作。

我们以一份约二十个精心挑选的项目清单启动了这次冲刺，每个项目都针对一条特定的用户旅程。Claude 以毫秒为单位估算了每个项目的影响，我们将这些估算汇总起来，以此设定本次冲刺的目标。有些项目相当大，但我们认为很可能在两周内完成其中大部分。

到第三天，我们就达成了十三个目标中的十二个。

计划中的项目提前落地了。为了实现更快的启动，我们在 HTML 中内置了一个静态输入框，让用户可以在 React 初始化期间就开始输入，并预编译了 V8 代码缓存，这样桌面端外壳的主进程就不必从头重新编译。为了实现更快的导航，我们让输入框在对话切换之间保持挂载，在用户悬停时预取会话，并将侧边栏的重渲染减少了 90%。

我们还留出了空间，让 Claude 去识别机会并提出新的工作方向。这些工作方向迅速成长为各自独立的完整项目，远远超出了我们最初的目标。于是我们设定了新的目标，然后寻找更多可以衡量的东西：

@Claude 我们最终几乎资助了原始项目清单上的每一个项目，甚至更多。让我们重新梳理一下 […] 我们还有哪些没有探索过，我们可以在哪些方面持续爬坡，现阶段最大的机会在哪里？[…] 我对各种疯狂的想法都持开放态度

任何东西都可以持续爬坡

从一开始，我们就知道自己希望以比部署节奏更快的速度进行迭代。Claude 可以异步工作很多个小时，甚至通宵，我们希望让它无需等待实地数据反馈就能验证自己的原型。为了实现这一点，我们寻找了其他在实验室中衡量性能的方法。

Sam 找到了第一条线索：

媒体内容 · 前往原文查看

#claude-apps-perf · 讨论串

Sam 下午 12:34

除了墙钟计时，我们还能做什么？比如说，我们能否测量 JS 指令数？

ClaudeApp 下午12:42

可以。对于纯 JS 的热点路径，可以统计字面指令数：在 Valgrind 下用 node --predictable 运行基准测试，并与已检入的基线进行比较——一次运行，无需统计。

对于浏览器路径，Chromium 下没有指令计数，但有一系列其他确定性计数：每次交互的 React 提交次数、V8 精确覆盖率给出的函数调用次数、布局和样式重算次数、DOM 变更次数。你想先要哪个？

Sam 下午12:49

我们开一个线程探索 valgrind + Ir + --predictable，再开新线程分别跑每个浏览器/React 基准测试。在所有线程里都 @ 我。你知道我们想要什么。开始吧

根据一段真实对话重现。

十一分钟后，五个线程已在运行，每个都聚焦于不同的测量：指令数、V8 调用次数、React 提交次数、样式重算次数和 DOM 变更次数。

我们对每一个新基准都抱有一定怀疑。每个基准都有两项职责：第一，是 Claude 可以在实验室中推动的一项指标；第二，是 CI 中的一道护栏，其数值只能单向收紧。如果一个基准不稳定，或者它实际上与用户延迟并不相关，我们就会把它丢弃，而不是让 Claude 爬错山头。

@Claude 请证明针对这些基准中的每一个进行爬坡优化，都能带来可测量的实际运行时间性能提升。对于任何无法证明这一点的候选基准，我们都会将其下线。

实际运行时间是用户能感受到的，但它噪声很大，而毫秒级数据太不稳定，无法用作 CI 门禁。指令计数很有吸引力，因为它们是确定性的，但我们仍然需要 Claude 证明它们与实际运行时间相关联。

于是我们让 Claude 去降低两条热路径的指令计数：一条是组装对话消息树的例程，另一条是扫描 Claude Code 输出中状态行的扫描器。Claude 用 Valgrind 对两者进行了性能分析，发现第一条路径中有四分之一的指令是多态字典查找，同一个消息 ID 被重复解析了三次。

一小时后，它把两条路径的指令计数分别降低了 48% 和 31%，实际运行时间分别下降了 78% 和 44%。我们提交了两个新的棘轮。从那时起，任何提高这两条路径指令计数的 PR 都会导致 CI 失败，而一个每日任务会在计数下降时随时下调各自的上限。

这引出了这次冲刺的核心教训。有了 Claude，对某事物进行度量，就能让它变得可处理。

过去，度量是第零步：你先加一个指标，等数据积累起来，然后才开始理解问题。而在 Claude 这里，它是攀登的第一步。一旦 Claude 有了一个要超越的数字，它就能开始优化。这意味着，我们能做的杠杆率最高的事情，就是找到更多可以度量的东西。

这个循环，一个线程接一个线程

这一切都运行在同一个 Slack 频道里，多位工程师和 Claude 在每个线程中一起协作。从那里开始，这次冲刺进入了一个循环：

有人会就某段旅程中缓慢的一段开一个线程，通常还会附上截图或录屏。

Claude 会追踪整个流程，然后找到或构建一个能证明该问题的基准测试。

一旦在实验室里得到有希望的结果，Claude 就会带着一个 PR 回来——往往是好几个，按风险和审查需求来划分大小，任何用户可见的内容都放在功能开关之后。

上线之后，Claude 会观察部署情况并读取线上数据。

如果性能有所提升，Claude 就通过把基准测试的阈值收紧来锁定这一成果；如果没有提升，它就关掉功能开关并继续迭代。

然后它又去寻找同一段旅程中的下一个缓慢之处。

举个例子：有人分享了一段屏幕录制，显示页面加载后侧边栏的行才陆续弹出来。Chat 和 Cowork 这两行在不同时间才渲染完成，让页面显得卡顿。我们现有的监控手段没有一个检测到这个问题。最接近的是 累积布局偏移，但每次偏移的得分只有大约 0.008——远在 0.1 的良好阈值之内。

Issac 想到一个主意，直接引用底层的Layout Instability APIClaude 创建了一个遥测事件，将每个sources的layout-shift条目映射到命名区域（例如侧边栏、对话记录）和阶段（例如首次绘制之前、可输入之后）。它添加了一个集成测试，在侧边栏已填充数据的情况下打开页面，将侧边栏的数据保持到首次绘制之后，并在任何命名区域出现任何偏移时判定失败。Claude 以此作为基准来证明修复有效：该测试在 main 分支上 20 次运行 20 次失败，在 PR 上 20 次运行 20 次通过。

事件部署后，Claude 读取了现场数据，发现 31% 的网页加载在页面可用之后、没有任何用户交互的情况下移动了某些东西。由此，Claude 逐一排查了各项原因：一行迟到的表头、用户姓名加载完成后横向滑动的光标、滚动条弹出时移动的列表。Claude 批量修复了最主要的几处问题，当这些问题解决后，它又发现了下一批。

视频 · 前往原文观看

视频侧边栏卡顿，前后对比 · 限速 4G

那只是一个线程。在冲刺期间，我们一次运行了一百五十多个。

横向扩展

一旦这个循环在单个线程上跑通，要在更多线程上运行它就只是多开几个线程的事。Claude 不会在最初的请求完成后就关闭线程，而是会继续干下去。单个线程会提交五十个、有时上百个优化 PR。越来越多的新线程是由 Claude 而非我们中的任何人开启的，去追逐它自己发现的优化机会，作为独立调查或夜间任务的一部分。频道里的工程师之一 Shelley 评论道：“[这个模型]是个数字狂魔。”

每一次测量都能发现可改进之处。Claude 做了一次 React hook 普查，发现输入框的输入路径上有 6,900 个 hook 和 900 个 store 订阅，每次按键都会触发重新渲染。Claude 统计了样式重计算，发现单个 :root:has() 选择器让每次 DOM 变更多花 24 毫秒。Claude 追踪了首次绘制之后的代码路径，发现一个遗留的 location.reload() 每天造成五十万次隐藏重载，而我们的任何加载指标都看不到这些。Claude 读取了空闲标签页的 profiler 采样，发现相同的缓存快照每分钟被克隆进 IndexedDB 两次，全都发生在主线程上。

我们很少知道一个线程会通向哪里。在一次 CPU 卡顿排查中，Claude 注意到高亮一个已完成的代码块会让页面冻结大约一秒。它在实验室里深挖，找到了元凶：em dash（长破折号）。如果一条回复的 markdown 中包含任何非 Latin-1 字符，比如 em dash 或弯引号，V8 就会把整个字符串存为 UTF-16，这会让每一个语法高亮正则都走上更慢的双字节路径。

Claude 用一个二十行的改动修复了它：在 highlight 之前把每个代码块复制成一字节字符串。

到第二周时，我们几乎无法把产出汇总成每日更新。最忙的日子里，落地的改动超过两百项。Claude 不断提出新的基准测试；大约三分之一的 PR 包含了额外的遥测或防护栏，而每新增一个监测工具，就会产生更多讨论串，也带来更多机会。

在同一个频道里工作意味着一切都公开进行。我们随时跳进彼此的讨论串，争论决策、庆祝胜利。消息传开了：其他团队开始把他们的改动带进这个频道，让它们接受性能审查。由于引入了所有这些防护栏和 Claude 技能，新项目在写法上都有了微妙但更注重性能的改进。

防护栏

我们为这样的节奏做好了准备。因为我们几乎触碰到的每一处都是热路径（首次绘制、输入框、对话记录），所以我们一开始就建立了安全机制。每个 PR 都要经过自动化审查，并至少有一名人工批准；单元测试永远先于优化；任何可能引发用户可见问题的改动，都要通过一个短期功能开关来发布。

当开关开始堆积时，我们开了一个讨论串来协调它们的上线和清理。Claude 把每个开关归类为终止开关或渐进放量，并在安全后立即将其退役。在这两周里，我们引入了近两百个开关，其中超过一半在结束时已经被清理掉。

我们也知道，性能优势在快速迭代的代码库中会逐渐衰减，而 Anthropic 的代码发布节奏很快。一旦某个项目被证明带来了收益，我们就会投入精力去保护它。例如，静态合成器在设计上就是脆弱的。我们几乎立即向用户展示页面的 HTML 副本，然后让 React 直接在其上渲染。

视频 · 前往原文观看

视频静态合成器，前后对比 · 限速 4G

如果 React 渲染偏差哪怕一个像素，魔法就会失效。因此 Claude 构建了数十道防护措施：

静态标记通过在 jsdom 中渲染真实的 React 组件来生成，并有测试保证两者永远不会偏离。

一套集成测试套件在十四个视口尺寸下将静态页面与 React 渲染结果进行对比，并断言对齐误差在 1 px 以内。

一个按键测试会直接输入贯穿整个交接过程，任何按键丢失或顺序错乱都会导致测试失败。

在实际运行中，每次交接都会报告精确到十分之一像素的偏移。Claude 会为任何非零移动的事件开启一个讨论线程。

并非所有问题都能在实验室里被发现，因此我们还用上了最古老的防护手段：增量发布。高风险变更先向员工发布，然后向 1% 的用户发布，最后才向所有人发布。我们在内部发布静态输入框四小时后，一位同事分享了一段屏幕录制，展示了一个我们的任何指标都看不到的布局偏移。当他在新标签页中打开 claude.ai 时，输入框会下移——但那并不是我们的代码造成的。

媒体内容 · 前往原文查看

#claude-apps-perf · 讨论串

Marius下午6:15

我偶尔会看到，在新标签页中打开 claude.ai 时出现一个较小的（大概 15–20px）垂直布局偏移（把输入框向下推）（重新加载页面时则不太明显）。我不太能确定到底是什么导致的，但它确实存在

屏幕录制 · 0:02

ClaudeApp 下午7:05

在你的录制中找到了——是 Chrome 在调整页面大小，而不是从静态输入框到真实输入框的交接（在你今天全部 49 次加载中，那个交接测得都是 0 px）。

在新标签页上，Chrome 会在页面下方绘制它自己的 56 px 页脚（“Managed by anthropic.com · Customize Chrome”）。当该标签页导航到 claude.ai 时，这个页脚会消失，页面因此高出 56 px，但只在我们首次绘制后约 100 ms 才发生。

/new 会把问候语和输入框放在距页面顶部 18% 页面高度的位置，所以它们会下移 0.18 × 56 ≈ 10 px（你的视频测得是 10）。重新加载时没有页脚需要移除，因此只发生在新建标签页；所谓“偶尔”取决于首次绘制是否快过尺寸调整。

它之所以只是“偶尔”发生，是因为需要 Chrome 在你仍停留在新建标签页时就从地址栏预渲染该页面：这个隐藏页面以较矮的高度完成布局，只有在显示之后才会被调整尺寸。

这个问题一直潜伏着；只是页面以前从未那么早进行绘制。我们的布局测试看不到它，因为无头 Chrome 没有可收回的浏览器 UI，而且占位符和应用是一起移动的。

根据一段真实对话重现。

不知怎么的，Claude 把它追溯到了 Chrome 推测性加载中的一个边缘情况。当用户在地址栏中输入 URL 时，Chrome 会在后台以当前标签页的高度预渲染该页面。在由组织管理的浏览器上，新标签页会因为一个页脚而略矮一些。当用户按下回车键时，claude.ai 的第一帧显示的是那个略矮的布局，而 Chrome 在大约十分之一秒后对其进行了调整大小。Claude 在调整大小过程中固定了布局，我们还添加了一个测试来模拟预渲染流程。

引导

这个循环很有成效，但它并不是自主运行的。让它保持快速、安全且不偏离正轨是我们的工作，而这分为三个部分。

野心。 默认情况下，Claude 对范围很谨慎。它会把发现的问题记成工单，对可行性含糊其辞，还会在估算上留出余量。但我们对自己的护栏很有信心。我们做的很多事情，尤其是在早期，就是鼓励 Claude 更大胆一些。

媒体内容 · 前往原文查看

#claude-apps-perf · 讨论串

ClaudeApp 下午3:32

是的——一个小 PR，就能让 Code 拥有 Chat 和 Cowork 已经具备的同样的计时标记。我这周就提上去；现实地说，Code 的数字还要等几天，等合并、部署和一个基线窗口。

Raymond下午3:32

如果你现在就提上去，我会把它合并并部署。我们有能力做任何事。请更大胆一些

ClaudeApp 下午3:33

马上办——PR 会在一小时内提上去。

根据一段真实对话重现。

当我们开始达到自己设定的目标时，我们注意到讨论串会慢下来。Sam 一个讨论串接一个讨论串地发同样的消息：“让我们继续把它压下去，目标不是终点。下一步是什么？要有野心。”

品味。每个线程都有一个具名的真人负责人，Claude 会用前后对比截图或录屏标出任何用户可感知的改动，交由他们裁定。表格应该逐格填充，还是等整行完成后再显示？加载骨架屏应该立即出现，还是半秒后才出现？流式文本逐词淡入的效果，是否值得花掉帧预算的五分之一？Claude 寻找各种办法来削减毫秒数，而我们则权衡其中的取舍。

方向。我们把每个线程都刻意收窄，聚焦于某一个基准或某一段旅程，并要求 Claude 只在这个范围内寻找改进。我们把这些线程看作一百五十把寻找钉子的锤子。我们的大多数决策都围绕排序和用户影响：优先处理哪些界面，如何合并那些相互冲突的线程，以及何时关闭一个已经收益递减的线程。有一个 900 行的 PR 只得到了一行回复：“我打算拍板否决——每次发送省 2ms，不值得为此维护这个构建插件的复杂度。”

8 毫秒的预算

我们的一个支线任务展示了所有环节如何协同工作。为了演示对实时语法高亮中所用正则表达式的一项优化，Claude 附上了一段录屏，展示实验室中一个长回答正在流式输出。在角落里，它加了一个帧率读数，是在页面中根据动画帧时间戳计算出来的。

媒体内容 · 前往原文查看

#claude-apps-perf · 线程

Raymond下午 2:33

这其实算是个挺狠的基准测试。我们是被限制在 60 fps 吗？你能试着把滚动和流式渲染的流畅度拉到 120 吗？据我所知你的机器可能不支持这个

ClaudeApp 下午2:34

对，现在的机器跑在 60 Hz，因为 headless Chromium 默认就是这样。我相信它可以被驱动到 120（不限制 vsync 或用 DevTools 帧控制）——先确认这一点，然后我会针对 8.3 ms 的帧预算重新跑一遍评测。

ClaudeApp 下午2:59

关于 120 Hz 机器的进展：成功了。在 headless Chrome 中通过 DevTools 的 begin-frame 控制实现确定性的 120 Hz 帧步进——240 个 begin-frame 正好对应 240 帧，每帧 8.33 ms，所以“这一帧是否满足 120 Hz 的预算”变成了一个精确读数，而不是有噪声的读数。

Raymond下午3:05

太厉害了

绝了

根据一段真实对话重现。

机制和目标确定后，Claude 就开始动手了。每个绘制帧的预算只有 8.33 毫秒，于是 Claude 逐帧梳理一段长回复一帧一帧地，为每一帧计时，找出慢的部分。它通过记忆化已完成的块，消除了每个分块中的 O(message length) 工作，把不断增长的代码围栏的 tokenization 逻辑移到了 worker 中，并逐格渲染表格。

在那一个线程中，我们合并了近六十个 PR。长回复对主线程的阻塞总时长从原来的约 750 毫秒降到了约 200 毫秒，CPU 占用降到约三分之一，并且在 120 Hz 的 MacBook 上从头到尾保持 120 fps。这台 120 Hz 的设备本身也变成了一项每夜运行的任务，由 Claude 负责监控性能回退。

现在，Claude 在网页端和桌面端上的长回答流式输出流畅度提升了约 4 倍。

我们重建了流式渲染器，使其只处理仍在变化的内容，因此在较慢的笔记本上，长回复的卡顿减少了 9 倍，最严重的一次冻结缩短了 4.5 倍，而在 120Hz 的 MacBook 上，它从头到尾都能保持 120fps。

— ClaudeDevs（@ClaudeDevs）2026 年 8 月 24 日

当我们开始这轮冲刺时，我们并没有计划去针对流式输出时帧与帧之间的毫秒数做爬山优化。但结果发现我们确实可以把它们数出来——而任何我们能数出来的东西，Claude 都能爬上去。

下一步

今天，claude.ai 和桌面应用的速度大约是 8 月初的 3 倍，而棘轮机制应当能让它们保持在这一水平。但我们还没做完：第 95 百分位、其他使用路径，以及超长对话仍有改进空间。在另一篇帖子中，我们还会写到这次冲刺期间把我们带到上游的一些支线任务，相关贡献已进入 Electron、Chromium、Node.js 等。

当我们在内部分享这些结果时，Issac 总结得最好：“哪怕六个月前，你也不可能说服我这是可能的。”我们预计会继续以这种方式工作，一次一个线程，无论规模多大。这个频道仍在继续。

感谢 Alfred Xing、Anthony Morris、Benjamin Pasero、Chase McCoy、Joshua N.、Luke Taylor、Marius Schulz 和 Shelley Vohr 的贡献。特别感谢 Boris Cherny 鼓励我们更加雄心勃勃。
