iT邦幫忙

2025 iThome 鐵人賽

DAY 10
2
DevOps

初探 LLM 可觀測性:打造可持續擴展的 AI 系統系列 第 10

【Day 10】LLM 的「工具」思維:用 Function Calling 讓你秒懂 ReAct、MCP 與 A2A

  • 分享至 

  • xImage
  •  

https://ithelp.ithome.com.tw/upload/images/20250924/20149562mvmhIUkACa.jpg

前言

在先前關於 Google Agent 白皮書的探討中,我們觸及了一個核心觀點:一個大型語言模型(LLM)之所以能被稱為「Agent」(代理人),其關鍵區別在於它是否具備 調用「工具」(Tool)的能力。

一個純粹的 LLM,無論多麼強大,它的知識都被凍結在訓練數據的截止日期。它像一個博學的歷史學家,能告訴你過去的一切,卻無法告訴你「今天」的天氣。而 Agent 則不同,它能透過使用工具,主動與外部世界互動、獲取即時資訊、執行特定任務,從而打破數據的牢籠,真正地介入並影響真實世界。

Agent 與 Model 的分水嶺 — 「工具(Tool)」

這篇文章將帶你踏上一段從微觀到宏觀的旅程。我們將從一個最簡單的程式碼範例出發,讓你徹底理解「工具」的本質,並最終你會發現,無論是 OpenAI 的 Function Calling,還是複雜的 MCP(Model Context Protocol)、A2A(Agent-to-Agent)協議,其背後的思想都是驚人地統一。

第一步:最小但最強大的起點 — Function Calling

讓我們忘掉所有複雜的術語,回到最根本的問題:如何讓 LLM 使用我們提供的能力?答案就是描述

所謂的「工具」,在本質上就是一個我們希望 LLM 在需要時能夠「請求調用」的函式(Function)。為了讓 LLM 理解這個工具,我們需要用它能懂的語言(通常是 JSON 格式)來描述它。

const tools = [
  {
    type: "function",
    name: "get_weather",
    description: "Get the current weather for a city.",
    parameters: {
      type: "object",
      properties: {
        city: { type: "string", description: "City name, e.g., Taipei" },
        unit: { type: "string", enum: ["c", "f"], default: "c" }
      },
      required: ["city"],
      additionalProperties: false
    }
  }
];

這份描述包含兩個核心部分:

  1. 函式定義 (Function Definition):告訴 LLM 這個工具的名稱是什麼,以及它的作用是什麼。例如,get_current_weather,作用是「獲取指定地點的即時天氣」。這個描述至關重要,因為 LLM 會根據用戶的提問來判斷是否應該使用這個工具。
  2. 參數定義 (Parameter Definition):告訴 LLM 這個工具需要哪些輸入參數。例如,get_current_weather 需要一個叫做 location 的參數,而且這個參數的類型是「字串」。同時,我們也要明確告知哪些參數是「必須的」。

實際流程

想像一下,當用戶問「東京今天天氣如何?」,整個流程如下圖所示:

https://ithelp.ithome.com.tw/upload/images/20250924/2014956272TXXDL859.png
https://towardsdatascience.com/create-an-agent-with-openai-function-calling-capabilities-ad52122c3d12/

  1. Ask
    • Application:將用戶問題「東京今天天氣如何?」連同我們定義好的  get_current_weather 工具描述,一起發送給 OpenAI API。
  2. Choose
    • LLM:它分析了用戶的問題,並看到了我們提供的工具描述。它判斷出 get_current_weather 這個工具非常適合回答這個問題,並且從問題中提取出必要的參數 location 是「東京」。
    • API 回應:API 並沒有直接回答天氣,而是回傳一個「工具調用請求」,內容大概是:「請幫我調用 get_current_weather 函式,並傳入參數 {'location': 'Tokyo'}」。
  3. Do
    • Application:收到這個請求後,就在我們自己的程式環境中,真正地執行了 get_current_weather(location='Tokyo') 這個函式。這個函式可能會去呼叫一個真實的氣象 API,並得到結果,例如 {"temperature": "15", "condition": "晴天"}。
  4. Tell
    • Application:將上一步的執行結果,連同原始的對話紀錄,再次發送給 OpenAI API。
    • LLM:這次,LLM 擁有了它需要的全部資訊(用戶的問題 + 工具的結果)。它會用自然語言組織最終的答覆。
    • 最終回覆:模型生成並回傳:「東京今天的天氣是 15 度,天氣晴朗。」

看到這裡,你應該明白了,「工具」一點也不神秘。它就是一個「LLM 負責決策,客戶端負責執行」的協作模式。我們為 LLM 提供了能力的「說明書」,它在需要時告訴我們該用哪個能力以及如何用,我們執行後再把結果回饋給它。這是所有後續玩法(ReAct、MCP、A2A)的共同骨架。

