三个重叠的基础设施 BugAnthropic Postmortem · 可视化阅读
原文
Anthropic Engineering · 2025-09-17

三个重叠的基础设施 Bug,怎么把 Claude 的回答质量拖下去的

8 月初到 9 月初,用户开始零星报告 Claude 的回答变差了。Anthropic 一开始把这些反馈当成了正常的噪声, 到 8 月底才开始系统调查 ——查到了三个独立、但时间叠加在一起的基础设施 Bug。 这篇是他们公开的事故复盘。

10–14 分钟阅读 2025 年 8 月 5 日 – 9 月 18 日 三个并发 Bug · 跨 TPU / GPU / Trainium
TL;DR

三个 bug 同时发生,让诊断变得格外棘手:短上下文请求被路由到 1M 上下文服务器TPU 上的运行时优化让模型偶尔吐出泰文/中文乱码XLA 编译器在近似 top-k 上选错 token。 没有任何一个 bug 是"故意降级"。

一句关键澄清:Anthropic 从不因为流量、时段或服务器负载主动降低模型质量。 用户感受到的下降,全部来自基础设施层面的真实 bug。

「我们直说一句:我们从不因需求、时段或服务器负载来降低模型质量。用户报告的问题完全是基础设施 Bug 造成的。」 — Anthropic Engineering
0.8% → 16%
Sonnet 4 受影响请求比例(8/5 引入 → 8/31 峰值),路由错误叠加 8/29 负载均衡变更后扩大
~30%
期间 Claude Code 用户至少有一条消息被路由到错误服务器
3
独立但时间重叠的 bug,各平台症状不同,让早期信号互相掩盖
~6 周
从最早 bug 引入(8/5)到最后一处回滚完成(9/18),跨 TPU / GPU / Trainium 全部修复
01 · 部署架构

Claude 同时跑在三种硬件、三个云上 —— 任何改动都要在所有平台等效

Anthropic 通过一方 API、Amazon Bedrock 和 Google Cloud Vertex AI 给数百万用户服务 Claude。 模型同时运行在 AWS Trainium、NVIDIA GPU 和 Google TPU 上 —— 这种多平台部署带来了容量和地理覆盖,也让任何基础设施改动的验证成本变得很高。

每种硬件性格不同,需要各自的优化路径。但 Anthropic 给自己设的硬约束是: 不论请求落到哪个平台,用户得到的回答质量应该是一致的。 这意味着任何一个底层修改,都要在所有平台和配置下重新验证一遍。

这次事故里几乎所有的麻烦都源自这个等效约束:bug 在不同硬件上以不同形式露出来 —— TPU 路径上是输出乱码和编译器选错 token,第三方平台上是路由错误 —— 症状的多样性反而模糊了"这是同一类问题"的信号。

· 部署平台

第一方 APIconsole / claude.ai
AWS Bedrock第三方
Vertex AI第三方

多平台部署提供地理覆盖与冗余,但每次基础设施改动都要在所有平台上等效验证

· 推理硬件

AWS Trainium专用 ASIC
NVIDIA GPU通用
Google TPUXLA 编译

这次事故中,TPU 路径暴露了两个独立问题(输出乱码 + XLA top-k); 路由 bug 则跨所有平台。

读者要 get 到的关键点:多平台等效是一个"承诺",不是一个免费午餐。 所有要给用户更好体验的优化,都得回答一个问题:它在所有平台上是否都还等效?
02 · 事故时间线

三个 Bug 重叠 + 一次"例行"负载均衡变更,把症状从噪声放大到无法忽视

第一个 bug 在 8 月 5 日就引入了,但只影响 Sonnet 4 的 0.8% 请求 —— 噪声水平。 8 月 25 / 26 日又叠加了两个 bug。真正让事故被注意到的,是 8 月 29 日的一次负载均衡变更, 它意外把更多短上下文请求路由到了为 1M 上下文配置的服务器,让一切症状被放大。

