跳到正文
土土金API

開始

錯誤碼與重試

出錯時先看 HTTP 狀態碼:429、500、502、503 可以退避重試,400、401、403、404、413 是請求或帳戶的問題,重試不會成功。餘額不足返回 403,不是 OpenAI 的 429。

請求出錯時會返回 HTTP 錯誤狀態碼和一個 JSON 錯誤體。判斷要不要重試,看狀態碼就夠了:429、500、502、503 可以等一會兒再試;400、401、403、404、413 是請求本身或帳戶設定的問題,原樣重試不會成功,只會浪費時間。

錯誤體格式

JSON
{
  "error": {
    "code": "",
    "message": "无效的令牌 (request id: 2026111202521796606900082...)",
    "type": "new_api_error"
  }
}
欄位說明
message可讀的錯誤描述,末尾帶 request id
type錯誤類別
code錯誤碼,例如 insufficient_user_quota、model_not_found;很多錯誤這裡是空字串

code 經常為空,程式裡請以 HTTP 狀態碼為準,code 只作補充判斷。Claude Messages 介面(/v1/messages)在轉發階段出錯時,錯誤體是 Anthropic 的格式,即 {"type": "error", "error": {...}};認證、餘額這類請求前的檢查失敗,所有介面都用上面的格式。

找客服排查時,把 message 裡括號中的 request id 一起發過來(客服微信 JsnonoChat),我們能據此定位到這一次請求。建議在日誌裡完整記錄錯誤響應。

狀態碼對照

狀態碼含義常見原因重試
400請求有誤JSON 格式不對、缺少必填參數、參數取值超出範圍、模型不支援某個參數、輸入超過模型的上下文長度不重試,先修正請求
401認證失敗Key 填錯、已刪除、已停用、已過期,或這把 Key 的額度上限用完不重試
403沒有權限帳戶餘額不足(insufficient_user_quota)、IP 不在 Key 的白名單(access_denied)、模型不在 Key 的模型白名單、Key 的分組不可用、帳戶被停用不重試
404不存在路徑寫錯(比如漏了 /v1)、請求的資源不存在不重試
413請求體太大一次傳入的圖片、音訊或文本過大不重試,壓縮或拆分後再發
429請求過多觸發了本站或模型服務的限流退避後重試
500服務內部錯誤服務端處理請求時出現異常退避後少量重試
502閘道器錯誤模型服務返回了異常響應,或連線中斷退避後重試
503暫時不可用模型服務繁忙;或者 Key 所在分組沒有這個模型的可用渠道(model_not_found)退避後重試;帶 model_not_found 時換分組

餘額不足在這裡返回 403,錯誤碼 insufficient_user_quota。OpenAI 官方介面遇到額度不足返回的是 429。如果你的程式碼沿用 OpenAI 的判斷邏輯,請把 403 單獨處理:提醒充值或切換帳戶,不要放進重試佇列。

503 並提示 model_not_found

這表示當前 Key 所在的分組沒有這個模型的可用線路,常見於模型名拼錯或者分組裡本來就沒有這個模型。處理順序:

  1. 核對模型名,要和模型廣場裡的寫法完全一致。
  2. 用同一把 Key 呼叫模型列表介面,看返回裡有沒有這個模型。
  3. 沒有的話,在模型詳情頁查這個模型有哪些分組,換一把對應分組的 Key,見選擇分組。

重試策略

可以重試的錯誤(429、500、502、503)用指數退避加隨機抖動:第 1 次等 1 秒左右,之後每次翻倍,設一個上限,最多重試 3 到 5 次。抖動能避免大量客戶端在同一時刻一起重試。

OpenAI 官方 SDK 自帶重試,遇到 429、5xx 和連線錯誤會自動退避重試,重試次數和超時都可以設定:

import os
from openai import OpenAI

client = OpenAI(
    base_url="https://www.tutujin.com/v1",
    api_key=os.environ["TUTUJIN_API_KEY"],
    max_retries=4,   # 默认 2 次
    timeout=60.0,    # 单次请求超时,秒
)

# 单个请求临时调整
resp = client.with_options(max_retries=6, timeout=120.0).chat.completions.create(
    model="gpt-5.4-mini",
    messages=[{"role": "user", "content": "你好"}],
)

不用 SDK、直接發 HTTP 請求時,可以這樣寫:

import os
import random
import time

import requests

RETRYABLE = {429, 500, 502, 503}


def post_with_retry(path, payload, max_attempts=5):
    url = "https://www.tutujin.com/v1" + path
    headers = {"Authorization": f"Bearer {os.environ['TUTUJIN_API_KEY']}"}
    for attempt in range(max_attempts):
        r = requests.post(url, json=payload, headers=headers, timeout=60)
        if r.status_code not in RETRYABLE or attempt == max_attempts - 1:
            r.raise_for_status()  # 400/401/403/404/413 直接抛出
            return r.json()
        retry_after = r.headers.get("Retry-After", "")
        delay = float(retry_after) if retry_after.isdigit() else min(30, 2**attempt)
        time.sleep(delay + random.uniform(0, 1))

流式請求出錯

流式請求在開始返回資料之前出錯,和普通請求一樣返回錯誤狀態碼。如果資料已經開始返回,HTTP 狀態碼已經是 200,出錯表現為流提前結束、沒有收到最後的 data: [DONE]。客戶端要把「沒收到 [DONE] 就斷開」當作失敗處理,已經輸出的半截內容按需丟棄或提示使用者重試。

排查清單

  • 401:列印請求頭確認 Key 完整、沒有多餘空格或換行,在控制台確認 Key 未過期、未停用、額度上限沒用完。
  • 403:看 message 判斷是餘額、IP 白名單、模型白名單還是分組問題,對應去控制台調整。
  • 404:確認地址是 https://www.tutujin.com/v1 開頭的完整路徑。
  • 429:降低併發,或者把請求分散到多把 Key,見限流說明。
  • 一直 5xx:記下 request id,聯絡客服。

沒找到答案?加客服微信 JsnonoChat,傳送報錯資訊裡的 request id,我們幫你排查。