iT邦幫忙

2025 iThome 鐵人賽

DAY 10
0

在前幾天的文章中,我們已經學會了如何準備食材(提示詞)、認識了我們的頂級廚師(Kernel),甚至還學會了他的招牌絕活 Function Calling。今天的第 10 天,我們要來探討一個更深層的廚房哲學問題:我們的 AI 廚房,應該是全自動化,還是需要總鋪師我本人——也就是你,開發者——來手動確認每一步關鍵操作呢?

這對應到 Semantic Kernel (SK) 中一個非常重要的概念:函式調用模式 (Function Invocation Modes)


全自動化的米其林廚房:自動調用 (Auto Invoke)

想像一下,一間配備了最先進 AI 機器人的米其林廚房。客人點餐後,從切菜、烹煮到擺盤,所有流程一氣呵成,總鋪師只需要在旁邊優雅地喝著咖啡,監督著一切順利進行。這就是 SK 的預設行為——

自動調用 (Auto Invoke)

當你像前幾天那樣,把 FunctionChoiceBehavior 設置為 Auto 且不做任何額外設定時,SK 就會進入這個模式。整個 Function Calling 的生命週期會由 SK 自動完成:

  1. AI 模型決定:AI 判斷需要呼叫某個函式來完成任務。
  2. SK 執行:SK 接收到指令後,立刻執行對應的 Plugin 函式。
  3. 結果回傳:SK 將函式執行的結果送回給 AI 模型。
  4. 最終回應:AI 模型根據函式結果,生成最終的自然語言回覆給使用者。

這個過程行雲流水,完全不需要你介入干預。對於大多數情境,例如查詢天氣、簡單的資料檢索,這種全自動模式效率最高,也是我們最推薦的起手式。

總鋪師的親自把關:手動調用 (Manual Invoke)

然而,有些菜色需要總鋪師的精湛手藝與親自確認。比如,當客人點了一道需要「炙燒干貝佐魚子醬」的昂貴料理時,AI 助手的建議很好,但你可能想親自檢查干貝的品質,並決定炙燒的火侯。這就是

手動調用 (Manual Invoke) 的精神。

手動調用賦予了開發者

完全的控制權。在 AI 決定要呼叫某個函式之後,流程會暫停,將「決策」交還給你。你可以決定是否、何時、以及如何執行這個函式。

這在以下場景中至關重要:

  • 使用者確認 (Human-in-the-loop):執行敏感操作前,例如「AI 想要下單一支價值 10 萬元的股票,您確定嗎?」或是「AI 準備刪除這個檔案,請確認」。
  • 複雜的流程控制:在函式執行前後,你可能需要插入自訂的日誌記錄、資料驗證,或是根據函式結果觸發不同的業務邏輯。
  • 成本與安全控管:在執行函式前,你可以檢查呼叫的成本,或者根據某些安全策略來否決這次呼叫。

要啟用手動模式,你只需要在設定 FunctionChoiceBehavior 時,將 autoInvoke 參數設為 false

實戰演練:打造一個需要手動確認的天氣查詢機器人

接下來,讓我們用一段完整的程式碼,來看看手動模式是如何運作的。我們將建立一個天氣機器人,但在它實際呼叫 WeatherForecastUtils 之前,會先在主控台印出一條訊息,模擬開發者介入確認的過程。

C#

using Microsoft.SemanticKernel;
using Microsoft.SemanticKernel.ChatCompletion;
using Microsoft.SemanticKernel.Connectors.OpenAI;
using System.Text.Json;

// 假設我們有這些 Plugin
public class WeatherForecastUtils
{
    [KernelFunction, Description("Gets the weather for a city.")]
    public static string GetWeatherForCity(string cityName)
    {
        // 假裝查詢天氣
        Console.WriteLine($"[Plugin] 正在查詢 {cityName} 的天氣...");
        return $"台灣 {cityName} 今天天氣晴朗,溫度 28 度。";
    }
}

public class DateTimeUtils
{
    [KernelFunction, Description("Gets the current time.")]
    public static string GetCurrentTime() => DateTime.Now.ToString("HH:mm");
}

