三次近期问题的事后分析

本文翻译自 Anthropic 官方博客:A postmortem of three recent issues

译者注:本文展示了 Anthropic 对基础设施问题的透明度和技术深度,提供了处理复杂分布式系统问题的宝贵经验。

8 月到 9 月初,三个基础设施错误间歇性地降低了 Claude 的响应质量。我们现在已经解决了这些问题,并想解释发生了什么。

8 月初,一些用户开始报告 Claude 的响应质量下降。这些初始报告很难与用户反馈的正常变化区分开来。到 8 月下旬,这些报告的频率和持续性增加,促使我们展开调查,最终发现了三个独立的基础设施错误。

坦率地说:我们从未因为需求、一天中的时间或服务器负载而降低模型质量。用户报告的问题完全是由于基础设施错误造成的。

我们认识到用户期望 Claude 提供一致的质量,我们对确保基础设施变更不影响模型输出保持了极高的标准。在最近的这些事件中,我们没有达到那个标准。以下事后分析解释出了什么问题,为什么检测和解决花费的时间比我们希望的更长,以及我们正在改变什么以防止类似的未来事件。

我们通常不分享有关我们基础设施的这种级别的技术细节,但这些问题的范围和复杂性证明了更全面的解释是合理的。

我们如何大规模提供 Claude

我们通过我们的一流 API、Amazon Bedrock 和 Google Cloud 的 Vertex AI 向数百万用户提供 Claude。我们在多个硬件平台上部署 Claude,即 AWS Trainium、NVIDIA GPU 和 Google TPU。这种方法提供了在全球范围内服务用户所需的容量和地理分布。

每个硬件平台都有不同的特性,需要特定的优化。尽管有这些变化,我们对模型实现有严格的等效性标准。我们的目标是,无论哪个平台服务他们的请求,用户都应该获得相同质量的响应。这种复杂性意味着任何基础设施变更都需要在所有平台和配置上进行仔细验证。

事件时间线

Claude API 上的事件说明性时间线。黄色:检测到问题,红色:性能下降加剧,绿色:部署修复。

Claude API 上的事件说明性时间线。黄色:检测到问题,红色:性能下降加剧,绿色:部署修复。

这些错误的重叠性质使诊断特别具有挑战性。第一个错误于 8 月 5 日引入,影响了对 Sonnet 4 发出的大约 0.8% 的请求。8 月 25 日和 26 日的部署又产生了两个错误。

尽管初始影响有限,但 8 月 29 日的负载平衡变更开始增加受影响的流量。这导致更多用户体验到问题,而其他人继续看到正常的性能,造成了令人困惑和矛盾的报告。

三个重叠的问题

下面我们描述导致性能下降的三个错误,它们发生的时间以及我们如何解决它们:

1. 上下文窗口路由错误

8 月 5 日,一些 Sonnet 4 请求被错误地路由到为即将推出的 1M token 上下文窗口配置的服务器。此错误最初影响了 0.8% 的请求。8 月 29 日,例行的负载平衡变更无意中增加了路由到 1M 上下文服务器的短上下文请求数量。在 8 月 31 日受影响最严重的一小时中,16% 的 Sonnet 4 请求受到影响。

在此期间发出请求的 Claude Code 用户中,大约有 30% 至少有一条消息被路由到错误的服务器类型,导致响应质量下降。在 Amazon Bedrock 上,错误路由的流量在 8 月 12 日达到所有 Sonnet 4 请求的 0.18% 的峰值。8 月 27 日至 9 月 16 日期间,Google Cloud 的 Vertex AI 上错误路由的请求少于 0.0004%。

然而,一些用户受到更严重的影响,因为我们的路由是"粘性"的。这意味着一旦请求由错误的服务器提供服务,后续的后续请求很可能由同一个错误的服务器提供服务。

解决方案:我们修复了路由逻辑,以确保短上下文和长上下文请求被定向到正确的服务器池。我们在 9 月 4 日部署了修复。到 9 月 16 日完成了对我们一流平台和 Google Cloud 的 Vertex AI 的推出,到 9 月 18 日完成了 AWS Bedrock 的推出。

2. 输出损坏

