# 书籍生成容错机制说明

## 核心问题

用户之前遇到的痛点：
1. **AI调用失败后任务卡住**，用户不知道发生了什么
2. **长时间无响应**，用户傻等一天也不知道进度
3. **没有自动重试**，一次失败就彻底失败
4. **没有用户通知**，前端无法实时显示错误信息

## 解决方案

### 1. AI调用重试机制（3次重试 + 指数退避）

**文件**: `fault-tolerance.ts` → `callLLMWithRetry()`

**工作流程**:
```
AI调用失败 
  ↓
等待2秒后重试 (第1次)
  ↓  
等待4秒后重试 (第2次)
  ↓
等待8秒后重试 (第3次)
  ↓
全部失败 → 标记失败 + 通知用户
```

**特点**:
- 指数退避：2秒 → 4秒 → 8秒 → 16秒 → 30秒（最大）
- 每次重试都会记录到数据库的errorMsg字段
- 每次重试都会通过WebSocket通知用户

**代码示例**:
```typescript
const response = await callLLMWithRetry(
  messages,
  undefined,
  {
    bookId: state.bookId,
    nodeId: 'generate_outline',
    attempt: 0,
    maxAttempts: 3,
  }
);
```

### 2. 节点级超时控制

**文件**: `fault-tolerance.ts` → `executeNodeWithTimeout()`

**超时配置**:
```typescript
generate_outline: 5分钟      // 大纲生成
generate_sections: 10分钟    // 节生成
generate_subsections: 15分钟 // 小节生成
write_chapters: 30分钟       // 内容生成（最长）
write_foreword: 5分钟        // 前言
write_afterword: 5分钟       // 后记
```

**工作流程**:
```
节点开始执行
  ↓
启动超时计时器
  ↓
节点执行完成 → 清除计时器 → 通知用户
  ↓
超时 → 抛出错误 → 触发自动恢复
```

**代码示例**:
```typescript
const response = await executeNodeWithTimeout(
  state.bookId,
  'generate_outline',
  async () => {
    return callLLMWithRetry(...);
  },
  5 * 60 * 1000  // 5分钟超时
);
```

### 3. 进度监控和长时间无响应告警

**文件**: `fault-tolerance.ts` → `startProgressMonitor()`

**监控策略**:
```
每1分钟检查一次进度
  ↓
10分钟无进度更新 → 第1次警告（用户收到通知）
  ↓
20分钟无进度更新 → 第2次警告（建议手动干预）
  ↓
30分钟无进度更新 → 尝试自动恢复
```

**通知内容**:
- 第1次："生成进度长时间未更新，系统正在监控中..."
- 第2次："生成任务可能已卡住，建议刷新页面或重新生成"
- 第3次："系统检测到任务异常，正在尝试自动恢复..."

**代码示例**:
```typescript
// 在主生成器中启动
const stopMonitor = startProgressMonitor(bookId);

try {
  // 执行生成任务
} finally {
  // 无论成功或失败都停止监控
  stopMonitor();
}
```

### 4. 失败自动恢复机制

**文件**: `fault-tolerance.ts` → `attemptAutoRecovery()`

**恢复策略**:
```
检测到任务失败/超时
  ↓
等待5分钟（给AI服务恢复的时间）
  ↓
重新加入队列
  ↓
最多尝试2次
  ↓
2次都失败 → 标记为最终失败 → 通知用户手动操作
```

**限制**:
- 最多自动恢复2次（防止无限循环）
- 每次恢复间隔5分钟
- 达到最大次数后标记为最终失败

**代码示例**:
```typescript
// 进度监控器检测到异常时自动调用
await attemptAutoRecovery(bookId);
```

### 5. WebSocket实时通知

**文件**: `fault-tolerance.ts` → `notifyUser()`

**通知类型**:
```typescript
type: 'ai_retry'          // AI调用重试
type: 'ai_failed'         // AI调用最终失败
type: 'node_start'        // 节点开始执行
type: 'node_complete'     // 节点执行完成
type: 'node_timeout'      // 节点执行超时
type: 'progress_warning'  // 进度警告（10分钟）
type: 'progress_critical' // 进度严重警告（20分钟）
type: 'auto_recovery'     // 正在自动恢复
type: 'recovery_success'  // 自动恢复成功
type: 'recovery_failed'   // 自动恢复失败
type: 'recovery_error'    // 自动恢复出错
```

**通知内容**:
```json
{
  "type": "book_generation_notification",
  "data": {
    "bookId": "1",
    "timestamp": 1234567890,
    "type": "ai_retry",
    "nodeId": "generate_outline",
    "attempt": 1,
    "maxAttempts": 3,
    "message": "AI调用失败，正在重试 (1/3)..."
  }
}
```

## 集成方式

### 方式1：在节点中使用（推荐）

