Semantic Kernel 入門系列:🔥Kernel 核心和🧂Skills 技能

2023-04-10 06:01:11

理解了LLM的作用之後,如何才能構造出與LLM相結合的應用程式呢?

首先我們需要把LLM AI的能力和原生程式碼的能力區分開來,在Semantic Kernel(以下簡稱SK),LLM的能力稱為 semantic function ,程式碼的能力稱為 native function,兩者平等的稱之為function(功能),一組功能構成一個技能(skill)。 SK的基本能力均是由skill構成。

有了一堆skill之後並不能直接執行,需要有一個設定和管理的單元,就像是MVC 需要ASP.NET框架一樣,Skill也需要有一個Kernel進行組織管理。

Kernel 除了組織管理Skill,還兼顧了基礎服務的設定,例如OpenAI/Azure OpenAI的授權資訊,預設的LLM模型選擇等等。另外當涉及到上下文的管理,技能引數的傳遞時,Kernel也能發揮重要的作用。

接下來我們就以開始著手上手SK應用開發的學習。

準備階段

  1. 首先準備一個應用環境,Console 可以,ASP.NET 也可以,Notebooks 也可以。使用Notebooks的話推薦參考官方的Notebooks合集Uncle John's Semantic Kernel Recipes
  2. 應用環境準備好之後,和所有的.Net 庫一樣,接下來就是安裝SK的nuget 包。由於是一個較新的包,所以更新變化會比較快。
dotnet add package Microsoft.SemanticKernel --prerelease
  1. 接下來進行應用內的準備工作,首先建立一個 kernel;
using Microsoft.SemanticKernel;
var kernel = Kernel.Builder.Build();
  1. 然後設定基礎模型,基礎模型目前有四個:

    • TextCompletion,最常用的GPT-3的模型,常用於文字生成
    • ChatCompetion,GPT3.5模型,也就是所謂的ChatGPT的模型,基本就用於聊天功能
    • EmbeddingGeneration,嵌入模型,這個將用於Memory的生成和搜尋,在後期能力擴充套件時將會有極大的用途
    • ImageGeneration,圖形模型,也就是DALL-E模型,用於圖片的生成

    由於Azure OpenAI提供了和Open AI相同的能力,所以以上的模型設定可以選擇OpenAI的介面,也可以選擇Azure OpenAI的介面,根據自己有哪個選哪個的原則使用。

    當然以上模型也提供了基本的介面定義,如果有自己的LLM AI介面的話,也可以自行實現相關介面,然後使用。

    這裡以OpenAI的介面為例,繼續進行學習。

// 簡單的技能任務使用TextCompletion即可
// 1. ServiceId 用於指定當前模型的設定,相同的模型不能有重複的ServiceId設定
// 2. modelId 指定TextCompetion所使用的LLM 模型,目前基本為 text-davinci-003
// 3. apikey OpenAI 介面呼叫需要使用的APIkey
kernel.Config.AddOpenAITextCompletionService("ServiceId","text-davinci-003",Environment.GetEnvironmentVariable("OPENAI_API_KEY"));

Semantic Function

  1. 註冊一個Semantic Function
using Microsoft.SemanticKernel.SemanticFunctions;

// ⚠️ Semantic Function的核心就是prompt⚠️ 
// 這裡偷懶,使用Semantic Kernel官方樣例庫裡面的的Summary Skill
var prompt = 
"""
[SUMMARIZATION RULES]
DONT WASTE WORDS
USE SHORT, CLEAR, COMPLETE SENTENCES.
DO NOT USE BULLET POINTS OR DASHES.
USE ACTIVE VOICE.
MAXIMIZE DETAIL, MEANING
FOCUS ON THE CONTENT

[BANNED PHRASES]
This article
This document
This page
This material
[END LIST]

Summarize:
Hello how are you?
+++++
Hello

Summarize this
{{$input}}
+++++
""";
// 使用擴充套件方法在Kernel上註冊一個SemanticFunction 
// prompt 是Semantic Function的核心,如何設計一個好的prompt是成功構建Semantic Function的關鍵所在,也是未來LLM AI 應用中的重要內容
// PromptTemplateConfig 用於設定prompt 模板的相關引數
// functionName 是自定義的功能名稱[可選]
// skillName 是自定義的技能名稱[可選]
var summaryFunction = kernel.CreateSemanticFunction(prompt,new PromptTemplateConfig());

