# 03 A postmortem of three recent issues - 透明工程文化的典范实践

> **发布时间**：2025年9月17日\
> **原文链接**：<https://www.anthropic.com/engineering/a-postmortem-of-three-recent-issues\\>
> **核心定位**：通过公开技术故障分析，展示Anthropic"Security First"理念下的透明工程文化

***

## 📖 文章概览

这是一篇**极其罕见**的技术Postmortem，Anthropic公开了导致Claude响应质量下降的三个基础设施Bug的完整技术细节。这种透明度在AI行业中几乎是独一无二的。

### 核心声明

> **官方声明**：我们从不因需求、时间或服务器负载而降低模型质量。用户报告的问题完全是由于基础设施Bug。

这个声明非常重要——它直接回应了社区关于"Claude在高峰期变笨"的猜测。

***

## 🏗️ Claude的规模化服务架构

### 多平台部署策略

```
Claude服务架构：

┌─────────────────────────────────────────────────────────────┐
│  用户访问点                                                   │
├─────────────────────────────────────────────────────────────┤
│  • Anthropic First-party API                                │
│  • Amazon Bedrock                                           │
│  • Google Cloud Vertex AI                                  │
└─────────────────────────────────────────────────────────────┘
        ↓
┌─────────────────────────────────────────────────────────────┐
│  硬件平台                                                     │
├─────────────────────────────────────────────────────────────┤
│  • AWS Trainium                                             │
│  • NVIDIA GPUs                                              │
│  • Google TPUs                                              │
└─────────────────────────────────────────────────────────────┘
```

### 关键挑战

**平台差异**：

* 每个硬件平台有不同的特性
* 需要特定的优化
* 但必须保证**等价性**

**核心目标**：

> 用户应该获得相同质量的响应，无论哪个平台服务他们的请求。

**复杂度**：

```
任何基础设施变更都需要：
1. 跨所有平台验证
2. 跨所有配置测试
3. 确保输出等价性

这种复杂性是Bug的温床
```

***

## 📅 事件时间线

### 可视化时间线

```
2025年8月
┌────────┬────────┬────────┬────────┬────────┬────────┬────────┐
│  5日   │  12日  │  25日  │  26日  │  29日  │  31日  │  4日   │
├────────┼────────┼────────┼────────┼────────┼────────┼────────┤
│  🟡    │  🟡    │  🔴    │  🔴    │  🔴    │  🔴    │  🟢    │
│ Bug#1  │ Bug#1  │ Bug#2  │ Bug#3  │ 负载   │ 高峰   │ 修复   │
│ 引入   │ 影响   │ 引入   │ 引入   │ 均衡   │ 影响   │ #1     │
│ 0.8%   │ 扩散   │        │        │ 改变   │ 16%    │        │
└────────┴────────┴────────┴────────┴────────┴────────┴────────┘

2025年9月
┌────────┬────────┬────────┬────────┬────────┐
│  2日   │  4日   │  12日  │  16日  │  18日  │
├────────┼────────┼────────┼────────┼────────┤
│  🟢    │  🟢    │  🟢    │  🟢    │  🟢    │
│ 修复   │ 修复   │ 修复   │ 修复   │ 完全   │
│ #2     │ Bug#3  │ Bug#3  │ 部署   │ 解决   │
│        │ (部分) │ (完全) │ 完成   │        │
└────────┴────────┴────────┴────────┴────────┘
```

### 关键观察

**重叠的复杂性**：

```
三个Bug时间重叠
    ↓
导致诊断困难
    ↓
用户报告矛盾
    ↓
难以定位根因
```

**负载均衡的意外后果**：

```
8月29日的负载均衡改变
    ↓
意外增加了受影响的流量
    ↓
从0.8%飙升到16%
    ↓
大量用户开始报告问题
```

***

## 🐛 三个Bug的技术深度分析

### Bug #1: 上下文窗口路由错误

#### 问题描述

**错误行为**：

```
短上下文请求被错误路由到配置为1M Token上下文窗口的服务器

结果：
- 响应质量下降
- 用户体验不一致
```

#### 影响范围

| 平台             | 高峰影响    | 时间范围        |
| -------------- | ------- | ----------- |
| Claude API     | 16%     | 8/31高峰期     |
| Claude Code    | 30%     | 受影响期间至少1条消息 |
| Amazon Bedrock | 0.18%   | 8/12开始      |
| Vertex AI      | 0.0004% | 8/27-9/16   |

**"粘性"路由的问题**：

```
一旦请求被路由到错误的服务器
    ↓
后续的follow-up请求很可能继续路由到同一服务器
    ↓
某些用户受到严重影响
```

