DeepSeek API 錯誤全解:七個狀態碼的含義與修復

凌晨一點。key 貼好了,base URL 設好了,手指按下 Enter 跑第一條 curl——0.4 秒後,終端吐出一個 400 狀態碼和一坨 JSON,內文精確指出請求斷在哪裡。十五個詞的解釋,每個字都是真的,加起來什麼用都沒有。這一幕我不止一次親歷,而且總發生在不該寫程式的鐘點。

DeepSeek API 的每則錯誤訊息都長這樣:技術上完整,實務上沒用——直到你學會讀它。這篇文章把每個狀態碼從 log 裡的紅字變成具體的修復動作:地圖用官方錯誤碼表,路況用社群真實案例。如果你還在設定階段,先看 DeepSeek API 上手指南;這篇是給「昨天還能跑、今天突然不行」的人準備的。

DeepSeek 官方只有七個狀態碼

官方文件列出的錯誤碼恰好七個,不多不少。這是好消息:你的錯誤必然落在這七個桶裡,而且每個桶都有明確的責任人——你、你的帳戶、或者伺服器端。

名稱含義誰來修
400Invalid Format請求體格式錯誤
401Authentication FailsAPI key 不對
402Insufficient Balance帳戶餘額不足
422Invalid Parameters格式對,但參數值不合法
429Rate Limit Reached觸發並發限制你,然後等
500Server Error伺服器端內部錯誤DeepSeek
503Server Overloaded服務過載DeepSeek,然後等

這張表還能再分三組。改請求:400 和 422——伺服器端拒收你送的東西,原樣重送一萬次也一樣失敗。改帳戶:401 和 402——問題在 key 或餘額,不在程式碼。等一等再重試:429、500、503——請求本身沒問題,是時機不對。

注意表裡沒有的:504。DeepSeek 不發 504。如果你看到 504,那是你和模型之間的某個中間層——閘道、代理、雲端函式——自己造出來的。後面細說。

把請求想像成一封信。400 是信封格式寫錯,櫃檯直接退回,根本進不了分揀機;401 是窗口職員不認你的證件;402 是郵票用完了。這三種情況下,把同一封信再寄一次不會有任何變化——要改的是信封、證件或郵票本。

400:請求壞掉的六種方式

最常見的錯誤碼,花樣也最多。一份中文社群的生產環境追蹤把 400 的成因大致分為參數問題約 42%、資料格式約 28%——和英文論壇的分布對得上。下面六種模式,幾乎涵蓋你會遇到的一切;其中第一種,我自己隔幾個月就會重新踩一遍。

1. messages 傳了物件而不是陣列。 API 要的是列表,單獨一則訊息包在字典裡不行。這份會被拒:

{"model": "deepseek-v4-flash", "messages": {"role": "user", "content": "Hello"}}

這份能通過:

{"model": "deepseek-v4-flash", "messages": [{"role": "user", "content": "Hello"}]}

2. 數字被傳成了字串。 "temperature": "0.7" 失敗,"temperature": 0.7 通過。你的 JSON 序列化器可能在背後偷偷加引號——檢查真正送出去的封包,而不是原始碼裡寫的那份。

3. 用了已棄用的模型名。 這一條最陰險。舊名 deepseek-chatdeepseek-reasoner 已於 2026 年 7 月 24 日退役,現行模型是 deepseek-v4-flashdeepseek-v4-pro。成千上萬的教學還掛著舊名,從 2025 年的部落格原樣抄來的程式碼今天必然出錯。現行模型清單見我們的 V4 模型解讀

4. tools 陣列格式錯誤。 工具定義的 schema 跑偏——巢狀層級不對、缺 type 欄位——在推理開始前就會被拒。LibreChat 這類前端使用者回報過一模一樣的案例。

5. image_url 內容區塊。 文字 API 不接受訊息裡帶圖片附件;把視覺格式的載荷送給 deepseek-v4-flash,回傳的是 400,不是優雅降級。

6. 用戶端協定不匹配。 最詭異的一種:Claude Code 使用者接 DeepSeek 時撞上 400 Failed to deserialize the JSON body... messages[1].role: unknown variant 'system', expected 'user' or 'assistant'。部分 Claude Code 版本(2.1.154 及以後)不接受那個位置的 system 角色,而 DeepSeek 的 OpenAI 相容端點偏偏會發——一篇有完整記錄的案例給出的修復:降級到 @anthropic-ai/claude-code@2.1.148 並設 DISABLE_AUTOUPDATER=1。兩邊都沒 bug,只是兩套協定各自往前走,走岔了。目前相容狀態我們追蹤在 Claude Code 接入指南裡。

