測驗:LiteLLM Router、負載平衡與容錯重試
共 5 題,點選答案後會立即顯示結果
1. 使用 litellm.Router 的主要目的是什麼?
2. 在 model_list 中,多個條目使用「相同的 model_name」代表什麼?
3. 若不指定 routing_strategy,Router 預設使用哪種負載平衡策略?
4. 關於 fallbacks 與負載平衡的差別,下列何者正確?
5. 關於 num_retries 的行為,下列敘述何者正確?
系列第 3 篇,共 4 篇|難度:L2-進階
前置:已讀 #01(基本呼叫)、#02(統一介面),了解 API key 與多環境部署
一句話說明
litellm.Router 就是一個「智慧配電盤」:你把好幾個模型部署(不同 key、不同供應商)接進來,它幫你自動分流、壞掉自動切換、逾時自動重試——讓你的服務在 production 不會因為單一供應商抽風就整個掛掉。
在 #01、#02 我們都是直接呼叫 litellm.completion(),一次打一個 key。這在自己玩沒問題,但上線後你會遇到:
- OpenAI 突然回你
429 Rate limit exceeded,使用者就吃到錯誤 - 某個 API key 的額度用完了,服務直接中斷
- 某家供應商當天不穩,延遲飆高
Router 就是為了解決這些「高可用(High Availability)」問題而生。
為什麼需要 Router:production 的高可用需求
先看 #01 那種寫法會有什麼問題:
import litellm
# 直接呼叫,只有一條路
response = litellm.completion(
model="gpt-4o",
messages=[{"role": "user", "content": "你好"}],
)
Code language: PHP (php)這在幹嘛:拿一個 key,打一個模型。這條路一旦塞車或斷掉,使用者就直接收到錯誤。
Router 的思路完全不同:「同一個模型別名,背後綁多個部署,壞了就換下一個。」
from litellm import Router
router = Router(
model_list=[
{
"model_name": "gpt-4o", # 對外的別名
"litellm_params": {
"model": "azure/gpt-4o-deploy-1",
"api_key": "azure-key-1",
"api_base": "https://xxx-1.openai.azure.com",
},
},
{
"model_name": "gpt-4o", # 同一個別名,第二個部署
"litellm_params": {
"model": "openai/gpt-4o",
"api_key": "openai-key-1",
},
},
],
)
response = router.completion(
model="gpt-4o", # 呼叫別名,Router 決定實際打哪個
messages=[{"role": "user", "content": "你好"}],
)
Code language: PHP (php)這在幹嘛:你只喊 gpt-4o,Router 自己在兩個部署(一個 Azure、一個 OpenAI)之間挑一個來打。第一個塞車,就用第二個。
✅ 必看懂:
Router的核心概念是「一個model_name別名 ← 對應多個部署」。這是後面所有功能的基礎。
model_list:把多個部署綁成同一個別名
model_list 是一個 list,每個元素代表「一個部署」。逐欄位翻譯:
{
"model_name": "gpt-4o", # ① 對外別名,你的程式碼只認這個
"litellm_params": { # ② 實際怎麼打這個部署
"model": "azure/gpt-4o-deploy-1", # 真正的供應商/模型
"api_key": "azure-key-1", # 這個部署專屬的 key
"api_base": "https://xxx.openai.azure.com", # 端點
},
}
Code language: PHP (php)對照翻譯:
「對外我叫
gpt-4o。
你要打我的時候,實際是打 Azure 上那個叫gpt-4o-deploy-1的部署,
用azure-key-1這把鑰匙,打到那個 api_base。」
關鍵在 model_name 可以重複。重複的 model_name = 同一個別名的多個後端,Router 就會在它們之間做負載平衡:
model_list = [
# 三個都叫 gpt-4o,但是三個不同部署
{"model_name": "gpt-4o", "litellm_params": {"model": "azure/deploy-1", "api_key": "k1", "api_base": "https://a1..."}},
{"model_name": "gpt-4o", "litellm_params": {"model": "azure/deploy-2", "api_key": "k2", "api_base": "https://a2..."}},
{"model_name": "gpt-4o", "litellm_params": {"model": "openai/gpt-4o", "api_key": "k3"}},
]
Code language: PHP (php)這在幹嘛:三個部署共用 gpt-4o 這個名字。每次呼叫 Router 會挑一個,把流量分散開,也避免單一 key 撞到 rate limit。
📌 知道就好:實務上
api_key別寫死,用os.environ.get("AZURE_KEY_1")讀環境變數。範例為了看得清楚才寫明文。
負載平衡策略:Router 怎麼決定打哪個
當一個別名有多個部署,Router 要選一個。選法由 routing_strategy 決定:
router = Router(
model_list=model_list,
routing_strategy="simple-shuffle", # 選擇策略
)
Code language: PHP (php)常見策略,認得就好,不用背細節:
| 策略 | 白話 | 什麼時候用 |
|---|---|---|
simple-shuffle |
隨機挑(可依權重) | 預設,最簡單好用 |
least-busy |
挑目前手上請求最少的 | 想讓負載更平均 |
usage-based-routing |
挑目前 token 用量最低的 | 想貼著 rate limit 榨效能 |
latency-based-routing |
挑最近回應最快的 | 對延遲敏感的場景 |
✅ 必看懂:不指定就是
simple-shuffle,對多數人夠用。**先別過早優化**——除非你真的量到某個策略更好,否則預設就好。
你也可以給部署加權重,讓流量按比例分配:
{
"model_name": "gpt-4o",
"litellm_params": {"model": "azure/deploy-1", "api_key": "k1", "api_base": "..."},
"rpm": 100, # 這個部署每分鐘上限 100 次請求,Router 會據此分流
}
Code language: PHP (php)這在幹嘛:告訴 Router「這個部署每分鐘最多吃 100 次」,它就不會把它打爆,會把多的流量導到別的部署。
fallbacks 容錯:主模型倒了自動換備援
負載平衡是「同一別名多部署」;fallbacks 是「A 別名整組都不行,就換 B 別名」。這是跨供應商的最後一道防線。
router = Router(
model_list=[
{"model_name": "gpt-4o", "litellm_params": {"model": "openai/gpt-4o", "api_key": "k_openai"}},
{"model_name": "claude", "litellm_params": {"model": "anthropic/claude-sonnet-4-5", "api_key": "k_anthropic"}},
],
fallbacks=[
{"gpt-4o": ["claude"]}, # gpt-4o 全掛了,就改用 claude
],
)
response = router.completion(
model="gpt-4o",
messages=[{"role": "user", "content": "你好"}],
)
Code language: PHP (php)逐行翻譯 fallbacks 那行:
{"gpt-4o": ["claude"]}
「如果呼叫gpt-4o的所有部署都失敗了,
就自動改打claude,使用者不會感覺到中斷。」
fallbacks 是一個 list,可以設多層:
fallbacks=[
{"gpt-4o": ["claude", "gemini"]}, # 先試 claude,claude 也掛就試 gemini
]
Code language: PHP (php)這在幹嘛:主力 gpt-4o → 備援 claude → 再備援 gemini。一路往下退,直到有一個成功。
✅ 必看懂:**負載平衡(同別名多部署)解決「單一 key 塞車」;fallbacks(別名 → 別名)解決「整家供應商掛掉」。兩層是搭配用的。**
重試與逾時:num_retries 和 timeout
就算沒設 fallback,網路請求本來就會偶發失敗。Router 內建重試和逾時控制:
router = Router(
model_list=model_list,
num_retries=3, # 單一部署失敗,最多重試 3 次
timeout=30, # 每次請求超過 30 秒就當失敗
)
Code language: PHP (php)逐欄翻譯:
num_retries=3:「這個請求失敗了?別急著報錯,再自動試 3 次。」timeout=30:「等超過 30 秒還沒回?當它掛了,觸發重試或 fallback。」
重試的順序邏輯(大方向理解就好):
- 打某個部署 → 失敗
num_retries內:換同別名的別的部署重試- 同別名都試完還不行 → 觸發
fallbacks換別名 - 全部退完還不行 → 才真的往上丟錯誤
📌 知道就好:LiteLLM 對
429(rate limit)、500、逾時這類「可重試錯誤」才會重試;像401(key 錯)、400(請求格式錯)這種你重試一百次也沒用的,它不會重試,會直接報錯。這是對的行為——別把它「修」成全部重試。
🚩 紅旗:AI 幫你寫 Router 時要警覺這些
AI 寫 Router 設定時看起來都很像樣,但這幾個地方特別容易埋雷:
🚩 紅旗 1:fallback 目標模型根本沒在 model_list 裡
router = Router(
model_list=[
{"model_name": "gpt-4o", "litellm_params": {...}},
],
fallbacks=[{"gpt-4o": ["claude"]}], # 🚩 claude 根本沒定義在 model_list!
)
Code language: PHP (php)問題:fallbacks 指向的 claude 沒有出現在 model_list 裡,真的觸發 fallback 時會直接炸掉——而且平常不會發現,等到 production 主模型真的掛了那一刻才爆。跟 AI 說:「確認 fallbacks 裡每個模型名稱都有對應的 model_list 條目。」
🚩 紅旗 2:num_retries 設超大
router = Router(model_list=model_list, num_retries=10) # 🚩 10 次重試
Code language: PHP (php)問題:重試不是免費的。10 次重試 × 30 秒 timeout = 使用者可能等 5 分鐘才收到錯誤,而且每次重試都燒錢燒 token。合理範圍通常 2~3 次。看到很大的重試數要問:「這個重試次數的依據是什麼?會不會讓使用者等太久?」
🚩 紅旗 3:把所有部署的 key 寫死在程式碼裡
"litellm_params": {"model": "openai/gpt-4o", "api_key": "sk-proj-abc123..."} # 🚩 明文金鑰
Code language: PHP (php)問題:金鑰進了版控就是災難。應該是 os.environ["OPENAI_API_KEY"] 或從 secret manager 讀。看到明文 sk- 開頭的字串一律當紅旗。
🚩 紅旗 4:完全沒設 timeout
沒有 timeout,某個供應商 hang 住時你的請求會卡到天荒地老,fallback 也不會觸發(因為它還在「等」,沒失敗)。沒看到 timeout 就問 AI:「這個 Router 沒設 timeout,供應商 hang 住會怎樣?」
Vibe Coder 驗收檢查點
Router 最麻煩的地方是:平常都正常,你根本不知道 fallback 到底有沒有真的接住。 所以要主動「製造失敗」來驗收。
檢查點 1:先確認基本呼叫會動
# save as test_router.py
from litellm import Router
router = Router(
model_list=[
{"model_name": "main", "litellm_params": {"model": "openai/gpt-4o-mini", "api_key": "你的真key"}},
],
)
resp = router.completion(model="main", messages=[{"role": "user", "content": "說 ok"}])
print(resp.choices[0].message.content)
Code language: PHP (php)預期:印出模型回覆。跑得動代表 Router 基本盤 OK。
檢查點 2:用「壞 key」模擬主模型失敗,驗證 fallback 生效
這是最重要的一步——故意把主模型的 key 設成錯的,看它會不會乖乖切到備援:
router = Router(
model_list=[
# 主模型:故意用壞掉的 key
{"model_name": "primary", "litellm_params": {"model": "openai/gpt-4o", "api_key": "sk-WRONG-KEY"}},
# 備援:用正確的 key
{"model_name": "backup", "litellm_params": {"model": "openai/gpt-4o-mini", "api_key": "你的真key"}},
],
fallbacks=[{"primary": ["backup"]}],
num_retries=1,
)
resp = router.completion(model="primary", messages=[{"role": "user", "content": "說 ok"}])
print(resp.model) # 看實際回應是哪個模型
print(resp.choices[0].message.content)
Code language: PHP (php)預期結果:主模型因 key 錯(401)失敗 → 觸發 fallback → 由 backup 成功回應。print(resp.model) 應該顯示 gpt-4o-mini(備援),而不是報錯。
如果直接報錯而沒切備援,代表 fallback 沒生效——回頭檢查紅旗 1(fallback 目標有沒有在 model_list)。
檢查點 3:直接問 AI 幫你檢查設定
把你的 Router 設定貼給 AI,問:
「這個 litellm Router 設定,如果主供應商 429 rate limit,請求會怎麼走?fallbacks 裡的模型名稱有沒有都對應到 model_list?num_retries 和 timeout 的組合,最壞情況使用者要等多久?」
看不懂就這樣問 AI
- 「用白話解釋 litellm 的
model_list裡model_name重複代表什麼,我是初學者。」 - 「負載平衡和 fallbacks 差在哪?各解決什麼問題?舉一個 production 情境。」
- 「幫我看這段 Router 設定有沒有金鑰寫死、fallback 目標不存在、重試次數太大的問題。」
小結
| 概念 | 一句話 | 解決什麼 |
|---|---|---|
model_list |
一個別名綁多個部署 | 統一入口 |
負載平衡(routing_strategy) |
同別名多部署間分流 | 單一 key 塞車 / rate limit |
fallbacks |
別名壞了換別名 | 整家供應商掛掉 |
num_retries / timeout |
失敗重試、逾時放棄 | 偶發網路錯誤 |
記住三層防線:重試(同部署再試)→ 負載平衡(換同別名部署)→ fallbacks(換別名)。驗收的關鍵動作是「用壞 key 主動製造失敗」,確認備援真的接得住。
下一篇(#04)我們會把這些設定搬到 LiteLLM Proxy Server,讓整個團隊共用同一套 Router 設定與金鑰管理。
進階測驗:LiteLLM Router、負載平衡與容錯重試
共 5 題,包含情境題與錯誤診斷題。