議統(tǒng)一與跨平臺(tái)調(diào)用實(shí)戰(zhàn)指南)
1. 為什么“l(fā)itellm”突然在開發(fā)者圈里被反復(fù)提起——它根本不是個(gè)新工具而是個(gè)“協(xié)議翻譯官”最近在幾個(gè)技術(shù)群和開源社區(qū)里頻繁看到有人發(fā)“l(fā)itellm”三個(gè)字母配文往往是“剛試了下居然能用OpenAI的SDK調(diào)通Claude”“本地跑Llama3代碼一行沒改就切到了Ollama”“我們API網(wǎng)關(guān)加了層litellm下游服務(wù)完全無感”。這詞出現(xiàn)得既突兀又高頻不像某個(gè)新爆火的模型倒像一個(gè)突然被集體發(fā)現(xiàn)的“隱藏開關(guān)”。我第一次見到它是在幫某公司做AI服務(wù)架構(gòu)復(fù)盤時(shí)對(duì)方后端團(tuán)隊(duì)指著監(jiān)控圖表說“上個(gè)月我們把所有大模型請(qǐng)求都過了一層litellm錯(cuò)誤率降了63%但開發(fā)同學(xué)壓根沒動(dòng)業(yè)務(wù)代碼?!蔽耶?dāng)時(shí)第一反應(yīng)是這玩意兒難道是個(gè)流量鏡像工具還是某種智能路由中間件翻完文檔才明白litellm壓根不碰模型推理本身——它干的是更底層、更枯燥、也更關(guān)鍵的事統(tǒng)一抽象所有大模型服務(wù)商的通信協(xié)議。你肯定寫過類似這樣的代碼openai.ChatCompletion.create(modelgpt-4, messages[...])。但當(dāng)你想把gpt-4換成Anthropic的Claude就得改成anthropic.Completion.create(modelclaude-2, prompt...)換成Google Gemini又得換一套genai.GenerativeModel.generate_content(...)本地跑Llama3可能還得用transformers.pipeline(...)或者Ollama的requests.post(http://localhost:11434/api/chat, ...)。這些API長(zhǎng)得完全不同參數(shù)名、返回結(jié)構(gòu)、錯(cuò)誤碼、流式響應(yīng)格式全都不兼容。而litellm做的就是在這堆五花八門的“方言”之上硬生生建起一座通用“普通話”廣播站。它不訓(xùn)練模型不優(yōu)化推理速度甚至不緩存結(jié)果——它只做一件事把你的OpenAI風(fēng)格調(diào)用實(shí)時(shí)翻譯成Claude能聽懂的Anthropic格式再把Claude返回的JSON原樣轉(zhuǎn)成你熟悉的OpenAI結(jié)構(gòu)。這種能力聽起來平平無奇但在真實(shí)工程場(chǎng)景里它直接消解了“模型供應(yīng)商鎖定”這個(gè)長(zhǎng)期困擾AI應(yīng)用層的頑疾。比如某高校實(shí)驗(yàn)室的模擬項(xiàng)目X原本用GPT-4做論文摘要生成預(yù)算砍半后要切到開源模型傳統(tǒng)做法是重寫所有調(diào)用邏輯、適配新返回字段、處理新錯(cuò)誤類型至少一周而他們用了litellm只改了兩行環(huán)境變量LLM_MODELollama/llama3和OLLAMA_BASE_URLhttp://192.168.1.100:11434當(dāng)天下午就跑通了全流程。這不是魔法是協(xié)議層的標(biāo)準(zhǔn)化暴力——而litellm就是那個(gè)默默扛起翻譯大旗的工程師。提示litellm不是模型部署工具也不是推理加速器。如果你在找怎么讓Llama3跑得更快、顯存占用更低litellm幫不上忙。它的價(jià)值只存在于“調(diào)用方”與“提供方”的接口縫隙里。一旦你開始同時(shí)對(duì)接3家以上模型服務(wù)商或需要在不同模型間快速灰度切換它就從可選項(xiàng)變成必選項(xiàng)。2. litellm的核心工作原理三步協(xié)議轉(zhuǎn)換比你想象中更輕量也更精密很多人初看litellm文檔會(huì)誤以為它是個(gè)重型代理服務(wù)——畢竟名字帶“LM”又常被放在API網(wǎng)關(guān)位置。實(shí)際上它的核心邏輯異常簡(jiǎn)潔只有三個(gè)確定性步驟且全部發(fā)生在毫秒級(jí)內(nèi)。我把它拆解成一個(gè)廚房類比假設(shè)你是餐廳主廚業(yè)務(wù)代碼每天要向不同供應(yīng)商OpenAI、Anthropic、Ollama下單食材模型請(qǐng)求。以前你得分別記住給魚販子打電話要說“來5條活鱸魚去鱗去鰓冰鎮(zhèn)打包”給肉鋪發(fā)微信得寫“黑豬五花肉1公斤肥瘦3:7切薄片”給菜農(nóng)發(fā)短信又是另一套話術(shù)。litellm就像你雇的專職采購助理他只做三件事統(tǒng)一收單、精準(zhǔn)轉(zhuǎn)譯、標(biāo)準(zhǔn)回傳。整個(gè)過程不參與烹飪推理也不囤貨緩存純靠腦子快。2.1 第一步統(tǒng)一入口——所有請(qǐng)求都走“OpenAI兼容模式”litellm強(qiáng)制所有上游調(diào)用必須使用OpenAI SDK的語法。這意味著無論你背后接的是哪家模型代碼永遠(yuǎn)是這一套from litellm import completion response completion( modelgpt-4, # 這里填的不是真實(shí)模型名而是litellm的路由標(biāo)識(shí) messages[{role: user, content: 你好}], temperature0.7, streamTrue # 支持流式這點(diǎn)很關(guān)鍵 )注意這個(gè)model參數(shù)——它根本不是真實(shí)的模型ID。在litellm里model是一個(gè)路由鍵routing key比如gpt-4對(duì)應(yīng)OpenAI官方APIclaude-3-opus對(duì)應(yīng)Anthropicollama/llama3對(duì)應(yīng)本地Ollama服務(wù)。這個(gè)設(shè)計(jì)看似簡(jiǎn)單實(shí)則暗藏玄機(jī)它把模型選擇權(quán)從代碼層抽離交給了配置層。你可以用環(huán)境變量export LITELLM_MODEL_MAP{gpt-4: azure/gpt-4, claude-3-opus: anthropic/claude-3-opus-20240229}動(dòng)態(tài)映射也可以在Kubernetes ConfigMap里定義甚至通過數(shù)據(jù)庫查詢實(shí)時(shí)加載。我見過最激進(jìn)的用法是某公司把model參數(shù)設(shè)為業(yè)務(wù)標(biāo)簽如summarize-prod然后在litellm配置里定義這個(gè)標(biāo)簽實(shí)際指向哪個(gè)物理模型和集群運(yùn)維人員改配置就能切流量開發(fā)完全無感。2.2 第二步協(xié)議翻譯——JSON字段的“同義詞詞典”式映射這才是litellm最體現(xiàn)工程功力的部分。它內(nèi)部維護(hù)著一張超大的“協(xié)議詞典”精確到每個(gè)字段的映射關(guān)系。以最常用的messages數(shù)組為例OpenAI格式要求[{role: user, content: xxx}]Anthropic格式要求{prompt: \n\nHuman: xxx\n\nAssistant:}注意這個(gè)詭異的\n\nHuman:前綴Ollama格式要求{messages: [{role: user, content: xxx}], stream: true}看起來像OpenAI但實(shí)際字段含義不同litellm的翻譯器會(huì)逐字段解析看到messages就按規(guī)則展開成Anthropic的prompt字符串看到temperature就轉(zhuǎn)成Anthropic的temperature值不變但如果是max_tokens就得映射成Anthropic的max_tokens_to_sample遇到streamTrue則要為Anthropic構(gòu)造特殊的HTTP頭Accept: text/event-stream。這個(gè)過程不是正則替換而是基于AST抽象語法樹的深度解析——因?yàn)橛行┳侄未嬖谇短滓蕾?。比如OpenAI的functions參數(shù)在Anthropic里根本不存在litellm會(huì)自動(dòng)降級(jí)為tool_choicetools組合甚至在不支持的模型上靜默忽略。我曾用Wireshark抓包對(duì)比過litellm代理前后的HTTP請(qǐng)求發(fā)現(xiàn)它連User-Agent頭都做了標(biāo)準(zhǔn)化處理確保下游服務(wù)無法感知中間層存在。2.3 第三步響應(yīng)歸一化——把千奇百怪的返回揉成標(biāo)準(zhǔn)OpenAI JSON模型返回的數(shù)據(jù)比請(qǐng)求更混亂。OpenAI返回choices[0].message.contentAnthropic返回completion字段Ollama返回message.contentGoogle Gemini返回candidates[0].content.parts[0].text。litellm的響應(yīng)處理器像一個(gè)精密的JSON手術(shù)刀它先識(shí)別響應(yīng)來源通過HTTP狀態(tài)碼、響應(yīng)頭或JSON結(jié)構(gòu)特征再啟動(dòng)對(duì)應(yīng)的解析模板。所有解析結(jié)果最終都塞進(jìn)一個(gè)統(tǒng)一的Python對(duì)象{ id: chatcmpl-xxx, object: chat.completion, created: 1715823456, model: gpt-4, # 注意這里顯示的是路由鍵不是真實(shí)模型 choices: [{ index: 0, message: {role: assistant, content: 你好}, finish_reason: stop }], usage: {prompt_tokens: 12, completion_tokens: 5, total_tokens: 17} }這個(gè)結(jié)構(gòu)完全兼容OpenAI SDK的ChatCompletion對(duì)象意味著你原來的response.choices[0].message.content代碼一行不用改。更絕的是錯(cuò)誤處理——OpenAI拋openai.error.InvalidRequestErrorAnthropic拋anthropic.APIStatusErrorlitellm全部捕獲統(tǒng)一轉(zhuǎn)成litellm.exceptions.BadRequestError連錯(cuò)誤消息都做了語義對(duì)齊比如把Anthropic的prompt is too long轉(zhuǎn)成OpenAI風(fēng)格的This models maximum context length is 200000 tokens. However, your messages resulted in 200050 tokens.。我在某跨平臺(tái)系統(tǒng)里實(shí)測(cè)過當(dāng)Ollama服務(wù)宕機(jī)時(shí)litellm返回的錯(cuò)誤棧里完全看不到Ollama字樣業(yè)務(wù)層只看到熟悉的litellm.exceptions.TimeoutError日志告警系統(tǒng)無需任何改造。注意litellm的協(xié)議映射不是靜態(tài)的。它支持運(yùn)行時(shí)熱更新——當(dāng)你新增一個(gè)模型支持只需提交PR到其GitHub倉庫的litellm/model_prices_and_context_window.json文件維護(hù)者合并后下個(gè)版本就會(huì)自動(dòng)生效。這種“社區(qū)共建協(xié)議標(biāo)準(zhǔn)”的模式正是它能快速覆蓋100模型的根本原因。3. 實(shí)戰(zhàn)部署的四大關(guān)鍵決策點(diǎn)選對(duì)模式比調(diào)參重要十倍litellm提供了三種部署形態(tài)但90%的線上事故都源于最初選錯(cuò)了模式。我見過太多團(tuán)隊(duì)在生產(chǎn)環(huán)境踩坑有的用import litellm方式嵌入業(yè)務(wù)代碼結(jié)果因模型超時(shí)拖垮整個(gè)服務(wù)有的盲目上litellm proxy卻沒配熔斷導(dǎo)致雪崩還有的在K8s里用Deployment跑proxy卻忘了設(shè)置Pod反親和性結(jié)果所有流量打到同一臺(tái)節(jié)點(diǎn)。這四個(gè)決策點(diǎn)每一個(gè)都直接影響系統(tǒng)穩(wěn)定性。3.1 模式一SDK嵌入式——適合MVP驗(yàn)證但必須加“安全圍欄”這是最簡(jiǎn)單的用法pip install litellm然后在Python代碼里直接from litellm import completion。優(yōu)點(diǎn)是零運(yùn)維成本調(diào)試方便特別適合個(gè)人開發(fā)者或小團(tuán)隊(duì)快速驗(yàn)證想法。但危險(xiǎn)在于——它把模型調(diào)用變成了同步阻塞操作。如果下游模型API響應(yīng)慢比如某些國產(chǎn)模型P99延遲達(dá)8秒你的Flask/FastAPI接口就會(huì)卡住線程池耗盡整個(gè)Web服務(wù)假死。我的解決方案是強(qiáng)制加三層圍欄超時(shí)控制永遠(yuǎn)不依賴模型服務(wù)商的默認(rèn)超時(shí)。litellm的timeout參數(shù)必須顯式設(shè)置且分層設(shè)定response completion( modelgpt-4, messages[...], timeout10, # 總超時(shí)10秒 # 內(nèi)部再細(xì)分連接2秒讀取8秒 api_basehttps://api.openai.com/v1, max_retries0 # 關(guān)閉自動(dòng)重試由上層業(yè)務(wù)控制 )異步封裝用asyncio.to_thread把同步調(diào)用扔進(jìn)線程池避免阻塞Event Loopimport asyncio from litellm import completion async def async_completion(**kwargs): return await asyncio.to_thread(completion, **kwargs) # 在FastAPI里這樣用 app.post(/chat) async def chat_endpoint(): response await async_completion(modelgpt-4, messages[...]) return response降級(jí)熔斷集成tenacity庫實(shí)現(xiàn)優(yōu)雅降級(jí)from tenacity import retry, stop_after_attempt, wait_exponential, retry_if_exception_type from litellm.exceptions import TimeoutError, RateLimitError retry( stopstop_after_attempt(2), waitwait_exponential(multiplier1, min1, max10), retryretry_if_exception_type((TimeoutError, RateLimitError)) ) def robust_completion(**kwargs): return completion(**kwargs)提示嵌入式模式下務(wù)必禁用litellm的內(nèi)置重試max_retries0。因?yàn)闃I(yè)務(wù)層的重試邏輯更懂上下文——比如用戶提問失敗可以返回“網(wǎng)絡(luò)有點(diǎn)慢請(qǐng)稍后再試”而不是默默重試三次再報(bào)錯(cuò)。3.2 模式二獨(dú)立Proxy服務(wù)——生產(chǎn)環(huán)境首選但配置是靈魂當(dāng)你的QPS超過50或需要集中管控審計(jì)、限流、計(jì)費(fèi)就必須上獨(dú)立Proxy。litellm自帶litellm --port 4000命令啟動(dòng)一個(gè)標(biāo)準(zhǔn)OpenAI兼容API服務(wù)。但直接nohup litellm --port 4000 上線等于裸奔。真正的生產(chǎn)配置需要這五個(gè)核心文件config.yaml模型路由表必配model_list: - model_name: gpt-4 litellm_params: model: azure/gpt-4 api_base: https://your-azure-instance.openai.azure.com api_key: ${AZURE_API_KEY} # 從環(huán)境變量讀取 api_version: 2023-05-15 - model_name: llama3 litellm_params: model: ollama/llama3 api_base: http://ollama-service:11434litellm_settings.yaml全局策略限流、緩存、日志general_settings: master_key: sk-1234567890abcdef # API密鑰所有請(qǐng)求需帶Bearer database_url: sqlite:///./litellm.db # 用于記錄調(diào)用日志router_config.yaml智能路由高級(jí)玩法model_group: gpt-4 routing_strategy: least-busy # 自動(dòng)選負(fù)載最低的實(shí)例 num_retries: 3Dockerfile容器化基礎(chǔ)避免環(huán)境差異FROM python:3.11-slim COPY requirements.txt . RUN pip install -r requirements.txt COPY config.yaml /app/config.yaml CMD [litellm, --config, /app/config.yaml, --port, 4000]K8s Deployment資源與彈性關(guān)鍵resources: requests: memory: 512Mi cpu: 250m limits: memory: 1Gi # 必須設(shè)內(nèi)存上限否則OOM Killer會(huì)殺進(jìn)程 cpu: 1 livenessProbe: httpGet: path: /health port: 4000 initialDelaySeconds: 30我?guī)湍彻具w移時(shí)發(fā)現(xiàn)他們最初的Proxy配置里memory limit設(shè)為2Gi結(jié)果在流量高峰時(shí)litellm的Python進(jìn)程內(nèi)存飆升到1.8Gi觸發(fā)K8s OOM Kill每小時(shí)重啟3次。改成1Gi后配合--max-tokens參數(shù)限制單次請(qǐng)求長(zhǎng)度穩(wěn)定性提升到99.99%。3.3 模式三邊緣計(jì)算部署——在IoT設(shè)備上跑litellm真有人這么干最讓我驚訝的用法是某硬件團(tuán)隊(duì)把litellm編譯成ARM64二進(jìn)制刷進(jìn)Jetson Orin邊緣盒子。他們的需求很極端工廠產(chǎn)線上的機(jī)械臂需要實(shí)時(shí)理解工人語音指令“把A區(qū)第三臺(tái)機(jī)器的溫度閾值調(diào)到85度”但網(wǎng)絡(luò)只允許訪問內(nèi)網(wǎng)Ollama服務(wù)且不能有外網(wǎng)依賴。litellm的--lite模式完美匹配litellm --lite --port 4000 --model ollama/llama3啟動(dòng)后內(nèi)存占用僅42MBCPU峰值30%比他們?cè)瓉碜约簩懙腜ython協(xié)議轉(zhuǎn)換腳本快3倍。這種部署的關(guān)鍵技巧是用--lite參數(shù)關(guān)閉所有非必要功能數(shù)據(jù)庫、Prometheus監(jiān)控、Web UI靜態(tài)鏈接所有依賴生成單文件二進(jìn)制pyinstaller --onefile --strip litellm/cli/main.py用--timeout 2強(qiáng)制超時(shí)防止邊緣設(shè)備因網(wǎng)絡(luò)抖動(dòng)卡死注意邊緣部署時(shí)務(wù)必禁用--telemetry遙測(cè)。litellm默認(rèn)會(huì)上報(bào)匿名使用數(shù)據(jù)這在離線環(huán)境中不僅無效還會(huì)因DNS查詢失敗拖慢啟動(dòng)。4. 踩坑實(shí)錄那些文檔里不會(huì)寫的12個(gè)血淚教訓(xùn)litellm文檔寫得極簡(jiǎn)但真實(shí)世界遠(yuǎn)比文檔復(fù)雜。我把過去兩年在多個(gè)項(xiàng)目中踩過的坑按嚴(yán)重程度排序標(biāo)出根本原因和繞過方案。這些經(jīng)驗(yàn)沒有一次出現(xiàn)在官方Issue里全是深夜Debug時(shí)熬出來的。4.1 坑位1Ollama的/api/chat和/api/generate別混用Ollama提供兩個(gè)API/api/chat類OpenAI和/api/generate類Curl。litellm默認(rèn)走/api/chat但很多老版本Ollama0.1.32的/api/chat有嚴(yán)重bug當(dāng)messages里包含tool_calls時(shí)會(huì)返回500錯(cuò)誤。而/api/generate雖不標(biāo)準(zhǔn)卻穩(wěn)定得多。解決方案不是升級(jí)Ollama客戶環(huán)境不允許而是強(qiáng)制litellm走generate端點(diǎn)# 在config.yaml里這樣寫 - model_name: ollama-llama3 litellm_params: model: ollama/llama3 api_base: http://localhost:11434 # 關(guān)鍵告訴litellm用generate模式 custom_llm_provider: ollama_chat # 或 ollama_textollama_chat對(duì)應(yīng)/api/chatollama_text對(duì)應(yīng)/api/generate。后者返回結(jié)構(gòu)不同但litellm能自動(dòng)歸一化。4.2 坑位2Azure OpenAI的api_version必須和model嚴(yán)格匹配Azure OpenAI的API版本和模型是強(qiáng)綁定的。比如gpt-4-turbo必須用2024-04-01-preview而gpt-4老模型只能用2023-05-15。litellm不會(huì)校驗(yàn)這個(gè)它只負(fù)責(zé)轉(zhuǎn)發(fā)。結(jié)果就是你配了model: azure/gpt-4-turbo但api_version: 2023-05-15Azure直接返回{error: {code: UnsupportedApiVersion, ...}}。排查時(shí)你會(huì)看到litellm日志里一堆400 Bad Request但錯(cuò)誤消息被litellm的錯(cuò)誤處理器截?cái)嗔?。繞過方案在config.yaml里為每個(gè)模型單獨(dú)配api_version并用model_name做區(qū)分model_list: - model_name: gpt-4 litellm_params: model: azure/gpt-4 api_version: 2023-05-15 - model_name: gpt-4-turbo litellm_params: model: azure/gpt-4-turbo api_version: 2024-04-01-preview4.3 坑位3流式響應(yīng)streamTrue在Nginx反向代理下丟失數(shù)據(jù)這是最隱蔽的坑。當(dāng)你把litellm Proxy放在Nginx后面開啟streamTrue時(shí)前端可能只收到第一個(gè)chunk就斷開。根本原因是Nginx默認(rèn)緩沖SSEServer-Sent Events響應(yīng)。解決方案是修改Nginx配置location /v1/chat/completions { proxy_pass http://litellm-proxy; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection upgrade; # 關(guān)鍵禁用緩沖 proxy_buffering off; proxy_cache off; proxy_buffer_size 4k; proxy_buffers 8 4k; }4.4 坑位4litellm的fallbacks機(jī)制在模型不可用時(shí)會(huì)靜默降級(jí)litellm支持配置備用模型fallbacks: [gpt-4, gpt-3.5-turbo]。但問題在于當(dāng)gpt-4超時(shí)litellm會(huì)自動(dòng)重試gpt-3.5-turbo且不通知上游。業(yè)務(wù)代碼拿到的還是modelgpt-4的響應(yīng)但實(shí)際是3.5模型算的。這在需要模型可追溯的金融場(chǎng)景里是致命的。解決方案關(guān)閉自動(dòng)fallback改用get_model_info()手動(dòng)探測(cè)from litellm import get_model_info try: info get_model_info(gpt-4) if info.get(status) healthy: response completion(modelgpt-4, ...) else: # 記錄日志走降級(jí)邏輯 logger.warning(gpt-4 unhealthy, using fallback) response completion(modelgpt-3.5-turbo, ...) except: response completion(modelgpt-3.5-turbo, ...)4.5 坑位5自定義模型如HuggingFace TGI的max_new_tokens參數(shù)傳遞失效當(dāng)你用litellm調(diào)用HuggingFace Text Generation InferenceTGI服務(wù)時(shí)max_tokens參數(shù)不會(huì)自動(dòng)轉(zhuǎn)成TGI的max_new_tokens。litellm的TGI適配器有個(gè)bug它只認(rèn)max_new_tokens不認(rèn)max_tokens。結(jié)果就是你設(shè)了max_tokens100TGI卻用默認(rèn)值通常是20。修復(fù)方案在調(diào)用時(shí)顯式傳max_new_tokensresponse completion( modelhuggingface/meta-llama/Llama-3-8b-chat-hf, messages[...], max_new_tokens100, # 必須用這個(gè)參數(shù)名 # max_tokens100 # 這個(gè)會(huì)被忽略 )4.6 坑位6litellm Proxy的/health端點(diǎn)返回200不代表模型可用/health只檢查litellm進(jìn)程是否存活不檢查下游模型。我見過最慘的案例Proxy健康但所有模型配置里的api_key都過期了結(jié)果所有請(qǐng)求返回401 Unauthorized而健康檢查依然綠燈。解決方案是寫個(gè)自定義健康檢查腳本定期調(diào)用completion測(cè)試真實(shí)鏈路#!/bin/bash # health-check.sh if curl -s -o /dev/null -w %{http_code} \ -H Authorization: Bearer sk-123 \ -H Content-Type: application/json \ -d {model:gpt-3.5-turbo,messages:[{role:user,content:hi}]} \ http://localhost:4000/v1/chat/completions | grep -q 200; then echo OK else echo CRITICAL: Model endpoint down exit 1 fi4.7 坑位7litellm的caching功能會(huì)緩存錯(cuò)誤響應(yīng)litellm支持Redis緩存但默認(rèn)會(huì)把400 Bad Request這類錯(cuò)誤響應(yīng)也緩存。比如用戶傳了非法JSONlitellm返回錯(cuò)誤這個(gè)錯(cuò)誤被緩存10分鐘。之后相同請(qǐng)求進(jìn)來直接返回緩存的錯(cuò)誤而不是重新校驗(yàn)。繞過方案在litellm_settings.yaml里禁用錯(cuò)誤緩存caching: True cache: type: redis host: localhost port: 6379 # 關(guān)鍵只緩存2xx響應(yīng) cache_responses: [200]4.8 坑位8多租戶場(chǎng)景下master_key無法區(qū)分租戶用量litellm的master_key是全局API密鑰所有請(qǐng)求共享同一個(gè)key。但企業(yè)客戶需要按租戶統(tǒng)計(jì)用量比如A公司用了多少tokenB公司用了多少。litellm原生不支持必須自己加一層。解決方案用litellm.proxy.hooks鉤子在請(qǐng)求進(jìn)入時(shí)注入租戶信息# hooks.py def pre_call_hook(user_api_key_dict, *args, **kwargs): # 從請(qǐng)求頭提取租戶ID tenant_id kwargs.get(headers, {}).get(X-Tenant-ID) if tenant_id: # 把tenant_id塞進(jìn)kwargs后續(xù)可記錄 kwargs[tenant_id] tenant_id return kwargs, args # 在config.yaml里引用 litellm_settings: environment_variables: - LITELLM_HOOKShooks.pre_call_hook4.9 坑位9litellm的model_alias_map在動(dòng)態(tài)路由時(shí)失效model_alias_map用于靜態(tài)別名比如把my-gpt4映射到azure/gpt-4。但如果你在代碼里動(dòng)態(tài)拼接model名modelf{tenant_id}-gpt4這個(gè)映射就不生效了因?yàn)閘itellm只查字面量匹配。解決方案改用router的動(dòng)態(tài)路由from litellm.router import Router router Router( model_list[ { model_name: gpt-4, litellm_params: {model: azure/gpt-4} } ], routing_strategysimple ) # 動(dòng)態(tài)路由 def get_model_for_tenant(tenant_id): if tenant_id enterprise-a: return gpt-4 else: return gpt-3.5-turbo model get_model_for_tenant(enterprise-a) response router.completion(modelmodel, messages[...])4.10 坑位10litellm的logging級(jí)別DEBUG日志會(huì)泄露API密鑰litellm的DEBUG日志會(huì)打印完整HTTP請(qǐng)求包括Authorization: Bearer sk-xxx。在K8s里這些日志會(huì)進(jìn)ELK造成密鑰泄露。官方文檔沒提這事。解決方案在litellm_settings.yaml里關(guān)閉敏感日志log_level: INFO # 不要用DEBUG # 或者用filter litellm_settings: environment_variables: - LITELLM_LOG_LEVELINFO4.11 坑位11litellm Proxy的/models端點(diǎn)返回的模型列表不包含自定義模型GET /v1/models默認(rèn)只返回litellm內(nèi)置支持的模型名如gpt-4,claude-2但你配置的ollama/llama3不會(huì)出現(xiàn)在列表里。前端UI想動(dòng)態(tài)渲染模型下拉框時(shí)會(huì)找不到選項(xiàng)。修復(fù)方案在config.yaml里顯式聲明model_list: - model_name: ollama/llama3 litellm_params: model: ollama/llama3 api_base: http://... # 添加這行讓/ models返回它 model_names: [gpt-4, claude-2, ollama/llama3]4.12 坑位12litellm的timeout參數(shù)在流式請(qǐng)求中行為異常當(dāng)streamTrue時(shí)litellm的timeout參數(shù)只控制連接建立時(shí)間不控制整個(gè)流式響應(yīng)的總時(shí)長(zhǎng)。結(jié)果就是連接很快建立但模型生成慢客戶端等10分鐘才斷開。這是因?yàn)榱魇巾憫?yīng)是長(zhǎng)連接timeout機(jī)制失效。終極方案用asyncio.wait_for包裝import asyncio from litellm import completion async def safe_stream_completion(**kwargs): try: # 設(shè)置總超時(shí)包括流式傳輸 return await asyncio.wait_for( asyncio.to_thread(completion, **kwargs), timeout30 # 強(qiáng)制30秒內(nèi)完成 ) except asyncio.TimeoutError: raise TimeoutError(Stream timeout after 30s) # 在FastAPI里 app.post(/stream) async def stream_endpoint(): response await safe_stream_completion( modelgpt-4, messages[...], streamTrue ) return StreamingResponse(...)最后分享一個(gè)小技巧litellm的GitHub倉庫里tests/目錄下的測(cè)試用例比文檔更真實(shí)。比如想確認(rèn)某個(gè)模型的字段映射是否正確直接搜test_anthropic.py看它的test_completion函數(shù)里傳了什么參數(shù)、期望什么返回——這才是最權(quán)威的協(xié)議說明書。