#### 根本原因

```python
# 伪代码说明问题

def route_request(request):
    if request.context_length <= 200k:
        # 应该路由到短上下文服务器
        server = get_short_context_server()
    else:
        # 应该路由到长上下文服务器
        server = get_long_context_server()
    
    # Bug: 路由逻辑有误
    # 部分短上下文请求被发送到长上下文服务器
    # 长上下文服务器针对1M Token优化，对短请求性能不佳
```

#### 修复方案

```
1. 修正路由逻辑
2. 确保短/长上下文请求路由到正确的服务器池
3. 9月4日部署修复
4. 9月16日完成Vertex AI部署
5. 9月18日完成Bedrock部署
```

***

### Bug #2: 输出损坏

#### 问题描述

**症状**：

```
用户在英文提示的响应中看到泰语或中文字符
代码中出现明显的语法错误

示例：
用户问题（英文）→ 响应包含 "สวัสดี"（泰语）
```

#### 技术原因

**运行时性能优化导致的Bug**：

```
Token生成过程：

正常情况：
Context → 计算概率 → 选择Token → 输出

Bug情况：
Context → 计算概率 → [性能优化Bug] → 错误的Token获得高概率
                                    ↓
                                不应该出现的Token（如泰语字符）
                                被选中并输出
```

**具体机制**：

```python
# 伪代码说明

def generate_next_token(context, probabilities):
    # 性能优化（有Bug）
    # 错误地给某些罕见Token分配了高概率
    
    # 例如：在英文上下文中
    # "hello" 的概率应该是 0.8
    # "สวัสดี" 的概率应该是 0.0001
    
    # 但Bug导致：
    # "hello" 的概率 = 0.2  ❌
    # "สวัสดี" 的概率 = 0.7  ❌（错误！）
    
    return sample_from_probabilities(probabilities)
```

#### 影响范围

* **平台**：仅限Claude API的TPU服务器
* **模型**：Opus 4.1, Opus 4（8/25-28），Sonnet 4（8/25-9/2）
* **第三方平台**：未受影响

#### 修复方案

```
1. 识别问题（9月2日）
2. 回滚有问题的配置
3. 添加检测测试（检测意外字符输出）
4. 集成到部署流程
```

***

### Bug #3: 近似Top-k XLA:TPU编译错误

#### 最复杂的Bug

这个Bug展示了现代AI系统的复杂性——一个涉及编译器、精度、硬件优化的深层问题。

#### 背景：Token采样机制

```
Claude生成文本时：

步骤1：计算每个可能下一个词的概率
      ↓
步骤2：使用Top-p采样
      - 只考虑累积概率达到阈值的Token
      - 典型阈值：0.99 或 0.999
      ↓
步骤3：从这些Token中随机选择
```

#### Top-k操作的挑战

**在TPU上的复杂性**：

```
挑战：
1. 模型跨多个芯片运行
2. 概率计算分布在不同位置
3. 需要在芯片之间协调数据来排序
4. 这是一个分布式排序问题

传统解决方案：
使用"近似Top-k"操作
- 快速但不精确
- 对最低概率Token不精确（可接受）
- 但不应该影响最高概率Token
```

#### Bug的发现过程

**第一次发现（2024年12月）**：

```python
# 问题：temperature=0时，最高概率Token偶尔被丢弃

# 临时修复
if temperature == 0:
    # 特殊处理，确保最高概率Token不被丢弃
    return most_probable_token()
```

**根本原因（2025年8月揭示）**：

```
混合精度算术问题：

模型计算：bf16（16位浮点）
向量处理器：fp32原生（32位浮点）

TPU编译器（XLA）优化：
- 将某些操作转换为fp32以提高运行时性能
- 由xla_allow_excess_precision标志控制（默认true）

问题：
- 操作应该在相同精度上一致
- 但由于优化，运行在不同精度级别
- 精度不匹配导致对哪个Token概率最高的不一致
- 最高概率Token有时从考虑中消失
```

#### 2025年8月26日的部署

**好意导致坏结果**：

```
目标：修复精度问题，改进概率处理
实现：重写采样代码

结果：
✅ 修复了一些问题
❌ 但暴露了更棘手的问题

移除了12月的临时修复
    ↓
暴露了近似Top-k操作的深层Bug
    ↓
返回完全错误的结果
    ↓
仅对某些批处理大小和模型配置
```

#### 调试的困难

