打破文字監獄:LLM 工具呼叫(Tool Use)與函式呼叫(Function Calling)的實作與應用

自主 AI 代理的進化之路:打破大腦罐子,賦予 LLM 現實世界的行動力

想像一下這個畫面:你身邊有一個絕頂聰明的天才朋友,他讀遍了世界上所有的書籍、智商高得嚇人,基本上就是一本行走的活字典。你問他任何歷史事件或艱深的科學理論,他都能對答如流。

但是,他被關在一個完全沒有網路、與世隔絕的房間裡。

這意味著他的知識永遠停留在房間門被鎖上的那一天。他無法幫你查今天晚上的即時天氣、沒辦法幫你訂餐廳,他甚至連自己房間裡的電燈開關都按不到。他唯一能做的,就是不斷地跟你說話。這個情境,正是傳統大型語言模型(LLM)最真實的處境。我們常常被 ChatGPT 展現出流暢、博學的對話能力所震撼,但回歸本質,它的知識是靜態的。如果我們沒有在它與外部世界之間建立起橋樑,它解決現實問題的能力就會遇到一道非常硬的瓶頸。而這場演化歷史的關鍵轉捩點,就是工具呼叫(Tool Use / Function Calling)。這項核心技術正在打破文字生成的枷鎖,在那個關著聰明朋友的房間牆上鑿出一個洞,並遞給他一隻連上網的手機、一台計算機,甚至是一把車鑰匙。

一、 機制拆解:文字與程式碼的無縫交接

工具呼叫聽起來很像魔法,但在底層工程設計上,它是一套極其嚴謹的協定。

想像 LLM 是這家餐廳的「明星主廚」。當客人(使用者)點了一杯新鮮蘋果汁,主廚本人是不會親自去切蘋果或按果汁機的。

在廚房(系統)開始運作之前,必須經歷以下三個核心階段:

1. 工具定義(宣告階段)

開發者必須先用 LLM 聽得懂的格式,給主廚一份詳細的「廚房設備清單」。明確告訴它:廚房裡有一台果汁機,名字叫做 blender_tool,它的用途是把水果打成汁,需要帶入的參數是「水果種類」與「攪拌時間」。

2. LLM 決策階段(結構化輸出)

當客人點了蘋果汁,主廚的大腦(推理引擎)開始研判,對照清單後決定:「要完成這個請求,我必須使用 blender_tool」。此時,主廚並不是親自動手,而是寫了一張結構化的電子表單——也就是 JSON 格式的點菜單。這張 JSON 表單會精準標示:"tool": "blender_tool", "arguments": {"fruit": "apple", "time": 30}。到目前為止,LLM 所做的依然只是「生成文字」,它根本沒有碰到任何實體系統。

3. 框架執行(二廚接手)

主廚把這張 JSON 單子遞出去後,廚房裡的「二廚」——也就是代理框架(Agent Framework)或編排層會接手。二廚看懂了表單,轉身去啟動真正的果汁機(執行程式碼)。程式碼跑完、果汁打好後(取得執行結果),二廚再把這杯果汁端回主廚面前。最後,主廚看著結果,將其轉化為親切的人類語言對客人說:「新鮮蘋果汁已經準備好了!」

LLM 工具呼叫三步驟流程

這樣的系統為代理(Agent),它扮演一個協調與管理者的角色,完美解決了強大的自然語言推理能力與現實世界龐大外部功能之間的鴻溝。

以下是用 TypeScript 搭配 OpenAI SDK 實作上述三步驟的完整範例:

import OpenAI from 'openai'

const openai = new OpenAI()

// 模擬一個實際執行的天氣工具函數(避免外部 API 呼叫失敗)
async function mockFetchWeather(location: string) {
  return {
    location,
    temperature: 15,
    condition: 'Overcast',
    precipitation: '20%'
  }
}

// 1. 工具定義:告訴 LLM 廚房裡有什麼設備
const tools = [
  {
    type: 'function' as const,
    function: {
      name: 'get_weather',
      description: '取得指定城市的即時天氣',
      parameters: {
        type: 'object',
        properties: {
          location: { type: 'string', description: '城市名稱' },
        },
        required: ['location'],
      },
    },
  },
]

