客戶端只有一個模型:閘道器按對話狀態自動分檔
把模型選擇從使用者介面拿掉 —— 使用者端只暴露一個模型名,規劃走強模型、執行落價效比模型,分檔發生在請求本來就要經過的那一跳上。
社群真正在抱怨什麼
「每個人設定裡的模型都不一樣,同一份 prompt 在兩個人那裡跑出不同結果」「新人第一週問得最多的就是該選哪個模型」「我們要下線一個模型,得逐臺改開發機的環境變數」—— 模型選擇被推給了最沒有依據做這個判斷的人:使用者看不到自己的用量,更判斷不出這次請求值不值得上強模型。
一刀切降到便宜模型又會掉檔:規劃與架構判斷交給小模型,返工比省下的錢更貴。而真正該分的是「這次請求在做什麼」—— 規劃還是執行,這件事客戶端從來就沒告訴過閘道器。
GateLLM 怎麼做
客戶端只保留一個模型名,閘道器側用 from "*" 的全面映射把客戶端請求的任何名字正規化 —— 使用者在自己設定裡改成別的也不改變落點。使用者端不再需要解釋「該選哪個」。
分檔依據是對話裡本來就有的標記:Claude Code 的 plan 模式會注入 Plan mode is active(進入)與 Exited Plan Mode(退出)。指令碼掛在入口模型的 before 槽,從末尾訊息向前掃描、取末次出現的標記判定目前狀態,再調 context.useModel() 切路由 —— 判定是字串位置比較,不另起一次分類模型呼叫,也不多加一跳網路。
自動分檔必須掛 before 槽:after 槽拿到的是翻譯後的上游 body,讀不到客戶端注入的標記,且 after 槽的 useModel 只能同協議,而 plan 到執行是跨模型路由切換。入口模型與執行模型的 request_payload 類規則(如 prompt_cache_key)要各配一份 —— plan 態不切走、用入口模型的規則,執行態切走後用目標模型的規則。
落地的 5 個手段
- 入口正規化:客戶端只暴露一個模型名,from "*" 全面映射把任何客戶端名正規化為指定落點
- 自動分檔:before 槽指令碼從末尾向前取末次標記切路由 —— 進入標記會永久留在對話歷史,用「是否包含」判斷會永遠誤判為 plan 態
- 多協議護欄:指令碼開頭先判 context.sourceProtocol,非 Anthropic 請求直接放過 —— 同一個入口模型服務多種客戶端時不會被誤切走
- 可觀測:日誌模型列 SW 標籤標記指令碼切路、MM 標籤標記身份映射;統計與計費按最終模型名歸集,每次分檔的落點可稽核
- 零客戶端配合:改設定不用逐臺改開發機、映射與規則熱生效(唯一例外:指令碼記憶體上限 SCRIPT_MEMORY_LIMIT_MB 改動需重啟)