第二步:串聯工具,實現一個簡易 ReAct 流程

現在,我們把難度稍微提高一點。如果用戶的問題更複雜,需要多個步驟才能解決呢?例如:「東京今天天氣如何?我應該怎麼穿搭?」

這就需要一個最基礎的 ReAct (Reason + Act) 流程。LLM 會像人一樣思考,一步步地分解問題,並重複調用工具來搜集資訊,直到它認為資訊足夠為止。

整個流程會是這樣:

  1. 第一次循環 (獲取天氣)
    • LLM (Reason):分析問題「東京今天天氣如何?我應該怎麼穿搭?」。它意識到,要推薦穿搭,首先必須知道天氣。於是它決定調用 get_current_weather 工具。
    • Application (Act):收到調用請求,執行函式,得到天氣結果 {"temperature": "15", "condition": "晴天"},然後將這個結果回傳給 LLM。
  2. 第二次循環 (判斷與最終回覆)
    • LLM (Reason):現在它擁有了新的上下文:「用戶想知道東京的穿搭建議,而我已經知道那裡是 15 度晴天」。LLM 根據這些資訊進行推理,判斷 15 度是稍涼的天氣,晴天很舒適。它認為現在的資訊已經足夠回答用戶的完整問題了,不再需要調用其他工具。
    • 最終回覆:LLM 生成最終答案:「東京今天 15 度晴,天氣不錯!建議您可以穿一件長袖 T 恤搭配一件薄外套,褲子可以選擇休閒長褲。」

實戰演練

// 步驟 1: 定義我們擁有的所有工具函式
async function get_weather({ city, unit = "c" }) {
  console.log(`[Tool Executed]: get_weather(city: "${city}")`);
  return JSON.stringify({ city, unit, temp: 15, condition: "sunny" }); // 模擬東京的天氣
}

// 新增的工具:根據溫度提供穿搭建議
async function get_fashion_advice({ temp }) {
  console.log(`[Tool Executed]: get_fashion_advice(temp: ${temp})`);
  if (temp > 25) {
    return JSON.stringify({ advice: "天氣很熱,建議穿 T-shirt 和短褲。" });
  } else if (temp > 15) {
    return JSON.stringify({ advice: "天氣有點涼,建議穿長袖上衣和一件薄外套。" });
  } else {
    return JSON.stringify({ advice: "天氣冷,建議穿毛衣和保暖外套。" });
  }
}

// 步驟 2: 讓 LLM "看得懂" 我們的工具說明書
const tools = [
  {
    type: "function",
    function: {
      name: "get_weather",
      description: "取得指定城市的即時天氣",
      parameters: {
        type: "object",
        properties: {
          city: {
            type: "string",
            description: "城市名稱,例如:台北",
          },
        },
        required: ["city"],
      },
    },
  },
  {
    type: "function",
    function: {
      name: "get_fashion_advice",
      description: "根據溫度提供穿搭建議",
      parameters: {
        type: "object",
        properties: {
          temp: {
            type: "number",
            description: "溫度數值",
          },
        },
        required: ["temp"],
      },
    },
  },
];

// 步驟 3: 建立一個工具名稱到函式的映射,方便後續呼叫
const toolMap = {
  get_weather,
  get_fashion_advice, // 將新工具加入 map
};

// 核心 ReAct 循環
async function ask(question) {
  console.log(`User: ${question}\n`);

  // 第一次請求,送出問題和工具列表
  let res = await client.chat.completions.create({
    model: "gpt-4o-mini",
    messages: [{ role: "user", content: question }],
    tools: tools,
    tool_choice: "auto",
  });

  let message = res.choices[0].message;
  const messages = [{ role: "user", content: question }, message];

  // 只要 LLM 回應的是工具調用,就繼續循環
  while (message.tool_calls) {
    console.log("LLM wants to call tools:", message.tool_calls.map(c => `${c.function.name}(${c.function.arguments})`).join(", "));
    
    const toolOutputs = [];
    for (const toolCall of message.tool_calls) {
      const fn = toolMap[toolCall.function.name];
      const args = JSON.parse(toolCall.function.arguments);
      const result = await fn(args);
      
      console.log(`[Tool Output for ${toolCall.function.name}]: ${result}`);
      
      toolOutputs.push({
        tool_call_id: toolCall.id,
        role: "tool",
        name: toolCall.function.name,
        content: result,
      });
    }

    // 將工具的執行結果加到對話歷史中
    messages.push(...toolOutputs);

    // 帶著新的資訊 (工具產出) 再次請求 LLM
    res = await client.chat.completions.create({
      model: "gpt-4o-mini",
      messages: messages,
      tools: tools,
      tool_choice: "auto",
    });
    message = res.choices[0].message;
    messages.push(message);
  }
  
  // 當 LLM 不再回傳工具調用時,代表它已準備好最終答案
  console.log(`\nLLM (Final Answer): ${message.content}`);
}

