# 模型路由

Fallback 優先序、tier 與 dispatcher 模型如何決定由哪個模型回應。

## 模型優先序與 tier

已註冊模型以有序清單存於 `config.json` 的 `models`。此順序即 fallback 優先序（見下方 LLM fallback）。`POST /v1/model/priority` 會把列出的名稱依序移到最前面，其餘保持在後。

每個模型可在 `model_tag`（`{"<provider>@<model>": "<tier>"}`）帶一個 tier：

| Tier | 意義 |
|---|---|
| `S` | 最強——需要深度或精確度的程式與工作 |
| `A` | 多數工作的預設，比旗艦低一級 |
| `B` | 主流中階 |
| `C` | 快速便宜；能依指示穩定呼叫工具 |
| `pass` | 自動路由、subagent 與 fallback 永不挑選，即使請求指名也一樣（v1.1.0 起）；僅在 session 指定時使用 |

未設定 tier 的模型依內建命名規則判斷：S = `claude-fable`、`claude-opus`、`gpt-*-astra`；A = `gpt-*-sol`、`grok-4.5+`、`claude-sonnet`、`gpt-*-terra`、`gemini-*-pro`、`deepseek-pro`、`glm`、`kimi`；B = `claude-haiku`、`gpt-*-luna`、`gemini-*-flash`、4.5 以下的 `grok`、`deepseek`；C = `*-mini`、`*-nano`、`gemini-*-flash-lite` 與 open-weight 模型（`gemma*`、`gpt-oss`、`qwen*`、`llama*`）。v1.0.19 將 `gpt-*-sol` 與 `grok-4.5+` 由 S 調降為 A。Tier 每次請求即時讀取，變更不需重啟。

## LLM fallback

只有以 `auto` 執行的請求才會 fallback：綁定特定模型的 session，或指定 `model` 的 `/v1/chat/completions` 呼叫都不做 fallback。送出逾時時先在同一個模型重試，最多三次、間隔 15 秒；遇到 rate limit 則分別在 5、10、15 秒後重試，最多三次；超出 context window 時不換模型：v1.3.0 起 Agenvoy 取超限錯誤中最小的 token 數（至少 4,096）作為該模型在本次行程內的輸入上限，把最舊的歷史與工具步驟刪到原大小的 80% 以內（`CONTEXT_OVERFLOW_KEEP_RATIO`）後重送；v1.3.1 起刪減前會先移除 decision model 判定已用不到的工具步驟。已無可刪內容時以 `[Limit]` 錯誤結束。其餘送出失敗才轉手：Agenvoy 依優先序由上而下，略過 `pass` 模型與失敗模型同一供應商的所有模型，逐一做健康檢查（timeout 10 秒），由第一個有回應者接手。全部沒有回應時再跑一輪，最多四輪。最後一筆非 `pass` 項目是最後防線。

略過 context window 容納不下輸入之模型的行為移除於 v1.2.1。v1.0.20 之前 `pass` 模型一律被移到最後；v1.0.20 至 v1.0.27 間 fallback 仍會依它在清單中的位置嘗試。

## Dispatcher 模型

Dispatcher LLM 決定由哪個 worker 模型處理任務。它在 `exec.Run` 中經 `exec/model.Route` → `selectWithLLM` 執行（只要設定了 decision model 就與 `selectWithDecision` 同時競速，採用先取得的有效回覆，見 [Decision Model](/zh/providers-typesafe)；原本控制此行為的 `dispatcher_beta` 開關移除於 v1.3.2；TypeSafe 的 `selectWithJev` 路徑移除於 v1.3.1），早於 `Execute()` 進入迭代迴圈，輸入為已註冊模型清單、依解析後 tier 分組的所有模型（先看使用者設定，再套命名規則）、下方的工作類別表、使用者訊息，以及命中 skill 的提示。其路由呼叫以 `ReasoningNone` 發出，timeout 為 30 秒。

無意義時會略過路由：呼叫端明確指定的模型直接使用（未註冊則失敗）；session 綁定 `auto` 以外的模型時使用該模型；registry 只有一個可選模型時直接回傳。上述情況下若 session 的 reasoning 為 `auto`，仍會呼叫選擇器，但只取 reasoning 等級。

Dispatcher 第一行回傳工作類別、第二行回傳以逗號分隔的模型名稱（v1.1.0 起），因此 reasoning 為 `auto` 的 session 也能由工作類別決定等級，不需 decision model。第一個已註冊、非 `pass` 且未在冷卻中的名稱成為主要模型。自 v1.0.20 起，清單其餘部分不再決定 fallback——fallback 依上述優先序進行。它把請求歸入 [Decision Model](/zh/providers-typesafe) 頁表格中的五種工作類別之一，再依該類別的 tier 順序挑選。自 v1.0.21 起，LLM dispatcher、decision model 分派（v1.3.1 之前為 TypeSafe 分類器）與 subagent planner 讀取同一張工作類別表（`internal/session/config/tier.go`）與同一套命名規則，排序結果一致；在此之前 LLM dispatcher 不區分 `research` / `work`，code、chat、fetch 以外的請求一律走 S > A > B > C。Dispatcher 被告知永不回傳 `pass` 模型，仍回傳的 `pass` 名稱會被丟棄（v1.1.0 之前請求仍可指名）。同 tier 內，訂閱制供應商 `claude-code`、其次 `codex` 的模型排在所有其他供應商之前。同一基礎模型註冊於多個供應商時，優先 `claude-code`，其次 `codex` / `grok-oauth`，再來 `copilot`、直接 API，最後 `openrouter`。`reasoning_guide` 的 `subagent_dispatch` 主題把同一張表降一級（S→A、A→B、B→C）提供給主 agent，作為各 leg `model` 的參考，因此 `code` 工作的 leg 讀到 A > B > C > S。Dispatcher 呼叫失敗時，下一個 dispatcher 候選依固定的供應商排名挑選；全部無回應時僅依優先序決定。

在 TUI 以 `/model` → `dispatch`，或以帶 `dispatcher` 欄位的 `POST /v1/model` 設定。

自 v1.3.3 起 dispatcher model 也負責 `run_command`／`background_command` 確認上的一句說明：只在實際跳出確認時以 `ReasoningNone` 呼叫一次（唯讀指令不會詢問），只帶請求與該次呼叫，不讀也不寫入 session 歷史，上限 10 秒，回答截至 240 字元。未設定 dispatcher model 或呼叫失敗時，確認不顯示說明。
