程序接上 AI 服务之后,迟早要跟报错打交道:响应里回来一段 JSON,只扫一眼 message 里那句英文就开猜,排查自然低效。报错其实是结构化的:外层一个 error 对象,里面的 type、code、message 各管一段信息——type 定类别,code 给细目,message 是给人读的描述。读懂这三层,报错就从「碰运气」变成「按图索骥」。这篇拆解响应结构、常见错误类型的对照关系,以及拿到错误后能不能重试的判断依据。
响应长什么样:一个 error 对象三层信息
出错的响应有统一外壳:HTTP 状态码打头,响应体里是一个 error 对象。对象内三个常用字段分工明确:type 是错误类别,决定你往哪一类原因去想;code 是更细的错误码,同一个类别里区分具体情形;message 是给人读的文字描述,适合快速扫一眼,不适合拿来做程序判断——文案措辞可能随版本微调(截至发稿版本,以官方更新日志为准),把程序逻辑挂在 message 字符串上,等于把地基打在沙子上。工程上的正确姿势因此很清楚:程序读 type 与 code 做分支处理,message 留给日志与人看。三层信息各归其位,排查才有章法。
常见类型对照:四族高频原因
常见错误类别可以归成四族,每族对应一种动作。请求问题一族:参数写错、格式不合法、模型名拼错,属于你这边能改的错,改对为止。身份与权限一族:key 无效、被吊销、权限不够——遇到这一族先查 key 的状态,key 失效乃至泄露后的处理路径见key 泄露一篇。限流一族:请求太快或用量超限,响应里通常带等待提示,额度与档位的关系见限额分档一篇。服务端一族:模型或基础设施临时故障,责任不在你的代码。对照着记一个原则:前两族改了再发,第三族等一等再发,第四族先查状态再决定动不动。拿到报错先归族,动作就不会乱。
重试的判断:哪些错值得再发一次
拿到错误后的第一个决策是:重试还是改代码。判断依据就在 type 里。请求类错误重试没有意义——参数错了发一百次还是错,改对为止。限流类错误值得重试,但要退避着来:立即原样重发只会撞得更狠,指数退避是通行做法,第一次等一秒、失败再翻倍;连续撞限还要考虑降并发或调额度。服务端错误可以重试,但次数要有上限,别让重试逻辑自己变成无限循环——重试超限的收场形式之一是 exceeded retry limit 这类提示,出现它就说明该停下来看原因了。重试前还有一步值得做:先看服务状态页,大面积故障时所有人的重试都在给系统添堵,等恢复再发更体面,状态页怎么读见服务状态页一篇。
排查路径:从响应到动作
结构读熟之后,排查可以固定成一条路径:先看 HTTP 状态码定大类;再看 type 归族——请求、身份、限流、服务端对号入座;然后看 code 找细目,对照官方错误码文档确认语义;最后才是读 message 补充细节。三件配套动作值得养成习惯:把完整响应原样记进日志,别只存 message 一句;给不同 type 配不同的处理分支,而不是一律弹窗报错;报障时带上请求标识,找官方支持才对得上号。另有一条对照线:网页版 ChatGPT 的报错是另一套形态——页面提示而非 JSON 响应,两套报错各自的分流处理见ChatGPT 页面报错一篇。动手练一遍很有效:让 DeepSeek 生成几种典型错误响应的示例并逐字段讲解,再让 Kimi 把你项目里的报错处理代码按「type 分支、退避重试、日志留痕」三条过一遍,漏哪补哪。
| 排查顺序 | 读哪一层 | 这一步定下什么 |
|---|---|---|
| 第一步 | HTTP 状态码 | 先定大类 |
| 第二步 | error.type | 归族:请求、身份、限流、服务端 |
| 第三步 | error.code | 对照官方错误码文档确认细目语义 |
| 第四步 | error.message | 补充细节,只供人读,不进程序判断 |
错误结构速查
- 外壳:HTTP 状态码加 error 对象,type、code、message 各管一段
- 分工:type 定类别,code 给细目,message 供人读不作判断依据
- 四族:请求、身份权限、限流、服务端,先归族再动手
- 重试:请求类改代码,限流类退避重试,服务端类先查状态页
- 习惯:完整响应进日志,逻辑挂在 type 上不挂在文案上
错误结构快问快答
- message 能拿来写程序判断吗?:不建议。文案可能随版本调整,判断条件说失效就失效;逻辑挂在 type 与 code 上才稳,message 只进日志。
- 限流错误立刻重发行不行?:不行。原样重发大概率再撞,按指数退避等一等再发,连续撞限就降并发,硬撞只会把窗口越撞越紧。
- 同样的请求时对时错,是为什么?:多半是限流或服务端波动。看响应的 type 归哪族,再对照状态页确认有没有故障,别急着改代码。


