<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>Function-Calling on Tarragon</title><link>https://tarrragon.github.io/blog/tags/function-calling/</link><description>Recent content in Function-Calling on Tarragon</description><generator>Hugo -- gohugo.io</generator><language>zh-TW</language><copyright>Tarragon (CC BY 4.0)</copyright><lastBuildDate>Mon, 11 May 2026 00:00:00 +0000</lastBuildDate><atom:link href="https://tarrragon.github.io/blog/tags/function-calling/index.xml" rel="self" type="application/rss+xml"/><item><title>4.3 Tool use 原理：LLM 跟外部世界互動</title><link>https://tarrragon.github.io/blog/llm/04-applications/tool-use-principles/</link><pubDate>Mon, 11 May 2026 00:00:00 +0000</pubDate><guid>https://tarrragon.github.io/blog/llm/04-applications/tool-use-principles/</guid><description>&lt;p>&lt;a href="https://tarrragon.github.io/blog/llm/knowledge-cards/tool-use/" data-link-title="Tool Use" data-link-desc="LLM 透過結構化呼叫外部工具（讀檔、查資料庫、發 API request）來擴展能力的設計、function calling 跟 MCP 是常見實作">Tool use&lt;/a> 把 LLM 從「會生成文字的模型」延伸到「能參與工程系統的元件」。它的核心機制是 structured output——把 LLM 的機率分佈約束到工程系統可解析的格式、讓下游程式能對 LLM 的輸出做確定性處理。&lt;a href="https://tarrragon.github.io/blog/llm/knowledge-cards/function-calling/" data-link-title="Function Calling" data-link-desc="模型訓練階段建立的「呼叫工具」能力：知道何時該呼叫、傳什麼參數">Function calling&lt;/a> 是 structured output 的工程化形態、由模型訓練端跟推論端共同支撐。協議層級的對應（structured output / function calling / MCP 三者怎麼疊）見 &lt;a href="https://tarrragon.github.io/blog/llm/04-applications/application-protocols/" data-link-title="4.6 應用層協議：function calling / structured output / MCP" data-link-desc="三個常被混為一談的概念：模型能力、sampling 約束、server 協議，三者的層級差異與組合方式">4.6 應用層協議&lt;/a>。&lt;/p>
&lt;p>本章寫的是「為什麼需要 tool use」「structured output 怎麼運作」「設計工具時該如何思考副作用」這類跟具體 framework 無關的原理。OpenAI function calling spec、Anthropic tools API、JSON Schema constrained sampling 等具體格式半年一變、不在本章焦點；本章寫的是「換 spec 之後仍然成立」的設計取捨。&lt;/p>
&lt;h2 id="本章目標">本章目標&lt;/h2>
&lt;p>讀完本章後你能：&lt;/p>
&lt;ol>
&lt;li>解釋為什麼 LLM 需要呼叫工具、純生成解不了什麼問題。&lt;/li>
&lt;li>看到 structured output / JSON mode 設定時、知道它在限制 sampling 的哪一層。&lt;/li>
&lt;li>判讀「這個模型 tool use 為什麼表現崩」的常見根因。&lt;/li>
&lt;li>設計工具時用「副作用範圍 + 信任邊界」思考、不只看「功能對不對」。&lt;/li>
&lt;/ol>
&lt;h2 id="為什麼-llm-需要呼叫工具">為什麼 LLM 需要呼叫工具&lt;/h2>
&lt;p>LLM 的能力邊界決定了什麼任務「光靠生成解不了」：&lt;/p>
&lt;ul>
&lt;li>&lt;strong>即時資料&lt;/strong>：模型訓練後不知道現在發生的事。「查今天天氣」「現在股價」必須拉外部資料。&lt;/li>
&lt;li>&lt;strong>精確計算&lt;/strong>：模型對大數運算、長乘法、開根號等表現不穩、calculator 一行解決。&lt;/li>
&lt;li>&lt;strong>副作用&lt;/strong>：把檔案寫到磁碟、發 email、call API——這些是「動作」、文字本身不會觸發磁碟 / 網路 / 外部系統的狀態變更（這也是為何要設計 &lt;a href="https://tarrragon.github.io/blog/llm/knowledge-cards/sandbox/" data-link-title="Sandbox" data-link-desc="把程式跑在受限制環境的隔離技術、限制檔案 / 網路 / 系統呼叫權限、是 tool use 跟 MCP server 副作用控制的基礎">sandbox&lt;/a> 來限制副作用範圍）。&lt;/li>
&lt;li>&lt;strong>持久化狀態&lt;/strong>：模型本身無狀態、需要外部資料庫 / vector store / file system 儲存跨對話的資料。&lt;/li>
&lt;li>&lt;strong>規模化操作&lt;/strong>：搜尋一千個 file、處理 batch、跑 SQL——這些是 deterministic、用程式跑比讓模型「逐字模擬」快幾個量級。&lt;/li>
&lt;/ul>
&lt;p>Tool use 解的不只是「能力延伸」、更是「把 LLM 跟確定性系統接起來」。沒有 tool use、LLM 只能在自己的文字宇宙裡跑；有了 tool use、它變成可以呼叫資料庫、寫檔、發網路請求的「會說話的 agent」。&lt;/p>
&lt;p>這個跨界本身帶來新的問題：模型輸出必須能被工程系統消費。自然語言對人類友善、對程式不友善——下一節要解的就是這個橋。&lt;/p>
&lt;h2 id="structured-output-是-llm-跨入工程系統的橋">Structured Output 是 LLM 跨入工程系統的橋&lt;/h2>
&lt;p>自然語言對下游 parser 不友善：同一個意思有無限種表達、模型可能加 prefix、加 disclaimer、加 markdown 格式、漏關鍵欄位。如果直接 regex 解析、會 case by case 補例外、最終 parser 比 LLM 還複雜。&lt;/p>
&lt;p>Structured output 解這個問題：把 LLM 的輸出約束到預定義的結構（JSON、YAML、XML、特定 schema）。實作機制有幾種：&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Prompt-level&lt;/strong>：在 prompt 裡明確要求「請輸出 JSON、schema 是 X」。靠模型 follow instruction 的能力、不保證 100% 合法。&lt;/li>
&lt;li>&lt;strong>JSON mode / response_format&lt;/strong>：推論伺服器在 &lt;a href="https://tarrragon.github.io/blog/llm/03-theoretical-foundations/sampling-and-decoding/" data-link-title="3.5 Sampling 與 Decoding 策略" data-link-desc="Greedy、beam search、top-k、top-p、temperature、min-p：模型輸出後怎麼挑下一個 token">sampling&lt;/a> 階段（從機率分佈挑下一個 token 的步驟）對每個 token 都套合法 JSON 約束、把不合法的選項機率歸零。&lt;/li>
&lt;li>&lt;strong>Grammar-constrained sampling&lt;/strong>：用 grammar（描述合法語法的形式化規則、實作上常用 BNF 或類似格式）描述合法輸出形狀、推論時逐 &lt;a href="https://tarrragon.github.io/blog/llm/knowledge-cards/token/" data-link-title="Token" data-link-desc="LLM 處理文字時的最小單位：介於字元與單字之間">token&lt;/a> 過濾。可以約束到任意嚴格的結構。&lt;/li>
&lt;li>&lt;strong>Function calling 訓練&lt;/strong>：模型訓練階段就教「該怎麼呼叫工具」、輸出格式內建在模型行為裡。&lt;/li>
&lt;/ul>
&lt;p>四種機制的層級不同：prompt-level 是「請模型自律」、JSON mode 跟 grammar 是「sampling 階段強制」、function calling 是「訓練讓模型自然」。越靠近 sampling / 訓練端的機制越穩、但實作越複雜。&lt;/p></description><content:encoded><![CDATA[<p><a href="/blog/llm/knowledge-cards/tool-use/" data-link-title="Tool Use" data-link-desc="LLM 透過結構化呼叫外部工具（讀檔、查資料庫、發 API request）來擴展能力的設計、function calling 跟 MCP 是常見實作">Tool use</a> 把 LLM 從「會生成文字的模型」延伸到「能參與工程系統的元件」。它的核心機制是 structured output——把 LLM 的機率分佈約束到工程系統可解析的格式、讓下游程式能對 LLM 的輸出做確定性處理。<a href="/blog/llm/knowledge-cards/function-calling/" data-link-title="Function Calling" data-link-desc="模型訓練階段建立的「呼叫工具」能力：知道何時該呼叫、傳什麼參數">Function calling</a> 是 structured output 的工程化形態、由模型訓練端跟推論端共同支撐。協議層級的對應（structured output / function calling / MCP 三者怎麼疊）見 <a href="/blog/llm/04-applications/application-protocols/" data-link-title="4.6 應用層協議：function calling / structured output / MCP" data-link-desc="三個常被混為一談的概念：模型能力、sampling 約束、server 協議，三者的層級差異與組合方式">4.6 應用層協議</a>。</p>
<p>本章寫的是「為什麼需要 tool use」「structured output 怎麼運作」「設計工具時該如何思考副作用」這類跟具體 framework 無關的原理。OpenAI function calling spec、Anthropic tools API、JSON Schema constrained sampling 等具體格式半年一變、不在本章焦點；本章寫的是「換 spec 之後仍然成立」的設計取捨。</p>
<h2 id="本章目標">本章目標</h2>
<p>讀完本章後你能：</p>
<ol>
<li>解釋為什麼 LLM 需要呼叫工具、純生成解不了什麼問題。</li>
<li>看到 structured output / JSON mode 設定時、知道它在限制 sampling 的哪一層。</li>
<li>判讀「這個模型 tool use 為什麼表現崩」的常見根因。</li>
<li>設計工具時用「副作用範圍 + 信任邊界」思考、不只看「功能對不對」。</li>
</ol>
<h2 id="為什麼-llm-需要呼叫工具">為什麼 LLM 需要呼叫工具</h2>
<p>LLM 的能力邊界決定了什麼任務「光靠生成解不了」：</p>
<ul>
<li><strong>即時資料</strong>：模型訓練後不知道現在發生的事。「查今天天氣」「現在股價」必須拉外部資料。</li>
<li><strong>精確計算</strong>：模型對大數運算、長乘法、開根號等表現不穩、calculator 一行解決。</li>
<li><strong>副作用</strong>：把檔案寫到磁碟、發 email、call API——這些是「動作」、文字本身不會觸發磁碟 / 網路 / 外部系統的狀態變更（這也是為何要設計 <a href="/blog/llm/knowledge-cards/sandbox/" data-link-title="Sandbox" data-link-desc="把程式跑在受限制環境的隔離技術、限制檔案 / 網路 / 系統呼叫權限、是 tool use 跟 MCP server 副作用控制的基礎">sandbox</a> 來限制副作用範圍）。</li>
<li><strong>持久化狀態</strong>：模型本身無狀態、需要外部資料庫 / vector store / file system 儲存跨對話的資料。</li>
<li><strong>規模化操作</strong>：搜尋一千個 file、處理 batch、跑 SQL——這些是 deterministic、用程式跑比讓模型「逐字模擬」快幾個量級。</li>
</ul>
<p>Tool use 解的不只是「能力延伸」、更是「把 LLM 跟確定性系統接起來」。沒有 tool use、LLM 只能在自己的文字宇宙裡跑；有了 tool use、它變成可以呼叫資料庫、寫檔、發網路請求的「會說話的 agent」。</p>
<p>這個跨界本身帶來新的問題：模型輸出必須能被工程系統消費。自然語言對人類友善、對程式不友善——下一節要解的就是這個橋。</p>
<h2 id="structured-output-是-llm-跨入工程系統的橋">Structured Output 是 LLM 跨入工程系統的橋</h2>
<p>自然語言對下游 parser 不友善：同一個意思有無限種表達、模型可能加 prefix、加 disclaimer、加 markdown 格式、漏關鍵欄位。如果直接 regex 解析、會 case by case 補例外、最終 parser 比 LLM 還複雜。</p>
<p>Structured output 解這個問題：把 LLM 的輸出約束到預定義的結構（JSON、YAML、XML、特定 schema）。實作機制有幾種：</p>
<ul>
<li><strong>Prompt-level</strong>：在 prompt 裡明確要求「請輸出 JSON、schema 是 X」。靠模型 follow instruction 的能力、不保證 100% 合法。</li>
<li><strong>JSON mode / response_format</strong>：推論伺服器在 <a href="/blog/llm/03-theoretical-foundations/sampling-and-decoding/" data-link-title="3.5 Sampling 與 Decoding 策略" data-link-desc="Greedy、beam search、top-k、top-p、temperature、min-p：模型輸出後怎麼挑下一個 token">sampling</a> 階段（從機率分佈挑下一個 token 的步驟）對每個 token 都套合法 JSON 約束、把不合法的選項機率歸零。</li>
<li><strong>Grammar-constrained sampling</strong>：用 grammar（描述合法語法的形式化規則、實作上常用 BNF 或類似格式）描述合法輸出形狀、推論時逐 <a href="/blog/llm/knowledge-cards/token/" data-link-title="Token" data-link-desc="LLM 處理文字時的最小單位：介於字元與單字之間">token</a> 過濾。可以約束到任意嚴格的結構。</li>
<li><strong>Function calling 訓練</strong>：模型訓練階段就教「該怎麼呼叫工具」、輸出格式內建在模型行為裡。</li>
</ul>
<p>四種機制的層級不同：prompt-level 是「請模型自律」、JSON mode 跟 grammar 是「sampling 階段強制」、function calling 是「訓練讓模型自然」。越靠近 sampling / 訓練端的機制越穩、但實作越複雜。</p>
<p>理解這個 stack 的價值是：看到「模型輸出 JSON 不穩」時、知道該往哪一層下手。Prompt 寫得清楚不夠的話、要動 sampling 約束；sampling 約束打開了還不穩、要看模型本身的 tool use 訓練覆蓋度。</p>
<h2 id="function-calling-跟-free-form-generation-的取捨">Function Calling 跟 Free-form Generation 的取捨</h2>
<p>「讓 LLM 呼叫工具」有兩條路：</p>
<p><strong>Function calling</strong>（模型訓練支撐）：</p>
<ul>
<li>模型訓練時看過大量「使用者問題 → 工具呼叫格式」的範例、知道該怎麼決定要不要呼叫、傳什麼參數。</li>
<li>優點：呼叫格式穩、模型「自然」知道何時該呼叫；不需要 prompt 工程寫很長。</li>
<li>缺點：受訓練資料分佈影響大、跨模型行為不一致；只支援模型訓練過的協議格式。</li>
<li>適合：主流 / 大型模型、想用最少 prompt 工程拿穩定行為。</li>
</ul>
<p><strong>Free-form + structured output</strong>（推論時約束）：</p>
<ul>
<li>寫 prompt 描述工具、用 grammar / JSON mode 約束輸出。</li>
<li>優點：跨模型可移植、不依賴模型 fine-tune；支援任意自訂協議格式。</li>
<li>缺點：模型可能不知道「何時該呼叫」、需要 prompt 工程描述觸發條件；嚴格約束下品質可能受影響。</li>
<li>適合：跨多家 LLM 都要用同一套程式、或用較弱的模型不能依賴 function calling 訓練。</li>
</ul>
<p>實際應用常混用：主流模型走 function calling、fallback 模型走 free-form。但混用增加維護成本、小型應用挑一條走通常更簡單。</p>
<p>判讀「該用哪一條」的訊號：</p>
<ul>
<li>目標模型主流 + 規模大（&gt;30B）→ function calling、函式呼叫格式通常穩、prompt 工程量最低（注意：Llama 3 70B 等大模型也有 function calling 訓練不均的 case、實際採用前最小驗證）。</li>
<li>目標模型小或非主流 → free-form + structured output、跨模型較穩。</li>
<li>想跨 LLM 供應商可移植 → free-form + 標準化 schema、不綁特定 provider 的 function spec。</li>
</ul>
<h2 id="為什麼本地小模型-tool-use-失敗率高">為什麼本地小模型 Tool use 失敗率高</h2>
<p>寫 code 場景的本地小模型（7B、14B 級）跑 <a href="/blog/llm/knowledge-cards/tool-use/" data-link-title="Tool Use" data-link-desc="LLM 透過結構化呼叫外部工具（讀檔、查資料庫、發 API request）來擴展能力的設計、function calling 跟 MCP 是常見實作">tool use</a> 經常失敗、表現訊號清楚：</p>
<ul>
<li>呼叫格式錯（JSON 不合法、欄位拼錯）。</li>
<li>參數胡亂填（type 不對、value 超出 schema 範圍）。</li>
<li>不該呼叫時呼叫（簡單問題硬要叫 calculator）。</li>
<li>該呼叫時不呼叫（複雜計算自己算錯）。</li>
<li>連續呼叫 loop（一直叫同一個工具不收斂）。</li>
</ul>
<p>根因有兩層、訓練端跟推論端各佔一半：</p>
<p>訓練端：</p>
<ul>
<li>Tool use 範例在預訓練資料中比例低（網路文字主要是「人類對話」、不是「人類 + 工具 trace」）。</li>
<li><a href="/blog/llm/03-theoretical-foundations/training-pipeline/" data-link-title="3.4 訓練流程：pre-train → SFT → RLHF" data-link-desc="LLM 的三階段訓練：預訓練、指令微調、人類反饋強化學習；各階段目標與最新替代方案">SFT 階段</a>才大量加 tool use 資料、但 SFT 規模相對小、小模型容量有限、學不全。</li>
<li>大模型（70B+）SFT 學得進、能 generalize；小模型 SFT 容量不夠、tool use 只在訓練過的 narrow 場景表現好。</li>
</ul>
<p>推論端（同一個模型在不同推論配置下失敗率不同）：</p>
<ul>
<li><strong>Temperature 過高</strong>：分佈被拉平、原本合法 JSON 的 token 機率被攤稀、不合法 token 反而被 sample 到。Tool use 場景建議 T ≤ 0.3。</li>
<li><strong>Context 接近上限</strong>：tool schema + 歷史對話 + retrieval result 把 context 用滿、模型在末段對 schema 的記憶衰減、輸出開始飄。</li>
<li><strong>多 tool / 巢狀 schema</strong>：可選工具超過 5 個、或單個 tool 參數有 3 層巢狀時、小模型 capacity 不足以同時 hold 所有結構約束。</li>
</ul>
<p>緩解策略：</p>
<ul>
<li><strong>限制 tool 數量</strong>：把可用 tool 控制在 3-5 個內、小模型較能 handle。</li>
<li><strong>詳細 prompt 描述每個 tool</strong>：補模型訓練的不足。</li>
<li><strong>強 structured output 約束</strong>：用 grammar 強制輸出合法、把不合法輸出的機率在 sampling 階段壓到零。</li>
<li><strong>重試 + fallback</strong>：第一次失敗的話、加 error feedback 重試；多次失敗 fallback 到「不用 tool」的 free-form。</li>
<li><strong>接受能力限制</strong>：複雜 multi-step tool use 本地小模型現階段做不好、切到雲端。</li>
</ul>
<p>判讀「該不該本地跑 tool use」的反射：先看任務的 tool 複雜度，單 tool / 簡單呼叫本地堪用，multi-step / 跨多 tool 通常需要 30B+ 模型，否則失敗率高到不實用。</p>
<h2 id="工具的副作用範圍設計">工具的「副作用範圍」設計</h2>
<p>設計給 LLM 用的工具時、除了「功能對不對」、把「副作用範圍 + 可逆性」一起納入設計。</p>
<p>可逆性 spectrum、由低風險到高風險：</p>
<table>
  <thead>
      <tr>
          <th>等級</th>
          <th>副作用</th>
          <th>例子</th>
          <th>適合的審查模型</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>1</td>
          <td>純讀、無副作用</td>
          <td>search、read file、query DB</td>
          <td>完全自動</td>
      </tr>
      <tr>
          <td>2</td>
          <td>寫 sandbox / staging</td>
          <td>write to scratch file、test environment</td>
          <td>完全自動 + 事後審</td>
      </tr>
      <tr>
          <td>3</td>
          <td>寫本地持久化</td>
          <td>edit code file、modify config</td>
          <td>step-by-step 審查</td>
      </tr>
      <tr>
          <td>4</td>
          <td>寫共享 / production</td>
          <td>git push、deploy、modify DB production</td>
          <td>強制人類確認、也是 <a href="/blog/llm/knowledge-cards/prompt-injection/" data-link-title="Prompt Injection" data-link-desc="把惡意指令藏進 LLM 會讀到的內容、誘導 LLM 跑出非開發者預期行為的攻擊類別、OWASP LLM01 列入頭號威脅">prompt injection</a> 攻擊高風險區</td>
      </tr>
      <tr>
          <td>5</td>
          <td>操作真實世界</td>
          <td>發 email、買股票、控制硬體</td>
          <td>強制人類確認 + audit、prompt injection 影響不可逆</td>
      </tr>
  </tbody>
</table>
<p>每升一級、人類審查的需求越高、agent 的自主度越低。設計工具時、把同樣功能切到不同等級可以大幅降風險：</p>
<ul>
<li>「edit file」分成「propose diff」（等級 2）+「apply diff」（等級 3）、前者自動、後者要確認。</li>
<li>「query DB」分成「SELECT」（等級 1）+「INSERT / UPDATE」（等級 4）、前者自動、後者強制確認。</li>
<li>「run shell command」是 spectrum 上分佈最廣的工具——讓 LLM 自由跑 shell 等於開放等級 1-5 全部、是常見的 over-permissioned 設計。</li>
</ul>
<p>這個 framing 跟 OS 的權限模型同概念：least privilege 套用到 LLM tool use。每個工具設計時、先問「最差情況是什麼」、再決定該不該全自動。個人 dev 場景跑本地 LLM 的 tool use / MCP server 權限判讀（檔案系統 / shell / 網路存取邊界、第三方 MCP 信任）見 <a href="/blog/llm/06-security/tool-use-permission-model/" data-link-title="6.2 tool use 與 MCP server 的權限模型" data-link-desc="個人 dev 場景下 tool use / MCP server 的副作用權限：檔案系統 / shell / 網路存取邊界、第三方 MCP 信任、副作用的可逆性">6.2 tool use 與 MCP server 的權限模型</a>。</p>
<h2 id="結構化輸出的失敗模式">結構化輸出的失敗模式</h2>
<p>Structured output 用得好的時候、parser 不用寫 error handling；用得不好的時候、會撞到幾種典型失敗：</p>
<ul>
<li><strong>Schema 太嚴</strong>：模型「失敗」次數多、流程卡住。例如要求 enum 只能是 5 個值、但實際 query 有第 6 種情境、模型只能硬選一個錯的。</li>
<li><strong>Schema 太寬</strong>：模型輸出歧義、下游解析失敗。例如欄位定義成 <code>string</code>、模型可能輸出空字串、null、<code>&quot;N/A&quot;</code>、<code>&quot;none&quot;</code>、各種變體。</li>
<li><strong>Free-form 跟 structured 混合</strong>：要求 JSON 但同時要求「reasoning 寫在 markdown」、模型容易把 markdown 寫進 JSON string 亂掉 escape。</li>
<li><strong>巢狀太深</strong>：超過 3 層的 JSON 巢狀、模型容易在中間漏 <code>}</code> 或 <code>,</code>。Grammar-constrained sampling 可解、純 prompt 控制就脆弱。</li>
</ul>
<p>緩解模式：</p>
<ul>
<li><strong>Schema 寬度配合 retry</strong>：先用較寬 schema、解析失敗時 retry + 把錯誤訊息餵回模型修正。</li>
<li><strong>拆步驟</strong>：把複雜 structured output 拆成多個小步驟、每步驟一個簡單 schema、累積成完整結果。</li>
<li><strong>Few-shot 範例</strong>：在 prompt 裡放 3-5 個正確輸出範例、比文字描述 schema 更穩。</li>
</ul>
<h2 id="何時不需要-tool-use">何時不需要 Tool use</h2>
<p>Tool use 的適用面有邊界、下列情境純生成已足夠、加 tool use 反而增加成本與失敗點：</p>
<ul>
<li><strong>純文字產出任務</strong>：寫文章、改寫、翻譯、摘要——輸出本身是文字、不需要副作用、tool use 沒戲。</li>
<li><strong>單一回應對話</strong>：使用者問問題、模型答問題、不需要去 fetch 外部資料時。模型參數記憶覆蓋的範圍直接回答即可。</li>
<li><strong>靠 prompt + 模型內知識能解的任務</strong>：簡單 reasoning、code generation 不需要 file I/O、解釋程式碼——這些 tool use 加進去 overhead 大於收益。</li>
<li><strong>小型 in-process 應用、tool 數量極少（1-2 個）</strong>：可能直接 if-else 比 function calling 更簡單。</li>
</ul>
<p>判讀反射：先問「不用 tool use 能不能做到」、能做就保留純生成路徑。Tool use 是 LLM 能力延伸、把「加 tool use」當「應用變高級」的標誌會踩到過度設計、single-call 能解的問題包進 tool 是常見浪費。</p>
<h2 id="何時過時--何時不過時">何時過時 / 何時不過時</h2>
<p><strong>不會過時的部分</strong>：</p>
<ul>
<li>「LLM 輸出需要被工程系統消費」這個 framing。</li>
<li>Structured output 是 LLM 跟工程接軌的底層機制。</li>
<li>Function calling vs free-form 的取捨判讀。</li>
<li>訓練資料分佈如何影響 tool use 能力（小模型崩的根因）。</li>
<li>副作用範圍 / 可逆性 spectrum 的設計框架。</li>
</ul>
<p><strong>會變的部分</strong>：</p>
<ul>
<li>具體 schema spec（OpenAI function spec → Anthropic tools API → 未來的標準化）。</li>
<li>各 framework 的 tool 註冊 API。</li>
<li>哪些模型 function calling 訓練得好（會隨新模型更新）。</li>
<li>Grammar-constrained sampling 的具體實作（llama.cpp / vLLM / Outlines 等會持續演化）。</li>
</ul>
<p>看到新 tool use 介面或新 framework 時、回到本章的 framing 評估：它支援哪一層的 structured output、訓練過哪些 protocol、對副作用範圍有沒有設計——這些問題的答案決定它在你的場景能不能用。</p>
<h2 id="下一章">下一章</h2>
<p>下一章：<a href="/blog/llm/04-applications/agent-architecture/" data-link-title="4.4 Agent 架構原理" data-link-desc="Agent loop 結構、失敗模式、什麼任務適合 vs 不適合、跟人類審查的協作模型">4.4 Agent 架構原理</a>、看 LLM 自主決策的設計取捨。副作用等級跟 HITL 時機怎麼配（pre-act / mid-stream / post-hoc）見 <a href="/blog/llm/04-applications/human-ai-collaboration/" data-link-title="4.5 人機協作拓樸：何時人介入、怎麼介入" data-link-desc="Centaur vs Cyborg 工作模式、jagged frontier、HITL 三種觸發時機（pre-act / mid-stream / post-hoc）、確認流程的設計避免橡皮圖章化">4.5 人機協作拓樸</a>。本地 dev 場景把 tool use 落地到「實際給 wrapper 寫權限」的 hands-on、見 <a href="/blog/llm/01-local-llm-services/hands-on/permission-boundary/" data-link-title="Hands-on：Ollama 改檔案 / 寫程式碼的權限邊界在哪" data-link-desc="四組對照實驗：Ollama 自己沒 FS / shell 權限、wrapper 才有；--dry-run / --confirm / --auto 三檔審查粒度的取捨">Ollama 改檔案 / 寫程式碼的權限邊界</a>；個人 dev 視角的 tool use / MCP 權限判讀見 <a href="/blog/llm/06-security/tool-use-permission-model/" data-link-title="6.2 tool use 與 MCP server 的權限模型" data-link-desc="個人 dev 場景下 tool use / MCP server 的副作用權限：檔案系統 / shell / 網路存取邊界、第三方 MCP 信任、副作用的可逆性">6.2</a>。</p>
]]></content:encoded></item><item><title>4.6 應用層協議：function calling / structured output / MCP</title><link>https://tarrragon.github.io/blog/llm/04-applications/application-protocols/</link><pubDate>Mon, 11 May 2026 00:00:00 +0000</pubDate><guid>https://tarrragon.github.io/blog/llm/04-applications/application-protocols/</guid><description>&lt;p>&lt;a href="https://tarrragon.github.io/blog/llm/knowledge-cards/function-calling/" data-link-title="Function Calling" data-link-desc="模型訓練階段建立的「呼叫工具」能力：知道何時該呼叫、傳什麼參數">Function calling&lt;/a>、&lt;a href="https://tarrragon.github.io/blog/llm/knowledge-cards/structured-output/" data-link-title="Structured Output" data-link-desc="讓 LLM 輸出可被 parser 穩定消費的推論階段設計：JSON mode、schema-guided decoding、grammar 約束都屬於這一層">structured output&lt;/a>、&lt;a href="https://tarrragon.github.io/blog/llm/knowledge-cards/mcp/" data-link-title="MCP（Model Context Protocol）" data-link-desc="LLM application ↔ 外部 tool server 之間的標準化協議、複用 OpenAI 相容 API 的成功模式">MCP&lt;/a> 是 LLM 應用落地時最常被混為一談的三個術語。三者解的問題層級完全不同：function calling 是&lt;strong>模型能力&lt;/strong>（訓練階段建立）、structured output 是**&lt;a href="https://tarrragon.github.io/blog/llm/knowledge-cards/sampling-constraint/" data-link-title="Sampling Constraint" data-link-desc="推論時限制下一個 token 候選集合的控制手段，用來把模型生成導向合法格式或特定選項">sampling 約束&lt;/a>&lt;strong>（推論階段控制）、MCP 是&lt;/strong>server 協議**（架構層標準化）。把三者放回正確層級、應用設計就會變清楚；混為一談會看到「我啟用了 function calling 為什麼還需要 structured output」「MCP 跟 function calling 衝突嗎」這類根本誤解。&lt;/p>
&lt;p>本章把三者的層級差異拆開、解釋為什麼會出現 MCP、跟它們在實際應用中怎麼組合。具體 spec 細節（OpenAI function calling JSON 格式、Anthropic tools API、MCP server 實作）不在本章——這些半年一變、本章寫的是「換 spec 之後仍成立」的概念結構。&lt;/p>
&lt;h2 id="本章目標">本章目標&lt;/h2>
&lt;p>讀完本章後你能：&lt;/p>
&lt;ol>
&lt;li>用一句話分別說清楚三者解什麼問題。&lt;/li>
&lt;li>看到「啟用 function calling」「設定 structured output」「裝 MCP server」這些句子時、知道在說哪一層。&lt;/li>
&lt;li>判斷一個 LLM 應用該用哪幾個組合、什麼情境只需要一部分。&lt;/li>
&lt;li>解釋為什麼 MCP 會出現、它複用了哪個成功模式。&lt;/li>
&lt;/ol>
&lt;h2 id="三個概念的層級差異">三個概念的層級差異&lt;/h2>
&lt;table>
 &lt;thead>
 &lt;tr>
 &lt;th>概念&lt;/th>
 &lt;th>解的問題&lt;/th>
 &lt;th>在哪一層&lt;/th>
 &lt;th>跟模型訓練的關係&lt;/th>
 &lt;/tr>
 &lt;/thead>
 &lt;tbody>
 &lt;tr>
 &lt;td>Function calling&lt;/td>
 &lt;td>模型怎麼「知道」要呼叫工具&lt;/td>
 &lt;td>模型能力&lt;/td>
 &lt;td>訓練時建立、寫進權重&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>Structured output&lt;/td>
 &lt;td>模型輸出怎麼被 parser 確定性消費&lt;/td>
 &lt;td>Sampling 約束&lt;/td>
 &lt;td>推論時控制、跟訓練無關&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>MCP&lt;/td>
 &lt;td>LLM application 怎麼接外部 tool&lt;/td>
 &lt;td>Server 協議&lt;/td>
 &lt;td>不涉模型、純架構標準&lt;/td>
 &lt;/tr>
 &lt;/tbody>
