我們現在所建立的 AI 工具,基本上就只是呼叫 LLM 模型,然後請他回答問題,他事實上就大約是 2 ~ 3 年前 chat-gpt 剛出來的那樣,但是還有加上一些 Workflow。
接下來你會發現有很多事情它都不知道,例如最常見到的例子就是問天氣之類的,如果你問他台北天氣現在是什麼,他那時應該是會說不知道。
而這個就是我們今天有講的主題 :
> Function calling
大約在 2023 年時 OpenAI 提出了 Function Calling,最初的目的就是為了 :
讓 LLM 可以與外部介接,並且可以拿到外部的資料。
下圖是以我們要取得現在時間
來當做它的範例,來說明他的流程。順到說一下這個功能真的有用,你有時後直接問 AI,他都會回奇怪的時間給你,像如果你用 gpt-4o-mini 每一次都給你很奇怪的時間,但 gpt-5 後就看起來都是正確的,反正這個只是範例。
然後還有幾個重點 :
- LLM 不會幫你執行 Function,而是只和你說用那個 Function
- 有沒有 Function Calling 的功能要看 LLM 有沒有提供
🤔 奇怪 ? 為什麼我用 LangChain 和 OpenAI SDK 這些可以直接回時間給我 ?
因為你用的是 Agent 或是 SDK 有自已實作,所以如果你只是單純的如下程式碼這樣 :
import OpenAI from "openai";
const client = new OpenAI();
const getWeather = async (city: string): Promise<string> => {
return `The weather in ${city} is sunny!`;
};
const tools: OpenAI.Chat.Completions.ChatCompletionTool[] = [
{
type: "function",
function: {
name: "get_weather",
description: "Get the weather for a given city. ex. Q:what is the weather in taipei? A:The weather in taipei is sunny!",
parameters: {
type: "object",
properties: {
city: {
type: "string",
description: "The city to get weather for"
}
},
required: ["city"]
}
}
}
];
const response = await client.chat.completions.create({
model: "gpt-5-nano",
messages: [
{ role: "user", content: "what is the weather in taipei" }
],
tools: tools,
tool_choice: "auto"
});
console.log("Initial response:", response.choices[0].message.tool_calls);
然後我們的 console log 的結果就會如下,他就只會和你說要呼叫那個工具 :
Initial response: [
{
id: 'call_TSt3nZvE8lCmJ6tCoLaGhc82',
type: 'function',
function: { name: 'get_weather', arguments: '{"city":"taipei"}' }
}
]
所以這裡幾點重點在於 :
像如果你在 LangChain 用 createAgent 產生,那他會自動幫你呼叫,而用 Gemini SDK Python 版本的它也會幫你自動呼叫,例如下面的連結。
https://ai.google.dev/gemini-api/docs/function-calling?hl=zh-tw&example=meeting#javascript_2
以下為 LangChain 的程式碼範例,由於 LangChain 的 createAgent 本身產出的 React Agent,所以他會自動的呼叫 tool 來執行。
https://docs.langchain.com/oss/javascript/langchain/agents
import { createAgent, tool } from "langchain";
const getCurrentTime = tool(
async () => {
return new Date().toISOString();
},
{
name: "get_current_time",
description: "Get the current time.",
}
);
const agent = createAgent({
model: "openai:gpt-5-nano",
tools: [getCurrentTime],
});
const result = await agent.invoke({
messages: [{ role: "user", content: "今天幾號" }],
});
console.log(result);
執行的結果,可以看出他整個流程是 :
{
messages: [
HumanMessage {
"id": "9b7518d0-f8e1-451a-ad66-669cd481e567",
"content": "今天幾號",
"additional_kwargs": {},
"response_metadata": {}
},
AIMessage {
"id": "chatcmpl-CKJWCOelT9iEGqtTK8U30IpH1ZFjC",
"content": "",
"name": "model",
"additional_kwargs": {
"tool_calls": [
{
"id": "call_ry3Rc1pvI9XidWFgKm6Pfilh",
"type": "function",
"function": "[Object]"
}
]
},
"response_metadata": {
"tokenUsage": {
"promptTokens": 128,
"completionTokens": 600,
"totalTokens": 728
},
"finish_reason": "tool_calls",
"model_provider": "openai",
"model_name": "gpt-5-nano-2025-08-07"
},
"tool_calls": [
{
"name": "get_current_time",
"args": {
"input": ""
},
"type": "tool_call",
"id": "call_ry3Rc1pvI9XidWFgKm6Pfilh"
}
],
"invalid_tool_calls": [],
"usage_metadata": {
"output_tokens": 600,
"input_tokens": 128,
"total_tokens": 728,
"input_token_details": {
"audio": 0,
"cache_read": 0
},
"output_token_details": {
"audio": 0,
"reasoning": 576
}
}
},
ToolMessage {
"id": "23c36162-247f-4dec-9863-75e6881ab0ea",
"content": "2025-09-27T07:20:26.774Z",
"name": "get_current_time",
"additional_kwargs": {},
"response_metadata": {},
"tool_call_id": "call_ry3Rc1pvI9XidWFgKm6Pfilh"
},
AIMessage {
"id": "chatcmpl-CKJWH4F0ZighUiqP0CyFpiOtj4dtp",
"content": "今天是 2025 年 9 月 27 日。若以你所在的時區,時間可能會有差異。需要我幫你換算成你的時區嗎?",
"name": "model",
"additional_kwargs": {},
"response_metadata": {
"tokenUsage": {
"promptTokens": 174,
"completionTokens": 498,
"totalTokens": 672
},
"finish_reason": "stop",
"model_provider": "openai",
"model_name": "gpt-5-nano-2025-08-07"
},
"tool_calls": [],
"invalid_tool_calls": [],
"usage_metadata": {
"output_tokens": 498,
"input_tokens": 174,
"total_tokens": 672,
"input_token_details": {
"audio": 0,
"cache_read": 0
},
"output_token_details": {
"audio": 0,
"reasoning": 448
}
}
}
]
}
下面這些 Best Practice 是我自已融合 OpenAI 與 Google Gemini 產生的,可以參考看看,但不一定要服用。
最小驚訝原則 PLA
,簡單的說就是你的 function 的命名與介面儘量直覺點,不要讓維護者看到你寫的 function 在想這個要衝啥小。🤔 不要讓同一個 Agent 塞那麼多 tool,那要如何處理呢 ?
事實上這題我們之前就有解過,只是他不是為了解 tool 這題,我們用的手法就是 :
每個 Agent 都有各自的職責,然後前面有一個 Route Agent
如下圖,我們是不是可以將這些 tool 放在各自職責的 Agent 中呢 ? 對吧,可以省 Token、又可以讓 LLM 要使用更精確。
🤔 Function 內可以用 Cache 來優化效率與成本
都說是 function 了,實際上就我和我們常寫的 function 是相同的,所以當然如果你這個 function 是有處理一些很耗效能的東西,並且情況允許的話,當然可以使用。
有關 Cache 的一些問題可以看很久以前的這幾篇文章。
🤔 Function 的一些特殊設計重點
要有寡等性喔
,這個應該很基本,就是不要,LLM 呼叫 2 次,最終狀態就有問題,例如使用者重複結帳相同商品的情況啊。要有 retry
喔,如果是非 LLM Function Calling 我覺得就看用戶好不好 retry 與團隊政策,但在 LLM Function Calling 情境下,因為從 LLM 開始重試要花 token 所以在這種情況下,建議統一都有 retry 機制。這篇文章我們學習到了以下幾個重點 :
它的概念事實上蠻簡單的,只是要注意一些小事情,接下來我們用它來為我們的 AI 工具人增加一些新功能。