這幾年來,生成式 AI 的應用一路從產出文字、圖片,逐步進化到「做事」的 AI Agent。這個發展過程真的很有趣,AI 從「會聊天的模型」變成「會幫你做事的助理」,而且還越來越像個能自己判斷該怎麼做的夥伴。
但關於什麼是 AI Agent,如果你上 Google 查一下,會看到一堆不同的定義,有的偏重技術、有的強調應用,但有共識的應該是 AI Agent 是一種「以任務為導向」的 AI,不是等著我們下一步一步的指令,而是能自己想辦法完成任務。可以根據目標,自主決定要怎麼做、中間需要什麼工具,甚至如果遇到問題,會自己找方法解決。
也就是說,AI Agent 不只是懂自然語言(模型),很重要的是還要能跟外部系統互動(工具),像是真正去執行某些工作——不管是查資料、操作系統、叫 API,甚至跑一段自動化流程。從這個角度來看,它已經不是單純的「聊天機器人」了,而是具備「自主性」和「行動力」的智能程式。
像是 OpenAI 推出的 Agent SDK,就是很明確就是往這個方向前進。讓開發者可以打造出能根據使用者需求,自動判斷接下來該做什麼的 Agent。舉個例子好了:如果你要訂一張機票,不需要一步步告訴它先查航班、再比價、再訂票,而是你只需要說「幫我訂一張下週從台北飛東京的機票」,Agent 就會自己搞定整個流程,中間該叫哪些 API、要怎麼處理資料,都不需要你操心。(當然這中間會涉及一些安全性/隱私等問題,我們先不討論以免失焦)
但問題是每一個平台都有自已的一套API,對於開發者來說,如何在不同平台間切換,或是同時使用多個平台的API,就會是一個很大的挑戰。所以這幾年就看到很多類似 LangChain 這樣的框架出現,幫助開發者整合不同的AI模型和API,讓我們可以專注在商業邏輯的撰寫,而不是花太多時間在處理各種API的差異。以 Python 語言來說,大家都知道 LangChain,而.NET我推薦的就是 Semantic Kernel啦。
Semantic Kernel 是 Microsoft 開發的開源工具,目標對齊 LangChain 專門幫助開發者整合各種AI模型和API。提供一的介面,讓開發者可以輕鬆在不同的AI平台之間切換,並且能夠同時使用多個平台的API。隨著AI技術的快速發展,Semantic Kernel也在不斷更新,包含 RAG 的應用,而現在當然包含了 AI Agent 的實作支援。這樣的工具對於想要打造 AI Agent 的開發者來說,可以減少許多開發上的障礙。
這次的鐵人賽,打算再次以 Semantic Kernel 為主軸,實現多種的 AI Agent 原型打造。從概念到實際的程式碼範例。相對的對於簡單的生成任務,著重的篇數就不會那麼多。不過現在不管是LangChain 或是 Semantic Kernel,都是進版的非常快速,所以如果有任何新的功能或是改變,都是正常現象,所以每一篇文章的內容,所使用的版本可能會隨著時間有所不同。而以 Semantic Kernel來說,如果你在前二年的鐵人賽有看過我撰寫的文章,那麼現在的版本已經和當時有很大的差異了。因此一開始我還是針對目前最新的版本來做基本使用的介紹。
身為 .NET 開發者,不管你有沒有接觸過 Semantic Kernel,接下來的內容都會對你有幫助。因為我會從最基礎的 Semantic Kernel 核心開始講起,讓你能夠一步步了解這個框架。
簡單來說,Semantic Kernel 就像是 AI 世界的瑞士刀。它是 Microsoft 開發的開源工具,專門幫我們處理 AI 整合的各種麻煩事。目前它支援 C#、Python 和 Java,所以習慣用 Python、Java 語言也能上手。
想像一下,你在組裝一台電腦。有主機板、CPU、記憶體、硬碟等零件,每個都有自己的功能,但只有當它們正確組合在一起時,才能變成一台能用的電腦。Semantic Kernel 也是這樣,它由幾個核心元件組成,每個都扮演著不可或缺的角色。
如果用一個生活化的比喻來說明:把 Semantic Kernel 想像成一家餐廳,那麼...
Kernel 就像是餐廳的經理,負責統籌全場。當客人(使用者)點餐時,經理會協調廚房(AI 模型)、服務生(Plugins)、甚至是外送員(外部 API),確保整個服務流程順暢。在程式碼裡,Kernel 是你最常打交道的對象,所有的指令都是透過它來發號施令。
// 就像聘請一位經理
var kernel = Kernel.CreateBuilder()
.AddOpenAIChatCompletion(modelId: "gpt-4", apiKey: "your-key")
.Build();
Connector 就像是翻譯官。不管是要連接 OpenAI、Azure OpenAI、還是 Google Gemini,Connector 都能幫你搞定溝通問題。如果哪天想換個 AI 模型,只要換個 Connector,其他程式碼幾乎不用改!這正也是解決不同平台 API 整合的關鍵。
這是實作 AI Agent 最關鍵的部分!Plugin 就像是給 AI 配備的工具箱。裡面可以放各種工具(Functions),比如:
Function 可以是兩種類型:
[KernelFunction]
[Description("Retrieves the today temperature of the city.")]
public int GetTemperature(
[Description("The name of the city to get the temperature for.The city names in the weather data are in English")]
string city)
{
// 真正去查詢天氣的程式碼
}
Memory 讓 AI 能記住之前的對話內容、學習過的知識,甚至是你上傳的文件內容。有了 Memory,AI 就像是有了自己的筆記本,能夠累積經驗、持續學習。短期記憶(Chat History)和長期記憶(Knowledge Base)都可以透過 Memory 來實現。短期記憶通常用於對話場景,讓 AI 能記住前幾輪的對話內容;長期記憶則是用來存放較永久的資訊,像是產品手冊、公司政策等,簡單來說長期記憶就就是用來打造 RAG 應用。
這是整個系統最神奇的地方!透過 Function Calling 機制,AI 不只會思考,還能行動。當使用者說「幫我查台北的天氣」時:
整個過程完全自動化,你不需要寫一堆 if-else 來判斷使用者想做什麼。AI 會自己判斷、自己選工具、自己執行。
Semantic Kernel 早期有個 Planner 元件專門做規劃,但隨著現在模型能力的提升,直接用 Function Calling 更簡單有效,所以在 1.0 版之後就改用這個方式了。也就沒有 Planner 這個元件了。
以大家熟悉的客服系統來說, Semantic Kernel 的整個開發體驗會大幅提升。
以前的做法是這樣的:
其實滿累的對吧?
而 Semantic Kernel 則是:
就這麼簡單!感覺就像是給 AI 裝上了手腳,它終於能自己動手做事了。
先讓我們用一個基本的生成範例來看看如何使用 Semantic Kernel 。這個範例連接到 OpenAI 的聊天服務,並建立一個簡單的聊天機器人範例,不包含 function calling 的功能,也不具短期記憶對話功能,實務上LLM應用的APP也不總是以Chat為出發點,很多時候是以單一任務為主。
本文範例使用 Microsoft.SemanticKernel 套件,版本 1.64.0
using Microsoft.SemanticKernel;
namespace day1;
class Program
{
static async Task Main(string[] args)
{
// 連接到 OpenAI 的聊天服務,並建立一個簡單的聊天機器人範例
// 這個範例不包含 function calling 的功能
// 不具短期記憶對話功能
Kernel kernel = Kernel.CreateBuilder()
.AddOpenAIChatCompletion(
apiKey: Config.OpenAI_ApiKey,
modelId: Config.ModelId)
.Build();
while (true)
{
Console.Write("You: ");
var input = Console.ReadLine();
if (string.IsNullOrWhiteSpace(input) || input.Equals("exit", StringComparison.OrdinalIgnoreCase))
break;
var response = await kernel.InvokePromptAsync(input);
Console.WriteLine($"AI: {response} \n\n");
}
Console.WriteLine("\n Bye!");
}
}
Kernel 建立與設定:
Kernel.CreateBuilder()
建立 Kernel 物件,並用 .AddOpenAIChatCompletion()
設定 OpenAI 的 API 金鑰與模型名稱。.Build()
產生 Kernel 實例。互動式對話迴圈:
while (true)
進行 for 迴圈,持續等待使用者輸入。呼叫 AI 回應:
kernel.InvokePromptAsync(input)
將使用者的提問輸入送給 LLM,取得 AI 回應。注意事項:
這樣的架構讓你能夠很快體驗 Semantic Kernel 與 OpenAI 聊天服務的整合,後續只要擴充 Kernel 設定或加入 Plugin/Function,就能打造更進階的 AI Agent。
延伸上面的範例,我們可以加入短期記憶的功能,讓AI能夠記住之前的對話內容,進而提供更連貫的回應。以下是修改後的程式碼範例:
// 連接到 OpenAI 的聊天服務,並建立一個簡單的聊天機器人範例
// 這個範例不包含 function calling 的功能
// 具備短期記憶對話功能
Kernel kernel = Kernel.CreateBuilder()
.AddOpenAIChatCompletion(
apiKey: Config.OpenAI_ApiKey,
modelId: Config.ModelId)
.Build();
// 建立對話歷史
ChatHistory history = [];
// 從 kernel 取得聊天服務
var chatCompletionService = kernel.GetRequiredService<IChatCompletionService>();
// 開始聊天對話
Console.Write("User > ");
string? userInput;
while ((userInput = Console.ReadLine()) is not null)
{
if (string.IsNullOrWhiteSpace(userInput) || userInput.Equals("exit", StringComparison.OrdinalIgnoreCase))
break;
// 加入使用者訊息到對話歷史
history.AddUserMessage(userInput);
// 以串流方式獲取 AI 回應
var result = chatCompletionService.GetStreamingChatMessageContentsAsync(
history,
kernel: kernel);
// Stream the results
string fullMessage = "";
var first = true;
await foreach (var content in result)
{
if (content.Role.HasValue && first)
{
Console.Write("Assistant > ");
first = false;
}
Console.Write(content.Content);
fullMessage += content.Content;
}
Console.WriteLine();
// 加入 AI 回應到對話歷史
history.AddAssistantMessage(fullMessage);
// Get user input again
Console.Write("User > ");
}
Console.WriteLine("\n Bye!");
這段程式碼示範如何讓 Semantic Kernel 聊天機器人具備「短期記憶」功能,讓 AI 能根據上下文持續對話。重點說明如下:
Kernel 建立與聊天服務取得:
Kernel.CreateBuilder()
並設定 OpenAI 參數,建立 Kernel 物件。kernel.GetRequiredService<IChatCompletionService>()
取得聊天服務,方便後續串流回應。對話歷史管理:
ChatHistory history = []
,用來儲存每一輪對話的訊息(包含使用者與 AI 回應的訊息)。history.AddUserMessage(userInput)
將訊息加入對話歷史記錄。串流式 AI 回應:
chatCompletionService.GetStreamingChatMessageContentsAsync(history, kernel: kernel)
取得 AI 回應,支援逐字串流顯示。await foreach
方式即時顯示 AI 回覆內容,提升使用者體驗。AI 回應納入歷史:
history.AddAssistantMessage(fullMessage)
,將訊息加入對話歷史記錄,讓後續對話能參考上下文。結束條件:
優點與應用:
這個範例讓你體驗 Semantic Kernel 如何輕鬆實現短期記憶對話,為打造更智慧的 AI Agent 奠定基礎。
User > 柴犬和秋田犬的外型很類似,從哪些特徵可以比較輕易的識別出來
Assistant > 柴犬和秋田犬的確外型有不少相似之處,但還是有幾個明顯的特徵可以較容易區分牠們:
1. **體型大小**
- **柴犬(Shiba Inu)**屬中小型犬,肩高約35-41公分,體重約8-10公斤,體型較輕盈。
- **秋田犬(Akita Inu)**屬大型犬,肩高約58-70公分,體重30-50公斤,體格壯碩、肌肉發達。
2. **臉型與表情**
- **柴犬**臉型偏尖,五官集中,表情比較靈巧、銳利,有點像狐狸。
- **秋田犬**臉型寬厚、較圓,表情沉穩,毛髮較豐厚,大眼睛給人比較溫和的感覺。
3. .....(以下省略1000字)
User > 你說二者的體重有差異,但你覺得一般人可以一眼看出體重嗎?
Assistant > 你問得很好!一般人其實在**現場看照片或影片時,確實不太可能直接判斷出體重的數字**,也很難一眼精確分辨兩隻狗狗到底有多重。
但是**體重差異會直接反映在體型大小上**,這其實才是直觀且容易分辨的——
### 怎麼一眼看出差別?
- **秋田犬體積就是「大上一號」**:成年秋田犬站在旁邊,可能比十歲小朋友還高,和成年人的膝蓋差不多;柴犬大多僅到小朋友膝蓋的位置。
- **柴犬比較嬌小精幹**:光用圖片看(尤其單獨、沒有標尺對比時),確實不容易判斷大小;但如果同時有兩犬站一起,或與人同框,就會很明顯。
- **抽象判斷**:秋田犬感覺「壯、圓、厚大」,柴犬則是「小、銳、俐落」。
### 除非同框,不然怎麼分?
當然,假如只看到一隻狗的照片、畫面裡沒有其他東西做比例參考,**單單憑體型確實還是不夠直觀**。
所以這時,**臉型(秋田圓、柴尖)、耳朵大小、毛蓬鬆度(秋田更厚密)、尾巴粗細**等五官/身體特徵,就變成更實用的判斷依據。
---
**小結論:**
- 體型(身形大小)是差異最大、最明顯的特點,但比較常需要有參照物(例如人),不然單看照片很容易混淆。
- 如果只有單獨照片,那就多留意臉型、表情、毛量、耳朵尾巴等細節。
希望這樣讓你更有信心現場分辨!
可以看在第二個提問中,針對「一般人是否能一眼看出體重」這個問題,AI能夠根據上下文理解使用者的疑問,識別是對象是前面提到的柴犬和秋田犬,進而給出更貼近的解答。這就是短期記憶對話的威力!
第一天的內容用二個基礎範例來說明 Semantic Kernel 的使用。在這個系列文章中,我希望能透過有限的文字及範例,一起來認識 Semantic Kernel,打造出屬於自己的 AI Agent。
我們下篇見!