一句话结论:把接口返回的原始响应体原样打出来,不要只留你程序包装过的那一句话。
400 Bad Request 这种字符串对定位问题的贡献接近于零,真正的答案在它下面被丢掉的那个 JSON 里。一个真实案例:400 Bad Request 说明不了任何问题
一位客户上报的原文只有一行:400 一般是内容安全和参数问题,大概率是内容安全。这是猜测,不是结论。因为同一次调用,接口真正返回的响应体可能是下面三种中的任意一种,而它们对应三种完全不同的处理动作:
后台日志能查到什么,查不到什么
这是最需要先建立的认知:后台日志是计费账本,不是错误日志。必须留存的 7 个字段
排查一次报错需要的信息就这些。缺任何一项都会让排查退化成猜测:响应体不要截断。 常规业务日志里截断到 200 字符是合理的,但排障场景下错误详情经常出现在末尾。至少保留前 2000 字符;图片类接口若担心 base64 刷屏,只在
status_code >= 400 时全量打印即可——错误响应体本来就不长。正确的错误捕获写法
核心原则只有一条:分两层捕获,并且在任何一层都不要丢弃原始信息。- 传输层异常:连接被重置、TLS 握手失败、超时、DNS 失败。此时根本没有 HTTP 响应,能留的只有异常原文。
- HTTP 层错误:服务端返回了 4xx / 5xx。此时一定有响应体,必须读出来。
Python / requests
Python / OpenAI SDK
官方 SDK 已经把三样东西都挂在异常对象上了,只是很多人只print 了一句自己的中文提示:
Node.js
用 SDK 时:fetch 时,这一步是最容易出事的地方:
cURL 复现
请客户复现时,给这条命令最省事——它把状态码、响应头、响应体、耗时一次性全带出来:-i打印响应头,x-request-id就在里面;-sS关掉进度条但保留错误输出;-w在末尾附加状态码与总耗时,方便和超时配置对照。
封装工具与自研中台怎么办
一个正面例子
下面这条报错来自某位客户的 ComfyUI 节点:400 Bad Request 难看得多,但信息是完整的,几秒钟就能定死方向:
结论直接就出来了:这是传输层问题,与内容安全、与参数统统无关,也不会产生计费(请求根本没完成)。排查路径见图片 API 连接中断排查。
对比一下:一个是包装得很干净但什么也说明不了的
400 Bad Request,一个是又长又丑但直接指向根因的 errno 10054。排障场景下,原始、难看、完整的错误远胜于友好、简洁、被改写过的错误。常见工具去哪里找原文
自研中台的三条原则
1
透传,不要改写
中间层可以追加上下文(哪个业务、哪个租户、第几次重试),但不能替换上游返回的
error.message。一旦改写,原文就没有第二个地方可以找回。2
面向用户的提示和面向开发的原文分开存
参考 Gemini 图片错误处理 里的三分结构:
userMessage(给终端用户看的友好文案)、devMessage(给开发看的判定结论)、rawResponse(原始响应体,一字不改)。前两个可以随便润色,第三个必须原样入库。3
永远不要出现「未知错误」
走到兜底分支时,把
status、x-request-id 和响应体前 2000 字符一并记下来。一个带着原文的「未分类错误」是可排查的;一句干净的「未知错误」不是。反面清单:这些写法会让问题无法排查
except Exception as e: print("调用失败")—— 异常对象整个被丢掉,连是哪一层的问题都不知道;- 只记 HTTP 状态码,不记响应体 —— 就是本页开头那个案例;
raise_for_status()之前不读resp.text—— 正文还在内存里,就是没人取;fetch里if (!resp.ok) throw new Error(resp.statusText)—— body 随响应对象一起被扔了;- 客户端重试成功后只留一条漂亮的 200 —— 把每次尝试单独记一条,否则你永远看不到底层断了多少次,还容易把自己的重试误读成渠道行为;
- 日志只打屏不落盘、或按天覆盖 —— 等客户反馈到你这里时,原始记录往往已经滚没了;
- 报障时只发一张手机拍的屏幕照片 —— 请直接复制文本,截图里的错误经常正好被裁掉半行。
什么时候找客服
先自己走完上面的留存与判读,如果满足下面任一条,就带着材料找客服核查:- 拿到了完整响应体,但
error.message指向上游方向(upstream_error、上游 5xx 原文、渠道明确报错); - 同一份请求参数换个模型或换个时间段就正常,只有某个特定模型稳定失败;
- 报错是
500+write_response_body_failed这类下行链路问题,且稳定复现(这类不计费,排查方法见连接中断排查); - 你怀疑计费与实际调用对不上——这时
request_id是唯一能精确对账的锚点。
报障信息模板(可直接复制)
企业微信客服
相关文档
API 手册
常见错误码对照表、认证方式与速率限制
连接中断排查
ECONNRESET、errno 10054、SSL EOF 这类传输层报错的完整排查路径日志查询 API
用接口批量拉调用日志,
request_id 怎么查、怎么对账看懂日志计费金额
为什么失败调用不进日志,以及「有无计费记录」这条判据怎么用
超时怎么配置
各类模型的 timeout 分档、已调大仍超时的逐层排查
图片 API 必读
同步调用、base64 前缀差异、
400 invalid_image_file 的图片预处理