可以注意到的是在prompt中,有一個變數引數 {{$input}},這是SK的預設輸入引數,用於注入需要處理的使用者輸入,這樣的格式用於預防Prompt Injection,這就是另外一個話題了。

  1. 執行Function
// 定義需要處理的輸入
var input = "Multi-modal interfaces are becoming increasingly popular for app developers. These interfaces allow users to interact with apps in a variety of ways by combining different modes of input and output, such as voice, touch, and visuals, to create a more interactive and engaging user experience. In this blog we will overview how you can use Semantic Kernel with a multi-modal example.  ";
// 通過 Kernel 執行 function 
var resultContext = await kernel.RunAsync(input,summaryFunction);
// 輸出結果
resultContext.Result.Dump();
// output 
// Multi-modal interfaces are becoming increasingly popular for app developers, combining different modes of input and output such as voice, touch, and visuals to create a more interactive and engaging user experience. Semantic Kernel can be used to create a multi-modal example.

以上就完成了一個簡單的Semantic Function的使用。

好的,我們繼續。

Native Function

  1. 宣告一個Native Skill
using Microsoft.SemanticKernel.SkillDefinition;
// 這裡偷懶,使用Semantic Kernel CoreSkills中的 TextSkill
public class TextSkill {
	[SKFunction("Convert a string to uppercase.")]
	public string Uppercase(string text)
	{
		return text.ToUpper(System.Globalization.CultureInfo.CurrentCulture);
	}
}

這裡只需要對方法新增一個SKFunction的註釋,就可以轉變為一個SK的Native Function。

  1. 註冊Native Skill
// skillInstance 就是Native Skill的範例
// skillName 自定義的技能名稱 [可選]
var textSkill = kernel.ImportSkill(new TextSkill(),nameof(TextSkill));

這裡使用到的是一個Import,意味著匯入了SkillInstance中所有的定義SKFunction。而Semantic Skill 也有一個對應的Import方法ImportSemanticSkillFromDirectory,可以從一個資料夾中匯入所有技能。

  1. 執行Function
// 註冊Native Function 如何沒有指定 SKFunctionName的話,都會是用方法宣告的名稱,使用nameof這種偷懶方法可以方便得從Skill集合中獲取對應的Function
var uppercaseFunction = textSkill[nameof(TextSkill.Uppercase)];
// 通過 Kernel 執行 function
var nativeResultContext = await kernel.RunAsync(input,uppercaseFunction);
// 輸出結果
nativeResultContext.Result.Dump();
// output:
// MULTI-MODAL INTERFACES ARE BECOMING INCREASINGLY POPULAR FOR APP DEVELOPERS. THESE INTERFACES ALLOW USERS TO INTERACT WITH APPS IN A VARIETY OF WAYS BY COMBINING DIFFERENT MODES OF INPUT AND OUTPUT, SUCH AS VOICE, TOUCH, AND VISUALS, TO CREATE A MORE INTERACTIVE AND ENGAGING USER EXPERIENCE. IN THIS BLOG WE WILL OVERVIEW HOW YOU CAN USE SEMANTIC KERNEL WITH A MULTI-MODAL EXAMPLE.

以上就完成了一個簡單的Native Function的使用。

鏈式呼叫

當完成了以上Skill和Function的準備之後,就可以想辦法將多個Skill串聯起來使用了,就像是命令列中的管道,函數語言程式設計中的管道一樣。

// kernel.RunAsync 本身就支援多個Function引數,並按照順序依次執行
var upperSummeryContext = await kernel.RunAsync(input, summaryFunction,uppercaseFunction);
//  輸出結果
upperSummeryContext.Result.Dump();

// output:
// MULTI-MODAL INTERFACES ARE BECOMING INCREASINGLY POPULAR FOR APP DEVELOPERS, COMBINING DIFFERENT MODES OF INPUT AND OUTPUT SUCH AS VOICE, TOUCH, AND VISUALS TO CREATE A MORE INTERACTIVE AND ENGAGING USER EXPERIENCE. SEMANTIC KERNEL CAN BE USED TO CREATE A MULTI-MODAL EXAMPLE.

至此,一個簡單的結合了LLM AI能力和原生程式碼能力的應用就構建成功了。


參考資料:

  1. Concepts Overview for Semantic Kernel | Microsoft Learn
  2. Kernel in Semantic Kernel | Microsoft Learn
  3. Skills in Semantic Kernel | Microsoft Learn
  4. How to write semantic skills in Semantic Kernel | Microsoft Learn
  5. How to write native skills in Semantic Kernel | Microsoft Learn
  6. SK-Recipes