错误码是给两类读者看的
AI 功能的错误处理常走向两个极端 ✗:要么只给用户一句"出错了" ✔,
要么把内部堆栈直接抛给前端 ✔。**错误要同时服务机器与用户** ✔。
一、给机器看的:稳定、可判定
```
{ "error": {
"code": "RATE_LIMITED", // 稳定枚举,别改 ✔
"retryable": true, // 是否可重试(机器据此决定 ✔)
"retry_after_ms": 3000, // 建议等待(若有 ✔)
"category": "quota", // 大类:input/quota/upstream/policy ✔
"trace_id": "..." // 便于排查 ✔
} }
```
**要点**:
二、给用户看的:可行动、不甩锅
| 别写 | 改写 |
|---|---|
| 请求失败 | 当前处理请求较多,请 3 秒后重试,或换更短的内容 |
| 超出限制 | 输入超过 20000 字,请拆分后提交(当前 31200 字) |
| 内部错误 | 服务暂时不可用,你的内容已保存,可稍后重试 |
| 403 | 你的账号暂无该功能权限,请联系管理员开通 |
**要点**:说清**发生了什么、怎么办、我的数据还在不在** ✔(见降级提示那篇 ✔)。
三、错误分类(决定处理方式)
```
① 输入类(可修正):格式错、超长、缺字段 → 提示用户改 ✔
② 权限类(不可重试):无权限、需确认 → 明确说明 ✔
③ 配额类(可等待):限流、额度用尽 → 给等待时间或替代方案 ✔
④ 上游类(可重试):5xx、超时 → 自动重试 + 降级 ✔
⑤ 策略类(不可重试):内容不合规、越权 → 明确拒绝 + 原因 ✔
```
**每一类对应不同的前端处理** ✔(别用一套提示覆盖全部 ✗)。
四、两个容易忽略的点
一条判据
> 调用方拿到的错误里,能否**不看文档**就知道"要不要重试" ✔?
> 不能,说明错误结构没有服务好机器 ✗。