// --- 主程式 ---
var builder = Kernel.CreateBuilder();
// 請記得換成你自己的 Azure OpenAI 設定
builder.AddAzureOpenAIChatCompletion(
    "your-deployment-name",
    "your-endpoint",
    "your-api-key");
builder.Plugins.AddFromType<WeatherForecastUtils>();
builder.Plugins.AddFromType<DateTimeUtils>();
var kernel = builder.Build();

var chatCompletionService = kernel.GetRequiredService<IChatCompletionService>();

// 透過設定 autoInvoke: false 來啟用手動調用
var settings = new OpenAIPromptExecutionSettings
{
    FunctionChoiceBehavior = FunctionChoiceBehavior.Auto(autoInvoke: false)
};

var chatHistory = new ChatHistory();
chatHistory.AddUserMessage("現在台北的天氣如何?");

while (true)
{
    // 1. 讓 AI 決定下一步
    var result = await chatCompletionService.GetChatMessageContentAsync(chatHistory, settings, kernel);

    // 2. 檢查 AI 是否只回傳了文字訊息
    if (!string.IsNullOrEmpty(result.Content))
    {
        Console.WriteLine($"[AI Assistant] > {result.Content}");
    }

    // 3. 取得 AI 想要呼叫的函式
    var functionCalls = FunctionCallContent.GetFunctionCalls(result).ToList();
    if (functionCalls.Count == 0)
    {
        // 如果沒有函式要呼叫,表示對話結束
        break;
    }

    // 4. 將 AI 的函式呼叫請求也加入歷史紀錄
    chatHistory.Add(result);

    // 5. 迭代所有函式呼叫並手動執行它們
    foreach (var functionCall in functionCalls)
    {
        Console.WriteLine($"[總鋪師的確認] > AI 想要呼叫 '{functionCall.PluginName}.{functionCall.FunctionName}'。準備執行...");

        // 6. 手動調用函式!
        var functionResultContent = await functionCall.InvokeAsync(kernel);

        // 7. 將函式執行的結果轉成 ChatMessageContent 並加入歷史紀錄
        chatHistory.Add(functionResultContent.ToChatMessage());
        Console.WriteLine($"[函式執行結果] > {JsonSerializer.Serialize(functionResultContent.Result)}");
    }

    // 8. 帶著新的結果回到迴圈,讓 AI 繼續思考
    Console.WriteLine("\n--- 將結果送回 AI,進行下一輪思考 ---\n");
}

當你執行這段程式碼,你會看到類似以下的輸出:

[總鋪師的確認] > AI 想要呼叫 'WeatherForecastUtils.GetWeatherForCity'。準備執行...
[Plugin] 正在查詢 台北 的天氣...
[函式執行結果] > "台灣 台北 今天天氣晴朗,溫度 28 度。"

--- 將結果送回 AI,進行下一輪思考 ---

[AI Assistant] > 台北現在天氣晴朗,氣溫是 28 度。

看到了嗎?在真正查詢天氣之前,我們的程式印出了「總鋪師的確認」,這就是我們介入的時機點!在這個 foreach 迴圈中,你可以加入任何你需要的邏輯。

結論:何時該自動?何時該手動?

  • 自動調用 (Auto Invoke):你的首選和預設。當你的工具(Plugins)是相對安全、無害的查詢,且你信任 AI 能獨立完成任務時,就讓它全速運轉吧!
  • 手動調用 (Manual Invoke):當你的 AI 需要操作一些具有副作用、高成本或需要權限的動作時,手動模式就是你的安全網。它讓身為總鋪師的你,永遠保有最終的決定權。

選擇哪種模式,取決於你想給予 AI 廚師多大的自主權。Semantic Kernel 的美妙之處,就在於它提供了這種彈性,讓你既能享受自動化的便利,也能在關鍵時刻親自掌勺。


完整程式碼範例


上一篇
Day 9: 點菜的藝術:Function Calling 的進階選項 (Behaviors)
下一篇
Day 11: 米其林星級湯底:用 Vector Stores 實現 RAG (Part 1 - 基礎與塑模)
系列文
AI 全餐,好吃嗎?用 Semantic Kernel 打造你的客製化滿漢全席!12
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言