一 Key 通道配置與報錯排查)
1. crewai 里 Litellm 報 BadRequestError先別急著改源碼如果你在用 crewai 搭多智能體流程模型層走的是 Litellm然后某天突然拋出一個litellm.exceptions.BadRequestError大概率不是 crewai 本身壞了也不是 Litellm 不支持國內(nèi)模型服務(wù)而是模型名和 base_url 的寫法沒對上 Litellm 的路由規(guī)則。我自己第一次遇到這個報錯時第一反應(yīng)是「Litellm 是不是不認(rèn)國內(nèi)這些 OpenAI 兼容端點」甚至去翻 Litellm 的 provider 源碼想加分支。結(jié)果折騰半天發(fā)現(xiàn)問題根本不在支持不支持而在于模型名前綴少寫了一個openai/。Litellm 看到?jīng)]有前綴的模型名會按它內(nèi)置的 provider 映射去猜猜不到就走到默認(rèn)分支參數(shù)拼出來不對服務(wù)端直接返回 400于是包裝成BadRequestError拋給你。這篇就圍繞這個場景展開crewai 調(diào)用 Litellm 時出現(xiàn)BadRequestError的排查路徑覆蓋 openai 兼容接口、模型名與 base_url 配置給出可復(fù)制的config.toml/settings.json骨架以及 TaoToken 統(tǒng)一 Key 通道的接入步驟。適合正在用 crewai Litellm 接國內(nèi)模型、被 400 卡住的人。核心檢索詞就三個crewai、Litellm、BadRequestError。先說結(jié)論最容易被忽略的一行改動是# 報錯寫法 llm LLM(modelqwen3-235b-a22b-instruct-2507, base_url..., api_keysk-xxx) # 正確寫法模型名前加 openai/ llm LLM(modelopenai/qwen3-235b-a22b-instruct-2507, base_url..., api_keysk-xxx)openai/這個前綴不是讓你去調(diào) OpenAI 官方而是告訴 Litellm這是一個 OpenAI 兼容端點請走/chat/completions那條路由。下面把原理、配置、驗證、排障一步步拆開。2. 為什么加openai/前綴就能解決 BadRequestError2.1 Litellm 的 provider 路由邏輯Litellm 處理一個模型名時會先做一次「provider 解析」。它的規(guī)則大致是如果模型名里帶/斜杠前面那段就被當(dāng)作 provider 標(biāo)識如果沒有斜杠就拿整個字符串去匹配內(nèi)置的模型清單。你寫qwen3-235b-a22b-instruct-2507沒有斜杠Litellm 在內(nèi)置清單里找不到完全匹配項就會 fallback 到默認(rèn) provider 推斷。推斷出來的調(diào)用方式和你的 base_url 不匹配請求體里可能缺字段、或者 endpoint 拼錯服務(wù)端返回 400。你寫openai/qwen3-235b-a22b-instruct-2507斜杠前是openaiLitellm 立刻知道走 OpenAI 兼容協(xié)議用 openai-client 發(fā)請求自動補(bǔ)/chat/completions。模型名斜杠后的部分原樣傳給服務(wù)端。這樣 base_url 指向哪個兼容服務(wù)都行。2.2 base_url 不要畫蛇添足官方文檔里有一句很關(guān)鍵的話不要在 base_url 上添加任何額外內(nèi)容比如/v1/embedding。LiteLLM 用 openai-client 發(fā)請求會自動補(bǔ)上相關(guān)端點路徑。也就是說你的 base_url 應(yīng)該停在版本號那一層https://your-endpoint.example.com/v1而不是https://your-endpoint.example.com/v1/chat/completions # 錯多寫一段路徑openai-client 再拼一次就變成/v1/chat/completions/chat/completions服務(wù)端當(dāng)然 400。2.3 兩種前綴對應(yīng)兩種端點你要調(diào)的端點模型名前綴說明/chat/completionsopenai/對話補(bǔ)全最常用/completionstext-completion-openai/傳統(tǒng)文本補(bǔ)全通過/v1/completions路由調(diào) openai 端點不需要額外前綴走路由時自動識別crewai 里的 LLM 調(diào)用基本都是對話補(bǔ)全所以記住openai/就夠了。3. TaoToken 統(tǒng)一 Key 通道的前置準(zhǔn)備3.1 為什么用統(tǒng)一 Key 通道crewai 項目里往往不止一個模型規(guī)劃用一個大模型執(zhí)行用另一個評審再用一個。如果每個模型都單獨配 key、單獨記 base_url配置會散得到處都是排查BadRequestError時你甚至分不清是哪個通道出的問題。統(tǒng)一 Key 通道的思路是所有 OpenAI 兼容請求都走同一個入口模型名區(qū)分具體模型key 只有一份。這樣配置集中、報錯集中、切換模型只改一個字符串。3.2 拿到 Key 和入口地址進(jìn)入控制臺創(chuàng)建 API Key入口在這里控制臺https://taotoken.net/console?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteAPI Keys 管理https://taotoken.net/api-keys?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewrite創(chuàng)建后你會得到一串sk-開頭的 key。base_url 用 API 地址https://taotoken.net/api注意這里不要在后面加/v1/chat/completions原因見 2.2。如果你用的客戶端要求帶版本號就寫到/api這一層讓 openai-client 自己補(bǔ)。3.3 環(huán)境變量先落地在動手改 crewai 代碼前先把 key 放進(jìn)環(huán)境變量避免硬編碼export TAOTOKEN_API_KEYsk-你的key export TAOTOKEN_BASE_URLhttps://taotoken.net/apiWindows PowerShell$env:TAOTOKEN_API_KEYsk-你的key $env:TAOTOKEN_BASE_URLhttps://taotoken.net/api這樣后面 config.toml 和代碼里都引用變量名換 key 不用改文件。4. 可復(fù)制的 config.toml 與 settings.json 骨架4.1 crewai 的 config.toml 骨架crewai 新版本支持用config.toml管理 LLM 配置。下面這份可以直接抄重點是model字段帶openai/前綴# config.toml [llm] # 統(tǒng)一走 OpenAI 兼容通道前綴 openai/ 不能省 model openai/qwen3-235b-a22b-instruct-2507 base_url https://taotoken.net/api api_key env:TAOTOKEN_API_KEY temperature 0.3 max_tokens 2048 [llm.fallback] model openai/qwen3-235b-a22b-instruct-2507 base_url https://taotoken.net/api api_key env:TAOTOKEN_API_KEYapi_key env:TAOTOKEN_API_KEY這種寫法讓 crewai 從環(huán)境變量讀不把 key 寫進(jìn)倉庫。4.2 settings.json 骨架如果你的項目用 JSON 配置等價寫法{ llm: { model: openai/qwen3-235b-a22b-instruct-2507, base_url: https://taotoken.net/api, api_key: env:TAOTOKEN_API_KEY, temperature: 0.3, max_tokens: 2048 } }4.3 代碼里直接構(gòu)造 LLM不走配置文件、直接在 Python 里構(gòu)造也可以import os from crewai import LLM llm LLM( modelopenai/qwen3-235b-a22b-instruct-2507, base_urlos.environ[TAOTOKEN_BASE_URL], api_keyos.environ[TAOTOKEN_API_KEY], ) if __name__ __main__: response llm.call( Analyze the following messages and return the name, age, and breed. Meet Kona! She is 3 years old and is a black german shepherd. ) print(response)對比一下報錯版本和修復(fù)版本唯一區(qū)別就是model字段# 報 BadRequestError modelqwen3-235b-a22b-instruct-2507 # 正常 modelopenai/qwen3-235b-a22b-instruct-25074.4 多模型場景的配置crewai 里不同 agent 用不同模型時每個都帶前綴[llm.planner] model openai/qwen3-235b-a22b-instruct-2507 base_url https://taotoken.net/api api_key env:TAOTOKEN_API_KEY [llm.executor] model openai/qwen3-235b-a22b-instruct-2507 base_url https://taotoken.net/api api_key env:TAOTOKEN_API_KEY模型名不同就換斜杠后面那段前綴和 base_url 保持不變。5. 最小復(fù)現(xiàn)請求與驗證動作5.1 先用 curl 驗證通道本身在改 crewai 之前先用 curl 確認(rèn) key 和 base_url 是通的把變量隔離出來curl -sS https://taotoken.net/api/chat/completions \ -H Authorization: Bearer $TAOTOKEN_API_KEY \ -H Content-Type: application/json \ -d { model: qwen3-235b-a22b-instruct-2507, messages: [{role: user, content: reply with ok}], max_tokens: 16 }注意這里 curl 直接打/chat/completions因為 curl 不會自動補(bǔ)路徑。如果這一步返回正常 JSON說明 key 和通道沒問題問題在 Litellm 的模型名寫法上。5.2 再用 Litellm 單獨驗證繞開 crewai直接調(diào) Litellm確認(rèn)前綴規(guī)則import os from litellm import completion resp completion( modelopenai/qwen3-235b-a22b-instruct-2507, base_urlos.environ[TAOTOKEN_BASE_URL], api_keyos.environ[TAOTOKEN_API_KEY], messages[{role: user, content: reply with ok}], max_tokens16, ) print(resp.choices[0].message.content)如果這個能通而 crewai 里不通那就是 crewai 的配置沒把model字段傳對。5.3 最后跑 crewai 最小示例import os from crewai import LLM llm LLM( modelopenai/qwen3-235b-a22b-instruct-2507, base_urlos.environ[TAOTOKEN_BASE_URL], api_keyos.environ[TAOTOKEN_API_KEY], ) response llm.call(Say hello in one word.) print(response)三步驗證的順序很重要curl 驗通道 → Litellm 驗前綴 → crewai 驗集成。哪一步斷掉問題就鎖定在哪一層。5.4 成功結(jié)果長什么樣正常返回是一段文本比如Hello。如果返回里帶choices、usage這些字段說明走的是標(biāo)準(zhǔn) OpenAI 兼容響應(yīng)結(jié)構(gòu)。crewai 拿到這個結(jié)構(gòu)后自己解析不會再拋BadRequestError。6. 本篇常見錯排查清單6.1 模型名沒加openai/前綴這是最高頻的原因。癥狀是BadRequestError堆棧里能看到get_llm_provider相關(guān)調(diào)用。修復(fù)就是加前綴。判斷方法把模型名打印出來看斜杠前是不是openai。6.2 base_url 多寫了路徑癥狀同樣是 400但錯誤信息里可能帶Not Found或路徑重復(fù)。檢查 base_url 是不是寫成了.../api/v1/chat/completions。正確寫法停在https://taotoken.net/api。6.3 前綴和端點不匹配調(diào)/chat/completions用了text-completion-openai/或者反過來。對照 2.3 的表格改。crewai 場景基本都是openai/。6.4 key 沒讀到環(huán)境變量癥狀是 401 而不是 400但有時會被包裝成BadRequestError。檢查os.environ.get(TAOTOKEN_API_KEY)是否有值。config.toml 里寫env:TAOTOKEN_API_KEY時確認(rèn)變量名拼寫一致。6.5 模型名斜杠后拼錯前綴對了但斜杠后的模型名寫錯服務(wù)端找不到模型也可能返回 400。把模型名復(fù)制到 curl 里單獨測一次確認(rèn)服務(wù)端認(rèn)這個名字。6.6 crewai 版本差異老版本 crewai 的 LLM 構(gòu)造參數(shù)和新版本略有不同。如果base_url傳了不生效檢查是不是要用api_base。看 crewai 的 LLM 類簽名或者打印llm.__dict__確認(rèn)參數(shù)進(jìn)去了。6.7 排查順序建議遇到BadRequestError別一上來就改源碼。按這個順序走先看模型名有沒有openai/前綴 → 再看 base_url 有沒有多寫路徑 → 再用 curl 驗通道 → 再用 Litellm 驗前綴 → 最后看 crewai 配置。九成問題在前兩步就解決了。7. 接入文檔與后續(xù)動作配置和排查都跑通后建議把 key 管理、模型切換這些動作固定下來。需要看更細(xì)的接入說明可以走接入文檔接入文檔https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteAPI Keys 管理https://taotoken.net/api-keys?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewrite如果你只是想快速驗證某個模型名能不能通用模型對話頁面直接試模型對話https://taotoken.net/chat?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewrite如果你在搭長期的編碼 Agent 或者多智能體流水線模型調(diào)用量大、需要穩(wěn)定通道可以看 Coding PlanCoding Planhttps://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewrite回到這篇的核心crewai 下 Litellm 的BadRequestError絕大多數(shù)情況就是模型名少了個openai/前綴加上就好。base_url 停在版本層別多寫路徑。先用 curl 驗通道再用 Litellm 驗前綴最后跑 crewai問題定位會快很多。