8 月 25 日,我们向 Claude API TPU 服务器部署了错误配置,导致在 token 生成期间发生错误。由运行时性能优化引起的问题偶尔会为给定上下文很少应该产生的 token 分配高概率,例如在响应英语提示时产生泰语或中文字符,或在代码中产生明显的语法错误。例如,一小部分用英语提问的用户可能会在响应中间看到"สวัสดี"。

此损坏影响了 8 月 25-28 日对 Opus 4.1 和 Opus 4 的请求,以及 8 月 25 日至 9 月 2 日对 Sonnet 4 的请求。第三方平台未受此问题影响。

解决方案:我们识别了该问题并于 9 月 2 日回滚了更改。我们已向我们的部署过程添加了意外字符输出的检测测试。

3. 近似 top-k XLA:TPU 误编译

8 月 25 日,我们部署了代码以改进 Claude 在文本生成期间选择 token 的方式。此更改无意中触发了 XLA:TPU¹ 编译器中的一个潜在错误,已确认会影响对 Claude Haiku 3.5 的请求。

我们还相信这可能影响了 Claude API 上 Sonnet 4 和 Opus 3 的子集。第三方平台未受此问题影响。

解决方案:我们首先观察到了影响 Haiku 3.5 的错误,并于 9 月 4 日回滚。后来我们注意到用户报告的 Opus 3 问题与此错误兼容,并于 9 月 12 日回滚。经过广泛调查,我们无法在 Sonnet 4 上重现此错误,但决定也出于高度谨慎回滚它。

同时,我们 (a) 一直在与 XLA:TPU 团队合作修复编译器错误,以及 (b) 推出了使用精确 top-k 和增强精度的修复。有关详细信息,请参阅下面的深入分析。

深入了解 XLA 编译器错误

为了说明这些问题的复杂性,以下是 XLA 编译器错误的表现方式以及为什么证明特别难以诊断。

当 Claude 生成文本时,它计算每个可能的下一个单词的概率,然后从此概率分布中随机选择一个样本。我们使用"top-p 采样"来避免无意义的输出——只考虑累积概率达到阈值(通常为 0.99 或 0.999)的单词。在 TPU 上,我们的模型跨多个芯片运行,概率计算发生在不同的位置。为了对这些概率进行排序,我们需要在芯片之间协调数据,这很复杂²。

2024 年 12 月,我们发现我们的 TPU 实现会在温度为零时偶尔丢弃最可能的 token。我们部署了一个解决方法来修复这种情况。

2024 年 12 月补丁的代码片段,用于解决 temperature = 0 时意外丢失 token 的错误。

2024 年 12 月补丁的代码片段,用于解决 temperature = 0 时意外丢失 token 的错误。

根本原因涉及混合精度算术。我们的模型在 bf16(16 位浮点)中计算下一个 token 的概率。然而,向量处理器是 fp32 原生的,因此 TPU 编译器(XLA)可以通过将某些操作转换为 fp32(32 位)来优化运行时。此优化过程由 xla_allow_excess_precision 标志保护,该标志默认为 true。

这导致了不匹配:应该在最高概率 token 上一致的操作在不同的精度级别运行。精度不匹配意味着它们不同意哪个 token 具有最高概率。这导致最高概率 token 有时完全从考虑中消失。

8 月 26 日,我们部署了采样代码的重写,以修复精度问题并改进我们在达到 top-p 阈值的极限处处理概率的方式。但在修复这些问题时,我们暴露了一个更棘手的问题。

代码片段显示了最小化的重现器,作为 2024 年 12 月更改的一部分合并,该更改根本分析了 2024 年 12 月绕过的"错误";实际上,这是 xla_allow_excess_precision 标志的预期行为。

代码片段显示了最小化的重现器,作为 2024 年 12 月更改的一部分合并,该更改根本分析了 2024 年 12 月绕过的"错误"。实际上,这是 xla_allow_excess_precision 标志的预期行为。

我们的修复删除了 12 月的解决方法,因为我们认为我们已经解决了根本原因。这导致了近似 top-k 操作中的一个更深的错误——一种性能优化,可以快速找到最高概率的 token³。此近似有时会返回完全错误的结果,但仅对于某些批大小和模型配置。12 月的解决方法无意中掩盖了这个问题。

与开发该算法的 XLA:TPU 工程师共享的潜在近似 top-k 错误的重现器。代码在 CPU 上运行时返回正确结果。