```
Bug行为极其不一致：

✅ 在CPU上运行正常
❌ 在TPU上失败

✅ 有时工作正常
❌ 有时失败

取决于：
- 之前/之后运行的操作
- 调试工具是否启用
- 批处理大小
- 模型配置

这是最难调试的Bug类型：非确定性、与环境相关
```

#### 最终解决方案

```
多管齐下的修复：

1. 与XLA:TPU团队合作修复编译器Bug
2. 切换到精确Top-k（牺牲一些性能）
3. 标准化一些操作为fp32精度
4. 接受轻微的效率影响

决策：
模型质量不可协商
→ 接受性能影响
```

**技术细节**：

```python
# 从近似到精确

# Before (有Bug)
def sample_tokens(logits, top_p=0.99):
    # 使用近似Top-k（快速但有Bug）
    top_k_tokens = approx_top_k(logits, k=calculated_k)
    return sample_from_top_p(top_k_tokens, top_p)

# After (修复)
def sample_tokens(logits, top_p=0.99):
    # 使用精确Top-k（稍慢但正确）
    # 并使用增强精度
    top_k_tokens = exact_top_k_fp32(logits, k=calculated_k)
    return sample_from_top_p(top_k_tokens, top_p)
```

#### 影响范围

* **确认影响**：Haiku 3.5（回滚于9/4）
* **可能影响**：Opus 3（回滚于9/12，Sonnet 4（预防性回滚）
* **第三方平台**：未受影响

***

## 🔍 为什么检测如此困难

### 1. 评估的局限性

```
问题：
现有的评估基准没有捕获这种降级

原因：
- Claude通常能很好地从孤立错误中恢复
- 偶尔的错误Token不会破坏整体响应
- 基准测试可能仍然"通过"

但用户注意到：
- 响应感觉"不太对"
- 质量不一致
- 有时表现异常
```

### 2. 隐私控制的挑战

```
Anthropic的隐私政策：
✅ 保护用户隐私
❌ 限制工程师访问用户交互

挑战：
- 用户报告"Claude表现不好"
- 但工程师无法访问具体的交互
- 难以重现或诊断问题

这是正确的权衡，但增加了调试难度
```

### 3. Bug的复杂重叠

```
三个Bug时间重叠
    ↓
每个产生不同症状
    ↓
在不同平台上
    ↓
影响不同模型
    ↓
创建混乱的报告混合

用户A: "Sonnet在代码任务上变差了"
用户B: "Opus在对话中很好"
用户C: "Haiku响应有奇怪的字符"

工程师：？？？ 哪个是真正的问题？
```

### 4. 嘈杂的评估

```
问题：
过度依赖嘈杂的评估

当社区报告飙升（8/29）
    ↓
但评估没有显示明显下降
    ↓
难以连接用户报告与特定变更
    ↓
延迟了问题识别和修复
```

***

## 🛠️ Anthropic的改进措施

### 1. 更敏感的评估

**目标**：能够可靠区分工作和损坏的实现

**方法**：

```python
# 开发新的评估

# 旧评估
def evaluate_model(model):
    return benchmark_score(model)  # 单一分数

# 新评估（更细粒度）
def evaluate_model(model):
    scores = {
        "consistency": measure_consistency(model),
        "character_distribution": check_unexpected_chars(model),
        "syntax_errors": count_syntax_errors(model),
        "context_handling": test_context_lengths(model),
        "edge_cases": test_edge_cases(model)
    }
    return scores

# 如果任何维度显著下降 → 警报
```

### 2. 在更多地方运行质量评估

**策略**：

```
不仅在开发/测试中运行评估
    ↓
在真实生产系统上持续运行
    ↓
捕获类似上下文窗口负载均衡的问题
```

**实现**：

```python
# 连续质量监控

@continuous_monitoring
def quality_check():
    # 从实际生产流量中抽样
    sample = get_production_sample(rate=0.01)  # 1%
    
    # 运行快速评估
    score = quick_eval(sample)
    
    # 检测异常
    if score < baseline - threshold:
        alert_team()
        trigger_detailed_analysis()
```

### 3. 更快的调试工具

**目标**：在不牺牲隐私的情况下，更好地调试社区反馈

**方法**：

```
开发基础设施和工具：
1. 允许有限、隐私保护的访问
2. 创建合成重现案例
3. 构建更好的日志和跟踪
4. 减少未来类似事件的修复时间
```

**示例工具**：

```python
# 隐私保护的调试

def analyze_user_report(report_id):
    # 不访问实际内容
    metadata = get_metadata(report_id)
    # 包括：模型、平台、时间戳、请求长度等
    
    # 查找类似模式
    similar_reports = find_similar_patterns(metadata)
    
    # 创建合成案例
    synthetic_case = generate_synthetic_reproduction(metadata)
    
    # 调试合成案例
    debug(synthetic_case)
```

