使用Semantic Kernel 建立自然語言請假系統
既然我們已經知道,可以透過 Semantic Kernel 輕易地建立聊天機器人/智能助理,我們之前(參考這篇)也看到了如何用自然語言驅動 AI ,來自動呼叫 IoT 控制開關燈類別中的方法,體驗過了它的威力,接著,我們就來實作一下,如何透過 Semantic Kernel 來建立一個可以透過自然語言請假的對談機器人。
我得說,我過去幾年做過無數次這個範例,試圖用自然語言以對談方式來完成請假。從最初LINE Bot 出現的時候,以手工苦刻的方式,來建立請假機器人,到使用 Azure AI 上的 Language Understanding 解決方案,讓機器人能夠『稍微』看懂用戶以自然語言的方式輸入的請假資訊,但整個過程從來沒有愉快過。
過去,電腦對自然語言的理解實在太差了,直到GPT的出現,直到有了LLM,一切才開始不同。現在,我們可以輕易地透過 Semantic Kernel 使用大語言模型,來建立一個類似底下這樣,表現非常好的自然語言請假系統:
你會發現,我們實作了一個可以幫助用戶請假的對談機器人。他會蒐集用戶的請假資訊,然後在資訊滿足之後,呼叫API來完成請假動作。
上面這段對談紀錄當中,黃色的部分就是AI自動進行的 Action,也就是具體的『請假』或是『查詢』動作,其他的則是自然語言的交談對話。
我們之前說過,透過 Semantic Kernel ,我們可以快速地完成上面這個功能的開發。為了完成這個需求,我們建立了底下這個 LeaveRequestPlugin 類別。這個類別裡面有三個方法,你可以從Description描述看到這些方法的功能(當然,範例裡面的Action暫且用示意的方式來呈現,不真的寫入資料庫):
// 請假功能 Plugin
public class LeaveRequestPlugin
{
[KernelFunction]
[Description("取得請假天數")]
public int GetLeaveRecordAmount([Description("要查詢請假天數的員工名稱")] string employeeName)
{
//修改顯示顏色
Console.ForegroundColor = ConsoleColor.Yellow;
Console.WriteLine($"\n [action]查詢 {employeeName} 請假天數。\n");
//還原顯示顏色
Console.ResetColor();
if (employeeName.ToLower() == "david")
return 5;
else if (employeeName.ToLower() == "eric")
return 8;
else
return 3;
}
[KernelFunction]
[Description("進行請假")]
public bool LeaveRequest([Description("請假起始日期")] DateTime 請假起始日期, [Description("請假天數")] string 天數, [Description("請假事由")] string 請假事由, [Description("代理人")] string 代理人,
[Description("請假者姓名")] string 請假者姓名)
{
Console.ForegroundColor = ConsoleColor.Yellow;
Console.WriteLine($"\n [action]建立假單: {請假者姓名} 請假 {天數}天,從 {請假起始日期} 開始,事由為 {請假事由},代理人 {代理人}\n");
//還原顯示顏色
Console.ResetColor();
return true;
}
[KernelFunction]
[Description("取得今天日期")]
public DateTime GetCurrentDate()
{
return DateTime.UtcNow.AddHours(8);
}
}
主程式的部分,則大同小異,我們採用 OpenAI 的 gpt-4-turbo-preview Model,作為這個服務的 AI Provider,我們給的 system prompt是底下程式碼中撰寫的這樣:
var OpenAIModel = "gpt-4-turbo-preview";
var OpenAIKey = "👉ApiKey👈";
// Create a new kernel builder
var builder = Kernel.CreateBuilder()
.AddOpenAIChatCompletion(OpenAIModel, OpenAIKey);
builder.Plugins.AddFromType<LeaveRequestPlugin>();
Kernel kernel = builder.Build();
// Create chat history 物件,並且加入
var history = new ChatHistory(
@"你是企業的請假助理,可以協助員工進行請假,或是查詢請假天數等功能。
若員工需要請假,你需要蒐集請假起始日期、天數、請假事由、代理人、請假者姓名等資訊。最後呼叫 LeaveRequest Method。
若員工需要查詢請假天數,你需要蒐集請假者姓名,最後呼叫 GetLeaveRecordAmount Method。
--------------
* 所有對談請用正體中文回答
* 請以口語化的方式來回答,要適合對談機器人的角色
");
當我們在主程式中給了這樣的 prompt ,並且將 LeaveRequestPlugin 掛上之後,主程式只有底下這樣的典型的 Semantic Kernel 對談 Loop:
// Get chat completion service
var chatCompletionService = kernel.GetRequiredService<IChatCompletionService>();
// 開始對談
Console.Write("用戶 > ");
string? userInput;
while (!string.IsNullOrEmpty(userInput = Console.ReadLine()))
{
// Add user input
history.AddUserMessage(userInput);
// Enable auto function calling
OpenAIPromptExecutionSettings openAIPromptExecutionSettings = new()
{
ToolCallBehavior = ToolCallBehavior.AutoInvokeKernelFunctions
};
// Get the response from the AI
var result = await chatCompletionService.GetChatMessageContentAsync(
history,
executionSettings: openAIPromptExecutionSettings,
kernel: kernel);
// Print the results
Console.WriteLine("AI助理 > " + result);
// Add the message from the agent to the chat history
history.AddMessage(result.Role, result.Content ?? string.Empty);
// Get user input again
Console.Write("\n用戶 > ");
}
}
}
就這樣程式寫完了。
開始運行之後,剩下的就是 AI 自己決定在需要查詢用戶請假天數時,去呼叫了 GetLeaveRecordAmount(string employeeName) 這個方法,然後把員工名稱當作參數傳入。有趣的是,當AI知道需要用戶名稱這個參數時,會主動問用戶的名稱。此外,當用戶提到從 “明天” 開始請假時(參考下圖),AI也會主動呼叫 GetCurrentDate() 這個位於 LeaveRequestPlugin 類別中的方法,來取得今天的時間日期,並推斷出明天的日期,因此就無需再去問用戶明天是幾月幾號:
我還嘗試把 description和變數名稱都特別改成中文,看看運行起來的狀況如何? 顯然,對於LLM來說,這根本不是問題。
這一切邏輯和行為,都是透過 GPT 和 Semantic Kernel 攜手自動完成,開發人員寫的只是提示(Prompt)以及適當的提供API或類別中的方法。
透過 Semantic Kernel ,這是有史以來讓我首次覺得,撰寫一個要能夠以自然語言進行請假的系統是如此的簡單、快速、有趣,這讓所謂的 AI 助理(Assistant) 和 Copilots 的開發,瞬間變得非常的容易。
下一個世代的應用程式軟體開發方式,已在眼前。
留言