Bug 1 · 上下文窗口路由错误
Bug 2 · TPU 输出乱码
Bug 3 · XLA 近似 Top-K 误编译
8/5
8/25
8/29
8/31
9/2
9/4
9/12
9/18
Bug 1 · 路由错误(0.8% → 16% 峰值) 9/4 修 · 9/18 完成全平台
8/29 负载均衡变更
Bug 2 · 输出乱码(仅一方 API · TPU) 9/2 回滚
Bug 3 · XLA Top-K 误编译(Haiku 3.5 / Opus 3 / 可能 Sonnet 4) 9/4 / 9/12 分批回滚
关键放大节点:8/29 的负载均衡变更让原本 0.8% 的路由错误扩散到 16%。 当负面反馈集中爆发时,团队没有立刻把它和这个"看起来很标准"的变更联系起来 —— 这是后来"为什么没早发现"那一节的核心教训。
03 · 三个 Bug 详解

每个 bug 都在不同的层面、不同的平台上以不同症状露出来

三张并列卡片,从「请求送到哪台机」、「token 怎么算」、「token 怎么排序」三个层面分别展开。 点开每张卡片可以看影响范围、根因、表现样例和修复方式。

click to expand · 每个 bug 一张
01
上下文窗口路由错误 request routing · 跨所有平台
+

8 月 5 日,部分 Sonnet 4 请求被错误地路由到了为即将上线的 1M token 上下文窗口配置的服务器上。 最初只影响约 0.8% 的请求 —— 在噪声里几乎看不出。

8 月 29 日的一次"例行"负载均衡变更,无意中把更多短上下文请求也送到了 1M 上下文服务器。 到 8 月 31 日的最差时段,16% 的 Sonnet 4 请求被影响

放大效应来自路由是「黏滞」的:一旦某次请求落在错误的服务器,它的后续 follow-up 通常也会粘在同一台服务器上 —— 少数用户因此被反复打到错误路径。

~30%
Claude Code 用户期间至少 1 次被错路由
0.18%
AWS Bedrock 上 Sonnet 4 错路由峰值(8/12 起)
0.0004%
Vertex AI 上的影响(8/27 – 9/16)
RESOLUTION 修复路由逻辑,把短/长上下文请求分别送到正确的服务器池。 9 月 4 日开始部署,9/16 完成一方平台与 Vertex AI,9/18 完成 AWS Bedrock
02
TPU 输出乱码 token 生成 · 仅一方 API · TPU 路径
+

8 月 25 日,Anthropic 在 Claude API 的 TPU 服务器上部署了一次错误配置。 一个为运行时性能引入的优化,导致 token 生成阶段偶尔给本不该出现的 token 分配了高概率 —— 比如英文 prompt 的回答中间冒出泰文或中文,或者代码里出现明显的语法错误。

EXAMPLE 英文问题 → 回答中间忽然出现「สวัสดี」(泰文「你好」),或者代码块里冒出毫无来由的中文字符。

影响窗口:Opus 4.1 / Opus 4 是 8/25 – 8/28;Sonnet 4 是 8/25 – 9/2。 第三方平台(Bedrock / Vertex AI)不受影响,因为它们走的不是这条 TPU 路径。

RESOLUTION 9 月 2 日定位到问题并回滚。事后给部署流程加了一项 「输出中是否出现非预期字符」的检测
03
XLA:TPU 近似 Top-K 误编译 采样选 token · 编译器深层 bug
+

8 月 25 日,Anthropic 部署了一份新代码来改进文本生成中如何选 token —— 意图是修一个 12 月就发现的混合精度问题,结果意外触发了 XLA:TPU 编译器里一个潜伏 bug

已确认影响 Claude Haiku 3.5 的请求;怀疑也影响了一方 API 上的 Sonnet 4 子集和 Opus 3。 Bedrock / Vertex AI 不受影响。

这个 bug 是整篇 postmortem 里最技术、也最值得展开的部分。下一节有完整故事 —— 从一年前的 workaround,到表层修复反而暴露出更深的问题。

RESOLUTION 9/4 回滚 Haiku 3.5;后续看到 Opus 3 上类似症状,9/12 回滚 Opus 3;Sonnet 4 虽然反复无法重现,但出于稳健也回滚。 正在与 XLA:TPU 团队修编译器;同时把近似 top-k 切换为更精确的 exact top-k
04 · XLA Top-K 深度复盘

一个 12 月的 workaround,"修好"了一个其实是预期行为的现象 —— 也顺手把更深的 bug 给盖住了

这是整起事故里最有教育意义的一段。它讲的是一个看起来"修好了"的问题, 其实只是一个编译器优化的预期行为;而原本被它意外掩盖的真正 bug, 在表层修复之后才浮上来。

