在 LINE Bot 開發中使用Semantic Kernel建立自然語言請假系統

身為 LAE(LINE API Expert) 與 LINE 的支持者,既然知道透過Semantic Kernel可以快速的開發對談機器人,那當然要嘗試用在 LINE Bot的開發上。

先前我們介紹過如何使用 Semantic Kernel 來開發一個支援記憶與對話前後文、可以用自然語言進行請假的對談機器人,但當時的架構是在 console 環境,負責記憶處理的 ChatHistory 是可以被長時間保存的實體物件,但換成了LINE Bot開發的WebAPI架構,一切就變的有所不同了。

首先,由於ChatHistory物件會隨著WebAPI行程消失而遺失,且我們的LINE Bot還得面對多個用戶,因此也無法簡單的用一個 ChatHistory 物件就保存所有用戶的對話紀錄。所以我們要做一些調整,為每一位用戶建立一個自己的ChatHistory物件。

因此,我們在 WebAPI 中撰寫了底下這樣的程式碼:

static Dictionary<string, ChatHistory> ChatHistoryByUser = new Dictionary<string, ChatHistory>();

private ChatHistory getHistoryFromStaticRepo(string UserId)
{
    if (ChatHistoryByUser.ContainsKey(UserId))
        return ChatHistoryByUser[UserId];
    else
        return new ChatHistory();
}

private void saveHistory(string UserId, ChatHistory chatHistory)
{
    if (ChatHistoryByUser.ContainsKey(UserId))
        ChatHistoryByUser[UserId] = chatHistory;
    else
        ChatHistoryByUser.Add(UserId, chatHistory);
}

這段程式碼以靜態方式儲存ChatHistory物件的Dictionary,搭配 getHistoryFromStaticRepo(string UserId) 和 saveHistory(string UserId, ChatHistory chatHistory) 這兩個方法,可以簡單地為每一個用戶保存對話狀態。

但請讀者留意,由於我們只是想用最簡單的方式來說明可行的做法,因此上面用靜態型別來暫時儲存對談紀錄,比較理想的實作還是採用資料庫或類似的儲存體,而非用靜態型別的記憶體變數來保存。

有了這兩個方法之後,我們在WebAPI主程式裡面,就可以大方地針對每一個用戶,在對談前取回聊天訊息:

// 在對談前取回聊天訊息
var history = getHistoryFromStaticRepo(LineEvent.source.userId);
if (history == null || history.Count() <= 0)
    history = new ChatHistory(
    @"你是企業的請假助理,可以協助員工進行請假,或是查詢請假天數等功能。
		若員工需要請假,你需要蒐集請假起始日期、天數、請假事由、代理人、請假者姓名等資訊。最後呼叫 LeaveRequest Method。
		若員工需要查詢請假天數,你需要蒐集請假者姓名,最後呼叫 GetLeaveRecordAmount Method。
		--------------
		* 所有對談請用正體中文回答
		* 請以口語化的方式來回答,要適合對談機器人的角色
		");

並且在對談後儲存聊天訊息:

if (LineEvent.type.ToLower() == "message" && LineEvent.message.type == "text")
{
    // Add user input
    history.AddUserMessage(LineEvent.message.text);

    // Enable auto function calling
    OpenAIPromptExecutionSettings openAIPromptExecutionSettings = new()
    {
        ToolCallBehavior = ToolCallBehavior.AutoInvokeKernelFunctions
    };

    // Get the response from the AI
    var result = chatCompletionService.GetChatMessageContentAsync(
        history,
        executionSettings: openAIPromptExecutionSettings,
        kernel: kernel).Result;

    // Add the message from the agent to the chat history
    history.AddMessage(result.Role, result.Content ?? string.Empty);
    // 在對談後儲存聊天訊息
    saveHistory(LineEvent.source.userId, history);
    responseMsg = result.Content;
}

其他程式碼的寫法,幾乎和先前 console 版本的 Semantic Kernel 完全相同。唯一的差別是我們在 LeaveRequestPlugin 類別的方法中稍微做了點修改,讓具體發生 action 的時候,傳送訊息給 admin(注意底下的 bot.PushMessage(…):

[KernelFunction]
[Description("進行請假")]
public bool LeaveRequest([Description("請假起始日期")] DateTime 請假起始日期, [Description("請假天數")] string 天數, [Description("請假事由")] string 請假事由, [Description("代理人")] string 代理人,
[Description("請假者姓名")] string 請假者姓名)
{
    isRock.LineBot.Bot bot = new LineBot.Bot(ChannelAccessToken);
    bot.PushMessage(AdminUserId, $"action [建立假單:  {請假者姓名} 請假 {天數}天 從 {請假起始日期} 開始,事由為 {請假事由},代理人 {代理人}]");

    return true;
}

如此這般,具有前後文記憶、可以透過自然語言請假的LINE Bot對談機器人就這樣完成了。

執行結果如下:
enter image description here

你會發現,在LINE裡面依舊可以很輕鬆地透過 Semantic Kernel 建立一個具有記憶且可以透過自然語言請假的對談機器人。由於這讓LINE Bot可以輕易的支援對談前後文和歷史訊息的記憶,並且可以透過LLM來剖析自然語言,理解語意,甚至自動執行相關的action(LeaveRequestPlugin類別中的method),大大的簡化了Chat Bot的開發。

過去,我要大費周章才寫得出一個具有記憶和理解前後文,且可以有效的識別用戶以自然語言輸入的 LINE Bot。如今,透過 LLM 和 Semantic Kernel 可以在一兩百行程式碼內就可以實現,而且效果遠比過去的 Chat Bot 好上一個檔次。

這個例子,大致可以看到 Semantic Kernel + LLM 可以為 LINE Bot 帶來的突破!!! 我認為, Chat Bot 開發,現在才正式開始。


參考 課程:
https://www.studyhost.tw/NewCourses/LineBot
參考 Repo:
GitHub - isdaviddong/ex_linebot_with_sk

留言

這個網誌中的熱門文章

在POC或迷你專案中使用 LiteDB

使用Qdrant向量資料庫實作語意相似度比對

專業的價值...

使用 Airtable 在小型需求上取代傳統資料庫

周末讀書會 - 一如既往