本簡報以 16:9 橫向為主
請旋轉手機
或改用平板 / 桌機觀看
從 Tool Schema 到 ReAct Loop,從把 RAG 包成工具到三大陷阱防禦。今天結束,你能寫出第一個會循環呼叫工具的 Agent,並守得住生產環境。
不會用工具的 LLM, 永遠停在聊天框裡。
Function Calling 是 LLM 從「文字產生器」變成「行動代理」的開關。
但執行權永遠在你手上——這是它能上生產的前提。
不是「聽過」,而是「跑得起來」。
搞清楚這個邊界,你才知道為什麼 Function Calling 是安全的、可控的,
而不是「讓 AI 直接動你的資料庫」這種恐怖故事。
它不知道現在幾點、不知道你的庫存、
不知道訂單狀態、不知道客戶是誰。
所有「即時 / 私有 / 動態」資料,它都沒有。
Tools 補三類能力:
模型只負責判斷該呼叫哪個。
執行、權限、稽核——全在你的程式裡。
名稱 + description + JSON Schema 參數定義,
一次傳給模型作為「可用工具清單」。
模型決定「呼叫哪個工具、帶什麼參數」,
回傳 tool_use 區塊,不執行任何事。
你的程式真正執行,把結果以 tool_result
送回模型繼續對話,必要時再循環。
// Anthropic Claude · 工具定義範例 { "name": "get_weather", "description": "查詢指定城市的當前天氣", "input_schema": { "type": "object", "properties": { "city": { "type": "string", "description": "城市名稱,例如 台北" }, "unit": { "type": "string", "enum": ["celsius", "fahrenheit"] } }, "required": ["city"] } }
Mock 兩個函式,組一個 while loop,丟一個「台北比東京熱幾度?」
看模型是不是真的會依序呼叫 get_weather × 2 → calculator × 1。
get_weather(city)、calculator(expression),description 寫到能精準觸發。stop_reason === 'tool_use' 就解析、執行 mock、把 tool_result push 回 messages。max_turns = 5 保護機制,超過就強制跳出。
ReAct 是當代最常見的 Agent 架構。
看懂它的本質——「狀態機 + 對話歷史」——你就會自己組任何 Loop。
使用者輸入 + 上輪 tool_result。
模型決定要呼叫哪個工具、帶什麼參數。
程式接手執行,取得結果。
直到 stop_reason = end_turn 才結束。
stop_reason: "tool_use"(Claude)/ finish_reason: "tool_calls"(OpenAI)= 想用工具。tool_use 區塊,把 input 傳入本地函式取結果。tool_result 角色把結果送回,讓模型繼續推理。
你的程式負責維護對話歷史(messages array)。
模型每次都看到完整歷史,所以它能「記住」前幾輪的工具結果繼續推理。
模型本身無記憶。記憶在你的陣列裡。
RAG 不一定要寫成獨立 pipeline。
包成工具給 Agent 用,模型自己決定何時查、查什麼——更彈性,也更接近真實場景。
公司 SOP、客戶資料、產品規格、會議紀錄、新政策——
這些是模型永遠不知道的「私有現在」。
在 D14 的 Agent 架構下:
search_docs 工具RAG 變成 Agent 的一個工具,不是獨立流程。
PDF / Word / 網頁 → 純文字
Chunking(含 overlap)
每塊轉向量入庫
問題 → 向量 → top-k
問題 + chunks → LLM
離線、文件更新才重跑、可預先準備好。
線上、每次提問執行、效能瓶頸通常在這。
使用者問 → 強制檢索 → 把 chunks 塞進 prompt → 模型生成。
簡單、可預期,但「閒聊也檢索」會浪費 token、也沒給模型決定權。
search_docs(query) 變一個 tool。
模型自己決定:寒暄不查、含糊問題先查、需要交叉比對就查多次。和 Agent Loop 天然契合。
用 CH6-3 的請假 SOP 範本,組一個有兩個工具的 Agent:
search_docs(query) + calculator(expr),問「我年資 2 年 10 個月,特休可以休幾天?」
chunks: [{id, section, text}]。search_docs(query) → top-2 chunks,mock 用關鍵字配對也行(不必真跑 embedding)。
Demo 跑一次就過很容易。生產環境跑一萬次都不爆——
你需要把這三個陷阱當成設計需求,而不是 bug 才補。
模型反覆呼叫同一工具,或工具回錯讓模型陷入重試循環。
結果:API 費用暴增,程式卡死,半夜被叫起來看 dashboard。
① max_turns 守門:通常設 5-10。
② 同工具計數:一輪對話內某工具被呼叫超過 N 次強制中止。
③ 監控 + 告警:上線後追單一對話的 turn 分佈。
模型呼叫不存在的工具名(例:send_email),或傳錯型別(字串塞給 integer 欄位)。
沒防禦時程式會直接 throw、整個 Agent crash。
const TOOLS = new Set(['get_weather','calculator']);
if (!TOOLS.has(name)) {
return {
success: false,
error: `tool "${name}" not available.
Available: ${[...TOOLS].join(', ')}`
};
}
外部 API 503、網路逾時、查無資料——程式沒包 try/catch,
或包了但只回空字串給模型。
結果:模型在不完整資訊下繼續推理,輸出錯誤答案,使用者以為是真的。
工具函式永遠回結構化結果:
{ success: false, error: '...' }
模型看到「查詢失敗,原因是 503」會誠實地告訴使用者,
看到空字串才會開始捏造。
寄信、寫資料庫、扣款、發出訂單——所有不可逆的事。
max_turns + 結構化錯誤不夠,因為 Agent 可能在「成功了但你以為失敗」的情況下重試一次,
於是同一封信寄兩次、同一筆款扣兩次。
order_uuid),同一個 ID 第二次來,工具直接回上次的結果,不重複執行。
用練習 1 的 Agent 為基底,依講義 mp2 三段壓測腳本各跑一次,
驗證 max_turns / 白名單 / try-catch 三層防禦真的有效。
need_recompute:true,看 max_turns 是否擋住。{success:false} 而非 500。
n8n AI Agent 節點 vs 直寫 Anthropic / OpenAI API。
不是哪個比較好,是哪個適合你眼前這個任務。
第一階段:n8n 把工具鏈邏輯跑通
流程對不對、模型有沒有用對工具、token 預算多少——拖一拖就知道。
不用花一天寫 Loop、debug schema。
第二階段:用程式重寫高頻 / 嵌入既有系統的部分
確認流程可行後,把需要嵌入產品、需要更高效能、需要更細控制的工具
搬到 Anthropic / OpenAI 直接呼叫。
你今天從「會用 ChatGPT 聊天」升級成「能寫一個會自己決定動手的 Agent」。
明天我們把它變成可以上線、可以驗收、可以付得起的東西。