# AI 调用稳定性增强(重试 + 统一兜底)设计 日期:2026-08-29 状态:已批准(Stage ④ 通过) ## 背景与目标 评审报告「稳定性与易用性 12/15」指出:缺少显式重试机制;未见对 AI 调用异常的统一兜底。现状核实: - `chatWithRetry`(src/ai/engine.ts)仅对 `EmptyContentError` 重试 1 次,网络错误/超时/429/5xx 均直接上抛 - `requestFix`(src/fix/aiFixEngine.ts)catch 后静默返回 null,用户看不到 AI 失败原因 - engine 主入口已有 `degraded + error` 兜底结构(`Promise.allSettled` + i18n 错误聚合),无需改动 - 多 AI 供应商切换已被评审认可为降级策略,无需改动 ## 方案 ### 1. 错误分类(src/ai/providers/base.ts) 新增 `ApiRequestError`(携带 HTTP status)+ `isRetryableError()`: | 错误 | 可重试 | |---|---| | EmptyContentError | 是 | | HTTP 429 / 5xx | 是 | | 超时(AbortError / DOMException name==='AbortError') | 是 | | 网络错误(TypeError) | 是 | | 401、其他 4xx、JSON 解析错 | 否,立即失败 | ### 2. provider 统一结构化抛错 openai-compatible.ts / gemini.ts / claude.ts:非 2xx 响应抛 `ApiRequestError`(携带 status 与响应文本)。401 保留现有 i18n 消息语义,同样结构化、不可重试。 ### 3. chatWithRetry 增强(src/ai/engine.ts) 固定策略:最多 3 次重试、指数退避 1s/2s/4s、按分类决定重试或立即上抛。所有调用入口(engine 三入口 + fix 链路)自动受益。 ### 4. fix 链路兜底透传(src/fix/aiFixEngine.ts) `requestFix` 不再吞错,将最终错误消息透传到 `FixResult.message`,复用 commands.ts 现有 `t('fix.aiFailed')` 通知管道。 ### 5. 单元测试 扩展既有 `tests/ai-empty-response.test.ts`(chatWithRetry 测试的既有归属,避免新建文件):mock provider 抛可重试/不可重试错误,验证重试次数、退避行为、立即失败路径、`isRetryableError` 分类。`tests/customFixEngine.test.ts` 一处测试名随行为语义更新。 ### 实现修订(编码期同步) - `src/fix/customFixEngine.ts` 存在与 aiFixEngine 相同的吞错模式(同一评审批评点),按同一模式修复:`requestFix` 不再吞错,`aiFixReviewIssue` 调用处 catch 后透传 `ai-error: <原因>` 到 `FixResult.message` - 引擎内部导出 `setRetryBaseDelayForTest` 测试钩子,避免测试真实等待 1s/2s/4s 退避 ## 验证链 `npm run lint` → `npm run compile` → `npm test` ## 涉及文件 - src/ai/providers/base.ts - src/ai/providers/openai-compatible.ts - src/ai/providers/gemini.ts - src/ai/providers/claude.ts - src/ai/engine.ts - src/fix/aiFixEngine.ts - src/fix/customFixEngine.ts - tests/ai-empty-response.test.ts - tests/customFixEngine.test.ts