Semantic Kernel (SK) 101

Mars Wang
15 min readMay 29, 2023

--

Photo by Matthew Manuel on Unsplash

Introduction

OpenAI開發的ChatGPT成為世界上最快速達到百萬使用者的應用程式,也重新帶動了Artificial Intelligence領域的熱潮,那麼就會開始出現了以下問題:

想要利用Programming languages的方式去連接LLM (Large Language Model),哪裡有這樣的抽象化方式可以實踐?

簡而言之:

什麼工具可以幫助企業加速實踐“AI Model落地化” ?

因此此篇要來介紹除了在目前為人熟知的Python當中的LangChain,另一個是由微軟(Microsoft)開發出.NET的Semantic Kernel,以下我會以SK簡稱。

Semantic Kernel

先上官網介紹SK的說明:

Semantic Kernel (SK) is a lightweight SDK that lets you easily mix conventional programming languages with the latest in Large Language Model (LLM) AI “prompts” with templating, chaining, and planning capabilities out-of-the-box.

簡化以上的說明:就是以程式碼(C#, Python)SDK的方式,連接到做好的LLM AI Model,並利用與LLM AI Model連接,做更多AI應用程式相關的開發,加速對於AI結合在Applications當中的實踐。

那麼SK當中的運作邏輯為何?先從字面上來拆解,建立初步的知識。

SK = Semantic + Kernel

Semantics

語義。意旨需要透過文字以及語句做剖析,並且這個內容是合理的,例如:這個男生想要從店裡買下宇宙,此句話就是一個語義上有問題的內容(不符合真實世界的觀點),但是文法規則(rule)上沒有錯誤。
以Programming Languages來說:以下在C#的世界當中,對variable賦值的規則(rule)並沒有錯誤[注意!是 (dataType var_name = value)這個規則],但是在語義(semantics)上因為23是一個數字,並不應該能夠賦值給字串,導致最後報錯。Semantics更加在意的是:flexible以及meaning的合理性,因此在SK當中希望,透過接收Users提出的Ask來分析語言的含義。

string name = 23; # error --> 但此賦值的規則並沒有錯誤 [datatype var_name = value]

→ 而相對的就是Syntax:語法,意旨針對文字的用法,類似語言的文法規則,例如:英文最基本就是[主詞S. + 動詞V. + 受詞O.],如果在一個句子當中放入了兩個動詞,那麼就是Syntax的錯誤,簡單說就是規則錯了。Syntax在意的點為:精準性(Precise)

Kernel

一個系統的核心、中心。在SK當中,Kernel意旨一個處理User’s ASK的processing engine,會使用目前現有的Plugins(過去版本稱Skills), Memories, Connectors結合後,去達到使用者定義的目標。
SK當中的Kernel定位在:orchestrators,如同指揮家一樣的角色,將所有執行都整合在其核心當中處理。

How to call Kernel in C#?

using Microsoft.SemanticKernel;

var myKernel = Kernel.Builder.Build(); # 透過call Build()來實例化Kernel,可以後續串接(Azure) Open AI, ...等動作

How does SK work?

SK workflow

SK以使用者的問題(ASK)作為目標,透過Kernel調用Planner,將Plugins、 Memories、Connectors的彙整,並組成一個Pipeline(multiple steps)來完成Users’ ASK,最後讓使用者得到回覆(GET Response)。

  • Planner: 用作建立各種steps,
  • Plugins(Skills): 就像是各個已經定義好的技能集合(semantic/native function),可以透過pre-defined skills來讓LLM Model知道要怎麼回答使用者的提問。
    - semantic function: 用語意來表達的的函數,像是”””Tell a short joke about {{$INPUT}}.””” 這樣類型的prompt,來引導LLM做出可靠且穩定的回答。
    - native function: 用傳統程式碼語法來表達的函數,像是text1 + text2。這樣直接用syntax來做邏輯的函數,而非用語意表達。
  • Memories: 顧名思義就是讓User使用時,上下文(context)是能夠記憶先前的問題或是回答,會透過Embedding這樣的vector資料型態,來表示資料(words or other data as vectors in a high-dimensions space)。
    SK當中也提供多個connectors來連接vector database:
    - Azure Cognitive Search
    - COSMOS DB
    - Pinecone
  • Connectors: 也可以從字面意思了解就是連結Microsoft原生or第三方的介接器,像是介接到Power Platform,或像是連接到vector database,做embedding資料的儲存以及讀取時,也會使用到SK已經設計好的connectors直接做使用。

我們後續文章會詳細討論Plugins, Memories, Connectors的應用以及舉例。

Demo

以下Demo會以C#為主展示

Prerequisite

  1. Azure Open AI或是Open AI服務 → 需準備API key以及部署好的model名稱,此次會以Azure Open AI舉例。
  2. Download .NET 6 or .NET 7
  3. 下載or git clone Semantic Kernel (Github)
  4. VSCode IDE with plugin Ployglot NoteBook

Get Started

先從Github Download檔案,若沒有下載Git的話,可以直接在Github repo當中如下圖一樣,直接下載成為zip檔案,再解壓縮。

Semantic Kernel (Github)

設定Config

必須要做configuration,才可以讓程式碼讀到在雲端上的LLM model,並做到後續Model的使用。

啟動VScode並打開此專案內容,找到資料夾semantic-kernel/samples/notebooks/dotnet的位置,此為本次intro的demo程式碼。

點擊config資料夾,複製settings.json.azure-example此份檔案中的內容,並在config資料夾底下新增檔案叫做settings.json,並依序將內容填寫完畢,如下圖:

做config設定

在Azure上找尋相關API Key以及Deployment時,可依照以下步驟使用:

需先建立open ai服務,才能進入此處做access

再來是Model deployments,會跳轉到Azure OpenAI Studio,新增deployments,並選取text-davinci-003做此demo範例(若有其他需求也可以另外選取其他model做介接)。

  • Model Name: text-davinci-003
  • Deployment Name: text-deployment → 將此名稱貼入settings.json當中的”model”內
建立model deployment
config/settings.json的最終樣貌

[Reminder]
如果想使用model是gpt-turbo-35的話,後續程式碼的部分會需要更改呼叫的function,請參考此issue

進入程式碼

用VScode打開位置為semantic-kernel/samples/notebooks/dotnet/00-getting-started.ipynb的檔案。此篇我們會以這個做詳細講解,後面篇章再將其他sample說明。

00-getting-started.ipynb程式碼頁面

[Reminder]
以下每一步驟的blocks都可以點擊左側執行按鈕,或是直接點選block後,鍵盤點擊shift+enter執行。

Step1:

會將我們先前設定configuration的密碼金鑰讀取,並利用 #!import 指令(稱作magic command),將其他的code或是notebook import到目前的source code當中。

// #!import -> Runs code from another notebook or source code file.  
#!import config/Settings.cs

Step2:

將nuget上的SK module給import到本專案當中做使用。

// Import Semantic Kernel
// #r --> directive adds a reference to a specified assembly
#r "nuget: Microsoft.SemanticKernel, 0.14.547.1-preview"

Step3:

建立起Kernel,並將相關的configuration都載入Kernel後,使用.AddXXTextCompletionService()這個Connector來跟Azure Open AI Service做Model串接。

using Microsoft.SemanticKernel;

// Set Simple kernel instance
IKernel kernel = KernelBuilder.Create();

// Configure AI service credentials used by the kernel
var (useAzureOpenAI, model, azureEndpoint, apiKey, orgId) = Settings.LoadFromFile();

if (useAzureOpenAI)
kernel.Config.AddAzureTextCompletionService(model, azureEndpoint, apiKey);
else
kernel.Config.AddOpenAITextCompletionService(model, apiKey, orgId);

Step4:

加入自定義的Plugins(之前稱作Skills),我們可以自己利用semantic的方式,提供LLM model prompt,並不斷迭代開發我們的prompt,來當使用者在詢問問題時的reliability以及credibility of LLM model。

因此Plugins就像是prompts集合,或是自定義的傳統語法functions (syntax, e.g. return textA + textB;),可以在此專案的資料夾semantic-kernel/samples/skills當中找到。
→ e.g. ChildrensBookSkill/BookIdeas,就稱為一個semantic function

以此次舉例會用到資料夾skills/FunSkill/Joke當中skprompt.txt的prompt,透過文字說明提示的方式,引導LLM做出適當的回應以及符合的回應格式。

###### Joke/skprompt.txt ######

WRITE EXACTLY ONE JOKE or HUMOROUS STORY ABOUT THE TOPIC BELOW

JOKE MUST BE:
- G RATED
- WORKPLACE/FAMILY SAFE
NO SEXISM, RACISM OR OTHER BIAS/BIGOTRY

BE CREATIVE AND FUNNY. I WANT TO LAUGH.
{{$style}}
+++++

{{$input}}
+++++

並且透過Joke/config.json的組態檔,設定此prompt該有多少的回覆隨機度(temperature)、token數量要有多少、input參數會有哪些…等設定。

###### Joke/config.json ######
{
"schema": 1,
"description": "Generate a funny joke",
"type": "completion",
"completion": {
"max_tokens": 1000,
"temperature": 0.9,
"top_p": 0.0,
"presence_penalty": 0.0,
"frequency_penalty": 0.0
},
"input": {
"parameters": [
{
"name": "input",
"description": "Joke subject",
"defaultValue": ""
}
]
}
}

使用kernel提供的語法來引入Plugins (也稱Skills),並且呼叫所需要的function (prompt):

// Load the Skills Directory
var skillsDirectory = Path.Combine(System.IO.Directory.GetCurrentDirectory(), "..", "..", "skills");

// Load the FunSkill from the Skills Directory
var funSkillFunctions = kernel.ImportSemanticSkillFromDirectory(skillsDirectory, "FunSkill");

// Run the Function called Joke
// InvokeAsync("<input for the prompt>") --> 可以在這邊調整input內容,查看不同input的response
var result = await funSkillFunctions["Joke"].InvokeAsync("time travel to dinosaur age");

// Return the result to the Notebook
Console.WriteLine(result);

最後得到回應:

A time traveler went back to the dinosaur age and was amazed by the size of the creatures. 
He asked one of the dinosaurs,
"How do you manage to get around with such short legs?"

The dinosaur replied, "It's easy, I just take my time!"

後續會針對Semantic Kernel提供更多深入的內容探討,各位對此篇文章有任何疑問或是feedback也歡迎聯絡我。

My Github: MarsWangyang (Mars Wang) (github.com)

My LinkedIn: Meng-Yang (Mars) Wang | LinkedIn

--

--