名词解释 · XLA

XLA = Accelerated Linear Algebra,Google 出的 ML 编译器。 它把 JAX / TensorFlow 写的高层数学(比如 softmax(x @ w + b)) 翻译成 TPU / GPU 的底层指令,并在中间做整图融合优化(把多个相邻算子合成一个 kernel,省掉显存来回搬运)。 TPU 上几乎所有 ML 代码都要经过它 —— 这个事故里被点名的「XLA:TPU」就是它的 TPU 后端。

CUDA C++ / Triton 让你手写 kernel,由你自己决定怎么用 GPU。
XLA 编译器 替你做优化,但你不能往里塞自己写的 kernel。

所以 XLA 不等于 CUDA,而是更像「ML 版 GCC + cuDNN」。 在 NVIDIA GPU 上,专家可以绕开框架直接写 CUDA / Triton kernel(FlashAttention 就是这么写的); 但 TPU 上没有这个逃生出口 —— XLA 是唯一一条路

为什么这件事跟事故强相关:这次 Bug 3 不是模型代码写错了, 而是编译器把 Anthropic 的高层代码编译错了。在 TPU 上 Anthropic 没法手写 kernel 顶替, 只能(1)等 XLA 团队修编译器、(2)找绕路写法、或(3)把 approximate top-k 换成 exact top-k —— 最后这次三种都做了。

理解了 XLA 这一层之后,接下来的故事就清晰了。Claude 生成文本时,对每个候选 token 算一个概率,再按这个分布随机采样。 我们用 top-p sampling 来避免胡言乱语 —— 只考虑累计概率达到阈值(通常 0.99 或 0.999)的那些 token。

在 TPU 上,模型是跨多颗 chip 切分的,概率计算分布在不同位置。要给这些概率排序, chip 之间必须协调数据 —— 这是一个分布式排序问题,比单机上写一行 sort 复杂得多。

timeline · 一年的故事 · december workaround → august rewrite → xla bug 浮现
2024-12workaround

发现一个奇怪现象:temperature=0 时,最高概率 token 偶尔被丢掉

团队在 TPU 实现里观察到 温度为 0 时偶尔会丢掉概率最高的 token。 当时打了一个 patch 来 work around 这种情况 —— 但没有真正搞清楚它为什么发生

背景mixed precision

真正的根因是混合精度,不是"bug"

模型用 bf16(16 位浮点)算下一 token 概率。但 TPU 的向量处理器是 fp32 原生的, 所以 XLA 编译器会自动把一部分操作提升到 fp32 来跑得更快 —— 这个优化由 xla_allow_excess_precision 标志控制,默认开启

这导致同一组本应一致的概率,在不同精度下被算了出来,于是它们对"谁是最高概率"的判断不一致 —— 最高概率 token 偶尔从候选里整个消失。

2025-08-11minimal repro

做出最小复现,确认这就是标志的预期行为,不是 bug

通过最小复现,团队认定 12 月看到的现象其实不是编译器 bug, 而是 xla_allow_excess_precision 默认开启情况下的预期行为。

2025-08-26rewrite

重写采样代码,统一精度,顺手移除了 12 月的 workaround

既然根因是混合精度,团队重写了采样代码、把精度问题修对, 并移除了那个原以为多余的 workaround。 ——表面上一切看起来更干净了。

修完之后底下露出来了

workaround 一直在意外掩盖一个更深的 bug:approximate top-k 偶尔返回完全错的结果

近似 top-k是 XLA:TPU 上的一个性能优化,能更快地找出最高概率的几个 token。 它的设计假设是「在最低概率的 token 上接受一点不准确」,正常情况下不影响质量 —— 除非它把最高概率 token 给丢了

移除 12 月的 workaround 后,这个 approximate top-k 在某些 batch size 和模型配置下会返回完全错的结果, 而 12 月的 workaround 之前一直误打误撞地把它盖住了。

更糟的是,bug 的行为极度不稳定:依赖前后跑了什么操作、依赖是否打开了调试工具, 同一个 prompt 一次能跑对一次跑错。

2025-09resolution

切回 exact top-k,把更多操作锁死在 fp32

调研中团队发现:exact top-k 在今天的 TPU 上已经没有当年那么大的性能代价了。 于是切换 approximate → exact top-k,并把若干额外操作标准化为 fp32 精度。 「模型质量是非 negotiable 的,效率上的微小代价可以接受。」

