理解了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應用開發的學習。
準備階段
-
首先準備一個應用環境,Console 可以,ASP.NET 也可以,Notebooks 也可以。使用Notebooks的話推薦參考官方的Notebooks合集和Uncle John's Semantic Kernel Recipes。
-
應用環境準備好之後,和所有的.Net 庫一樣,接下來就是安裝SK的nuget 包。由於是一個較新的包,所以更新變化會比較快。
dotnet add package Microsoft.SemanticKernel --prerelease
-
接下來進行應用內的準備工作,首先創建一個
kernel
;
var kernel = Kernel.Builder.Build;
using Microsoft.SemanticKernel; |
-
然後配置基礎模型,基礎模型目前有四個:
由於Azure OpenAI提供了和Open AI相同的能力,所以以上的模型配置可以選擇OpenAI的接口,也可以選擇Azure OpenAI的接口,根據自己有哪個選哪個的原則使用。
當然以上模型也提供了基本的接口定義,如果有自己的LLM AI接口的話,也可以自行實現相關接口,然後使用。
這裡以OpenAI的接口為例,繼續進行學習。
-
TextCompletion,最常用的GPT-3的模型,常用於文本生成
-
ChatCompetion,GPT3.5模型,也就是所謂的ChatGPT的模型,基本就用於聊天功能
-
EmbeddingGeneration,嵌入模型,這個將用於Memory的生成和搜索,在後期能力擴展時將會有極大的用途
-
ImageGeneration,圖形模型,也就是DALL-E模型,用於圖片的生成
kernel.Config.AddOpenAITextCompletionService("ServiceId","text-davinci-003",Environment.GetEnvironmentVariable("OPENAI_API_KEY"));
// 簡單的技能任務使用TextCompletion即可 |
// 1. ServiceId 用於指定當前模型的配置,相同的模型不能有重複的ServiceId配置 |
// 2. modelId 指定TextCompetion所使用的LLM 模型,目前基本為 text-davinci-003 |
// 3. apikey OpenAI 接口調用需要使用的APIkey |
Semantic Function
-
註冊一個Semantic Function
using Microsoft.SemanticKernel.SemanticFunctions;
var summaryFunction = kernel.CreateSemanticFunction(prompt,new PromptTemplateConfig);
// ⚠️ 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 是自定義的技能名稱[可選] |
可以注意到的是在prompt中,有一個變量參數 {{$input}}
,這是SK的默認輸入參數,用於注入需要處理的用戶輸入,這樣的格式用於預防Prompt Injection,這就是另外一個話題了。
-
執行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. ";
var resultContext = await kernel.RunAsync(input,summaryFunction);
// 定義需要處理的輸入 |
// 通過 Kernel 運行 function |
// 輸出結果 |
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
-
聲明一個Native Skill
using Microsoft.SemanticKernel.SkillDefinition;
[SKFunction("Convert a string to uppercase.")]
public string Uppercase(string text)
return text.ToUpper(System.Globalization.CultureInfo.CurrentCulture);
// 這裡偷懶,使用Semantic Kernel CoreSkills中的 TextSkill |
public class TextSkill { |
{ |
} |
} |
這裡只需要對方法添加一個SKFunction的注釋,就可以轉變為一個SK的Native Function。
-
註冊Native Skill
var textSkill = kernel.ImportSkill(new TextSkill,nameof(TextSkill));
// skillInstance 就是Native Skill的實例 |
// skillName 自定義的技能名稱 [可選] |
這裡使用到的是一個Import,意味著導入了SkillInstance中所有的定義SKFunction。而Semantic Skill 也有一個對應的Import方法ImportSemanticSkillFromDirectory,可以從一個文件夾中導入所有技能。
-
執行Function
var uppercaseFunction = textSkill[nameof(TextSkill.Uppercase)];
var nativeResultContext = await kernel.RunAsync(input,uppercaseFunction);
// 註冊Native Function 如何沒有指定 SKFunctionName的話,都會是用方法聲明的名稱,使用nameof這種偷懶方法可以方便得從Skill集合中獲取對應的Function |
// 通過 Kernel 運行 function |
// 輸出結果 |
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串聯起來使用了,就像是命令行中的管道,函數式編程中的管道一樣。
var upperSummeryContext = await kernel.RunAsync(input, summaryFunction,uppercaseFunction);
// kernel.RunAsync 本身就支持多個Function參數,並按照順序依次執行 |
// 輸出結果 |
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能力和原生代碼能力的應用就構建成功了。
參考資料:
-
Concepts Overview for Semantic Kernel | Microsoft Learn: https://learn.microsoft.com/en-us/semantic-kernel/concepts-sk/
-
Kernel in Semantic Kernel | Microsoft Learn:https://learn.microsoft.com/en-us/semantic-kernel/concepts-sk/kernel
-
Skills in Semantic Kernel | Microsoft Learn:https://learn.microsoft.com/en-us/semantic-kernel/concepts-sk/skills
-
How to write semantic skills in Semantic Kernel | Microsoft Learn: https://learn.microsoft.com/en-us/semantic-kernel/howto/semanticfunctions
-
How to write native skills in Semantic Kernel | Microsoft Learn: https://learn.microsoft.com/en-us/semantic-kernel/howto/nativefunctions
-
SK-Recipes:https://github.com/johnmaeda/SK-Recipes