与开发该算法的 XLA:TPU 工程师共享的潜在近似 top-k 错误的重现器。代码在 CPU 上运行时返回正确结果。

错误的行为令人沮丧地不一致。它取决于不相关的因素,例如在它之前或之后运行的操作,以及是否启用了调试工具。同一个提示可能在一个请求上完美运行,而在下一个请求上失败。

在调查期间,我们还发现精确的 top-k 操作不再具有曾经具有的禁止性性能惩罚。我们从近似 top-k 切换到精确 top-k,并将一些额外的操作标准化为 fp32 精度⁴。模型质量是不可协商的,因此我们接受了轻微的效率影响。

为什么检测很困难

我们的验证过程通常依赖于基准测试以及安全评估和性能指标。工程团队进行抽查,并首先部署到小的"金丝雀"组。

这些问题暴露了本应该更早识别的关键差距。我们运行的评估根本没有捕获用户报告的性能下降,部分原因是 Claude 通常可以从孤立的错误中很好地恢复。我们自己的隐私实践也在调查报告时造成了挑战。我们的内部隐私和安全控制限制了工程师可以访问用户与 Claude 的交互的方式和时间,特别是当这些交互未作为反馈报告给我们时。这保护了用户隐私,但阻止工程师检查识别或重现错误所需的有问题的交互。

每个错误在不同平台上以不同速率产生不同的症状。这创建了一组令人困惑的报告,没有指向任何单一原因。它看起来像随机的、不一致的性能下降。

更根本的是,我们过于依赖嘈杂的评估。尽管我们意识到在线报告的增加,但我们缺乏一种清晰的方法将这些与我们的每个最近更改联系起来。当 8 月 29 日负面报告激增时,我们没有立即将其与否则标准的负载平衡变更联系起来。

我们正在改变什么

随着我们继续改进我们的基础设施,我们也在改进我们评估和防止在我们提供 Claude 的所有平台上出现上述错误的方式。这是我们正在改变的:

  • 更敏感的评估:为了帮助发现任何给定问题的根本原因,我们开发了能够更可靠地区分工作实现和损坏实现的评估。我们将继续改进这些评估,以更密切地关注模型质量。
  • 在更多地方进行质量评估:尽管我们在系统上运行定期评估,但我们将在真正的生产系统上持续运行它们,以捕获诸如上下文窗口负载平衡错误之类的问题。
  • 更快的调试工具:我们将开发基础设施和工具,以更好地调试来自社区的反馈,同时不牺牲用户隐私。此外,这里开发的一些定制工具将用于减少未来类似事件(如果发生这些事件)的补救时间。

评估和监控很重要。但这些事件表明,我们还需要来自用户的持续信号,当 Claude 的响应不符合通常的标准时。观察到的特定变化的报告、遇到的意外行为的示例以及跨不同用例的模式都有助于我们隔离问题。

用户继续直接向我们发送反馈仍然特别有帮助。您可以在 Claude Code 中使用 /bug 命令,或者您可以使用 Claude 应用程序中的"拇指向下"按钮来这样做。开发人员和研究人员经常创建新的有趣方法来评估模型质量,这些方法补充了我们的内部测试。如果您想分享您的方法,请发送电子邮件至 feedback@anthropic.com

我们仍然感谢社区的这些贡献。

致谢

本文由 Sam McAllister 撰写,感谢 Stuart Ritchie、Jonathan Gray、Kashyap Murali、Brennan Saeta、Oliver Rausch、Alex Palcuie 和许多人。

[1] XLA:TPU 是优化编译器,将 XLA 高级优化语言——通常使用 JAX 编写——翻译成 TPU 机器指令。

[2] 我们的模型对于单个芯片来说太大,被分区到数十个或更多芯片上,使我们的排序操作成为分布式排序。TPU(就像 GPU 和 Trainium 一样)也有与 CPU 不同的性能特征,需要使用向量化操作而不是串行算法的不同实现技术。

[3] 我们一直在使用这个近似操作,因为它产生了显著的性能改进。近似的工作原理是接受最低概率 token 的潜在不准确性,这不应该影响质量——除非当错误导致它丢弃最高概率 token 时。

[4] 请注意,现在正确的 top-k 实现可能会导致在 top-p 阈值附近包含的 token 略有不同,在罕见情况下,用户可能受益于重新调整他们的 top-p 选择。