一 Key 打通多模型調(diào)用)
1. 為什么要在 K8s 里跑 LiteLLM 網(wǎng)關(guān)LiteLLM 是一個(gè)把多家大模型 API 統(tǒng)一成 OpenAI 兼容格式的網(wǎng)關(guān)你可以把它理解成集群里的「模型路由中樞」上游是各家模型服務(wù)下游是業(yè)務(wù) Pod中間由它負(fù)責(zé)鑒權(quán)、路由、限流和日志。放到 Kubernetes 里跑好處是副本可擴(kuò)、配置可版本化、密鑰可集中管理團(tuán)隊(duì)里誰(shuí)要用模型只認(rèn)一個(gè)集群內(nèi)地址就行。真正讓人頭疼的不是 LiteLLM 本身而是 Key 的散落。業(yè)務(wù) A 用一家、業(yè)務(wù) B 用另一家每個(gè) Pod 里塞一份密鑰輪換一次要改十幾個(gè) Deployment。我試過(guò)把 endpoint 和 Key 統(tǒng)一收斂到 TaoToken 這一層LiteLLM 只保留一份上游憑據(jù)模型名到實(shí)際后端的映射寫(xiě)在 ConfigMap 里改配置不用動(dòng)業(yè)務(wù)代碼。這篇就按這個(gè)思路把「Kubernetes 部署 LiteLLM 統(tǒng)一多模型 Key」的完整路徑走一遍包含可直接復(fù)制的 Deployment、Service、ConfigMap YAML以及用 curl 驗(yàn)證模型列表和一次對(duì)話請(qǐng)求的檢查動(dòng)作。適合誰(shuí)看手里有 K8s 集群、需要給多個(gè)團(tuán)隊(duì)或服務(wù)統(tǒng)一發(fā)模型能力的平臺(tái)同學(xué)已經(jīng)在用 LiteLLM 但 Key 管理混亂、想收斂入口的運(yùn)維同學(xué)以及準(zhǔn)備把本地 LiteLLM 遷到集群、想要一份能跑通的清單的人。讀完你應(yīng)該能拿到一個(gè)一次部署、穩(wěn)定路由多模型調(diào)用的最小可用形態(tài)。需要提前說(shuō)明的是LiteLLM 的鏡像、端口、環(huán)境變量在不同版本間偶有差異本文以ghcr.io/berriai/litellm:main-latest和 8000 端口為基準(zhǔn)你落地時(shí)按自己鎖定的 tag 微調(diào)即可。下面從集群前置檢查開(kāi)始。2. 部署前的集群檢查與 TaoToken 憑據(jù)準(zhǔn)備先把地基打牢再談部署。集群側(cè)要確認(rèn)三件事kubectl 能連上、節(jié)點(diǎn)資源夠、命名空間隔離好。LiteLLM 本體不重單副本 1 核 1Gi 起步足夠但它要維護(hù)到上游的連接池副本數(shù)建議至少 2 個(gè)做滾動(dòng)更新時(shí)的可用性兜底。kubectl version --short kubectl get nodes -o wide kubectl top nodes如果kubectl top報(bào) metrics 不可用說(shuō)明 metrics-server 沒(méi)裝不影響部署但后面排查資源問(wèn)題會(huì)少一個(gè)手段建議順手補(bǔ)上。接著建獨(dú)立命名空間別和業(yè)務(wù)混在一起kubectl create namespace litellm kubectl config set-context --current --namespacelitellm然后是憑據(jù)這一層。TaoToken 的定位是統(tǒng)一入口你需要在控制臺(tái)生成一個(gè) API Key后面 LiteLLM 就用這個(gè) Key 去訪問(wèn)上游。地址方面官網(wǎng)入口是 https://taotoken.net/?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content API 基址是 https://taotoken.net/api 注意 API 地址不帶查詢參數(shù)配置里填的就是這個(gè)純基址。生成 Key 的入口在控制臺(tái)的 API Keys 頁(yè)面對(duì)應(yīng) deep link 是 https://taotoken.net/console/api-keys?utm_sourcetaotoken_aicg_blog_endutm_contentapi_keysutm_campaignrewrite 。拿到形如sk-開(kāi)頭的字符串后不要寫(xiě)進(jìn) YAML 明文用 Secret 存。這里有個(gè)細(xì)節(jié)LiteLLM 讀取上游憑據(jù)既支持環(huán)境變量也支持配置文件里的api_key字段兩種方式我都給出來(lái)你按團(tuán)隊(duì)習(xí)慣選。先把 Secret 建好鍵名統(tǒng)一用upstream_api_key避免和 LiteLLM 自身的 master key 混淆kubectl create secret generic litellm-upstream \ --namespacelitellm \ --from-literalupstream_api_keysk-你的TaoToken密鑰再建一個(gè)給 LiteLLM 網(wǎng)關(guān)自身用的 master key業(yè)務(wù)側(cè)調(diào)用集群內(nèi)網(wǎng)關(guān)時(shí)校驗(yàn)用kubectl create secret generic litellm-master \ --namespacelitellm \ --from-literalmaster_keysk-litellm-local-2024兩個(gè) Secret 分開(kāi)是有原因的上游 Key 泄露影響的是你的額度網(wǎng)關(guān) master key 泄露影響的是集群內(nèi)調(diào)用權(quán)限輪換節(jié)奏和范圍都不一樣。到這里前置就緒下一節(jié)進(jìn)入可復(fù)制的配置。3. 可復(fù)制的 ConfigMap 與 Deployment 配置這一節(jié)是全文的核心配置寫(xiě)對(duì)了后面基本一次過(guò)。LiteLLM 的配置分兩塊一塊是config.yaml描述模型列表和上游地址一塊是 Deployment 的環(huán)境變量告訴它去哪讀配置、用哪個(gè) master key。先寫(xiě) ConfigMap。注意api_base指向 TaoToken 的 API 基址model字段寫(xiě)你要路由的模型名model_name是暴露給業(yè)務(wù)側(cè)的別名業(yè)務(wù)只認(rèn)別名換后端時(shí)改這里就行apiVersion: v1 kind: ConfigMap metadata: name: litellm-config namespace: litellm data: config.yaml: | model_list: - model_name: gpt-4o-mini litellm_params: model: openai/gpt-4o-mini api_base: https://taotoken.net/api api_key: os.environ/UPSTREAM_API_KEY - model_name: claude-sonnet litellm_params: model: anthropic/claude-3-5-sonnet-20241022 api_base: https://taotoken.net/api api_key: os.environ/UPSTREAM_API_KEY general_settings: master_key: os.environ/LITELLM_MASTER_KEY database_url: litellm_settings: drop_params: true request_timeout: 600os.environ/UPSTREAM_API_KEY是 LiteLLM 的語(yǔ)法表示從環(huán)境變量取值這樣密鑰不進(jìn) ConfigMap。drop_params: true建議開(kāi)著不同上游對(duì)參數(shù)支持不一致多余參數(shù)直接丟棄比報(bào)錯(cuò)友好。接著是 Deployment。鏡像用官方鏡像端口 8000把 ConfigMap 掛到/app/config.yaml環(huán)境變量從兩個(gè) Secret 注入apiVersion: apps/v1 kind: Deployment metadata: name: litellm namespace: litellm labels: app: litellm spec: replicas: 2 selector: matchLabels: app: litellm template: metadata: labels: app: litellm spec: containers: - name: litellm image: ghcr.io/berriai/litellm:main-latest args: - --config - /app/config.yaml - --port - 8000 ports: - containerPort: 8000 env: - name: UPSTREAM_API_KEY valueFrom: secretKeyRef: name: litellm-upstream key: upstream_api_key - name: LITELLM_MASTER_KEY valueFrom: secretKeyRef: name: litellm-master key: master_key volumeMounts: - name: config mountPath: /app/config.yaml subPath: config.yaml readinessProbe: httpGet: path: /health/readiness port: 8000 initialDelaySeconds: 15 periodSeconds: 10 livenessProbe: httpGet: path: /health/liveness port: 8000 initialDelaySeconds: 30 periodSeconds: 20 resources: requests: cpu: 250m memory: 512Mi limits: cpu: 1 memory: 1Gi volumes: - name: config configMap: name: litellm-configService 用 ClusterIP 就夠集群內(nèi)業(yè)務(wù)通過(guò)litellm-service.litellm.svc.cluster.local:8000訪問(wèn)要對(duì)外再疊 IngressapiVersion: v1 kind: Service metadata: name: litellm-service namespace: litellm spec: selector: app: litellm ports: - protocol: TCP port: 8000 targetPort: 8000 type: ClusterIP一次性 applykubectl apply -f litellm-configmap.yaml kubectl apply -f litellm-deployment.yaml kubectl apply -f litellm-service.yaml kubectl get pods -n litellm -w看到兩個(gè) Pod 都Running且READY 1/1就說(shuō)明探針過(guò)了。如果卡在CrashLoopBackOff先看日志多半是 config.yaml 縮進(jìn)或環(huán)境變量名對(duì)不上下一節(jié)驗(yàn)證時(shí)會(huì)順帶覆蓋。4. 用 curl 驗(yàn)證模型列表與一次對(duì)話請(qǐng)求部署完不驗(yàn)證等于沒(méi)部署。驗(yàn)證分兩步先確認(rèn)網(wǎng)關(guān)活著并能列出模型再打一次真實(shí)對(duì)話請(qǐng)求確認(rèn)上游鏈路通。第一步端口轉(zhuǎn)發(fā)到本地避免依賴 Ingresskubectl port-forward -n litellm svc/litellm-service 8000:8000另開(kāi)一個(gè)終端帶上 master key 請(qǐng)求模型列表curl -s http://127.0.0.1:8000/v1/models \ -H Authorization: Bearer sk-litellm-local-2024 | jq .返回里應(yīng)該能看到gpt-4o-mini和claude-sonnet兩個(gè)別名。如果返回 401說(shuō)明 master key 沒(méi)對(duì)上檢查 Secret 里的值和請(qǐng)求頭是否一致。第二步打一次對(duì)話請(qǐng)求驗(yàn)證上游真的通curl -s http://127.0.0.1:8000/v1/chat/completions \ -H Authorization: Bearer sk-litellm-local-2024 \ -H Content-Type: application/json \ -d { model: gpt-4o-mini, messages: [{role: user, content: 用一句話說(shuō)明什么是網(wǎng)關(guān)}], max_tokens: 64 } | jq .choices[0].message.content能打印出一句話回答就說(shuō)明 LiteLLM 用 TaoToken 的 Key 成功路由到了上游。再換claude-sonnet打一次確認(rèn)多模型路由都通。這一步很關(guān)鍵模型列表能列出不代表上游可達(dá)只有真實(shí) completion 返回才算打通。如果你更想先在網(wǎng)頁(yè)里確認(rèn)模型可用性可以走模型對(duì)話入口 https://taotoken.net/model-chat?utm_sourcetaotoken_aicg_blog_endutm_contentmodel_chatutm_campaignrewrite 用同一個(gè) Key 手動(dòng)發(fā)一條和集群內(nèi)結(jié)果對(duì)照能快速區(qū)分是網(wǎng)關(guān)問(wèn)題還是上游問(wèn)題。驗(yàn)證通過(guò)后業(yè)務(wù)側(cè)接入就簡(jiǎn)單了把 OpenAI SDK 的base_url指向http://litellm-service.litellm.svc.cluster.local:8000/v1api_key填 master keymodel填別名。業(yè)務(wù)代碼零改動(dòng)換模型只改 ConfigMap。5. 常見(jiàn)報(bào)錯(cuò)排查401、local proxy failed 與 reading choices部署階段最容易撞的幾類報(bào)錯(cuò)我按真實(shí)日志對(duì)照給你排一遍。401 Unauthorized。兩種來(lái)源要分清一種是請(qǐng)求網(wǎng)關(guān)時(shí) master key 不對(duì)日志里是Authentication Error檢查請(qǐng)求頭Authorization: Bearer和 Secret 是否一致另一種是網(wǎng)關(guān)訪問(wèn)上游時(shí)被拒日志里會(huì)出現(xiàn)upstream字樣說(shuō)明 TaoToken 的 Key 無(wú)效或額度問(wèn)題去控制臺(tái)核對(duì) Key 狀態(tài)。區(qū)分方法看報(bào)錯(cuò)里有沒(méi)有l(wèi)itellm前綴。local proxy failed / connection refused。這通常是 Pod 沒(méi)起來(lái)或端口不對(duì)。先kubectl get pods -n litellm看狀態(tài)再kubectl logs -n litellm pod-name看啟動(dòng)日志。如果日志停在讀取 config多半是 ConfigMap 掛載路徑不對(duì)確認(rèn)mountPath是/app/config.yaml且subPath匹配。如果報(bào)Address already in use檢查 args 里的端口和 containerPort 是否一致。reading choices 相關(guān)報(bào)錯(cuò)。這類多半是上游返回結(jié)構(gòu)不符合預(yù)期常見(jiàn)于模型名寫(xiě)錯(cuò)或上游不支持該參數(shù)。日志里會(huì)帶KeyError: choices或reading choices。處理辦法先在模型對(duì)話頁(yè)面用同一模型名手動(dòng)發(fā)一次確認(rèn)上游本身可用再檢查 ConfigMap 里model字段的 provider 前綴是否正確比如openai/和anthropic/不能混。drop_params: true能擋掉一部分參數(shù)不兼容的問(wèn)題。OAuth / token 過(guò)期類報(bào)錯(cuò)。如果你用的是需要 OAuth 的 providerLiteLLM 側(cè)要額外配置憑據(jù)刷新純 API Key 模式不會(huì)遇到??吹絆Auth字樣先確認(rèn)是不是誤配了需要交互登錄的 provider統(tǒng)一走 TaoToken 的 Key 模式可以規(guī)避這類問(wèn)題。Pod 一直 Pending。資源不夠或節(jié)點(diǎn)親和性問(wèn)題kubectl describe pod -n litellm pod-name看 Events多半是 requests 超過(guò)節(jié)點(diǎn)可分配量把 requests 調(diào)小即可。排查時(shí)記住一個(gè)順序先看 Pod 狀態(tài)再看容器日志最后看上游連通性。三步能定位九成問(wèn)題。日志命令kubectl logs -n litellm -l applitellm --tail100 kubectl describe pod -n litellm -l applitellm6. 長(zhǎng)期編碼與 Agent 場(chǎng)景的接入建議集群里跑通 LiteLLM 只是第一步真正省心的是把它接到日常編碼和 Agent 工作流里。如果你團(tuán)隊(duì)在用 Claude Code 這類工具或者要跑長(zhǎng)任務(wù)的 Agent建議把網(wǎng)關(guān)地址和 Key 固化到工具配置里而不是每次手動(dòng)填。長(zhǎng)期編碼場(chǎng)景更適合用 Coding Plan 這類按周期計(jì)費(fèi)的方式入口在 https://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_contentcoding_planutm_campaignrewrite 配合集群內(nèi) LiteLLM 做統(tǒng)一出口額度管理和路由就都在你手里了。接入文檔在 https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_contentdocutm_campaignrewrite 里面有各語(yǔ)言 SDK 的 base_url 填法照著改就行。幾個(gè)落地經(jīng)驗(yàn)ConfigMap 改動(dòng)后記得kubectl rollout restart deployment/litellm -n litellmLiteLLM 不會(huì)自動(dòng)熱加載副本數(shù)別只開(kāi) 1 個(gè)滾動(dòng)更新時(shí)會(huì)有短暫不可用給網(wǎng)關(guān)加個(gè) NetworkPolicy只允許業(yè)務(wù)命名空間訪問(wèn) 8000 端口減少暴露面。密鑰輪換時(shí)先更新 Secret再重啟 Deployment業(yè)務(wù)側(cè)無(wú)感。到這里一個(gè)能穩(wěn)定路由多模型調(diào)用的 LiteLLM 網(wǎng)關(guān)就在集群里跑起來(lái)了。后續(xù)要加模型只改 ConfigMap 里的model_list業(yè)務(wù)代碼一行不用動(dòng)。