&lt;/table>
&lt;p>三者正交、可獨立或組合：&lt;/p>
&lt;ul>
&lt;li>用 function calling 但不用 structured output：訓練過 tool use 的模型直接呼叫工具、靠模型自律輸出合法 JSON。&lt;/li>
&lt;li>用 structured output 但不用 function calling：模型沒訓練過 tool use、用 prompt + grammar 強制輸出合法格式。&lt;/li>
&lt;li>用 MCP 但不用 function calling：MCP 標準化 tool 的暴露方式、模型用什麼機制呼叫不重要。&lt;/li>
&lt;li>三者都用：function calling 讓模型穩、structured output 約束格式、MCP 提供 tool ecosystem。&lt;/li>
&lt;/ul>
&lt;p>把這張表記熟、再看 LLM 應用相關討論、會發現「這個工具支援 function calling」「我的應用要 MCP」這類句子實際在說不同層級。&lt;/p>
&lt;h2 id="function-calling-是模型能力">Function Calling 是模型能力&lt;/h2>
&lt;p>Function calling 是模型在訓練階段建立的能力：&lt;a href="https://tarrragon.github.io/blog/llm/03-theoretical-foundations/training-pipeline/" data-link-title="3.4 訓練流程：pre-train → SFT → RLHF" data-link-desc="LLM 的三階段訓練：預訓練、指令微調、人類反饋強化學習；各階段目標與最新替代方案">SFT 階段&lt;/a>大量「使用者 query + 該呼叫什麼工具 + 傳什麼參數」的範例、讓模型學會「看到 query 知道何時呼叫、怎麼呼叫」。&lt;/p>
&lt;p>判讀模型 function calling 強弱的訊號：&lt;/p>
&lt;ul>
&lt;li>該呼叫時呼叫、不該呼叫時不呼叫的準確度。&lt;/li>
&lt;li>呼叫格式合法率（不亂寫 JSON）。&lt;/li>
&lt;li>參數準確度（type 正確、value 合理）。&lt;/li>
&lt;li>多工具情況下選對工具的準確度。&lt;/li>
&lt;/ul>
&lt;p>這四個訊號跨模型差異大、根因是訓練資料分佈：&lt;/p>
&lt;ul>
&lt;li>OpenAI / Anthropic 旗艦模型 SFT 階段 function calling 範例大量、表現穩定。&lt;/li>
&lt;li>Llama 3 / Gemma 4 / Qwen3 開源旗艦模型 SFT 階段也加 function calling、但範例量不一、表現有落差。&lt;/li>
&lt;li>小型開源模型（&amp;lt; 14B）function calling 訓練嚴重不足；tool schema 複雜、多工具選擇、巢狀參數時失敗率高、單一工具 + 平坦 schema 仍可用。&lt;/li>
&lt;/ul>
&lt;p>理解這點的價值：看到「這個模型支援 function calling」的宣稱、要追問「&lt;a href="https://tarrragon.github.io/blog/llm/knowledge-cards/training-example-coverage/" data-link-title="Training Example Coverage" data-link-desc="訓練資料中的任務範例是否覆蓋足夠情境，決定模型在 function calling、格式輸出與邊界案例上的穩定性">訓練範例 coverage&lt;/a> 多廣」、不是 binary 的支援 / 不支援、是 &lt;a href="https://tarrragon.github.io/blog/llm/knowledge-cards/capability-spectrum/" data-link-title="Capability Spectrum" data-link-desc="把模型能力視為連續光譜而非支援 / 不支援二分，用覆蓋度、穩定性與失敗模式判讀真實可用性">spectrum&lt;/a> 的訓練深度。&lt;/p></description><content:encoded><![CDATA[<p><a href="/blog/llm/knowledge-cards/function-calling/" data-link-title="Function Calling" data-link-desc="模型訓練階段建立的「呼叫工具」能力：知道何時該呼叫、傳什麼參數">Function calling</a>、<a href="/blog/llm/knowledge-cards/structured-output/" data-link-title="Structured Output" data-link-desc="讓 LLM 輸出可被 parser 穩定消費的推論階段設計：JSON mode、schema-guided decoding、grammar 約束都屬於這一層">structured output</a>、<a href="/blog/llm/knowledge-cards/mcp/" data-link-title="MCP（Model Context Protocol）" data-link-desc="LLM application ↔ 外部 tool server 之間的標準化協議、複用 OpenAI 相容 API 的成功模式">MCP</a> 是 LLM 應用落地時最常被混為一談的三個術語。三者解的問題層級完全不同：function calling 是<strong>模型能力</strong>（訓練階段建立）、structured output 是**<a href="/blog/llm/knowledge-cards/sampling-constraint/" data-link-title="Sampling Constraint" data-link-desc="推論時限制下一個 token 候選集合的控制手段，用來把模型生成導向合法格式或特定選項">sampling 約束</a><strong>（推論階段控制）、MCP 是</strong>server 協議**（架構層標準化）。把三者放回正確層級、應用設計就會變清楚；混為一談會看到「我啟用了 function calling 為什麼還需要 structured output」「MCP 跟 function calling 衝突嗎」這類根本誤解。</p>
<p>本章把三者的層級差異拆開、解釋為什麼會出現 MCP、跟它們在實際應用中怎麼組合。具體 spec 細節（OpenAI function calling JSON 格式、Anthropic tools API、MCP server 實作）不在本章——這些半年一變、本章寫的是「換 spec 之後仍成立」的概念結構。</p>
<h2 id="本章目標">本章目標</h2>
<p>讀完本章後你能：</p>
<ol>
<li>用一句話分別說清楚三者解什麼問題。</li>
<li>看到「啟用 function calling」「設定 structured output」「裝 MCP server」這些句子時、知道在說哪一層。</li>
<li>判斷一個 LLM 應用該用哪幾個組合、什麼情境只需要一部分。</li>
<li>解釋為什麼 MCP 會出現、它複用了哪個成功模式。</li>
</ol>
<h2 id="三個概念的層級差異">三個概念的層級差異</h2>
<table>
  <thead>
      <tr>
          <th>概念</th>
          <th>解的問題</th>
          <th>在哪一層</th>
          <th>跟模型訓練的關係</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>Function calling</td>
          <td>模型怎麼「知道」要呼叫工具</td>
          <td>模型能力</td>
          <td>訓練時建立、寫進權重</td>
      </tr>
      <tr>
          <td>Structured output</td>
          <td>模型輸出怎麼被 parser 確定性消費</td>
          <td>Sampling 約束</td>
          <td>推論時控制、跟訓練無關</td>
      </tr>
      <tr>
          <td>MCP</td>
          <td>LLM application 怎麼接外部 tool</td>
          <td>Server 協議</td>
          <td>不涉模型、純架構標準</td>
      </tr>
  </tbody>
</table>
<p>三者正交、可獨立或組合：</p>
<ul>
<li>用 function calling 但不用 structured output：訓練過 tool use 的模型直接呼叫工具、靠模型自律輸出合法 JSON。</li>
<li>用 structured output 但不用 function calling：模型沒訓練過 tool use、用 prompt + grammar 強制輸出合法格式。</li>
<li>用 MCP 但不用 function calling：MCP 標準化 tool 的暴露方式、模型用什麼機制呼叫不重要。</li>
<li>三者都用：function calling 讓模型穩、structured output 約束格式、MCP 提供 tool ecosystem。</li>
</ul>
<p>把這張表記熟、再看 LLM 應用相關討論、會發現「這個工具支援 function calling」「我的應用要 MCP」這類句子實際在說不同層級。</p>
<h2 id="function-calling-是模型能力">Function Calling 是模型能力</h2>
<p>Function calling 是模型在訓練階段建立的能力：<a href="/blog/llm/03-theoretical-foundations/training-pipeline/" data-link-title="3.4 訓練流程：pre-train → SFT → RLHF" data-link-desc="LLM 的三階段訓練：預訓練、指令微調、人類反饋強化學習；各階段目標與最新替代方案">SFT 階段</a>大量「使用者 query + 該呼叫什麼工具 + 傳什麼參數」的範例、讓模型學會「看到 query 知道何時呼叫、怎麼呼叫」。</p>
<p>判讀模型 function calling 強弱的訊號：</p>
<ul>
<li>該呼叫時呼叫、不該呼叫時不呼叫的準確度。</li>
<li>呼叫格式合法率（不亂寫 JSON）。</li>
<li>參數準確度（type 正確、value 合理）。</li>
<li>多工具情況下選對工具的準確度。</li>
</ul>
<p>這四個訊號跨模型差異大、根因是訓練資料分佈：</p>
<ul>
<li>OpenAI / Anthropic 旗艦模型 SFT 階段 function calling 範例大量、表現穩定。</li>
<li>Llama 3 / Gemma 4 / Qwen3 開源旗艦模型 SFT 階段也加 function calling、但範例量不一、表現有落差。</li>
<li>小型開源模型（&lt; 14B）function calling 訓練嚴重不足；tool schema 複雜、多工具選擇、巢狀參數時失敗率高、單一工具 + 平坦 schema 仍可用。</li>
</ul>
<p>理解這點的價值：看到「這個模型支援 function calling」的宣稱、要追問「<a href="/blog/llm/knowledge-cards/training-example-coverage/" data-link-title="Training Example Coverage" data-link-desc="訓練資料中的任務範例是否覆蓋足夠情境，決定模型在 function calling、格式輸出與邊界案例上的穩定性">訓練範例 coverage</a> 多廣」、不是 binary 的支援 / 不支援、是 <a href="/blog/llm/knowledge-cards/capability-spectrum/" data-link-title="Capability Spectrum" data-link-desc="把模型能力視為連續光譜而非支援 / 不支援二分，用覆蓋度、穩定性與失敗模式判讀真實可用性">spectrum</a> 的訓練深度。</p>
<h2 id="structured-output-是-sampling-約束">Structured Output 是 Sampling 約束</h2>
<p><a href="/blog/llm/knowledge-cards/structured-output/" data-link-title="Structured Output" data-link-desc="讓 LLM 輸出可被 parser 穩定消費的推論階段設計：JSON mode、schema-guided decoding、grammar 約束都屬於這一層">Structured output</a> 是推論階段的技巧、跟模型訓練無關：在 <a href="/blog/llm/03-theoretical-foundations/sampling-and-decoding/" data-link-title="3.5 Sampling 與 Decoding 策略" data-link-desc="Greedy、beam search、top-k、top-p、temperature、min-p：模型輸出後怎麼挑下一個 token">sampling</a>（從機率分佈挑下一個 token 的步驟）時對每個 token 做 <a href="/blog/llm/knowledge-cards/grammar/" data-link-title="Grammar" data-link-desc="描述合法字串形狀的形式規則，在 structured output 中用來限制 LLM 每一步可輸出的 token">grammar</a> / schema 約束、不合法 token 的機率（logit、token 機率的對數）被歸零、把不合法輸出的可能性壓到不會被 sample。</p>
<p>主要實作機制（適用 / 限制條件附在每項下）：</p>
<ul>
<li><strong>JSON mode</strong>：每步 sampling 過濾、只允許「保持 JSON 仍合法」的 token。適用：絕大多數 OpenAI 相容 API 都有支援；限制：只保 JSON 合法、不保 schema 對位。</li>
<li><strong>Grammar-constrained sampling</strong>：用 <a href="/blog/llm/knowledge-cards/grammar/" data-link-title="Grammar" data-link-desc="描述合法字串形狀的形式規則，在 structured output 中用來限制 LLM 每一步可輸出的 token">grammar</a>（描述合法語法的形式化規則、實作上常用 <a href="/blog/llm/knowledge-cards/bnf/" data-link-title="BNF（Backus-Naur Form）" data-link-desc="用遞迴產生式描述語法的經典記法，是 CFG、parser 與 grammar-constrained sampling 常見的基礎表示">BNF</a> 或 <a href="/blog/llm/knowledge-cards/lark-grammar/" data-link-title="Lark Grammar" data-link-desc="Lark parser 使用的 EBNF-like grammar 格式，常被 structured output 工具拿來描述自訂輸出語法">Lark grammar</a>）描述完整輸出形狀、推論時逐 token 過濾。適用：需要嚴格自訂格式（<a href="/blog/llm/knowledge-cards/dsl/" data-link-title="DSL（Domain-Specific Language）" data-link-desc="為特定業務或技術領域設計的小語言，在 LLM 應用中常作為可解析、可驗證、可執行的中介輸出">DSL</a>、特定 query language）；限制：要伺服器層支援（llama.cpp、vLLM 有、有些雲端 API 沒）。</li>
<li><strong>Schema-guided</strong>：依 JSON Schema 動態決定每步允許哪些 token、強制 enum / type / required 等約束。適用：複雜結構化資料；限制：實作複雜度高、跨伺服器一致性差。</li>
<li><strong>Logit bias</strong>：對特定 token 加 bias、間接引導 sampling、最弱但最靈活的方式。適用：簡單的 token 黑名單 / 白名單；限制：無法保證結構合法。</li>
</ul>
<p>優勢相對 function calling：</p>
<ul>
<li><strong>跨模型可移植</strong>：不依賴模型訓練、任何能跑 sampling 的模型都能上。</li>
<li><strong>可任意自訂格式</strong>：不限於 OpenAI 或某 provider 的 function spec、想定義什麼 schema 都行。</li>
<li><strong>保證 100% 合法輸出</strong>：grammar 約束下不可能輸出 invalid JSON。</li>
</ul>
<p>代價：</p>
<ul>
<li><strong>約束太嚴可能跟模型「自然」輸出衝突</strong>：模型本來想說 A、grammar 強制只能說 B、品質會降。</li>
<li><strong>實作成本</strong>：grammar 解析跟動態 logit mask 在推論伺服器要支援、不是所有 server 都成熟。</li>
<li><strong>跟模型訓練脫鉤</strong>：模型「不知道」自己被約束、可能還是用沒用 function calling 訓練的「猜測」方式生成。</li>
</ul>
<p>實務上 structured output 跟 function calling 經常組合：function calling 訓練讓模型「自然」傾向合法輸出、structured output 約束兜底保證「真的合法」。</p>
<h2 id="mcp-是-server-協議">MCP 是 Server 協議</h2>
<p>MCP（Model Context Protocol、2024 年由 Anthropic 提出）是「LLM application ↔ 外部 tool server 之間的標準化協議」。它不在模型能力層、不在 sampling 層、是更高層的架構規範。</p>
<p>要理解 MCP 的定位、回顧 LLM 生態的歷史問題：</p>
<p>每個 LLM application（Cursor、Continue.dev、Claude Desktop、aider 等）要接每個 tool（檔案系統、資料庫、search、自訂 API），都得寫 adapter。N 個 application × M 個 tool 的整合成本是 N×M、生態擴張時成本爆炸。</p>
<p>MCP 把這個成本拆成兩段：</p>
<ul>
<li><strong>LLM application 端</strong>：實作 MCP client（一次）、之後支援任意 MCP server。</li>
<li><strong>Tool 端</strong>：實作 MCP server（一次）、之後被任意 MCP client 接到。</li>
</ul>
<p>整合成本從 N×M 降到 N+M。同樣的 ecosystem effect 跟模組零的 <a href="/blog/llm/00-foundations/openai-compatible-api/" data-link-title="0.3 OpenAI 相容 API" data-link-desc="為什麼幾乎所有本地 LLM 工具不用改就能切到本地：背後是同一套 API 形狀">OpenAI 相容 API</a> 一樣——標準化中介把生態整合複雜度從乘法降到加法。</p>
<p>MCP 涵蓋的「server 該提供什麼」包括：</p>
<ul>
<li>Tool 註冊（這個 server 提供哪些 tool）。</li>
<li>Tool schema（每個 tool 的參數定義）。</li>
<li>Tool 呼叫協議（呼叫方式 + 回應格式）。</li>
<li>Resource 暴露（檔案、文件等讀取資源）。</li>
<li>Prompt template 共享（reusable system prompt）。</li>
</ul>
<p>這些都在 protocol 層、模型怎麼用 tool（function calling 還是 structured output）不在 MCP 規範範圍——MCP 不管你模型強不強、它只管「tool 怎麼被暴露」。</p>
<h2 id="為什麼會出現-mcp">為什麼會出現 MCP</h2>
<p>MCP 是 LLM application 生態擴張到一定程度後的必然產物。觀察生態演化：</p>
<ul>
<li><strong>2023 早期</strong>：每個 LLM app 各自寫工具整合、Cursor 接 file system、Continue.dev 接 codebase、aider 接 git——各自的 adapter 邏輯互不通用。</li>
<li><strong>2024 中期</strong>：function calling spec 標準化（OpenAI 跟 Anthropic 各自定義）、解決「模型怎麼呼叫工具」、但「工具怎麼暴露給 application」還是各家自己處理。</li>
<li><strong>2024 底</strong>：Anthropic 提 MCP、把「工具暴露」也標準化、補完 ecosystem 拼圖。</li>
</ul>
<p>複用 OpenAI 相容 API 的成功模式：</p>
<ul>
<li><a href="/blog/llm/knowledge-cards/openai-compatible-api/" data-link-title="OpenAI 相容 API" data-link-desc="本地推論伺服器跟雲端 OpenAI 共用的 API 形狀標準">OpenAI 相容 API</a>：標準化「介面層 ↔ <a href="/blog/llm/knowledge-cards/inference-server/" data-link-title="Inference Server" data-link-desc="載入模型權重、處理 prompt、產生 token 的常駐 process">推論伺服器</a>」、所有 IDE plugin 都接這個。</li>
<li>MCP：標準化「LLM application ↔ tool server」、所有 application 都接這個。</li>
</ul>
<p>兩者都採用同個策略：定義最小可用標準、讓生態繞著標準長、所有 player 受益。</p>
<p>MCP 成熟度判讀訊號（不固化在某一個時間點、用這幾個 signal 重新評估）：</p>
<ul>
<li><strong>Application 採納範圍</strong>：主要 LLM application（Claude Desktop、Cursor、Continue.dev、其他主流 IDE / chat 介面）是否原生支援。</li>
<li><strong>Tool server catalog 規模</strong>：社群維護的 MCP server 數量跟覆蓋範圍（檔案系統、git、Slack、雲端 API 等是否都有現成 server）。</li>
<li><strong>本地推論生態接入度</strong>：Ollama、LM Studio 等本地伺服器是否原生支援 MCP（或仍以 OpenAI 相容 API 為主）。</li>
<li><strong>跨平台一致性</strong>：Windows / macOS / Linux 上的 MCP server 行為是否一致、SDK 是否穩定。</li>
</ul>
<p>四個訊號全部成熟前、MCP 仍處於「主要 application 支援、本地生態剛開始接」的擴張期；訊號逐步達標後、預期會像 OpenAI 相容 API 一樣成為應用層的默認標準。</p>
<p>它跟 function calling 的關係：MCP 提供 tool 的暴露機制、模型怎麼呼叫這些 tool 仍走 function calling（如果模型支援）或 structured output（如果用約束）。三者疊加而非互斥。</p>
<h2 id="三者組合的實際工作流">三者組合的實際工作流</h2>
<p>一個完整 LLM application 的典型 stack：</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln"> 1</span><span class="cl">使用者 prompt
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">  ↓
</span></span><span class="line"><span class="ln"> 3</span><span class="cl">LLM application（Claude Desktop / Cursor / 自家應用）
</span></span><span class="line"><span class="ln"> 4</span><span class="cl">  ↓ (MCP client、列出所有可用 tool)
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">MCP server pool（檔案系統 server、git server、自家 API server...）
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">  ↑
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">LLM application 把 tool 描述塞進 prompt
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">  ↓
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">推論伺服器（OpenAI API / Ollama / Anthropic API）
</span></span><span class="line"><span class="ln">10</span><span class="cl">  ↓ (function calling 訓練 + structured output 約束)
</span></span><span class="line"><span class="ln">11</span><span class="cl">模型輸出：「我要呼叫 tool X、參數是 Y」
</span></span><span class="line"><span class="ln">12</span><span class="cl">  ↓
</span></span><span class="line"><span class="ln">13</span><span class="cl">LLM application 用 MCP 把呼叫送到對應 server
</span></span><span class="line"><span class="ln">14</span><span class="cl">  ↓
</span></span><span class="line"><span class="ln">15</span><span class="cl">Server 執行、回應
</span></span><span class="line"><span class="ln">16</span><span class="cl">  ↓
</span></span><span class="line"><span class="ln">17</span><span class="cl">LLM application 把結果塞進 context、回到推論伺服器繼續</span></span></code></pre></div><p>三者各司其職：</p>
<ul>
<li><strong>Function calling</strong> 讓模型穩定輸出工具呼叫（訓練支撐）。</li>
<li><strong>Structured output</strong> 兜底保證呼叫格式合法（sampling 約束）。</li>
<li><strong>MCP</strong> 提供 tool ecosystem、application 不用為每個 tool 寫專屬 adapter（架構標準）。</li>
</ul>
<p>少了任一個都還能跑、但效率跟生態擴展性降一級：</p>
<ul>
<li>沒 function calling、靠 prompt + structured output、跨模型品質不穩。判讀訊號：同 prompt 在不同模型上 tool 呼叫格式錯誤率差 30% 以上。</li>
<li>沒 structured output、靠模型自律、偶有失敗。判讀訊號：&lt; 30B 模型在複雜 schema 下 JSON 合法率 &lt; 90%。</li>
<li>沒 MCP、每個 application 自己寫所有 tool 整合、ecosystem 不可規模化。判讀訊號：團隊維護 &gt; 5 個 tool adapter、每換 LLM provider 重寫一輪。</li>
</ul>
<h2 id="常見的組合誤用">常見的組合誤用</h2>
<p>三者組合在以下情境會失敗、是判讀「我的應用為何不穩」的常見候選：</p>
<ul>
<li><strong>Structured output 蓋過 function calling 訓練</strong>：模型訓練時用 Anthropic tools 格式、應用強制套 OpenAI function spec 的 grammar、模型輸出「合法但語意空洞」的 JSON（schema 對、欄位填湊數）。修法：用模型訓練過的 spec、避免在 grammar 層強制改寫。</li>
<li><strong>MCP server 在 prompt context 撐爆 tool 描述</strong>：MCP server 暴露幾十個 tool、每個都有 schema 跟 description、全塞進 system prompt 把 context budget 耗光。修法：dynamic tool selection（先讓 LLM 看「tool 摘要」選相關的、再把選中 tool 的詳細 schema 塞進 context）。</li>
<li><strong>Function calling + structured output 兩邊 schema 不一致</strong>：模型訓練的 function spec 跟 application 套的 JSON schema 欄位不對、模型輸出符合訓練 spec 但不符合 application schema、parser 失敗。修法：grammar 直接從 function spec 生、避免人工維護兩份。</li>
<li><strong>MCP server 沒做 input validation、prompt injection 通過 tool 結果污染 context</strong>：tool 回的內容沒檢查、惡意內容（如 PR 留言中的「請執行 rm -rf」）被模型當指令執行。修法：tool 輸出做 sanitization、可疑內容用 sandbox 標籤包起來、模型 prompt 明確區分「使用者指令」vs「tool 結果」。個人 dev 在自己機器上跑 MCP server 的權限模型（檔案系統 / shell / 網路存取邊界、第三方 MCP 信任）見 <a href="/blog/llm/06-security/tool-use-permission-model/" data-link-title="6.2 tool use 與 MCP server 的權限模型" data-link-desc="個人 dev 場景下 tool use / MCP server 的副作用權限：檔案系統 / shell / 網路存取邊界、第三方 MCP 信任、副作用的可逆性">6.2</a>；IDE 場景中 codebase / 外部文件 / 剪貼簿等 prompt injection 攻擊面見 <a href="/blog/llm/06-security/prompt-injection-in-ide/" data-link-title="6.3 IDE 場景的 prompt injection" data-link-desc="個人 dev 場景下 IDE 寫 code 工作流的 prompt injection：codebase 內容、外部文件、剪貼簿作為攻擊面、跟雲端 LLM 場景的差異">6.3</a>。</li>
</ul>
<h2 id="何時可以只用一部分">何時可以只用一部分</h2>
<p>三者組合的需求視場景而定：</p>
<ul>
<li><strong>單純 structured 輸出</strong>（不呼叫工具）：只需 structured output、不需 function calling / MCP。例：把使用者輸入分類成 enum、輸出固定 schema 的 JSON。</li>
<li><strong>In-process tool</strong>（直接 Python function）：function calling + 簡單 dispatcher、不需 MCP。應用規模小時最直接。</li>
<li><strong>跨 application 共用 tool</strong>：才需要 MCP。如果你只寫自己用的 app、in-process 比 MCP 簡單。</li>
<li><strong>用較弱模型</strong>：可能只用 structured output、跳過 function calling。</li>
</ul>
<p>三者的「最小可用組合」視應用複雜度而定。早期應用通常從 function calling 開始、規模化後加 MCP、品質要求高時加 structured output 兜底——演化路徑不必一步到位。</p>
<h2 id="何時過時--何時不過時">何時過時 / 何時不過時</h2>
<p><strong>不會過時的部分</strong>：</p>
<ul>
<li>三個層級的分界（模型能力 / sampling 約束 / server 協議）。</li>
<li>N×M → N+M 的標準化收益、跟 OpenAI 相容 API 的對應。</li>
<li>三者疊加而非互斥的設計取捨。</li>
<li>「最小可用組合」的判讀框架。</li>
</ul>
<p><strong>會變的部分</strong>：</p>
<ul>
<li>MCP 是 2024-2025 才標準化的協議、未來 5 年可能演化或被新協議補充（協議層更新慢、但會更新）。</li>
<li>各家 function calling spec 的具體格式（OpenAI / Anthropic / 開放標準會持續細化）。</li>
<li>Structured output 的具體實作（grammar engines / JSON mode 會持續優化）。</li>
<li>哪些工具有 MCP server 可用（生態 catalog 會擴展）。</li>
</ul>
<p>看到新協議或新 spec 時、回到本章三層 framing 問：它解的是哪一層？能不能跟既有的另兩層組合？這個問題的答案能很快定位新東西在 stack 中的位置。</p>
<h2 id="下一章">下一章</h2>
<p>下一章：<a href="/blog/llm/04-applications/workflow-patterns/" data-link-title="4.7 Workflow 編排模式" data-link-desc="Pipeline / router / parallel / reflection：多 LLM call 組合的四種基本模式與退化條件">4.7 Workflow 編排模式</a>、把多 LLM call 組合的設計模式整理出來。</p>
]]></content:encoded></item></channel></rss>