同时和 XLA:TPU 编译器团队推进底层 bug 的修复 —— 这条线在写文章时仍在进行。

Before · 被 workaround 盖住的版本
probs(bf16) → top-k(approximate) ↯

概率在不同精度下不一致 → 12 月加了 workaround 让"最高 token 偶尔丢"看不见 → workaround 同时也在意外掩盖近似 top-k 在某些 batch 下的失灵

After · 9 月的修复版本
probs(bf16) → fp32 sort → top-k(exact)

统一精度、改用 exact top-k。 性能代价小、质量稳,并把对 approximate top-k 的隐含信任改成显式选择。

这一段的真正教训不是「XLA 编译器有 bug」,而是: 你以为 workaround 在修一个 bug,它可能只是在掩盖另一个 bug。 在没有真正搞清楚根因之前移除 workaround,往往会让被它掩盖的更深问题第一次露出来。
05 · 为什么早期检测这么慢

评估钝化、隐私边界、症状混杂 —— 三股力量同时作用

Anthropic 的发布流程里有 benchmark、安全评估、性能监控、Spot Check、Canary 灰度。但在这次事故里, 这些手段集体失灵 —— 不是任何一道关卡彻底失效,而是它们都不够灵敏,捕捉不到"用户真正感受到的下降"

D1 · 评估太钝

Eval 抓不到用户描述的那种"质量变差"

Claude 经常能从一次孤立的错误里恢复回正常水平 —— 这让标准 benchmark 看上去「分数还行」,但用户在真实多轮对话里能感觉到不对。 这种钝化让团队对早期信号一直"半信半疑"。

D2 · 隐私边界

工程师看不到引发问题的真实交互

Anthropic 的内部隐私和安全控制限制工程师在何时何地查看用户与 Claude 的交互 —— 特别是当这些交互没有作为反馈主动报上来时。 这保护了隐私,但也让"找到能复现 bug 的样本"变得困难。

D3 · 症状混杂

三个 bug 在不同平台、不同模型上以不同比例发作

每个 bug 表现都不一样,加上不同平台不同发生率 —— 整体看上去像是"随机的、零星的质量下降",而不是某个具体改动出的问题。 反馈拼不出一个明确的原因。

更深一层,团队过度依赖了"嘈杂的评估"。8 月 29 日负面反馈集中爆发那天, 他们当然注意到了,但没有把它和当天那次「看起来很标准」的负载均衡变更联系起来 —— 这个变更在自己的指标看板上完全没出问题。

Anthropic 把这归结为「缺少把社区反馈和具体内部变更对齐起来的机制」。 换句话说,问题不是没人在看,而是没人能把外部信号和内部时间线对上。

06 · 改进措施

更敏感的评估、跑在真生产上的评估、能在隐私下做的 debug 工具

Anthropic 给出了三条具体改动方向。每一条都对应上一节的一个失灵点。

CHANGE 01

更敏感的评估

已经做出能更可靠区分「实现正常 / 实现损坏」的新评估。 会持续完善这些评估来更紧密地盯模型质量 —— 补的就是「Claude 能从单次失败恢复,所以总体分数还行」这个盲区。

CHANGE 02

把质量评估搬到真生产环境

以前是在专门系统上跑。现在会在真实生产系统上持续跑 —— 确保像「上下文窗口 + 负载均衡」这类组合错误能在用户感知前被指标抓住。

CHANGE 03

更快的、不牺牲隐私的 debug 工具

会开发新的基础设施和工具,在不破坏用户隐私的前提下处理社区反馈。 这次事故中临时打造的一些工具,未来事故里可以直接用来缩短定位时间。

closing thought

评估和监控很重要,但这场事故说明:在 Claude 表现不如平时时,我们也需要来自用户的持续信号。 你们对具体变化的描述、不正常行为的样例、不同使用场景中观察到的模式 —— 都是我们这次定位问题的关键拼图。

在 Claude Code 里用 /bug 命令,或在 Claude 应用里点「踩」,都能直接把反馈送回给我们。 如果你做出了好玩的、能补充我们内部测试的评估方法,欢迎写信到 feedback@anthropic.com。

— Anthropic Engineering · Sam McAllister 等