精彩(且驚人)的Semantic Kernel入門範例
之前開直播的時候,和線上朋友聊到,因為AI的出現,未來的應用程式,勢必會和現在有所不同。
先不要跳到黃仁勳說的,未來『每個開發人員都可以直接用自然語言做程式設計』(這樣也太駭人聽聞了一點),先看看眼下我們可以做到什麼程度。
你會發現透過 Semantic Kernel,這個所謂的 AI 開發框架,已經可以做到,讓 AI 自己決定何時(以及如何)呼叫一個類別(Class)中的方法(Method)。而我們只需要讓用戶輸入對話與機器人對談,就可以控制程式運行的流程與邏輯。也就是說,現在不需要滑鼠點選,不用選單操作,只要與機器人透過自然語言對談(底下的範例是打字,但當然可以是語音),就可以操控系統。
我前陣子一直說的,AI 會讓 GUI 有著天翻地覆的改變,意即如此。
看底下這個類別的程式碼:
//控制開關燈的類別
public class LightPlugin
{
//當前燈的狀態
public bool IsOn { get; set; } = false;
[KernelFunction]
[Description("取得燈的狀態")]
public string GetState()
{
return IsOn ? "on" : "off";
}
[KernelFunction]
[Description("改變燈的狀態")]
public string ChangeState(bool newState)
{
this.IsOn = newState;
var state = GetState();
// Print the state to the console
Console.WriteLine($"[Light is now {state}]");
return state;
}
}
上面這個很簡單的 LightPlugin 類別,具有兩個方法:GetState 和 ChangeState。這兩個方法都被標記為 [KernelFunction],這意味著它們可以直接被 AI 呼叫。
LightPlugin 類別中有一個全域屬性IsOn ,指的是當前的燈是開著還是關的。
從這邊你會看到, LightPlugin 這個類別包含的一個狀態(屬性),和兩個行為(方法),你可以將其比擬成一個IoT智慧型家電的控制物件,透過改變這個物件就可以控制家電。請在心裡想像一下,如果你過去,要寫程式讓用戶來操作這個物件,進而控制電燈的開或關,你會怎麼做?
做一個控制面板(GUI)? 還是做一個選單操作介面(Menu)? 來控制這個燈光的開啟和關閉。
那如果,這個控制機制要改成語音控制呢? 例如我希望用戶能夠用說的,電腦就能夠回報目前燈光的狀況,或是幫你直接開關燈,你是不是必須多撰寫很多程式碼,才能完成?
好,我們接著來看底下的程式碼,看看Semantic Kernel是如何完成這需求的:
private static async global::System.Threading.Tasks.Task Main(string[] args)
{
//Azure OpenAI 服務資訊
var DeployName = "👉模型佈署名稱👈";
var Endpoint = "https://👉API端點👈.openai.azure.com/";
var ApiKey = "👉ApiKey👈";
// 建立 kernel builder, 掛上 Azure OpenAI
var builder = Kernel.CreateBuilder()
.AddAzureOpenAIChatCompletion(DeployName, Endpoint, ApiKey);
builder.Plugins.AddFromType<LightPlugin>(); // 將 LightPlugin 加入 Kernel
Kernel kernel = builder.Build();
// 建立 chat history 物件,並且加入系統提示訊息(System Prompt)
var history = new ChatHistory();
history.AddSystemMessage("你是一個親切的智能家庭助理,可以協助用戶回答問題,交談時請使用中文。");
// Get chat completion service
var chatCompletionService = kernel.GetRequiredService<IChatCompletionService>();
// 開始對談
Console.Write("User > ");
string? userInput;
while (!string.IsNullOrEmpty(userInput = Console.ReadLine()))
{
// Add user input
history.AddUserMessage(userInput);
// Enable auto function calling
OpenAIPromptExecutionSettings openAIPromptExecutionSettings = new()
{
ToolCallBehavior = ToolCallBehavior.AutoInvokeKernelFunctions
};
// 從 AI 取得對談結果
var result = await chatCompletionService.GetChatMessageContentAsync(
history,
executionSettings: openAIPromptExecutionSettings,
kernel: kernel);
// 顯示結果
Console.WriteLine("Assistant > " + result);
// 將對話加入歷史訊息
history.AddMessage(result.Role, result.Content ?? string.Empty);
// Get user input again
Console.Write("User > ");
}
}
先看上面這段程式碼,搭配 剛才的LightPlugin之後,執行結果如下:
想像一下,這是一個智能助理管家(畢竟上面的 prompt 我們是這麼說的),當你回家了,這個AI會跟你說話:
歡迎回家!需要我為您開啟燈光或是播放輕快的音樂來放鬆一下嗎?
接著你說:
現在好黑,燈是開著嗎?
AI 想知道燈的狀況,因此它自己去呼叫了 LightPlugin 的 GetState() 方法,告訴你目前燈是關的,並且問你要不要開燈?
對不起,目前的燈光是關閉的,要我立即為您打開燈光嗎?
你說…
幫我開燈
這個敘述會促使 AI 去執行 LightPlugin 類別的ChangeState()方法,自動傳入參數 True,這時,燈開了,然後出現底下訊息
[Light is now on]
好的,燈已經打開了。如果還有其他需要的話,隨時告訴我喔。
後面的動作就不用我多解釋了,你用口語化的指令,告訴AI說,你要關燈,它就幫你關燈。你人在國外出差,要問家裡的燈是開是關,它就幫你查詢狀態,並且回報:
是的,您的家中燈光目前是關閉的。如果您需要改變狀態或有其他需要,隨時讓我知道。
這個系統的操作,不是用滑鼠、不是用選單、不是用手機 app,單純就是用口語化的指令,來控制一切。整個流程,由 AI 自己決定何時(when)/如何(How)呼叫 LightPlugin 的什麼(What) Method(方法),全部用 語意(Semantic) 為核心,所以這個框架被稱為 Semantic Kernel 我想是再適當不過的了。
你再看一下操作的影片,有沒有很讓人震驚?
誰控制這一切的? 誰回應了用戶的對談? 並且決定何時呼叫 API(或method),當然是 GPT 模型,看底下這段:
//Azure OpenAI
var DeployName = "👉模型佈署名稱👈";
var Endpoint = "https://👉API端點👈.openai.azure.com/";
var ApiKey = "👉ApiKey👈";
// Create a new kernel builder
var builder = Kernel.CreateBuilder()
.AddAzureOpenAIChatCompletion(DeployName, Endpoint, ApiKey);
builder.Plugins.AddFromType<LightPlugin>(); // Add the LightPlugin to the kernel
Kernel kernel = builder.Build();
kernel builder 建立了以 AzureOpenAIChatCompletion 方法為核心的 AI Kernel,並且添加了 LightPlugin 這個類別作為 Plugin。
接著,我們配置了 System Message (role為system的prompt):
// 建立 chat history 物件,並且加入系統提示訊息
var history = new ChatHistory();
history.AddSystemMessage("你是一個親切的智能家庭助理,可以協助用戶回答問題,交談時請使用中文。");
最後建立了 chatCompletionService 物件,並且開啟了對話迴圈,然後程式就動起來了:
// Get chat completion service
var chatCompletionService = kernel.GetRequiredService<IChatCompletionService>();
// 開始對談
Console.Write("User > ");
string userInput;
while ((userInput = Console.ReadLine()) != null)
{
// 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("Assistant > " + 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("User > ");
}
迴圈中,我們只是透過 AddUserMessage() 方法把用戶輸入的訊息傳遞給 AI,並且透過 GetChatMessageContentAsync() 方法取得回傳結果,這樣的對話之間,AI 就自己決定了要進行的行為,要呼叫的 API(Method),這還不驚人嗎?
以後的程式的核心,可能不是我寫的邏輯,而是 AI 決定的邏輯,我們只是提供了在什麼狀況下要呼叫什麼方法的指引(注意 LightPlugin類別的那兩個方法身上掛的 KernelFunction Attribute 與 Description Attribute ),然後,事就這麼成了。
在上面的範例中,應用程式的『核心』,已經不是我寫的邏輯,應用程式的核心,是AI。我只是提供AI所需要的功能(Plugin),然後用戶就可以透過與AI對談,完成所有的 Actions(行為)。
沒有複雜的UI操作介面,沒有複雜的邏輯指令,全都是自然語言溝通,全部是AI。
我第一次看到的時候是很震驚的,想像一下,如果上面的 LightPlugin類別是一個個的API,那未來的程式開發方式是不是會大大的改變?
我們會不會迎向一個透過自然語言就可以操作的系統? 甚至一個透過語音就可以控制的作業系統? 果真實現,那鋼鐵人裡面的人工智能助理Jarvis,還會遠嗎?
相關課程:
ChatGPT(Azure OpenAI) 對談機器人開發實戰 (studyhost.tw)
參考資料:
https://learn.microsoft.com/zh-tw/semantic-kernel/overview/
留言