開始
錯誤碼與重試
出錯時先看 HTTP 狀態碼:429、500、502、503 可以退避重試,400、401、403、404、413 是請求或帳戶的問題,重試不會成功。餘額不足返回 403,不是 OpenAI 的 429。
請求出錯時會返回 HTTP 錯誤狀態碼和一個 JSON 錯誤體。判斷要不要重試,看狀態碼就夠了:429、500、502、503 可以等一會兒再試;400、401、403、404、413 是請求本身或帳戶設定的問題,原樣重試不會成功,只會浪費時間。
錯誤體格式
{
"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 所在的分組沒有這個模型的可用線路,常見於模型名拼錯或者分組裡本來就沒有這個模型。處理順序:
重試策略
可以重試的錯誤(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": "你好"}],
)import OpenAI from 'openai'
const client = new OpenAI({
baseURL: 'https://www.tutujin.com/v1',
apiKey: process.env.TUTUJIN_API_KEY,
maxRetries: 4, // 默认 2 次
timeout: 60_000, // 单次请求超时,毫秒
})
// 单个请求临时调整
const resp = await client.chat.completions.create(
{
model: 'gpt-5.4-mini',
messages: [{ role: 'user', content: '你好' }],
},
{ maxRetries: 6, timeout: 120_000 },
)不用 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))const RETRYABLE = new Set([429, 500, 502, 503])
const sleep = (ms) => new Promise((r) => setTimeout(r, ms))
async function postWithRetry(path, payload, maxAttempts = 5) {
for (let attempt = 0; ; attempt++) {
const res = await fetch(`https://www.tutujin.com/v1${path}`, {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.TUTUJIN_API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify(payload),
signal: AbortSignal.timeout(60_000),
})
if (res.ok) return res.json()
if (!RETRYABLE.has(res.status) || attempt === maxAttempts - 1) {
throw new Error(`${res.status} ${await res.text()}`) // 不可重试,或已用完次数
}
const retryAfter = Number(res.headers.get('retry-after'))
const delay = retryAfter > 0 ? retryAfter * 1000 : Math.min(30_000, 1000 * 2 ** attempt)
await sleep(delay + Math.random() * 1000)
}
}流式請求出錯
流式請求在開始返回資料之前出錯,和普通請求一樣返回錯誤狀態碼。如果資料已經開始返回,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,我們幫你排查。