總覽與定位
從「單次 LLM 呼叫」到「多步驟編排」——LangChain、Agent 這類東西到底想解決什麼問題。
最單純的用法是:一段 prompt 進去、一段文字出來。但真實應用需要 LLM 做事——查今天的庫存、寫進資料庫、跨多個步驟完成一件任務。單次呼叫做不到這些:它不能執行動作、拿不到即時或私有資料、也無法可靠地把大任務拆成多步。
編排(Orchestration) 就是把 LLM 呼叫、工具、資料檢索與控制流組合成一個「能完成任務」的系統;Agent 則是編排的一種特殊形態——把「下一步做什麼」的決策權交給 LLM 自己。這也是 LangChain/LlamaIndex 等框架的共同命題。本篇刻意不綁定任何框架,只講底層心智模型,因為框架會換、原語不會。
三者常被混談,但各管一段:RAG 解決「把對的資料塞進 context」(檢索);LLM Gateway 解決「呼叫哪顆模型、怎麼控成本與流量」(模型路由);本篇的編排/Agent 解決「把多次呼叫與工具串成一個能完成任務的流程」(控制流)。RAG 常常只是 Agent 手上的其中一個工具。
核心原語:Tool / Function Calling
整個 Agent 世界的最小積木——讓模型「決定呼叫哪個函式、帶什麼參數」的機制。
Function Calling(也叫 Tool Calling)是這樣運作的:你把可用工具的「規格」告訴模型,模型在推理後不是回一段自然語言,而是回一個結構化的呼叫意圖(工具名稱+參數)。它自己不執行,執行是你的 runtime 的責任。四個環節:
name + arguments,而非散文。一個工具規格長這樣(框架無關,概念上就是「給模型看的函式簽章」):
{
"name": "get_order",
"description": "用訂單編號查詢訂單狀態與物流單號。當使用者詢問訂單進度時使用。",
"parameters": {
"type": "object",
"properties": {
"order_id": { "type": "string", "description": "訂單編號,如 A1234" }
},
"required": ["order_id"]
}
}
模型看得到的只有這份「說明書」。它靠 description 判斷何時該用、靠 parameters 知道要湊哪些參數——所以描述寫得爛,模型就召喚錯工具或亂填參數。
這是最容易誤解的一點:LLM 輸出的 tool call 只是一個意圖(intent),像填好一張申請單。真正去執行、去碰資料庫與外部 API 的,是你的 runtime。這個「決策」與「執行」的分離,正是後續 Agent Runtime 後端服務設計 與 Tool Gateway 安全邊界 兩篇要深入的地方——因為執行點就是風險點。
| schema 欄位 | 作用 | 寫不好會怎樣 |
|---|---|---|
name |
工具識別 | 命名含糊(do_stuff)→ 模型難判斷用途 |
description |
何時該用 | 最關鍵:描述不清 → 該用時不用、不該用時亂用 |
parameters |
參數約束 | 缺型別/必填約束 → 模型湊出無效參數,執行時炸 |
| 回傳(慣例) | 結果格式 | 結構混亂 → 模型讀不懂結果,下一步推理走偏 |
工具規格是「人給模型的介面契約」;契約寫得好壞,直接決定 Agent 可靠度。
塞幾十個工具給模型,反而讓它選擇困難、召喚錯工具、還吃掉大量 prompt token。實務上常用「工具分組/依情境只暴露相關子集」來收斂。這也預示了 MCP 這類協定要解的問題——工具太多、太雜、來源太散時,需要標準化的發現與描述方式(見第 6 節)。
Agent Loop:推理 → 行動 → 觀察
把「單次 tool call」升級成「持續迴圈」——這就是一個 Agent 的心臟。
單次工具呼叫只能處理「一步就能答」的問題。真正的 Agent 把 Tool Calling 包進一個迴圈:模型推理(Thought)下一步 → 行動(Action,發出 tool call) → runtime 執行後回傳觀察(Observation) → 模型讀完觀察再推理下一步……如此反覆,直到它認為資訊足夠、輸出最終答案。這個「Reason + Act」的迴圈常被稱為 ReAct 模式。
stateDiagram-v2
[*] --> Thought
Thought --> Action: 決定呼叫工具
Action --> Observation: runtime 執行完回傳
Observation --> Thought: 資訊還不夠
Thought --> Answer: 判斷資訊已足夠
Observation --> Halt: 撞上 max-iterations
Answer --> [*]
Halt --> [*]
看兩條出口:正常出口是 Thought → Answer(模型自己判斷夠了);另一條 Observation → Halt 是護欄強制中止。中間 Observation → Thought 那條回邊就是 context 每繞一圈就變長的地方。
這個迴圈每一輪都攜帶並更新一些狀態:
- 對話/執行歷史:使用者問題 + 歷次 Thought/Action/Observation,全部累積在 context 裡,一起餵回模型。
- 可用工具集:這一輪模型能選用的工具。
- 步數計數:走了幾輪——這是護欄的錨點(見下)。
迴圈的終止條件是「模型輸出不含 tool call 的最終答案」。但模型可能永遠不收斂:反覆呼叫同一個工具、在兩個動作間鬼打牆、或因為某步觀察看不懂而一直重試。因此每個正式 Agent 都必須設硬護欄:最大步數(max iterations)、逾時、以及重複動作偵測。撞到上限就中止並回報,而不是無限燒 token。
因為每一輪都把「歷史全文」再送一次給模型,走得越多步、context 越長,每一步的 token 成本與延遲都在往上疊。一個 5 步的 Agent,最後一步吃的 token 可能是第一步的好幾倍。這解釋了為什麼 Agent「能做很多事」的同時「又慢又貴」——第 5 節會把這筆帳算清楚。
編排模式光譜:Workflow vs Agent
不是「有沒有用 Agent」的二分法,而是一條從「確定性」滑到「自主性」的光譜。
業界一個好用的框架(框架無關)是把編排分成兩端:Workflow 是「LLM 與工具照預先寫死的程式路徑跑」;Agent 是「LLM 動態決定自己的流程與工具用法」。在這兩端之間有一整排常見模式,但要注意——除了最後的 Autonomous Agent,其餘全都還是 Workflow 的變體,差別只在 LLM 在既定結構內被賦予多少裁量權:
| 模式 | 控制流 | 何時用 |
|---|---|---|
| Prompt Chaining | 固定序列 | 任務能乾淨拆成穩定步驟(草稿→翻譯→潤稿) |
| Routing | 先分類再分流 | 輸入類型多樣,各走不同專用處理(客服工單分流) |
| Parallelization | 並行 + 匯總 | 可切分工作或需多次投票取共識(多面向審查) |
| Orchestrator–Workers | 協調者動態拆派 | 子任務數量/內容事前未知,由 LLM 現場拆解 |
| Evaluator–Optimizer | 生成→評估→改寫迴圈 | 有明確評分標準、值得多輪打磨(翻譯校準) |
| Autonomous Agent | LLM 全程自主決策 | 路徑無法預先枚舉、需長尾應變(開放式任務) |
關鍵:除最後一項外,其餘五種都屬 Workflow(結構由工程師預先定義);由上到下遞增的是「LLM 在既定結構內的裁量權」,只有 Autonomous Agent 才真正跨進 Agent。
Agent 不是越自主越高級。自主性換來的是不可預測、難除錯、成本浮動。實務準則是:能用固定 Workflow 解決的,就別上 Agent;只有當「路徑真的無法事先枚舉」時,自主性的代價才划算。「划算」不是形容詞——下面的互動 demo 把同一個任務同時餵給兩種控制流,把兩本帳算出來讓你看到交叉點落在哪裡。
任務:客服問答(如「訂單 #A1234 什麼時候到?」)。左欄是固定 pipeline:工程師事先為前 H 個分支各寫一個 handler,沒寫到的分支只能降級;右欄是自主 agent:不必枚舉分支,但每輪都得重送全歷史、還可能走錯路。兩欄吃同一組參數。
柱高=該次 LLM 呼叫的 prompt token。左欄每根等高(context 不累積),右欄逐輪長高(每輪都把歷史再送一次)——這就是 Agent Loop 那節說的「最後一步吃的 token 是第一步的好幾倍」。柱頂百分比是該輪仍在跑的機率,灰柱是被 max-iterations 砍掉的輪次。
橫軸是任務的情境分支數:workflow 的 handler 數固定不動,分支一多覆蓋率就掉、每次成功任務的成本往上翹;agent 不必枚舉分支所以是一條水平線。兩線相交處就是「該換 agent 了」的分界。
工程挑戰:可靠性 · 成本 · 可觀測性
Demo 裡「Agent 靈活勝出」很美好,但正式上線時,這三件事會反咬你一口。
把 Agent 從 demo 推到生產環境,難的從來不是「讓它動起來」,而是「讓它穩定、可負擔、看得見」。三個維度各有典型陷阱:
| 維度 | 典型問題 | 常見緩解 |
|---|---|---|
| 可靠性 | 幻覺 tool call、無限迴圈、工具回錯不會處理 | max iterations 護欄、參數校驗、工具錯誤回饋給模型重試、關鍵動作要人審 |
| 成本 | context 逐輪膨脹、每步都重送全歷史、步數失控 | 限制步數與工具數、歷史裁剪/摘要、快取、小任務用小模型 |
| 延遲 | 工具串行、每輪一次模型往返,累加起來很慢 | 可並行的工具並行、串流回覆、把確定步驟抽回 Workflow |
| 可觀測性 | 多步決策是黑盒,出錯難重現、難歸因 | 完整 trace 每一步 Thought/Action/Observation、記錄 token 與耗時、可重播 |
Agent 的三筆帳:對不對(可靠性)、貴不貴(成本/延遲)、看不看得見(可觀測性)。
模型可能召喚根本不存在的工具、或給存在的工具湊出無效參數。因為它輸出的只是「看起來合理的文字」,不保證對應真實系統。所以 runtime 必須把 tool call 當不可信輸入校驗:工具名在不在白名單?參數過不過 schema?——這正好接上 Tool Gateway、權限與安全邊界 那篇的核心。
對「不可逆或高風險」的動作(退款、刪資料、寄信給客戶),成熟做法是讓 Agent 走到那一步時暫停、等人確認再執行。把自主性限制在「安全的動作」上,危險動作留一道人為閘門——這是自主性與可控性之間最實用的折衷。
為何需要標準協定(MCP / A2A / ACP)
當工具、資料源、甚至別的 Agent 越來越多,「每對整合都自己刻」會爆炸——這就是協定要解的問題。
前面每個工具都要你手寫 schema、手接執行邏輯。當你有 M 個 Agent/應用、要接 N 個工具或資料源時,若每一對都各自客製,整合成本會逼近 M × N——每加一個新工具,所有 Agent 都要重接一次。這正是幾套新興協定想解的「整合爆炸」問題:
| 協定 | 連接的是 | 解決的核心問題 |
|---|---|---|
| MCP Model Context Protocol |
模型 ↔ 工具 / 資料 | 用標準協定描述與發現工具、資源、prompt,讓「一次實作、到處可用」,取代 M×N 客製 |
| A2A Agent-to-Agent |
Agent ↔ Agent | 讓不同團隊、不同框架做的 Agent 能互相委派任務與溝通 |
| ACP Agent Comm. Protocol |
Agent 互通 / 對照 | 與 A2A 同屬「Agent 間互通」路線,定位與取捨各有差異 |
把「工具接法」與「Agent 溝通」標準化,就像 USB/HTTP 之於硬體與網路——重點是通用介面,不是各自為政。
這裡刻意只講「為什麼需要標準協定」。角色分工(Host/Client/Server)、傳輸方式(stdio/HTTP+SSE)、訊息格式、與自建 Function Calling 的差異等,屬於 Model Context Protocol 深度解析、A2A Protocol、ACP 與 Agent 互通 三篇的守備範圍。你現在只需要記住那個動機:M×N 客製整合不可持續,所以要標準化。
面試折衷與實務選型
最值錢的判斷力不是「會不會搭 Agent」,而是「知道什麼時候不該用 Agent」。
面對一個需求,先問自己:這任務的路徑能不能事先枚舉?能,就用越確定性的方案越好;不能,才逐步往自主端移動。一個實用的決策階梯:
| 如果…… | 就用 | 理由 |
|---|---|---|
| 單次呼叫就能答,不需外部資料/動作 | 純 Prompt | 最便宜、最可預測,別過度設計 |
| 需要外部資料或動作,但步驟固定 | Workflow(Chaining/Routing) | 可預測、好測試、成本可估,涵蓋大多數場景 |
| 路徑無法事先枚舉、需長尾應變 | Agent(自主迴圈) | 用可預測性換靈活性;務必配護欄與可觀測性 |
| 含不可逆/高風險動作 | Agent + Human-in-the-loop | 自主歸自主,危險動作留人為閘門 |
選型階梯:從左(便宜可控)往右(靈活昂貴)逐級升,能停在左邊就別往右。
Q:什麼時候該用 Agent、什麼時候用 Workflow?
答:路徑能事先枚舉就用 Workflow(可預測、好除錯、成本可估);只有路徑無法枚舉、需長尾應變時才上 Agent,並付出不可預測與成本浮動的代價。
Q:Agent 上線最大的風險是什麼?
答:可靠性(幻覺 tool call、無限迴圈)、成本(context 逐輪膨脹)、可觀測性(多步黑盒)。對應要有 max-iterations 護欄、參數校驗、歷史裁剪、全程 trace。
Q:為什麼需要 MCP 這類協定?
答:Agent×工具的整合會走向 M×N 客製爆炸,標準協定讓工具「一次實作、到處插拔」。