一句話結論:把介面返回的原始響應體原樣打出來,不要只留你程式包裝過的那一句話。
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 的圖片預處理