**摘要:**OpenRouter 在 2026 年 11 月 11 日發布的教學文章,用一連串實測拆解 429 Too Many Requests 錯誤:OpenAI Python SDK 的預設重試在 60 個 prompt 的批次裡掉了 23 個,而改讀錯誤回應裡的限流標頭、或把溢出流量導向 fallback 模型,就能全數完成。對任何要讓 LLM 功能撐過真實流量的開發者來說,這組數字把「加個 retry」這個直覺直接打臉,值得在上線前重新檢查自己的重試邏輯。
429 的回應裡藏著誰的限制
429 的意思是:你在目前的時間窗內送出的請求數或 token 數超過上限。OpenAI、Anthropic 和 OpenRouter 都會回傳它,而且通常第一次出現,就是 app 第一次遇到真實流量、或批次工作同時開多個 worker 的時候。
OpenRouter 的做法是在錯誤的 metadata 裡給出 limit_source,告訴你撞到的是誰的限制:openrouter_free_tier_per_minute 是自家免費模型的每分鐘上限,upstream_provider_shared_pool 則是上游提供者的共享容量。兩者的解法完全不同——前者等重置就好,後者等也沒用,因為提供者不會告訴你容量什麼時候釋出,實測中這類錯誤根本沒帶重置標頭。
標頭本身才是重點:X-RateLimit-Limit 是上限,X-RateLimit-Remaining 是剩餘額度,X-RateLimit-Reset 是最早可以重試成功的時間,格式是毫秒級的 Unix 時間戳。OpenAI 和 Anthropic 用不同名稱傳達同樣的資訊,例如 OpenAI 的 x-ratelimit-reset-requests 是 1s 這種時長,兩家也都可能送出以秒計的 Retry-After。
為什麼限制 20 卻放行了 38 個
OpenRouter 對 poolside/laguna-s-2.1:free(每分鐘 20 個請求的限制)同時發送 40 個請求,結果 38 個成功、2 個回 429。這不是偶爾失靈:大多數 limiter 不會在每分鐘開頭乾淨地重置,Anthropic 用的是持續補充的 token bucket,OpenAI 甚至會在你流量爬升太快時回傳 slow_down 的 429,即使你還在每分鐘上限之內。
接著他們又用不同模式發了 161 個請求:每一分鐘測試裡成功數都超過 20。所以那個「20」應該當成 429 可能開始出現的門檻,而不是精確計數。另外要注意,OpenRouter 對帳戶上所有免費模型共用同一個每分鐘 limiter——實測中 Laguna 被擋住時,換打 minimax/minimax-m3.1-flash:free 的五個請求雖然通過了,但另一個免費模型照樣可能吃到同一個 429。
預設重試為什麼不夠
這是最有參考價值的一組數字。60 個 prompt、每次 10 個併發,走 OpenAI Python SDK(openai 3.26.1)的預設設定:SDK 對每個 429 重試兩次、約兩秒內放棄,總共送出 112 個 HTTP 請求,12 秒結束,23 個請求仍然失敗。更諷刺的是,每個失敗後視窗其實在 4 到 8 秒後就重置了——SDK 只是重試得太早、太密。OpenAI 的文件也註明,失敗的請求照樣計入你的每分鐘上限,所以盲目調高 max_retries 只會往已滿的視窗裡塞更多請求。
三種修法,三種代價
第一種:照伺服器給的時間重試。先讀 Retry-After(伺服器的直接指令),再讀 X-RateLimit-Reset,最後才退到指數退避,並在重置後加 1 到 5 秒的隨機抖動,避免十個 worker 同時灌滿新視窗。結果是 60 個全數完成,但 Python 跑了 89 到 92 秒,TypeScript 版(Node 24)要 106 到 218 秒。代價很清楚:穩,但慢。如果你這樣包住 SDK 呼叫,記得設 max_retries=0,否則你的每次嘗試會變成三個請求。
第二種:fallback 模型。溢出的請求改送到另一個模型,60 個在 13 秒內全數完成,花費 $0.000066,完全不用等。代價是回應品質和成本結構可能不一致,需要自己驗證 fallback 模型的輸出。
第三種:provider failover。同一個模型鎖定單一提供者、關閉 failover 時,150 個請求每輪最多失敗 32 個;開啟 failover 後,150 個每輪全部成功。實測中免費版 Gemma 4 31B 遇到上游限流,改用付費版當 fallback 就落到 DeepInfra 的容量上,只花了 $0.0000037。
還有一類容易被誤判的 429:OpenAI 和 Anthropic 在你到達月度消費上限時也回 429,重試到天荒地老都沒用,得等上限重置。OpenRouter 上額度問題則回 402。
資料到哪裡斷了,下一步做什麼
要坦白說:這篇教學的原始頁面文字在 Step 2 的 TypeScript 程式碼中段被截斷,所以 Step 3 和 Step 4 的完整實作細節我無法從摘錄中核實,上述 fallback 與 failover 的數字來自文章開頭的 Tl;dr 段落。同樣地,所有實測都是針對 OpenRouter API 的免費模型(poolside、minimax、google/gemma),付費層級的行為和其他提供者的確切限制,這份摘錄沒有確立。
儘管如此,可以動手檢查的事項很明確:
- 找出你的重試邏輯目前有沒有讀
Retry-After和X-RateLimit-Reset,而不是只靠 SDK 預設的短退避。 - 在 429 處理路徑上根據
limit_source分流:可重置的限制等重置,上游容量問題換 provider 或換模型。 - 用受控的併發批次對自己的 API 打一輪,記錄 429 比率和視窗重置時間——OpenRouter 的方法論(同批請求、對照重試策略)可以直接抄。
如果你已經在用 OpenRouter,順手可以把參數配置也移出程式碼,之前寫過的 OpenRouter Presets 正好處理這件事。限流處理和配置管理一起收乾淨,批次工作才不會在深夜炸給你看。