***

## 💡 深度洞察

### 洞察1：复杂性是不可避免的

```
现代AI系统：

多个硬件平台
    ×
多个模型
    ×
多个配置
    ×
分布式部署
    ═══════════════
    指数级复杂性

没有"简单"的大规模AI部署
```

**启发**：

```
不要试图消除复杂性
而要：
1. 建立更好的测试
2. 改进监控
3. 提高透明度
4. 快速迭代修复
```

### 洞察2：透明度建立信任

```
大多数公司：
"我们遇到了暂时的问题，已经解决了。"

Anthropic：
"这是三个Bug的完整技术细节，包括：
- 根本原因
- 为什么花时间修复
- 我们正在改变什么"

结果：
✅ 社区信任增加
✅ 工程文化展示
✅ 行业标准提升
```

### 洞察3：评估的局限性

```
关键教训：

评估不是万能的
     ↓
即使有全面的评估
     ↓
仍可能错过某些类型的降级
     ↓
需要多层监控：
- 自动评估
- 用户反馈
- 生产监控
- 持续测试
```

### 洞察4：精度问题的微妙性

```
混合精度计算的教训：

看起来无害的优化
     ↓
可能导致微妙但严重的Bug
     ↓
仅在特定配置下显现
     ↓
极难调试

性能优化 ≠ 免费午餐
始终有权衡
```

***

## 🎯 实践建议

### 对AI工程团队

#### 立即可做

1. **建立Postmortem文化**

   ```markdown
   # Postmortem模板

   ## 故障概述
   - 发生时间
   - 影响范围
   - 严重程度

   ## 时间线
   [详细的事件序列]

   ## 根本原因分析
   [使用5 Whys等方法]

   ## 修复措施
   - 临时措施
   - 长期解决方案

   ## 行动项
   - [ ] 任务1（负责人，截止日期）
   - [ ] 任务2（负责人，截止日期）

   ## 学到的教训
   [可以防止未来类似问题的见解]
   ```
2. **实施多层监控**

   ```python
   # 监控策略

   层级1：自动评估
   - 定期运行基准测试
   - 检测性能回归

   层级2：生产采样
   - 实时质量检查
   - 异常检测

   层级3：用户反馈
   - 结构化反馈收集
   - 趋势分析

   层级4：社区信号
   - 监控社交媒体
   - 分析报告模式
   ```
3. **构建隐私保护的调试工具**

   ```python
   # 在隐私和可调试性之间平衡

   def debug_with_privacy(issue_report):
       # 不访问实际内容
       # 但收集足够的元数据
       
       metadata = {
           "model": issue_report.model,
           "timestamp": issue_report.timestamp,
           "request_length": issue_report.request_length,
           "response_length": issue_report.response_length,
           "platform": issue_report.platform,
           # 不包括实际的提示或响应
       }
       
       # 查找模式
       pattern = analyze_pattern(metadata)
       
       # 重现
       reproduce_synthetically(pattern)
   ```

#### 中期目标

1. **开发细粒度评估**

   ```python
   # 不要只有整体分数
   # 测试特定能力

   evaluations = [
       ConsistencyEval(),
       CharacterDistributionEval(),
       SyntaxCorrectness(),
       ContextHandling(),
       EdgeCaseHandling(),
       # ... 更多
   ]

   # 任何单个失败都应该警报
   ```
2. **实施金丝雀部署**

   ```python
   # 不要一次部署到所有地方

   def deploy(new_version):
       # 阶段1：内部测试
       deploy_to("internal", new_version, percentage=100)
       monitor(duration="24h")
       
       # 阶段2：小金丝雀
       deploy_to("production", new_version, percentage=1)
       monitor(duration="24h")
       
       # 阶段3：逐步扩展
       for pct in [5, 10, 25, 50, 100]:
           deploy_to("production", new_version, percentage=pct)
           monitor(duration="6h")
           if detected_issues():
               rollback()
               break
   ```
3. **建立快速回滚机制**

   ```python
   # 一键回滚

   @emergency_button
   def rollback_immediately():
       """
       在检测到问题时立即回滚
       不需要复杂的审批流程
       """
       previous_version = get_last_stable_version()
       deploy(previous_version, fast_track=True)
       notify_team("Rolled back to {previous_version}")
   ```

### 对产品和领导团队

