標籤: 多模型協作

  • 別讓 LLM 幫你丟銅板

    別讓 LLM 幫你丟銅板

    📌 本文重點

    • 用小決策模型取代 LLM 處理「丟銅板」級判斷
    • 建立「雙大腦」架構:小模型決策,大模型推理
    • 以 0.8B/2B 模型降低成本、延遲並集中安全邏輯

    多數現在的 Agent pipeline,都在做一件超浪費的事:用昂貴的 LLM 做「單選題」、「要不要重試」、「走哪條 route」。結果是:

    • 每個小決策都要 多幾百 ms~數秒延遲
    • 成本被這些「丟銅板級」判斷吃掉 30–60%
    • 因為每次都要 prompt LLM,安全策略與控制邏輯難以驗證與重用

    💡 關鍵: 把「銅板級小決策」從 LLM 移到輕量模型,可大幅省下 30–60% 的成本與延遲開銷。

    System One / Decision Models(如 Jev、Jeff 系列)解的,就是這一層「決策邏輯」:不產生長文本,只輸出結構化 label / probabilities,在 20–50 ms 內做完一次判斷,讓 LLM 專心做它擅長的長文本推理與生成。

    下面會講:為什麼要導入這種決策模型、如何在現有 Agent 中插入一顆 0.8B/2B 模型,實作「雙大腦」架構,最後整理導入時的注意事項與常見踩坑。


    重點說明

    1. 先拆開:「決策」≠「生成」

    目前常見 Agent(工具調用、Router、Guardrail)都有這類 pattern:

    • 決定 用哪個 tool:"tool_1" / "tool_2" / "none"
    • 判斷 要不要重試:"retry" / "abort"
    • 風險標註:"low" / "medium" / "high"

    傳統作法是:

    1. 把上下文丟給 LLM
    2. 要求輸出 JSON
    3. 再 parse 成一個 label

    這會導致:

    • 成本:每次小決策都耗一個完整 LLM call
    • 延遲:生成 + parsing 帶來 300ms–數秒
    • 安全性:Prompt 工程非常脆弱,一個格式錯就整個 decision pipeline 崩

    System One 決策模型的設計哲學是:

    給我一個 context + 選項列表,我只回傳 每個選項的機率分佈,不跟你聊天。

    像 Jev 或開源 Jeff:

    • 輸入:{"context": ..., "options": ["use_search", "ask_user", "call_tool"]}
    • 輸出:{"use_search": 0.62, "ask_user": 0.18, "call_tool": 0.20}

    你可以直接在程式碼裡用這個分佈做 argmax、帶溫度抽樣、risk-aware routing,完全不用再 parse 文字。


    2. 「雙大腦」:小模型決策,大模型推理

    實務上最有用的模式是:一個 fast decision brain + 一個 reasoning LLM。

    • Decision Brain(例如 Jeff-0.8B / Jeff-2B):
    • 任務:routing、重試判斷、優先級、風險上報
    • 特性:單次 forward ~30 ms、本地可部署、輸出概率

    • Reasoning LLM(例如 GPT、Claude、Llama):

    • 任務:長文本生成、複雜推理、多步工具調用
    • 特性:成本高、延遲高,但能力強

    常見模式(改編自 Jev/Jeff 的 pattern):

    1. Router:決策模型選「用哪個 LLM / 哪個專家 Agent」
    2. Retry Policy:LLM 出錯,由決策模型判斷「重試/降階模型/人工接管」
    3. Risk Escalation:決策模型只要發現 high-risk,立即上報/阻斷,不讓 LLM 自己「想一想」
    4. Multi-Agent 協調:多個小 Agent 各自提案,由決策模型打分、選擇最適方案

    好處非常直接:

    • 成本降 30–80%:多數小決策不再叫大模型
    • 延遲變穩定:本地 decision 模型可維持 <50 ms
    • 安全邏輯集中:決策 policy 都寫在程式碼 + decision 模型裡,而不是散在 prompt

    💡 關鍵: 「雙大腦」架構把高成本 LLM 使用頻率壓到最低,同時讓安全與路由策略變得可觀測、可測試。


    3. 為什麼選 0.8B / 2B 決策模型?

    Jeff 這類 0.8B/2B 模型,實務上剛好落在:

    • 夠小:
    • 0.8B 量化後可在 CPU 或 M 系列 Mac 上跑
    • ~30ms/decision,TPS 可以拉到數百
    • 夠準:
    • 在 Jev 同類 benchmark 上能到 ~83% 正確率,接近 Jev
    • 對多選概率輸出做過校準(適合做 risk-based policy)

    💡 關鍵: 0.8B/2B 模型在 ~83% 正確率與 ~30ms 延遲之間取得平衡,非常適合作為高頻決策核心。

    對 Agent 來說,這種模型可以:

    • 作為 中央決策器:統一處理 route / retry / escalate
    • 作為 專用分類器:例如 ticket triage、工具選擇、user intent 分類
    • 透過本地 fine-tune/LoRA,快速貼合你的業務決策空間

    實作範例:在現有 Agent 中插入一顆決策模型

    以下以一個典型 LLM-based Agent 為例,有這幾步:

    1. 分類 user intent
    2. 決定是否查詢工具 / RAG
    3. 呼叫 LLM 生成回應

    我們要做的是:把第 1, 2 步改由 System One 決策模型處理。

    架構概觀

    User → (Decision Model) → route: {search, direct_llm, ask_clarify}
          → (Optional) Decision Model: retry / escalate
          → (LLM) 只在必要時被呼叫
    

    範例 1:HTTP API 版本(推論在遠端或內網)

    假設你有一個決策模型 API:POST /decision,輸入 context+options,輸出 probability。

    import requests
    
    DECISION_API = "https://decision.local/api/v1/decision"
    
    OPTIONS_ROUTE = ["direct_llm", "search", "ask_clarify"]
    
    def call_decision_model(context: str, options: list[str]) -> dict:
        payload = {
            "context": context,
            "options": options
        }
        resp = requests.post(DECISION_API, json=payload, timeout=0.2)
        resp.raise_for_status()
        return resp.json()["probs"]  # e.g. {"direct_llm": 0.2, "search": 0.6, ...}
    
    
    def route_request(user_query: str, history: list[str]) -> str:
        context = "\n".join([*history[-5:], f"User: {user_query}"])
        probs = call_decision_model(context, OPTIONS_ROUTE)
    
        # 簡單 argmax,實務上可加溫度或阈值
        choice = max(probs.items(), key=lambda x: x[1])[0]
        return choice
    
    
    def handle_request(user_query: str, history: list[str]):
        route = route_request(user_query, history)
    
        if route == "search":
            docs = search_api(user_query)
            return llm_answer_with_docs(user_query, docs)
        elif route == "ask_clarify":
            return "我需要多一點資訊才能幫你,能描述得再具體一些嗎?"
        else:  # direct_llm
            return llm_direct_answer(user_query)
    

    重點:

    • 決策模型輸出的是 probs,而不是自然語言
    • routing 邏輯安全可控,可以在程式碼中加入 risk threshold:
    if probs["search"] < 0.4 and probs["direct_llm"] < 0.4:
        # 模型不確定,改走安全路線
        route = "ask_clarify"
    

    範例 2:本地部署 Jeff-0.8B(以 Python + ggml 為例)

    以下為 pseudo-code,示意如何用本地 0.8B 決策模型取代雲端判斷:

    from my_decision_runtime import JeffModel
    
    # 載入量化後的 0.8B 模型(例如 Q4_0)
    model = JeffModel(
        model_path="./jeff-0.8b-q4.gguf",
        max_seq_len=2048,
    )
    
    OPTIONS_RETRY = ["retry", "fallback_small_llm", "escalate_human", "abort"]
    
    
    def decide_retry(error_summary: str, last_attempt_prompt: str) -> str:
        context = f"Error: {error_summary}\nLastPrompt: {last_attempt_prompt[:512]}"
        probs = model.predict(context=context, options=OPTIONS_RETRY)
        # probs: dict[str, float]
    
        # 基於風險的 policy
        if probs["escalate_human"] > 0.4:
            return "escalate_human"
        if probs["abort"] > 0.5:
            return "abort"
        # 其餘用 argmax
        return max(probs.items(), key=lambda x: x[1])[0]
    
    
    # 在你的 Agent 裡:
    
    def run_with_retry(prompt: str):
        try:
            return call_main_llm(prompt)
        except Exception as e:
            decision = decide_retry(str(e), prompt)
    
            if decision == "retry":
                return call_main_llm(prompt)
            elif decision == "fallback_small_llm":
                return call_small_llm(prompt)
            elif decision == "escalate_human":
                notify_oncall("LLM failure", prompt, str(e))
                raise
            else:  # abort
                raise
    

    這段展示了 Jeff 作為「錯誤策略決策器」:

    • 不再需要 LLM 生成「請重試」之類字串
    • 所有錯誤策略可以用程式碼寫死,決策模型只給概率與偏好

    建議與注意事項

    1. 資料標註與格式:把決策當「分類任務」設計

    導入決策模型前,要先把業務決策抽象成 明確選項 + context:

    • 標註格式建議:
    • context: 純文字,包含必要上下文(user input、歷史、meta)
    • options: 選項列表,例如 ["route_a", "route_b", "escalate"]
    • label: 真實選擇(其中一個 option)

    範例 JSON:

    {
      "context": "User: 我要查 2023 年度發票\nMetadata: plan=premium, region=tw",
      "options": ["billing", "tech_support", "sales"],
      "label": "billing"
    }
    

    不要 把決策模型當一般文本 LLM 用:

    • 不要要求它寫長回應
    • 不要在 output 裡混入自然語言,只保留 label / prob

    2. 評估指標與 reward 設計:先拆「業務 reward」再看模型 metrics

    常見坑是:

    • 把「業務 KPI」(例如轉換率、工單處理時間)直接當作模型訓練 reward
    • 或只看 accuracy,而忽略 不同錯誤的成本不對稱

    建議:

    • 模型層面:看 top-1 accuracy、calibration(Brier score)
    • 業務層面:再看
    • routing 正確率對 成本、延遲 的影響
    • risk decision 對 事故率、誤報率 的影響

    並且明確定義:

    • 哪些錯誤是 容忍型(例如選錯 LLM 只是有點慢)
    • 哪些錯誤是 致命型(例如錯過 high-risk 交易)

    讓 decision policy 在程式碼裡顯式處理這些差異,不要全丟給模型學。

    3. 延遲、量化、TPS:本地部署要先壓指標

    在本地跑 0.8B/2B 決策模型時,幾個容易忽略的點:

    • 量化策略:
    • Q4_0 / Q5_K 通常是延遲/精度的甜 spot
    • 過度量化(Q2 等)可能讓概率校準崩掉,對 decision 特別危險
    • TPS(吞吐量):
    • 估算公式:TPS ≈ (batch_size / latency_per_batch)
    • 若有大量併發 Agent,建議跑一個 decision service,統一打 batch
    • 延遲測試:
    • 在 staging 模擬實際 traffic,測試 end-to-end:user → decision → LLM
    • 對每種 decision path 分別量測(例如 search route vs direct_llm)

    4. Fallback 策略:永遠保留「不用 decision 模型」的路徑

    導入新 decision layer 很容易把整個系統綁死在它上面。建議:

    • 在 config 中預留 DECISION_MODEL_ENABLED 旗標
    • 實作 fallback policy:
    if not DECISION_MODEL_ENABLED or decision_model_unhealthy():
        # 回到簡單的 rule-based or default LLM
        route = default_route(user_query)
    

    這可以:

    • 快速 A/B test decision 模型的影響
    • 緊急時一鍵關閉 decision 層,避免整個系統因為一顆 0.8B 卡住

    5. 常見踩坑總結

    • 把決策模型當 LLM 文本模型用:要它寫長答案,結果 latency 又上來
    • 沒拆 rewards:直接用業務 reward 當 loss,導致 reward hacking(例如模型只選能快速結束對話的 route)
    • 忽略成本與延遲測試:只看 benchmark accuracy,不做真實流量測試
    • 選項設計過細:options 太多、含義不清,導致 decision noise 大

    導入 System One / Decision Models 的關鍵心態是:

    讓 LLM 做它擅長的推理與生成,把所有「丟銅板」級決策搬給一顆小而快、可控的模型。

    只要你願意把 Agent pipeline 中的各種 routing、重試、risk 判斷抽離出來,用一顆 0.8B/2B 決策模型接手,就能在 成本、延遲、安全性 上一次升級,真正做出「雙大腦」架構的智慧 Agent。

    🚀 你現在可以做的事

    • 清點現有 Agent pipeline 中所有「單選題」與「要不要重試」類決策,列成 options 清單
    • 寫一個簡單的 /decision API(可先 mock),在程式碼中改用「機率分佈 → route」的決策流程
    • 選一個 0.8B/2B 模型(例如 Jeff 類),在 staging 環境測試延遲、TPS 與成本改善幅度
  • Fugu 式多模型協作實戰拆解

    Fugu 式多模型協作實戰拆解

    📌 本文重點

    • 單一 LLM 容易遇到成本與供應商風險問題
    • Fugu 用任務類型與路由實現多模型協作
    • 多模型需要良好編排、仲裁與可觀測性
    • 建議從抽象 Task 與 adapter 漸進導入

    單一 LLM 做所有事情的痛點很明確:成本不可控、供應商風險高、效能無法對應不同任務類型。Sakana 的 Fugu 路線給了一個很務實的答案:用一層編排(orchestration)把多個模型(雲端 + 本地 + 專用 code model)協作起來,把「選模型、聚合結果、錯誤控制」變成一套可維護的工程結構,而不是散落在業務程式碼裡的 if-else。


    重點說明

    1. Fugu 式類型系統:先定「任務類型」,再談選哪個模型

    Fugu 的關鍵不是多模型本身,而是任務類型(task types)+ 類型安全的輸入輸出:

    • 每個任務明確定義:
    • input schema(如 QueryTask, CodeGenTask, LongFormTask)
    • output schema(如 Answer, CodePatch, SearchPlan)
    • 路由層只依賴任務類型與 metadata(長度、成本上限、延遲 SLA),不直接寫死「如果是寫程式就用 XXX」。

    範例(TypeScript 風格的 pseudo code):

    // 1. 任務類型定義
    interface BaseTaskMeta {
      maxLatencyMs: number;
      maxCostUSD: number;
      priority: 'low' | 'normal' | 'high';
    }
    
    interface QueryTask {
      type: 'query';
      input: { question: string; context?: string };
      meta: BaseTaskMeta & { allowWebSearch: boolean };
    }
    
    interface CodeGenTask {
      type: 'codegen';
      input: { spec: string; language: string };
      meta: BaseTaskMeta & { needTests: boolean };
    }
    
    interface LongFormTask {
      type: 'longform';
      input: { topic: string; minWords: number };
      meta: BaseTaskMeta & { allowStreaming: boolean };
    }
    
    type Task = QueryTask | CodeGenTask | LongFormTask;
    

    好處:

    • 模型路由只看 Task,不看業務細節,方便之後替換模型 / 供應商。
    • 不同模型可以有不同的 prompt / tool schema,但在編排層都被包成同一個 Task 抽象。

    💡 關鍵: 先用類型把任務抽象好,之後換模型或換供應商就變成「改路由」而不是「重寫業務程式碼」。


    2. 模型路由:任務類型 × 長度 × 成本

    一個實用的路由策略通常只靠幾個欄位就夠了:

    • 任務類型:
    • codegen → 專用 code model(如 o3-mini、DeepSeek-Coder、本地 Qwen code)
    • query → 一般對話模型(OpenAI / Anthropic / 本地)
    • longform → 長 context 模型(如 200k+ context),或拆段 + 聚合
    • 長度估計:預估輸入 token + 預計輸出 token,超過本地模型 context 就路由到雲端長上下文模型。
    • 成本與延遲:
    • maxCostUSD 控制是否可以打貴模型
    • maxLatencyMs 決定是否啟用並行查詢 + 快速仲裁

    簡化版路由器:

    function routeModel(task: Task): 'openai:gpt-4.1-mini' | 'local:qwen' | 'openai:o3-mini' {
      const estTokens = estimateTokens(task.input);
    
      if (task.type === 'codegen') {
        // code 任務預設走專用 code model
        return task.meta.maxCostUSD < 0.05 ? 'local:qwen' : 'openai:o3-mini';
      }
    
      if (task.type === 'longform') {
        if (estTokens > 120_000) return 'openai:gpt-4.1-mini';
        return 'local:qwen';
      }
    
      // query 一般問答
      if (task.meta.maxLatencyMs < 3000) {
        // 低延遲預算 → 本地或較小雲端模型
        return 'local:qwen';
      }
    
      return 'openai:gpt-4.1-mini';
    }
    

    這類路由就是 Fugu 類型系統在工程上的落地:先把任務分型,路由邏輯就自然長出來。

    💡 關鍵: 用 maxLatencyMs、maxCostUSD 這類 metadata 控制路由,可以在同一套架構裡同時優化成本與延遲。


    3. 回覆聚合與仲裁:多模型輸出怎麼合成一個答案

    多模型協作的價值在於:

    • 一部分模型擅長查(search / recall),一部分擅長寫(rewrite / explain)
    • 或同一任務交給兩個模型,透過仲裁降低幻覺

    典型做法:

    1. 並行呼叫 2–3 個模型:如本地 Qwen + 雲端 GPT
    2. 用一個「仲裁模型」來閱讀所有候選答案,輸出最終回覆與信心分數

    仲裁 prompt 示意:

    const arbiterPrompt = `你是仲裁模型。你會看到多個模型的回答,請:
    1. 比較其一致性與是否自相矛盾。
    2. 檢查是否有推理錯誤或明顯幻覺。
    3. 選出最可信的一個,並在有疑慮時標記「不確定」。
    
    輸出 JSON:
    {
      "winner": "model_a" | "model_b",
      "confidence": 0-1,
      "final_answer": "...",
      "notes": "..."
    }`;
    

    好處:

    • 提高可靠性(特別是檢索或工具調用密集場景)
    • 可以把仲裁結果記錄下來,用於後續離線分析各模型表現

    成本上升是必然,常見做法是:

    • 只在 高價值任務 / 有風險的 domain(法律、醫療) 開啟仲裁
    • 其他場景靠單模型 + tool verification 解決

    4. 單一 LLM vs 多 LLM 編排:實際取捨

    單一 LLM:

    • 優點:實作簡單、debug 容易、觀測鏈短
    • 缺點:
    • 價格彈性差:所有任務都用貴模型
    • 供應商風險:價格調整、限額、區域封鎖都直接影響產品
    • 難以對應極端需求(超長上下文、線下敏感數據)

    多 LLM 編排(Fugu 路線):

    • 優點:
    • 不同任務用最合適的模型 → 可靠性與成本可同時優化
    • 可以把敏感任務 route 到本地模型,降低隱私風險
    • 雲端服務掛了可以 fallback 到次佳方案
    • 缺點:
    • 觀測與 debug 變複雜(誰的錯?哪一層出問題?)
    • 延遲可能放大(串聯多步、多模型仲裁)
    • 各家 API、tool schema、系統提示格式不一致,需要一層 adapter

    對多數專案來說:

    • MVP 階段 → 單一 LLM + 清楚的 abstraction
    • 成本 / 隱私壓力出現後 → 漸進式導入多模型編排,而不是一次重寫

    💡 關鍵: 多模型不是為了「酷」,而是為了在成本、可靠性、隱私之間取得更穩定的折衷。


    實作範例:OpenAI + 本地 Qwen + 專用 code model

    以下給出一個可自建的最小多模型編排骨架(Node/TypeScript 風格,但概念可套任何語言)。

    1. API 介面設計

    對前端/上游只暴露一個 API:POST /v1/ai/execute,輸入統一的 Task 結構。

    // express / fastify handler
    app.post('/v1/ai/execute', async (req, res) => {
      const task: Task = req.body;
    
      const modelId = routeModel(task);
    
      const controller = new AbortController();
      const timeout = setTimeout(() => controller.abort(), task.meta.maxLatencyMs);
    
      try {
        const rawResponse = await callModel(modelId, task, { signal: controller.signal });
        const parsed = normalizeOutput(task, rawResponse);
    
        await logTask({ task, modelId, rawResponse: parsed });
    
        res.json(parsed);
      } catch (e) {
        const fallback = await tryFallback(task, modelId);
        res.json(fallback);
      } finally {
        clearTimeout(timeout);
      }
    });
    

    2. 模型 adapter:解決不同 API / token 格式

    常見坑是:

    • 系統訊令格式不同(OpenAI messages vs 本地單純 prompt)
    • tool / function call schema 不同

    用 adapter 隔離差異:

    async function callModel(modelId: string, task: Task, opts: { signal: AbortSignal }) {
      switch (modelId) {
        case 'openai:gpt-4.1-mini':
          return callOpenAI(task, opts);
        case 'openai:o3-mini':
          return callOpenAICode(task, opts);
        case 'local:qwen':
          return callLocalQwen(task, opts);
        default:
          throw new Error(`Unknown model ${modelId}`);
      }
    }
    
    async function callOpenAI(task: Task, { signal }: { signal: AbortSignal }) {
      const messages = buildMessagesFromTask(task);
      const resp = await openai.chat.completions.create({
        model: 'gpt-4.1-mini',
        messages,
        temperature: 0.2,
        response_format: { type: 'json_object' },
        signal,
      });
      return resp.choices[0].message.content;
    }
    
    async function callLocalQwen(task: Task, { signal }: { signal: AbortSignal }) {
      const prompt = buildPromptFromTask(task); // 單一 string
      const resp = await fetch('http://localhost:8000/v1/completions', {
        method: 'POST',
        body: JSON.stringify({
          model: 'qwen-32b-instruct',
          prompt,
          max_tokens: 2048,
          temperature: 0.1,
        }),
        signal,
      }).then(r => r.json());
      return resp.choices[0].text;
    }
    

    只要嚴格把「怎麼跟模型講話」鎖在 adapter 裡,上層就可以只面對 Task。


    3. 超時與 fallback 策略

    簡單可行的策略:

    1. 以延遲為主的 fallback:

    2. 本地模型超時 → fallback 到雲端小模型

    3. 雲端模型錯誤/超時 → fallback 到本地(或退化版回答)
    async function tryFallback(task: Task, failedModelId: string) {
      const fallbackId = pickFallbackModel(task, failedModelId);
      if (!fallbackId) throw new Error('No fallback model');
    
      const raw = await callModel(fallbackId, task, { signal: AbortSignal.timeout(2000) });
      return normalizeOutput(task, raw, { degraded: true, usedFallback: true, fallbackId });
    }
    
    1. 回應標註退化狀態:在 normalizeOutput 中加入:
    {
      "answer": "...",
      "meta": {
        "modelId": "local:qwen",
        "usedFallback": true,
        "fallbackFrom": "openai:gpt-4.1-mini",
        "degraded": true
      }
    }
    

    讓前端可以決定是否顯示「此回答為備援模型生成」。


    4. 觀測與日誌結構:解決「昨晚 agent 到底做了什麼」

    多模型編排很容易變成黑箱。建議最少做到:

    • 每個 Task 一個 traceId
    • log 中至少包含:
    • traceId, task.type, task.meta
    • 選擇的 modelId、fallback 情況
    • 每步 latency、token 使用量
    • 仲裁結果(如果有)

    示意:

    interface TaskLog {
      traceId: string;
      taskType: Task['type'];
      modelId: string;
      fallbackFrom?: string;
      latencyMs: number;
      inputTokens: number;
      outputTokens: number;
      success: boolean;
      error?: string;
    }
    
    async function logTask(log: TaskLog) {
      // 可寫入 ClickHouse / BigQuery / Elastic
      console.log(JSON.stringify({ kind: 'taskLog', ...log }));
    }
    

    這類結構化 log 是後續做「loop engineering」(自動 self-correct / regression test)與成本優化的基石。


    建議與注意事項

    1. 延遲放大:多模型 ≠ 多倍延遲

    • 儘量並行呼叫可獨立的模型,再用仲裁合併。
    • 嚴格設定 per-model timeout,避免某個模型拖垮整個請求。
    • 對長任務(如自動寫測試、長時間 agent loop)要分段 log,避免只看到「跑了一小時,掛了」。

    2. 工具 / 系統 prompt 不一致

    • 不同家模型對 system / tools / function calling 的支援度不同。
    • 最好的做法:
    • 定義自己的 工具層 schema(如 JSON Tool 定義)
    • 在 adapter 把它映射成各模型需要的格式
    • 千萬避免在業務邏輯裡到處寫 if (model === 'gpt-4.1-mini') 這種分支。

    3. 責任歸屬與 debug 困難

    多模型編排容易出現:

    • prompt 沒設好 → 模型亂回答
    • 路由策略不合理 → 小模型被丟去做艱難任務
    • 仲裁錯誤 → 明明較好的答案被丟掉

    實務上建議:

    • 為每一層定義清楚的「契約」:
    • 路由層:輸入 Task,輸出 modelId,不關心內容
    • adapter:保證把 Task 翻譯成該模型最佳格式
    • 仲裁層:對模型輸出負責,不對業務邏輯負責
    • 做回溯時先問:錯在路由、adapter、模型本身、還是仲裁?

    4. 不要一開始就 over-engineer

    • 若你現在是:一個雲端 LLM + 少數工具,建議只先做:
    • 抽出 Task 類型
    • 寫好 model adapter(即使目前只有一個模型)
    • 之後要引入本地 Qwen、專用 code model、Fugu 式仲裁機制,就只是替換實作,而不是重寫整個系統。

    核心結論: 多模型協作不是把更多模型硬塞進系統,而是用 清晰的任務類型 + 路由 + 仲裁 + 可觀測性,把「哪個模型做什麼」變成一個可以演進的工程決策。從這個角度看,你可以在自己的專案裡做一個「迷你 Fugu」,用極少的代碼換來更好的成本控制、可靠性與供應商彈性。


    🚀 你現在可以做的事

    • 在現有專案中抽出一層 Task 類型與 routeModel(),把模型選擇邏輯從業務程式碼移出來
    • 寫一個簡單的 model adapter(例如包一層 callModel()),即使目前只支援單一 gpt-4.1-mini
    • 為每次模型呼叫加上 traceId 與結構化 log,開始累積日後做成本與可靠性優化所需的資料