// 2. LLM 決策:生成 JSON 點單
const response = await openai.chat.completions.create({
  model: 'gpt-4o',
  tools,
  messages: [{ role: 'user', content: '倫敦天氣如何?' }],
})

const message = response.choices[0].message
const finishReason = response.choices[0].finish_reason
const toolCall = message.tool_calls?.[0]

// 3. 框架執行:二廚接手,呼叫真正的工具(模擬 API)
if (finishReason === 'tool_calls' && toolCall) {
  const { location } = JSON.parse(toolCall.function.arguments)
  const weatherResult = await mockFetchWeather(location)

  // 將結果回傳給 LLM,讓主廚轉換為人類語言
  const final = await openai.chat.completions.create({
    model: 'gpt-4o',
    messages: [
      { role: 'user', content: '倫敦天氣如何?' },
      // 必須把 LLM 的第一個回應(包含 tool_calls)原封不動帶回上下文
      message, 
      { 
        role: 'tool', 
        tool_call_id: toolCall.id, 
        content: JSON.stringify(weatherResult) 
      },
    ],
  })
  console.log(final.choices[0].message.content)
  // 「倫敦目前多雲,氣溫 15°C,降雨機率 20%。」
}

4. 觀念澄清:Tool Use 廣義 vs. Function Calling 狹義

在深入探討之前,有必要先釐清一組常被混用的關鍵名詞。技術文件與開發社群中,「Function Calling」與「Tool Use」經常交替出現,但它們的範疇並不完全重疊。

區分兩者是因為這直接影響系統架構的設計格局。理解這個區別後就會明白為什麼總結中提到的「代理互相呼叫」並非科幻,而是 Tool Use 廣義概念下的自然延伸。

Function Calling 狹義 vs. Tool Use 廣義

二、 工具代理的六大超能力場景

工具代理的六大超能力場景

經驗法則:每當代理需要突破 LLM 內部知識的界限、與外部世界互動時,就應該啟用工具呼叫模式。具體來說,凡是需要即時數據(如天氣、股價)、存取私有或企業內部資訊、執行精確數學計算、執行程式碼腳本,或是觸發真實世界的系統操作(如發送 Email、控制物聯網設備)的任務,都是工具呼叫的典型適用場景。反之,若任務僅涉及常識問答、歸納摘要或風格改寫等純文字生成範疇,則不需要動用工具。

當 LLM 裝備了工具,它在日常與企業場景中便能瞬間解鎖六大超能力。想像你對著 AI 助理說出一段日常工程指令:「幫我查蘋果公司最新股價,算算看如果我花 1500 美金買進,以現在的預算下週去倫敦出差還夠不夠用?順便發封 Email 通知長官我明天開會遲到。」

在幕後,這個代理會同時觸發多重工具呼叫:

  1. 讀取結構化 API:呼叫特定服務的 API,取得精準的結構化資料,如金融 API 回傳 JSON 格式的即時股價。
  2. 非結構化網頁檢索:透過搜尋引擎或網頁爬取,獲取散落在網路各處的非結構化即時資訊,如倫敦天氣與當地物價。
  3. 計算與資料分析(避開幻覺):大模型本質是機率模型,數學通常很糟糕,容易一本正經地胡說八道(幻覺)。但此時代理不需要自己算數學,它只要把公式封裝成 JSON 丟給計算機工具,讓真正的計算機程式算出精確到小數點後兩位的數字,完美避開幻覺。
  4. 與資料庫互動:存取企業內部的財務試算表或資料庫,比對使用者的個人可用餘額。
  5. 傳送通訊:確認出差預算無誤後,自動呼叫電子郵件服務,提取主管的聯絡資訊,發送一封語氣得體的信件。
  6. 控制系統與物聯網裝置:在授權範圍內,進一步控制實體世界的硬體(如關閉沙盒環境、調整物聯網設備)。

用 Vercel AI SDK 實作這個多重工具呼叫的場景,只需定義工具後讓 LLM 自行調度:

import { openai } from '@ai-sdk/openai'
import { generateText, tool } from 'ai'
import { z } from 'zod'

// 模擬外部工具的實際執行
const fetchStockAPI = async (ticker: string) => ({ ticker, price: 180 })
const sendMail = async (to: string, subject: string) => `Email sent to ${to}`