400 和 422 怎麼分

分界線是格式與數值。400 說你的 JSON 根本沒法解析成一個合法請求——結構壞了、型別錯了。422 說結構沒問題,但裡面的某個值不合法,比如 max_length 超過模型的上下文視窗。排查動作也不同:400 去看原始請求體;422 去讀參數文件、核對你的數字。

401:key 的四種死法

伺服器端的意思很直白:不認你這個人。四種原因涵蓋幾乎所有情況:

  1. 用錯了別家的 key。 OpenAI(或任何其他廠商)的 key 指向了 DeepSeek 的 base URL。長得都像 sk-...,能用的只有一個。
  2. 環境變數根本沒載入。 .env 檔案好好躺在那,但程序沒讀過它——用戶端拿著空字串就出門了。
  3. 不可見字元。 複製 key 時帶上的結尾換行或空格。列印 repr(api_key) 親眼看看。
  4. 代理剝掉了 Authorization 標頭。 公司代理和某些 API 閘道會悄悄幹這事。

六十秒診斷法:用 curl 直接打一個便宜的品牌鑑權端點(比如列出模型),中間不放任何東西。如果成功,key 是活的,嫌疑落在你的應用層——完整排查清單見 API key 指南

402 餘額不足:唯一永不重試的錯誤

沒有歧義:帳戶沒錢了。儲值之前,程式碼一行都不會跑。

誘惑在於把 402 也塞進統一的重試迴圈。別。重試餘額不足只會洗版 log,洗不出 token——這個狀態在兩次嘗試之間不可能自癒。真正有用的是監控:餘額掉到一天的消耗量以下就告警,按節奏儲值。你的負載一天燒多少錢,計費拆解裡有答案。

429:並發按帳戶算,不是按 key 算

這個機制大多數人理解錯了。DeepSeek 度量的是並發連線數,不是每分鐘請求數——而且按帳戶計,不按 key 計。你生成五個 key,共享的還是同一個池子,就像五張金融卡提的是同一個帳戶的錢。按照速率限制文件,截至 2026 年 8 月,上限是 deepseek-v4-pro 500 並發、flash 系模型 2500 並發。

一個「請求」從送出的那一刻起佔用一個槽位,直到回應完全返回——串流呼叫要等到流關閉。一次長思考會全程佔著槽位,這正是批次任務同時開火會撞上限、同樣的量攤開幾分鐘就沒事的原因。

三條出路,按省事程度排:

  • 攤開負載。 批次任務排隊、worker 錯峰,並確認你自己的重試邏輯沒有製造風暴(一批失敗後全部同時重試,會在最糟的時刻把佔用翻倍)。
  • 給請求打 user_id 標。 如果你用一個帳戶服務很多終端使用者,傳 user_id 能讓每個使用者拿到獨立的並發額度——多租戶的官方逃生門。識別碼必須匹配 [a-zA-Z0-9_-]、不超過 512 字元、不含隱私資訊。OpenAI 風格的 SDK 用 extra_body={"user_id": ...} 傳;Anthropic 的 SDK 用 metadata={"user_id": ...}
  • 申請擴容。 容量擴展免費,同一份文件頁上有申請入口。

還有一個讓團隊意外的 429 來源——我曾在一個「放著保險」的批次任務上親歷過:重試風暴。一波請求失敗後,所有 worker 按同一個計時器重試,整齊劃一的第二波往往觸發了第一波都沒觸到的限制。解藥是抖動(jitter)——給重試延遲加隨機量。

500 和 503:輪到伺服器端背鍋

500 是伺服器端處理一個合法請求時自己出了錯;503 是過載拒單。兩者都是暫時的,都是 DeepSeek 該修的,都值得退避重試。

一個細節:不是所有伺服器端的掙扎都表現成狀態碼。一個 200 回應的內文裡可能帶著 finish_reason: "insufficient_system_resource"——模型開跑了,中途資源不夠,提前停了。這不是 503,也不能盲目重試;先檢查內文裡的 finish_reason 欄位,再下結論。

逾時和 504:DeepSeek 從不發出的錯誤

翻回上面的七碼表。沒有 504——因為 504 Gateway Timeout 是你程式碼和 DeepSeek 之間的某個東西生產的:你的 nginx、你的雲端函式平台、公司代理。閘道按它設定的耐性等了(通常 30 或 60 秒),沒等到完整回應,就宣布上游死了。OpenClaw 使用者對這深有體會——它約 60 秒的內部逾時掐斷的恰恰是那些什麼問題都沒有的長生成。

