Files
2026Technology-Competition/docs/superpowers/specs/2026-08-09-llm-errorcode-alignment-design.md
T

121 lines
5.5 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# LLM 错误码对齐设计(retry/skip/abort UX
## 1. 背景与动机
`api-design.md` §7 错误码表定义了 LLM 相关错误码及其「用户选项」(`retry / skip / abort` / `配置 Key`),但 **engine 层没有暴露任何可供调用方/UI 决策的机器可读信息**
- `ChatResult` / `StructuredResult` 失败时仅有人类可读的 `error: str`
- 调用方无法区分「值得重试的网络/超时错误」与「重试无用的配置/结构错误」
- api 层的 `LLM_NETWORK_ERROR` 概念缺失(`LLMNetworkError` 的可重试语义无处映射)
本 backlog 目标:在 **engine 层**暴露结构化的 `error_code`,并让 api-design §7 表与异常树五类型一一对齐,为后续 UI 的 retry/skip/abort 对话框提供唯一事实源。
## 2. 非目标(明确不包含)
- 不实现 UI、不新增 API 端点、不动 state machine
- 不改变错误字符串格式与既有字段
- 不实现「按错误码自动重试」的自动化策略(本 backlog 只提供信息,决策权留在调用方)
## 3. 设计
### 3.1 异常树携带 error_code(事实源)
`src/genesis/inference/exceptions.py``LLMError` 基类新增类属性,五子类各覆写:
```python
class LLMError(Exception):
"""LLM 调用异常基类。error_code 与 api-design §7 错误码表一一对应。"""
error_code: str | None = None
class LLMNetworkError(LLMError):
error_code = "LLM_NETWORK_ERROR"
class LLMTimeoutError(LLMError):
error_code = "LLM_TIMEOUT"
class LLMNotConfiguredError(LLMError):
error_code = "LLM_NOT_CONFIGURED"
class LLMResponseError(LLMError):
error_code = "LLM_PARSE_ERROR"
```
- `error_code` 是 docs api-design §7 表中「错误码」列的机器可读值
- 新增未来异常类型时**必须**覆写 `error_code`(否则走 `None`,绝不伪造)
### 3.2 结果对象携带 error_code
`ChatResult` / `StructuredResult` 增加字段(默认 `None`,向后兼容):
```python
@dataclass
class ChatResult:
...
error_code: str | None = None # 失败时的 api §7 错误码;成功为 None
@dataclass
class StructuredResult:
...
error_code: str | None = None # 失败/parse_error 时的错误码;成功为 None
```
### 3.3 engine 透传(同源语义)
- `chat()` 失败路径:`error_code``error` 字符串**同源**——取最后一次失败(fallback 链)的 `LLMError.error_code`
- `chat_structured()` 解析耗尽:`status="parse_error"` + `error_code="LLM_PARSE_ERROR"`(来自导致解析失败的最后一次调用;若无 LLM 异常则取最近一次 JSONDecodeError 对应的 `LLM_PARSE_ERROR`
- `chat_structured()` 网络/超时失败:`status="failed"` + `error_code=<对应异常>`
- 退化:异常非 `LLMError`(不捕获、直接冒出)→ engine 不产生 error_code`None`),由上层兜底
### 3.4 error_code 语义表(与 api §7 对齐)
| 异常 | error_code | api §7 用户选项 | retryable 语义 |
|------|-----------|----------------|---------------|
| `LLMTimeoutError` | `LLM_TIMEOUT` | retry / skip / abort | ✅ 可重试 |
| `LLMNetworkError` | `LLM_NETWORK_ERROR` | retry / skip / abort | ✅ 可重试 |
| `LLMResponseError` | `LLM_PARSE_ERROR` | retry | ⚠️ 结构化可重试;chat 不建议 |
| `LLMNotConfiguredError` | `LLM_NOT_CONFIGURED` | 配置 Key | ❌ 配置问题 |
| 其他异常 | `None` | — | 上层兜底(`INTERNAL_ERROR` 语义由 API 层负责) |
> 注:api-design §7 表仍保留 `INTERNAL_ERROR` 行作为 API 层兜底(非 LLMError 异常由上层翻译),engine 层不产生该值。
### 3.5 文档修订
`docs/api-design.md` §7 错误码表新增行(对齐异常树):
```
| `LLM_NETWORK_ERROR` | 502 | 网络失败/5xx 重试耗尽 | retry / skip / abort | exceptions.LLMNetworkError |
```
并对 `LLM_PARSE_ERROR` / `LLM_TIMEOUT` 行的「来源」列保持与异常类型对应(已存在,无需改)。
## 4. 测试策略
- `tests/test_inference_errors.py`:各异常 `error_code` 类属性恒定值断言
- `tests/test_inference_types.py``ChatResult`/`StructuredResult` 新字段默认 `None`
- `tests/test_inference_engine.py`
- `chat()` 失败时 `error_code == "LLM_TIMEOUT"` / `"LLM_NETWORK_ERROR"` / `"LLM_NOT_CONFIGURED"`(对应脚本)
- 主模型超时 + 备用网络失败 → `error_code == "LLM_NETWORK_ERROR"`(同源:取最后一次)
- `chat_structured()` parse_error → `error_code == "LLM_PARSE_ERROR"`;网络失败 → `error_code == "LLM_NETWORK_ERROR"`
- 全量回归 `python -m pytest -v`(覆盖红线 fail_under=99,当前基线 119 passed / 100%
## 5. 验收标准
1. 五异常 `error_code` 与 api-design §7 一一对应
2. `ChatResult`/`StructuredResult` 失败路径返回结构化 `error_code`,成功路径为 `None`
3. `error_code``error` 同源(取最后一次失败异常),有测试证明
4. api-design §7 补 `LLM_NETWORK_ERROR`
5. 全量回归 ≥ 119 passed / 覆盖率 100%
6. 零新增依赖、零 UI 变更、向后兼容(旧构造不含 error_code 字段仍工作)
## 6. 涉及文件
- 修改:`src/genesis/inference/exceptions.py``src/genesis/inference/types.py``src/genesis/inference/engine.py`
- 修改:`docs/api-design.md`(§7 表格)
- 测试:`tests/test_inference_errors.py``tests/test_inference_types.py``tests/test_inference_engine.py`
## 7. 版本与状态
| 版本 | 日期 | 说明 |
|------|------|------|
| v1.0 | 2026-08-09 | 定稿版(含 2 项设计健全性修订:保留 INTERNAL_ERROR 兜底行、error_code 与 error 同源明写) |