供應商
Provider 實作位於外部模組 go-llm-router(v0.6.0),由 Agenvoy 抽出獨立維護。Agenvoy 一律透過 router.New(cfg) 建立 agent,並只呼叫單一 Agent.Send() 介面——本 repo 內已無任何 per-vendor 實作。
支援清單
共 11 家廠商。同時提供按量計費與訂閱兩種存取方式者,在 TUI 中兩條路徑收在同一列 —— 選完供應商後才會問要用哪一種,因此 Codex 與 xAI OAuth 在 TUI 中屬於認證方式而非獨立供應商。TUI /model add 清單因此共 12 列:11 家廠商加上 Local/Custom(compat)。GET /v1/providers 則把同一組攤平為 13 個條目,讓 codex 與 grok-oauth 各有自己的 ID,API client 可直接指定某一條認證路徑;compat 併列其後為第 14 筆。每筆另帶 logged_in,僅對三條 OAuth 路徑(codex、grok-oauth、copilot)有意義。
| 供應商 | ID | 認證 | 說明 |
|---|---|---|---|
| OpenAI | openai · codex |
API key 或 OAuth | API key 走 Chat Completions / Responses;OAuth 路徑使用 ChatGPT / Codex 訂閱,不需 API key,以 SSE 串流 |
| Anthropic Claude | claude |
API key | Messages API;預設啟用平行 tool use |
| Google Gemini | gemini |
API key | gemini-2.x / 3.x 系列 |
| xAI Grok | grok · grok-oauth |
API key 或 OAuth | API key 為按量計費;OAuth 路徑使用 xAI 訂閱 |
| GitHub Copilot | copilot |
OAuth | Device-code 登入流程,使用 GitHub 訂閱 |
| DeepSeek | deepseek |
API key | deepseek-chat(支援 tool use)與 deepseek-reasoner |
| Mistral | mistral |
API key | Mistral 自家託管模型 |
| NVIDIA NIM | nvidia |
API key | Nemotron、Llama、Mistral 等託管開源權重模型;免費額度不需綁定付款方式 |
| Ollama Cloud | ollama-cloud |
API key | Ollama 託管模型;額度以百分比顯示 |
| OpenRouter | openrouter |
API key | 聚合器——單一 key 路由到多家供應商的模型 |
| Cloudflare | cloudflare |
API token + account ID | Workers AI;可選填 gateway ID |
任何 OpenAI 相容端點
這 11 家之外,compat(Local/Custom)並不是第 12 家廠商,而是讓這份清單不封閉的擴充口。指向任何 OpenAI 相容的 /v1 base URL(可選填 key),它就成為可用的後端:Ollama、LM Studio、vLLM、LiteLLM、自架 gateway,或上週才推出 OpenAI 形狀 API 的新廠商。要接幾個就接幾個,每一個都是獨立命名的項目。
內建兩個本機端點(configs/jsons/local_compat.json):Ollama Local(http://localhost:11434/v1)與 Llama.cpp Local(http://localhost:8080/v1)。/model add 會以 GET /models 平行探測兩者(預算 500 ms),有回應者列在供應商清單最上方,直接進入模型選擇,不會寫入 config.json。端點模型以 <name>@<model> 註冊,端點名稱轉小寫(ollama@gemma3:4b);舊的 compat[NAME]@<model> 形式仍可接受,並在 config.json 載入或儲存時改寫為新形式。
新增模型時(TUI /model → add,或 GET /v1/provider/:provider/models)會即時取得模型清單;本機或自訂端點則取自該端點自己的 GET /models。repo 內不再存放靜態模型目錄。
設定
一切由 TUI 或本機 HTTP API 管理——沒有 agen model CLI 子指令:
| 工作 | TUI | HTTP |
|---|---|---|
| 新增 / 移除供應商或模型 | /model → add;在模型列按 d 移除 |
POST /v1/models、DELETE /v1/models/*name |
| 調整 fallback 優先序 | — | GET POST /v1/model/priority — {models} |
| 設定模型 tier | /model,在模型列按 t |
POST /v1/model/tier — {model, tier} |
| 選擇 dispatcher 模型 | /model → dispatch |
GET POST /v1/model — {dispatcher} |
| 選擇 summary 模型 | /model → summary |
GET POST /v1/model — {summary} |
| 選擇圖像產生器 | /model → image |
GET POST /v1/model — {image},填 provider 端點而非模型名稱 |
| 選擇 speech-to-text 模型 | /model → stt |
GET POST /v1/model — {stt},取值來自 GET /v1/model/audio |
| 選擇 text-to-speech 模型 | /model → tts |
GET POST /v1/model — {tts},取值來自 GET /v1/model/audio |
| 選擇 session 使用的模型 | /model(或以 Shift+W / Shift+S 在 auto 與已註冊模型間輪替) |
POST /v1/session/:id — {model, reasoning} |
| 儲存憑證 | /key |
POST /v1/provider/:provider/key |
| OAuth 登入 | /model |
GET /v1/provider/:provider/oauth(SSE device code) |
| 清除 OAuth 登入 | /model |
DELETE /v1/provider/:provider/oauth |
| 查詢額度 / 餘額 | Shift+U |
GET /v1/providers/quota |
模型路由是單一物件:GET / POST /v1/model 一併讀取與部分更新 dispatcher、summary、image、stt 與 tts。未帶到的欄位不動,"" 為清除。寫入 config.json 時對應 dispatcher_model、summary_model、image_generator、stt_model 與 tts_model。
音訊路由與模型註冊表分離。stt 與 tts 不是從 /model add 註冊過的模型中挑選,而是向目前握有憑證的 OpenAI 與 Gemini 即時查詢;現階段也只有這兩家支援音訊。tts 選 off 會同時把 generate_audio 從工具集中移除;stt 選 off 則讓 read_files 不再轉錄音訊與影片,Telegram / Discord 收到的語音訊息也會直接回覆提示要先選模型。
憑證(API key、OAuth token)存放於 OS keychain 的 agenvoy 服務,絕不寫入純文字 JSON。config.json 的 keys 只記錄已儲存的 key 名稱。
Daemon 監看 config.json;寫入後會重新載入 agent registry(並重連 Telegram / Discord),不需重啟。
模型優先序與 tier
已註冊模型以有序清單存於 config.json 的 models。此順序即 fallback 優先序:第一筆最先嘗試,最後一筆是最後防線。POST /v1/model/priority 會把列出的名稱依序移到最前面,其餘保持在後。
每個模型可在 model_tag({"<provider>@<model>": "<tier>"})帶一個 tier:
| Tier | 意義 |
|---|---|
S |
最強——需要深度或精確度的程式與工作 |
A |
多數工作的預設,比旗艦低一級 |
B |
主流中階 |
C |
快速便宜;能依指示穩定呼叫工具 |
pass |
自動路由與 subagent 永不挑選;fallback 排最後;可為 session 指定使用 |
未設定 tier 的模型依內建命名規則判斷。Tier 每次請求即時讀取,變更不需重啟。
Dispatcher 模型
Dispatcher LLM 決定由哪個 worker 模型處理任務。它在 exec.Start 中經 ResolveAgent → SelectAgentNames 執行,早於 Execute() 進入迭代迴圈,輸入為已註冊模型清單、目前的 tier 設定、使用者訊息,以及命中 skill 的提示。其路由呼叫以 ReasoningNone 發出,timeout 為 30 秒。
無意義時會略過路由:呼叫端明確指定的模型直接使用(未註冊則失敗);session 綁定 auto 以外的模型時使用該模型;registry 只有一個模型時直接回傳。
Dispatcher 回傳以逗號分隔的模型名稱。未知或冷卻中的名稱會被捨棄;其餘已註冊模型依優先序附加在後,pass tier 模型永遠排最後。同一基礎模型註冊於多個供應商時,優先 codex / grok-oauth,其次 copilot,再來直接 API,最後 openrouter。Dispatcher 呼叫失敗時,下一個 dispatcher 候選依固定的供應商排名挑選;全部無回應時僅依優先序決定。
在 TUI 以 /model → dispatch,或以帶 dispatcher 欄位的 POST /v1/model 設定。
Reasoning 等級
go-llm-router 將 reasoning 正規化為單一尺度——none、low、medium(預設)、high、xhigh、max——並依供應商映射(Claude thinking budget、Gemini thinking budget、OpenAI effort 等)。別名 minimal、extra、ultra 分別對應 low、xhigh、max。超出模型支援範圍的等級會被夾限(clamp),而非直接拒絕。
等級透過每次 Send 呼叫明確傳入;config.json 內沒有全域 reasoning 設定。在 TUI 以 Shift+A / Shift+D 輪替。
Fast 模式
Shift+F 切換 fast 模式,透過 router 傳遞 provider.ModeFast,讓支援的後端要求更快的服務層級。支援與否依模型而定(core.SupportFast)——例如較新的 OpenAI 世代、Claude Opus 4.8 / Opus 5、多數 Grok 模型與特定 Gemini 系列。不支援的模型會靜默回到預設層級。Fast 模式為行程區域性,不會持久化。
新增自訂 OpenAI 相容端點
使用 Local/Custom(compat),指向任何接受 OpenAI Chat Completions schema 的端點。URL 慣例沿用 Zed:輸入到 /v1 為止(例如 http://192.168.1.10:4000/v1);router 會自行接上 /chat/completions。內建的 Ollama 與 llama.cpp 連接埠不需另建條目。
儲存拆分(URL 與 key)
| 項目 | 位置 | API |
|---|---|---|
| URL | ~/.config/agenvoy/config.json 的 compats[] — {provider, url},provider 名稱轉大寫 |
config.UpsertCompat / config.GetCompatURL(internal/session/config) |
| API key | OS keychain | keychain.Set("COMPAT_<NAME>_API_KEY", value) |
GetCompatURL 先查 compats,再查內建本機端點。沒有 COMPAT_<NAME>_URL 這個 keychain key——它在一次「TUI 寫入 config、runtime 卻讀 keychain 導致永遠回退到 localhost」的 bug 後被移除。
已驗證的 compat 目標
| 目標 | 可用 | 說明 |
|---|---|---|
| Ollama | 是 | 內建於 http://localhost:11434/v1 |
| llama.cpp server | 是 | 內建於 http://localhost:8080/v1 |
| LM Studio | 是 | |
| vLLM | 是 | tool use 需 --enable-auto-tool-choice --tool-call-parser <name> |
| LiteLLM proxy | 是 | 以 virtual key 當作 Bearer token |
| Groq / Together / DeepInfra / Fireworks | 是 | |
| Azure OpenAI | 否 | 需要 api-key header(非 Bearer)與 ?api-version=——不支援 |
Send timeout 與失敗處理
| 層級 | 值 | 攔截的問題 |
|---|---|---|
| Provider HTTP client | 由 go-llm-router 各 provider 內部設定 |
傳輸層卡住 |
AgentSendTimeoutSec |
config.json 的 limits.agent_send_timeout_seconds,預設 600 |
exec 層以 context.WithTimeout 設下的上限 |
| 無回應 watchdog | 每 30 秒探測;探測失敗後每 10 秒重試;失敗 3 次即切換模型 | 串流卡住但未報錯 |
| Health check | 10 秒 | 各 fallback 候選的存活探測 |
失敗時 exec 層對 timeout 於同一模型最多嘗試三次(間隔 15 秒)、對 rate limit 於同一模型在 5 / 10 / 15 秒後重試,並對 rate-limit 與額度錯誤註冊 30 分鐘 cooldown;額度錯誤會立即切換。之後改用其他供應商的下一個健康模型。完整升級表見執行引擎頁。