修法幾乎永遠是調高這一跳的逾時——nginx 的 proxy_read_timeout、serverless 的函式逾時——而不是動 DeepSeek 的程式碼。

還有兩個時間相關的機制值得知道,都來自速率限制文件:

keep-alive 訊號。 長等待期間——比如深度推理呼叫出第一個 token 之前——伺服器端會發保活位元組,防止中間層把沉默當成斷線。非串流回應週期性發空行;串流回應發 SSE 註解行(: keep-alive)。如果你的用戶端庫或代理丟掉這些訊號,可能自己判定連線閒置然後殺掉它。處理好它們,至少別讓它們撐爆你的解析器。

10 分鐘死線。 請求排隊超過十分鐘還沒開始推理,伺服器端直接關閉連線。尖峰時段這就是佇列替你放棄。此時帶退避的重試是對的——如果持續發生,先看 DeepSeek 的狀態公告,再懷疑自己的程式碼退化了。

還有一個比想像中常見的奇案:有中文社群文章記錄過區域性 504,根因是 DNS 污染——某些網路裡 API 網域名稱解析出錯,直連 IP 卻正常,換成公共 DNS 後解決。如果 504 按地理聚集、其他都排查過了,先換個 DNS 試試,再改用戶端。

用戶端逾時也值一句話:連線逾時設在 3 秒左右,讀取逾時要容得下你最長的生成——對話 30 秒是地板,深度推理遠不是天花板。

一張可以直接貼在用戶端旁邊的重試決策表

整套 DeepSeek 錯誤排除思路壓縮成一張表:

重試?第一動作
400永不修請求體;把原始載荷打進 log
401永不curl 驗 key;查環境變數載入
402永不儲值;加餘額告警
422永不對照文件核對參數值
429退避+抖動;考慮 user_id 隔離
500指數退避
503指數退避;看狀態公告
逾時 / 504先調閘道逾時,再重試

重試邏輯本身小到可以背下來——只重試 {429, 500, 503},每次等更久,再加隨機:

RETRYABLE = {429, 500, 503}

def call_with_backoff(client, payload, max_attempts=5):
    for attempt in range(max_attempts):
        try:
            return client.post("/chat/completions", json=payload)
        except HTTPError as e:
            if e.status not in RETRYABLE:
                raise  # 你的 bug —— 修它,別重試它
            delay = min(8, 0.5 * 2 ** attempt) + random.uniform(0, 0.5)
            time.sleep(delay)  # 基數 0.5 秒,上限 8 秒,外加抖動
    raise RuntimeError("退避後仍然失敗")

社群的一篇排查手冊在這之上補了熔斷模式:連續失敗 N 次後停手冷卻,先發一個探針請求再恢復全線。跑正式流量時值得加上;寫腳本就是殺雞用牛刀。

常見問題

DeepSeek API 400 最常見的原因是什麼?

messages 欄位格式壞——通常是該傳陣列傳了物件、該傳數字傳了字串,或者從掛著 2026 年 7 月已退役模型名的舊教學裡抄來的請求。把實際送出的請求體打進 log(不是你以為送的那份),一眼就能看到兇手。

為什麼請求一直轉圈,最後什麼都沒回傳就斷了?

兩個嫌疑。如果在任何輸出之前就斷,多半是 keep-alive 機制被剝掉了:伺服器端發空行(或 SSE 註解)防止中間層殺連線,而鏈路上某個環節把它們丟了。如果整整十分鐘後才斷,那是推理啟動死線——佇列替你放棄了。兩種都值得退避重試;反覆出現就值得稽核你到 API 之間每一層的逾時設定。

504 是 DeepSeek 的錯誤嗎?

不是。官方文件定義了七個狀態碼,裡面沒有 504。504 由你和服務之間的閘道或代理在等待逾時後生成。把那一跳的逾時調高。

哪些錯誤該重試,哪些永遠不該?

429、500、503 用指數退避加抖動重試。400、401、402、422 永不重試——它們是確定性失敗(格式壞、key 壞、沒餘額、值不合法),在你改變些什麼之前,每次重試都回傳同樣的結果。

Claude Code 連 DeepSeek 為什麼報 400?

部分 Claude Code 版本不接受訊息陣列裡的 system 角色,而 DeepSeek 的 OpenAI 相容端點偏偏會發——反序列化當場失敗。降級到 @anthropic-ai/claude-code@2.1.148 並關閉自動更新,是協定錯位解決前社群驗證過的修復。


狀態碼就是 API 在跟你說話——話少、字面、且永遠誠實地說出問題在鏈路的哪一側。七個數字,三個桶,一個問題:信封、證件,還是排隊?答對這一問,log 還沒打開,除錯就做完了一半。