const result = await generateText({
  model: openai('gpt-4o'),
  tools: {
    getStockPrice: tool({
      description: '查詢股票即時價格',
      parameters: z.object({ ticker: z.string().describe('股票代碼,例如 AAPL') }),
      execute: async ({ ticker }) => fetchStockAPI(ticker),
    }),
    calculateBudget: tool({
      description: '計算預算是否足夠',
      parameters: z.object({ amount: z.number(), budget: z.number() }),
      execute: async ({ amount, budget }) => ({ isEnough: budget >= amount }),
    }),
    sendEmail: tool({
      description: '發送 Email 通知主管',
      parameters: z.object({ to: z.string(), subject: z.string() }),
      execute: async ({ to, subject }) => sendMail(to, subject),
    }),
  },
  prompt: '查 AAPL 股價,計算 1500 USD 夠不夠買,夠的話發信到 manager@company.com 通知主管',
})

// Vercel AI SDK 會自動調度並依序執行完所有需要呼叫的工具
console.log(result.text)

三、 開發框架的碰撞:LangChain 瑞士刀 vs. CrewAI 企業部門

在實作端,開發者如何把這些工具交給代理?開源社群中兩大框架代表了截然不同的設計哲學:

1. LangChain:快捷便利的萬能瑞士刀

LangChain 極強調整合的便利性。開發者可以使用一個簡單的 @tool 裝飾器(Decorator),它就像一張「神奇條碼貼紙」。你本來就有一段普通的 Python 程式碼用來查天氣,只要在程式碼正上方貼上標籤,LangChain 就會瞬間把它轉換成 LLM 能夠理解、並能寫入 JSON 點單的標準化工具。

開發者只要使用內建的 createToolCallingAgent,搭配代理執行器(AgentExecutor),就能把大腦與一整排工具綁在一起,快速誕生一個配備萬能瑞士刀的通用型代理。

import { tool } from '@langchain/core/tools'
import { ChatOpenAI } from '@langchain/openai'
import { ChatPromptTemplate } from '@langchain/core/prompts'
import { createToolCallingAgent } from 'langchain/agents'
import { AgentExecutor } from 'langchain/agents'
import { z } from 'zod'

const getWeather = tool(
  async ({ location }) => {
    // 模擬 API 回傳
    return JSON.stringify({ location, temp: 15, status: 'Cloudy' })
  },
  {
    name: 'get_weather',
    description: '取得指定城市的天氣',
    schema: z.object({ 
      location: z.string().describe('城市名稱,例如 London') 
    }),
  },
)

const llm = new ChatOpenAI({ model: 'gpt-4o', temperature: 0, streaming: false })

// LangChain Tool Calling Agent 強制需要 Prompt Template 且包含 agent_scratchpad
const prompt = ChatPromptTemplate.fromMessages([
  ['system', '你是一個貼心的天氣小助手。'],
  ['placeholder', '{chat_history}'],
  ['human', '{input}'],
  ['placeholder', '{agent_scratchpad}'],
])

const tools = [getWeather]
const agent = createToolCallingAgent({ llm, tools, prompt })
const executor = new AgentExecutor({ agent, tools })

const result = await executor.invoke({ input: '倫敦天氣如何?' })
console.log(result.output)

2. CrewAI:專業分工的企業架構

然而,LangChain 的全能超人模式有一個致命傷:當你貪心地把 100 個工具全部塞給同一個 AI 時,它的上下文視窗會被塞爆。同時閱讀 100 個工具的說明書極易導致 AI 認知過載、混淆,進而亂用工具,產生嚴重的幻覺。

CrewAI 則走向完全不同的哲學——專業分工。它不在於打造一個會 100 種工具的超人,而是組建一個有組織的企業部門。

LangChain 瑞士刀 vs. CrewAI 企業部門

在 CrewAI 的架構中,開發者會定義一個明確角色為「高階財務分析師」的代理,且只配備給他專屬的股票查詢工具(如 get_stock_data)。這個工具設計得極為細緻,若找不到程式碼,會嚴格引發錯誤訊號(如 ValueError)。分析師代理收到失敗訊號時,不會當機,而是運用 LLM 的推理能力去理解:「哦,我剛剛輸入的股票程式碼可能有錯。」接著自己想辦法修正、換個方式查,展現出極高的系統穩定性。