1. **培养透明文化**

   ```
   鼓励：
   ✅ 公开讨论失败
   ✅ 分享学到的教训
   ✅ 奖励发现问题的人

   避免：
   ❌ 责备文化
   ❌ 隐藏问题
   ❌ 惩罚报告坏消息的人
   ```
2. **投资监控基础设施**

   ```
   不要把监控视为"可有可无"

   监控 = 质量保证的眼睛

   没有监控 = 盲目飞行
   ```
3. **平衡速度与质量**

   ```
   快速迭代很重要
   但不要牺牲质量

   建立检查点：
   - 必须通过的评估
   - 必须运行的测试
   - 必须审查的变更
   ```

***

## 🚨 关键警告

### ⚠️ 混合精度计算的风险

**问题**：

```
性能优化（如混合精度）
     ↓
可能引入微妙的正确性问题
     ↓
仅在特定配置下出现
     ↓
极难调试
```

**建议**：

```python
# 始终验证正确性

def test_precision_sensitive_ops():
    # 在不同精度下测试
    result_fp16 = compute_fp16(input)
    result_fp32 = compute_fp32(input)
    
    # 验证数值稳定性
    assert_close(result_fp16, result_fp32, tolerance=acceptable_error)
    
    # 测试边缘情况
    test_with_extreme_values()
    test_with_zero_values()
    test_with_negative_values()
```

### ⚠️ 分布式系统的复杂性

**问题**：

```
多平台部署
     ↓
每个平台的微妙差异
     ↓
难以保证等价性
     ↓
Bug可能只在某些平台出现
```

**建议**：

```
1. 自动化跨平台测试
2. 定期运行等价性验证
3. 文档化平台差异
4. 建立平台特定的监控
```

### ⚠️ 过度依赖自动评估

**问题**：

```
自动评估可能错过某些类型的降级
特别是：
- 微妙的质量下降
- 用户体验问题
- 边缘情况
```

**建议**：

```
多层验证策略：
1. 自动评估
2. 人工审查
3. 生产监控
4. 用户反馈
5. 社区信号

不要只依赖一种方法
```

***

## 📊 价值评估

| 维度       | 评分    | 说明             |
| -------- | ----- | -------------- |
| **透明度**  | ⭐⭐⭐⭐⭐ | 罕见的完全技术透明度     |
| **教育价值** | ⭐⭐⭐⭐⭐ | 深入的技术细节，极具学习价值 |
| **文化示范** | ⭐⭐⭐⭐⭐ | 展示了理想的工程文化     |
| **行业影响** | ⭐⭐⭐⭐☆ | 为行业树立了新标准      |

***

## 🔗 与其他文章的关联

### 体现的核心理念

* **Security First**：质量不可协商，即使牺牲性能
* **透明度**：公开技术细节，建立信任

### 技术相关文章

* **Context engineering**：Bug #1涉及上下文窗口管理
* **Building effective agents**：可靠性是Agent的基础
* **SWE-bench**：自动化测试的重要性

***

## 💭 个人思考

### 思考1：透明度的力量

**观察**：

```
Anthropic本可以：
- 简单说"我们修复了一些问题"
- 不提供技术细节
- 避免潜在的负面报道

但他们选择：
- 完全透明
- 详细技术分析
- 承认错误和局限性

这是勇气
```

**启发**：

```
在信任稀缺的时代
透明度是最有价值的货币

短期可能有风险
但长期建立无价的信任
```

### 思考2：复杂性的不可避免性

**观察**：

```
即使是Anthropic这样的顶级团队
也会遇到复杂、微妙的Bug

这不是能力问题
是现代AI系统固有复杂性的体现
```

**启发**：

```
不要追求"零Bug"
而要追求：
1. 快速检测
2. 快速修复
3. 持续学习
4. 透明沟通
```

### 思考3：工程文化的重要性

**观察**：

```
Anthropic的Postmortem不是技术文档
更是文化宣言

它传达的信息：
- 我们不完美
- 但我们诚实
- 我们从错误中学习
- 我们持续改进
```

**启发**：

```
工程卓越 ≠ 从不犯错
工程卓越 = 如何处理错误

文化 > 技术栈
```

***

**最后的话**：

这篇Postmortem是AI行业的一个里程碑。它展示了：

1. **技术透明度的可能性**：即使在竞争激烈的行业，也可以公开技术细节
2. **文化的力量**：透明度建立的信任远超过短期风险
3. **复杂性的现实**：承认问题的存在是解决问题的第一步

**对行业的启示**：

* 其他AI公司会跟随吗？
* 透明度会成为新标准吗？
* 用户会奖励诚实吗？

**让我们拭目以待。但Anthropic已经树立了标杆。** 🎯