```typescript
import { callLLMWithRetry, executeNodeWithTimeout, FAULT_TOLERANCE_CONFIG } from '../fault-tolerance';

export async function generateOutlineNode(state: typeof GraphState.State) {
  try {
    const response = await executeNodeWithTimeout(
      state.bookId,
      'generate_outline',
      async () => {
        return callLLMWithRetry(
          buildOutlineMessages(...),
          undefined,
          {
            bookId: state.bookId,
            nodeId: 'generate_outline',
            attempt: 0,
            maxAttempts: FAULT_TOLERANCE_CONFIG.aiRetry.maxRetries,
          }
        );
      },
      FAULT_TOLERANCE_CONFIG.nodeTimeout.generate_outline
    );
    
    // 处理响应...
  } catch (error) {
    // 错误已记录，抛出给上层处理
    throw error;
  }
}
```

### 方式2：在主生成器中启动进度监控

```typescript
import { startProgressMonitor } from './fault-tolerance';

async generate(bookId: string, topic: string, bookScale: string) {
  // 启动进度监控
  const stopMonitor = startProgressMonitor(bookId);
  
  try {
    // 执行生成任务
    const stream = await this.graph.stream(initialState);
    for await (const step of stream) {
      // ...
    }
  } finally {
    // 无论成功或失败都停止监控
    stopMonitor();
  }
}
```

## 当前状态

### ✅ 已完成
1. 容错层核心逻辑（fault-tolerance.ts）
2. AI调用重试机制（3次重试 + 指数退避）
3. 节点级超时控制（6个节点各有不同超时时间）
4. 进度监控器（10/20/30分钟三级告警）
5. 自动恢复机制（最多2次，间隔5分钟）
6. WebSocket实时通知（12种通知类型）
7. 集成到大纲生成节点（outline.node.ts）
8. 集成到主生成器（index.ts）

### ⏳ 待完成
1. 集成到其他节点（sections.node.ts、content.node.ts、foreword.node.ts）
2. 前端WebSocket接收和显示通知
3. 前端UI展示错误信息和重试进度

## 测试建议

### 场景1：AI调用超时
```
1. 触发书籍生成
2. 等待5分钟（大纲节点超时时间）
3. 观察：
   - 终端日志："[容错] ⚠️ 节点 generate_outline 执行超时"
   - WebSocket通知：type='node_timeout'
   - 数据库：status='failed', errorMsg包含超时信息
   - 自动恢复：5分钟后重新加入队列
```

### 场景2：AI调用失败（网络错误）
```
1. 触发书籍生成
2. 断开网络或模拟API错误
3. 观察：
   - 终端日志："[容错] AI调用失败 (attempt 1/3)"
   - 等待2秒后自动重试
   - WebSocket通知：type='ai_retry', attempt=1
   - 3次都失败后：type='ai_failed'
   - 自动恢复机制启动
```

### 场景3：长时间无响应
```
1. 触发书籍生成
2. 在AI调用处设置断点或延迟
3. 观察：
   - 10分钟后：type='progress_warning'
   - 20分钟后：type='progress_critical'
   - 30分钟后：type='auto_recovery'，尝试自动恢复
```

## 优势总结

### 对比之前
| 问题 | 之前 | 现在 |
|------|------|------|
| AI调用失败 | 直接报错，任务卡住 | 自动重试3次，失败后自动恢复 |
| 超时 | 无超时控制，无限等待 | 节点级超时，超时自动处理 |
| 用户反馈 | 无反馈，用户傻等 | WebSocket实时推送进度和错误 |
| 长时间无响应 | 无检测机制 | 10/20/30分钟三级告警+自动恢复 |
| 自动恢复 | 仅重启时恢复 | 运行时自动检测+恢复（最多2次） |

### 用户体验提升
1. **不再傻等**：10分钟无响应就会收到警告
2. **不再困惑**：实时知道当前进度和遇到的问题
3. **不再手动重试**：系统自动重试和恢复
4. **明确的操作指引**：自动恢复失败后会提示手动操作

## 配置调整

所有配置集中在 `FAULT_TOLERANCE_CONFIG`：

```typescript
export const FAULT_TOLERANCE_CONFIG = {
  aiRetry: {
    maxRetries: 3,              // 调整重试次数
    initialDelayMs: 2000,       // 调整初始延迟
    maxDelayMs: 30000,          // 调整最大延迟
    backoffMultiplier: 2,       // 调整退避倍数
  },
  nodeTimeout: {
    generate_outline: 5 * 60 * 1000,    // 调整各节点超时时间
    // ...
  },
  progressMonitor: {
    maxIdleTimeMs: 10 * 60 * 1000,  // 调整告警阈值
    checkIntervalMs: 60 * 1000,     // 调整检查频率
  },
  autoRecovery: {
    maxRecoveryAttempts: 2,         // 调整最大恢复次数
    recoveryDelayMs: 5 * 60 * 1000, // 调整恢复延迟
  },
};
```