// 執行
ask("東京今天天氣如何?我應該怎麼穿搭?");

這個重複「思考 -> 調用工具 -> 觀察結果」的循環,就是 ReAct 模式的核心。

LLM 透過一次或多次的工具調用,不斷地豐富自己的上下文,最終在掌握了足夠的資訊後,給出一個全面且準確的答覆。

第三步:豁然開朗 — MCP 與 A2A 協議的統一視角

當你理解了上述的 ReAct 流程後,我們就可以把格局放得更大。現在,讓我們來看看那些看似複雜的架構圖。

https://ithelp.ithome.com.tw/upload/images/20250924/20149562GGxZUeEF67.png
https://towardsdatascience.com/create-an-agent-with-openai-function-calling-capabilities-ad52122c3d12/

MCP (Model Context Protocol) 工作流

在這張 MCP 工作流圖中,我們可以看到用戶提出請求「幫我查詢 AAPL 的最新股價並用 email 通知我」。

這張圖看起來複雜,但讓我們用「工具」的視角來重新解讀它:

  • MCP Hosts/Clients:這就是我們前面例子中的「我們 (Application)」,也就是負責執行工具的客戶端。
  • MCP Servers:這裡集成了各種能力,如 Web Services, Database, Local Files。在 LLM 眼中,這些服務的每一個 API (例如 get_stock_pricesend_email),都只是一個個可以被描述和調用的「工具」而已。
  • Tool Selection:這一步驟,正是 LLM 在進行我們前面所說的「Choose (選擇)」。它分析用戶意圖,決定需要調用 get_stock_price 和 send_email 這兩個工具。
  • API Invocation:這就是「Do (執行)」的過程,由客戶端真正地去執行工具。

看到了嗎?MCP 只是將我們前面單一的 Function Calling 流程,進行了規模化和標準化。它定義了一套通訊協定,讓 LLM (Model) 和執行端 (Client) 能夠更高效、更穩定地協作。但其核心思想從未改變:

LLM 依然是決策者,它眼中看到的所有外部服務,都只是一個個待選的「工具」

Agent-to-Agent (A2A) 協議

現在,我們把視角拉到最高層級:Agent 之間的協作。

https://ithelp.ithome.com.tw/upload/images/20250924/201495627CvillRVPA.png

當一個 Agent 需要另一個 Agent 幫忙時,會發生什麼?其實還是一樣的道理!

  • A2A 協議:你可以把它理解為一本「Agent 使用說明書」。它定義了另一個 Agent 對外提供了哪些能力(工具)以及調用這些能力需要什麼參數
  • 發起請求的 Agent (左):當它需要完成一個自身能力範圍之外的任務時,它的 LLM 會「看到」另一個 Agent 就像一個功能極其強大的「超級工具」。
  • 執行請求的 Agent (右):它接收到請求,執行內部邏輯(可能它自己也會再調用其他更小的工具),然後返回結果。

例如:一個「旅遊規劃 Agent」需要訂機票,但它自己沒有這個功能。但它知道有一個「票務預訂 Agent」。對「旅遊規劃 Agent」的 LLM 來說,「票務預訂 Agent」就是一個巨大的工具,這個工具的函式簽名可能是 book_flight(origin, destination, date)。

整個流程依然是:決策 -> 請求調用 -> 執行 -> 返回結果

結論:萬物皆 Tool,掌握思維的鑰匙

從一個簡單的 get_current_weather 函式,到一個處理多步驟任務的 ReAct 流程,再到更宏觀的 MCP 和 A2A 架構,我們發現其背後的邏輯竟然是如此統一。

核心的鑰匙,就是將一切外部功能、服務、乃至其他 Agent,都抽象為 LLM 眼中的「工具」。

一旦你掌握了這個視角,你就會有一種豁然開朗的感覺。因為你找到了一個可以舉一反三的思考框架:

  1. 定義能力:無論你的功能多複雜,都將其清晰地描述為一個或多個「工具」(定義名稱、作用、參數)。
  2. 交給 LLM 決策:相信 LLM 的自然語言理解和推理能力,讓它根據用戶需求,自行決定何時、以及如何調用這些工具。
  3. 專注於執行:你的應用程式只需要專注於穩定可靠地執行 LLM 的「工具調用請求」,並將結果忠實地反饋回去。

這就是 LLM Agent 的力量所在,也是未來智慧應用開發的核心範式。希望這篇文章,能幫助我們牢牢掌握這把開啟未來的鑰匙。


References:


上一篇
【Day 9】LLM 應用入門:你的 LLM 應用是 Model-based 還是 Agent-based?
下一篇
【Day 11】從玩具到工具:了解生產級 LLM Agent 下的冰山
系列文
初探 LLM 可觀測性:打造可持續擴展的 AI 系統11
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言