跑在開源模型上
模型層是怎麼跟代理層分開的——能力探測、多後端分流,以及小型開源模型在工具呼叫上那四種壞法,閘道各自替你處理掉的方式。
這裡的代理,不是針對某一個特定模型寫出來的。代理層需要的一切——對話、向量化、工具呼叫——都經過同一道閘道,而這道閘道說的是 OpenAI 相容的 HTTP 形狀,所以後面那個模型可以是託管的前沿 API、你自己跑的開源模型,或同時好幾個。
這一頁講的是這個說法底下的工程細節。它存在的理由很簡單:「支援開源模型」很好說,卻很難驗證,而正在評估平台的人,本來就該問到底。
這道閘道
後端就是資料表裡的一列,範圍限縮在該租戶內。每一列帶著 base URL、API 金鑰、模型名稱、種類(chat 或
embedding)和權重。新增或替換一個後端是改設定——不必部署,也不必重寫代理。
整個相依樹裡沒有任何一家廠商的 SDK。閘道發出的是對 OpenAI 相容介面的普通 HTTP 請求,所以只要實作了那個介面的東西——vLLM、Ollama、llama.cpp 的伺服器、多數商用 API——都不需要轉接程式碼就能用。
能力是探測出來的,不是假設出來的
啟動時,閘道會對一個已啟用的後端呼叫 /v1/models,讀回這個模型實際提供什麼:脈絡視窗、向量維度、宣告的能力。
模型的任何一項都沒有寫死。這件事的份量比表面上重:一個假設脈絡視窗有前沿模型那麼大的平台,遇到 32K 視窗的開源模型就會靜靜地溢出,而故障浮現的形式是一個被截斷或不知所云的答案,不是一則錯誤。
後端沒有回應探測時,閘道會把視窗記成未知,並且選擇不做裁切,而不是猜一個小數字。猜錯會無聲地刪掉模型原本用得上的脈絡;試了失敗,至少看得見。
小型開源模型的四種壞法
這些都不是假想的。每一項會被處理,都是因為它真的發生過。
1. 工具呼叫是以文字送過來的
很多開源模型無視結構化的 tool_calls 欄位,改把呼叫寫進回覆內文裡。常見的有兩種形狀:
<tool_call>
<function=search_docs>
<parameter=query>refund policy</parameter>
</function>
</tool_call><tool_call>
{"name": "search_docs", "arguments": {"query": "refund policy"}}
</tool_call>放著不處理,結果就是什麼都沒執行,而終端使用者在對話裡看到一堆原始標記。工具迴圈兩種形狀都解析、照常派送工具,並且——作為最後一道防線——在文字送出去之前,把任何殘留的 <tool_call> 標記清掉。原始的工具呼叫語法絕不能出現在終端使用者眼前,即使解析失敗也一樣。
2. 串流的工具呼叫是碎片
OpenAI 相容的伺服器,對於一次工具呼叫該怎麼切進串流區塊,各有各的做法。同一次呼叫可能拆成好幾個 partial delta 送達,模型一次要求多個工具時甚至會交錯。碎片會依索引累積、重組成完整的呼叫,之後才會有任何工具被執行。
3. 脈絡預算必須從真實的視窗算出來
可用的輸入預算是推算出來的,不是設定出來的:
input_budget =
probed_context_window − output_reservation − safety_margin並且設有下限,讓過於激進的保留量不至於把預算壓到零。在 32K 的模型上算出來的預算,和在百萬 token 的模型上完全不同,而這正是重點——同一份代理定義,在兩邊都跑得正確。
4. 推理把答案吃掉
在會先輸出推理、再給最終答案的模型上,一個只按答案長度抓的輸出預算會被推理吃光,使用者收到的是被截斷的回覆。輸出額度會往上調,把推理的 token 算進去,讓答案本身活下來。
分流與接手
同一種類的後端依權重挑選,所以流量可以拆——例如大部分請求走自架的小模型,其餘走比較強的託管模型。當一次請求以可重試的方式失敗時,閘道會先試其他符合條件的後端,之後才退回到對同一個後端做指數退避重試。
實務上的切法是看後果,不是看難度:唯讀、低風險的工作交給便宜的模型,任何會寫入或會定案的動作交給強的那一個。
這件事不做什麼
把邊界講清楚,比再列一串功能有用:
- 它不會讓小模型變得跟大模型一樣強。 工具的挑選——在一個雜亂的多步驟情境裡,判斷該呼叫哪個工具、帶什麼參數——最看得出模型素質的差距。把後果重大的工作搬到較小的模型之前,請先拿你自己的任務測過。
- 它不負責管理你的推論基礎設施。 如果你自架,GPU 容量、模型伺服器和它的可用時間都是你的事。閘道會繞過掛掉的後端;它沒辦法讓某個後端變快。
- 它不認證特定模型。 相容性工作針對的是模型會產出的那些形狀,不是一份測過的清單。任何 OpenAI 相容端點都預期可用;哪個模型適合你的工作負載,是你該自己跑一次的評估。