在生成式 AI 興起的時代,function calling(函數呼叫) 成為 LLM(大型語言模型)落地應用的重要能力。不管是讓 AI 自動查天氣、叫外送,還是查詢系統數據,function calling 都是關鍵的一步。那麼,不同的 LLM 模型,執行 function calling 的「成功率」會不會有差?
在前一篇文章中,我們介紹了如何使用 Semantic Kernel 輕鬆切換不同的 LLM 模型。在模型切換變得簡單之後,接下來我們可以進行一些有趣的實驗和比較,像是 AI Agent 在面對不同的 LLM 時,Function Calling 的成功率會有什麼差異,開源的小模型與商業雲端模型的表現會有多大差距,今天就進一步針對 Function Calling 成功率簡單做個實測比較。
另外要提醒一點,不是每個開源地端模型都有 function calling 的能力,許多本地部署、純推論型的開源模型並沒有針對function calling有特別訓練過,因此這些開源模型通常只會回傳一般對話內容,沒辦法主動識別並呼叫 API,即便有額外的開發包或框架像是LangChain來「包裝」function calling 能力,穩定性也會差很多。而目前 Ollama 提供的 gpt-oss 20b 是有支援 function calling 的,而其他模型可能就沒有,所以在測試前要先確認模型是否支援 function calling。
為了讓結果直觀好懂,我用同樣的 function calling 任務,分別對每個模型各做 20 次測試,記錄下 AI 成功觸發 GetOrderStatus
function call 的次數,每次測試都用相同的 prompt,盡量排除其他變數,單純比模型本身的 function calling 成功率。這次測試的是 gpt-4.1 與 gpt-oss 20b 模型,gpt-4.1 是 OpenAI 最新的商業雲端模型,gpt-oss 20b 則是本地部署的開源模型。這只是一個簡單的測試,實際應用中可能會有更多變數和複雜度,但可以作為一個初步的參考。
GetOrderStatus
函式來查詢訂單狀態。//gpt-4.1
var kernel = Kernel.CreateBuilder()
.AddOpenAIChatCompletion(
apiKey: Config.OpenAI_ApiKey,
modelId: Config.ModelId)
.Build();
kernel.Plugins.AddFromType<OrderService>();
使用 ollama 部署的本地 gpt-oss 20b 開源模型,
//gpt-oss:20b
private static Kernel CreateGptOss20AIKernel()
{
var kernel = Kernel.CreateBuilder()
.AddOllamaChatCompletion(
endpoint: new Uri(Config.Ollama_Endpoint),
modelId: Config.Ollama_ModelId)
.Build();
kernel.Plugins.AddFromType<OrderService>();
return kernel;
}
GetOrderStatus
函式:var testQuestions = new[]
{
"請幫我查詢訂單 ORD-001 的狀態",
"我想知道訂單 ORD-002 現在怎麼樣了",
"ORD-003 這個訂單的狀態是什麼?",
"能告訴我 ORD-004 的訂單狀況嗎?",
"查詢一下 ORD-005 的進度",
"ORD-006 訂單現在到哪個階段了?",
"我的訂單 ORD-007 狀態如何?",
"請檢查 ORD-008 的處理進度",
"ORD-009 這筆訂單的最新狀態",
"想了解 ORD-010 的配送情況",
"請查看訂單 ORD-011 的狀態",
"ORD-012 的訂單處理到哪了?",
"能幫我確認 ORD-013 的狀況嗎?",
"查詢訂單 ORD-014 的最新進度",
"ORD-015 這個訂單現在怎樣?",
"請告訴我 ORD-016 的狀態",
"想知道 ORD-017 訂單的情況",
"ORD-018 的處理進度如何?",
"請查詢 ORD-019 的狀態",
"ORD-020 這筆訂單的狀況"
};
public class OrderService
{
// 模擬的訂單資料(訂單編號 -> 狀態)
private readonly Dictionary<string, string> _orders = new Dictionary<string, string>
{
{ "A001", "已出貨" },
{ "A002", "處理中" },
{ "A003", "已取消" },
{ "A004", "已完成" },
{ "ORD-001", "處理中" },
{ "ORD-002", "已發貨" },
{ "ORD-003", "已完成" },
{ "ORD-004", "處理中" },
{ "ORD-005", "已發貨" },
{ "ORD-006", "已完成" },
{ "ORD-007", "處理中" },
{ "ORD-008", "已發貨" },
{ "ORD-009", "已完成" },
{ "ORD-010", "處理中" },
{ "ORD-011", "已發貨" },
{ "ORD-012", "已完成" },
{ "ORD-013", "處理中" },
{ "ORD-014", "已發貨" },
{ "ORD-015", "已完成" },
{ "ORD-016", "處理中" },
{ "ORD-017", "已發貨" },
{ "ORD-018", "已完成" },
{ "ORD-019", "處理中" },
{ "ORD-020", "已發貨" }
};
// 查詢訂單狀態的方法
[KernelFunction]
[Description("Retrieves the order status by order ID.")]
public string GetOrderStatus(
[Description("The ID of the order to retrieve the status for.")]
string orderId)
{
if (string.IsNullOrWhiteSpace(orderId))
{
return "訂單編號不可為空";
}
if (_orders.TryGetValue(orderId, out var status))
{
return status;
}
else
{
return "查無此訂單";
}
}
}
GetOrderStatus
函式的呼叫或是回應內容是否有包含訂單狀態。請注意這只是簡單的判斷方式,實際應用中可能需要更嚴謹的邏輯來確認 function calling 是否成功:// 檢查是否有函式調用的跡象
var lastMessage = history.LastOrDefault();
if (lastMessage?.Content?.Contains("GetOrderStatus") == true)
{
return true;
}
// 嘗試再次獲取回應並檢查是否有函式調用
var response = await chatService.GetChatMessageContentAsync(history, settings, kernel: kernel);
// 檢查回應中是否包含實際的訂單資訊(表示成功調用了函式)
return response.Content?.Contains("訂單狀態") == true ||
response.Content?.Contains("處理中") == true ||
response.Content?.Contains("已發貨") == true ||
response.Content?.Contains("已完成") == true ||
response.Content?.Contains("已取消") == true;
🤖 開始測試 OpenAI (gpt-4.1)...
測試 1/20: ✅ 成功
測試 2/20: ❌ 失敗
測試 3/20: ✅ 成功
測試 4/20: ✅ 成功
測試 5/20: ✅ 成功
測試 6/20: ✅ 成功
測試 7/20: ✅ 成功
測試 8/20: ✅ 成功
測試 9/20: ✅ 成功
測試 10/20: ✅ 成功
測試 11/20: ✅ 成功
測試 12/20: ❌ 失敗
測試 13/20: ✅ 成功
測試 14/20: ✅ 成功
測試 15/20: ✅ 成功
測試 16/20: ✅ 成功
測試 17/20: ❌ 失敗
測試 18/20: ✅ 成功
測試 19/20: ✅ 成功
測試 20/20: ✅ 成功
🤖 開始測試 Ollama (gpt-oss:20b)...
測試 1/20: ✅ 成功
測試 2/20: ✅ 成功
測試 3/20: ✅ 成功
測試 4/20: ✅ 成功
測試 5/20: ✅ 成功
測試 6/20: ✅ 成功
測試 7/20: ✅ 成功
測試 8/20: ✅ 成功
測試 9/20: ✅ 成功
測試 10/20: ✅ 成功
測試 11/20: ✅ 成功
測試 12/20: ❌ 失敗
測試 13/20: ✅ 成功
測試 14/20: ✅ 成功
測試 15/20: ✅ 成功
測試 16/20: ✅ 成功
測試 17/20: ✅ 成功
測試 18/20: ✅ 成功
測試 19/20: ✅ 成功
測試 20/20: ✅ 成功
測完之後,結果有點讓人跌破眼鏡:
但話說回來,這種測試還是會受到許多條件影響,包括:
總之,這次的實測結果讓人眼睛一亮,也讓我對開源模型的未來充滿期待,當然,這只是個簡單的測試,實際應用中還是要根據需求和場景來選擇最合適的模型。