用一副韁繩駕馭多個 LLM:harness 概念入門
什麼是 agent harness?為什麼工程團隊會需要「同時牽引」好幾個大型語言模型,而不是只呼叫一支 API?
騎士第一次跨上 Tuco 的背時,抓到的不是韁繩,而是一團亂線——三個模型、 兩套工具、一個不知道該聽誰的判斷。「harness」這個詞,原本就是拿來解決這 個問題的:它不是某支模型,而是包住模型的那層駕馭結構。
harness 到底是什麼
如果把 LLM API 想成一匹會跑但不聽話的馬,harness 就是韁繩、馬鞍、腳蹬 的總和。具體到工程上,一個 agent harness 通常包含:
- 呼叫層:重試、逾時、降級(model A 掛了自動切 model B)
- 工具層:function calling / tool use 的註冊、驗證、執行沙盒
- 記憶層:對話歷史、長期記憶、RAG 檢索結果如何塞進 context
- 仲裁層:多個模型的輸出誰說了算、要不要投票、要不要人工複核
單一模型呼叫不需要 harness,你直接打 API 就好。但一旦你的系統要「同時 牽引」兩個以上的模型——不管是因為成本、延遲、還是專長分工——harness 就從「加分項」變成「必需品」。
為什麼是「多個」模型
一顆星星就能照亮一條航道,但要繪製整片星圖,你需要好幾顆同時運作、 分工不同的星星。實務上,多模型 harness 常見的分工模式有三種:
- 路由(Router):一個小而快的模型先判斷任務類型,把請求分派給 最適合、最省成本的下游模型。
- 專才(Specialist):規劃模型負責拆解任務,執行模型負責寫程式或 呼叫工具,審查模型負責挑錯——分工明確,互不越界。
- 合議(Ensemble):同一個問題丟給多個模型,再用規則或另一個模型 彙整、投票,換取更穩定的輸出品質。
一個最小可行的 router harness,把請求依任務類型分派給三個下游模型:
type Task = 'plan' | 'code' | 'review';
const roster: Record<Task, string> = {
plan: 'model-a-planner',
code: 'model-b-coder',
review: 'model-c-reviewer',
};
async function dispatch(task: Task, input: string) {
const model = roster[task];
const result = await callModel(model, input);
return { model, result };
}騎士只需要決定「這一段航程該交給哪顆星星」,韁繩會處理剩下的呼叫細節。
韁繩鬆緊之間:harness 的取捨
harness 寫得越厚重,系統看起來越「聰明」,但也越難除錯、越貴、延遲越 高。所以設計 harness 時,真正的技術決策往往不是「要不要多模型」,而是 「要在哪一層收緊韁繩」:
- 呼叫層太鬆:一個模型逾時,整個系統卡死。
- 仲裁層太緊:每個回應都要三個模型輪流審查,延遲和帳單一起爆炸。
- 記憶層太鬆:context 塞爆,模型開始「失憶」或幻覺。
從一支 API 到一套駕馭系統
寫過最簡單的聊天機器人的人都知道,呼叫一支 LLM API 只需要幾行程式碼。 但當你的產品需要「規劃 + 執行 + 審查」同時運作,或是需要在延遲與品質 之間動態取捨,你其實已經在建造一套 harness 了——差別只在於你是不是 有意識地在設計它。
Tuco 背上的韁繩,從來不是用來控制牠往哪裡走,而是讓騎士在牠既有的 方向感之上,多一層可以收放的判斷力。好的 harness 也是一樣:它不取代 模型的能力,只是讓那份能力,能被穩定、可預期地牽引到目的地。