如果要用 TypeScript 實作「代理互相呼叫」——也就是結語中提到的場景——可以將另一個代理包裝成工具:

// 以下為概念示意,實際 API 依所選框架而定
const researchAnalyst = createAgent({ /* 研究分析師代理 */ })

const seniorAnalyst = createAgent({
  tools: [
    {
      name: 'delegate_to_research',
      description: '將研究任務委派給研究分析師',
      execute: async (task: string) => researchAnalyst.run(task),
    },
  ],
})
// 資深分析師可以視情況把任務丟給研究分析師

這種「代理即工具」的設計模式,正是 Tool Use 廣義概念的最佳體現。

四、 企業級火力展示:Google ADK 的無菌沙盒與自動化安全分水嶺

當我們把目光移向科技巨頭 Google 所打造的企業級解決方案——Google ADK (Agent Development Kit) 時,這套工具生態系展現出了更高維度的基礎設施優化。

1. Google 搜尋工具的內建原生支援

在 Google ADK 中,開發者不需要自己費工串接複雜的第三方 API。系統直接原生內建了 Google 搜尋工具,幾行程式碼就能直接拉入搜尋引擎的即時力量。

2. 安全的無菌室:內建程式碼執行沙盒

為了解決大模型精確計算的痛點,ADK 提供了一個高度安全的隔離沙盒解析器。當代理遇到複雜的資料分析或統計時,它會「自己寫一段程式碼」,然後把程式碼丟進這個與外界完全隔離的無菌沙盒裡去跑,跑出絕對精確的答案後再拿來回覆。這讓 AI 具備了在安全環境下自我打造工具的能力。

對於極度注重正確性的企業客戶,ADK 的企業搜尋代理可以直接翻找企業私有雲端資料庫。最驚豔的是,它產出的每一個回答,都會嚴格附上資料來源屬性(Attribution)(例如:「我是看了 2025 年 Q4 內部財報的第三頁得出這個結論的」),完美滿足企業的稽核與溯源機制。

技術分水嶺:Vertex AI 擴充功能(Extensions)vs. 函式呼叫(Function Calling)

在企業級應用中,有一個本質上的技術分水嶺,這直接影響了企業對「效率」與「安全控制」的權衡:

企業級技術分水嶺:自動化 vs. 手動控制

如果這個工具的功能不是查天氣,而是去刷卡扣款五十萬、或者是刪除整個客戶資料庫,全自動化會帶來極大的毀滅性風險。手動執行的函式呼叫,就在不可逆的實體操作觸發前,保留了一個至關重要的「人類確認中斷點(Human-in-the-loop)」。這就像發射飛彈前的最後確認,將核心控制權牢牢鎖在人類手裡。

總結:當代理開始互相發號施令

工具呼叫,就是那把將 AI 從與世隔絕的圖書館學者,變成現實世界超級行動者的關鍵鑰匙。下次看到手機裡的 AI 代理完美規劃好出差行程、查好即時匯率並發出確認信時,我們將知道這背後不是魔法,而是結構嚴謹、在幕後高速飛奔的 JSON 點菜單。然而,這項技術也將我們推向了一個更深層的未來課題:在先進的設計模式中,工具的定義甚至包含了「去呼叫另一個 AI 代理」。當任務過於複雜時,代理 A 可以把代理 B 當成工具呼叫;代理 B 為了查資料,又跑去呼叫了代理 C,這張網絡會愈織愈大。如果有一天,代理 C 在執行過程中因為某個工具的邊緣錯誤,執行了一筆錯誤的金融交易導致嚴重虧損。在這一層又一層、宛如黑盒子般複雜的代理協作網路中,我們到底該追究誰的責任?是寫下最初那句模糊指令的使用者?是寫出底層工具程式碼的開發者?還是這條決策鏈上的某個 AI 節點?當 AI 代理開始互相發號施令,人類的責任歸屬,將是我們在享受高度自動化之餘,下一個必須共同面對的最大挑戰。

參考資料


Agentic Design Pattern Tool Use Function Calling Agentic AI LLM LangChain CrewAI Google ADK AI Design Pattern Architecture