前言
上一章節我們瞭解了一下Semantic Kernnel中Plugins插件的概念以及學習了的 Semantic Kernel 模板插件的創建,本章節我們來學習 Native Plugins 原生函數插件使用。
通過函數定義插件
在之前的章節中我們介紹過在在 Semantic Kernel 中應用 Function Calling,在文中講解了Functioncalling的概念,以及在SK中的應用。
在Semantic Kernel中定義Native Plugins 函數插件,和 gpt-3.5-turbo 在 6 月 13 日 發佈的 Function Calling特別的像,這是通過增加外部函數,通過調用來增強 OpenAI 模型的能力。
在 Semantic Kernel 中定義函數插件
在Semantic Kernerl 中提供了很多定義Native Plugins的擴展方法來創建插件下面介紹最常用的幾種:
根據類型創建插件
SK源碼
public static KernelPlugin ImportPluginFromType<T>(this Kernel kernel, string? pluginName = null)
{
KernelPlugin plugin = CreatePluginFromType<T>(kernel, pluginName);
kernel.Plugins.Add(plugin);
return plugin;
}
- 定義
Native Plugins
在 Semantic Kernel 中定義函數插件,需要用到兩個特性KernelFunction和Description
KernelFunction特性把函數標記為一個SK的Native function;Description給函數和參數以及返回值加描述,方便LLMs能夠更好的理解。
具體使用如下
public class WeatherPlugin
{
public static string GetWeather => "WeatherSearch";
[KernelFunction, Description("根據城市查詢天氣")]
public string WeatherSearch([Description("城市名")] string city)
{
return $"{city}, 25℃,天氣晴朗。";
}
}
Kernel添加插件
kernel.ImportPluginFromType<WeatherPlugin>();
這就是剛才説的根據類型來創建SK插件
- 調用
var getWeatherFunc = kernel.Plugins.GetFunction(nameof(WeatherPlugin), WeatherPlugin.GetWeather);
var weatherContent = await getWeatherFunc.InvokeAsync(kernel, new() { ["city"] = "北京" });
Console.WriteLine(weatherContent.ToString());
- 輸出
北京, 25℃,天氣晴朗。
這是手動調用的方式當然也可以
IChatCompletionService會話模式自動調用。
根據對象創建
主要用到了ImportPluginFromObject這個擴展方法
public static KernelPlugin ImportPluginFromObject(this Kernel kernel, object target, string? pluginName = null)
{
KernelPlugin plugin = CreatePluginFromObject(kernel, target, pluginName);
kernel.Plugins.Add(plugin);
return plugin;
}
- 定義根據城市名獲取美食的插件
public class FinefoodPlugin
{
[KernelFunction, Description("根據城市獲取美食推薦")]
public string GetFinefoodList([Description("城市名")] string city)
{
return "烤鴨,滷煮,老北京炸醬麪,炒肝等";
}
}
和上一個使用 Type 註冊插件是一樣的操作
- 註冊並調用
FinefoodPlugin finefoodPlugin = new();
kernel.ImportPluginFromObject(finefoodPlugin);
var getWeatherFunc = kernel.Plugins.GetFunction(nameof(FinefoodPlugin), "GetFinefoodList");
var weatherContent = await getWeatherFunc.InvokeAsync(kernel, new() { ["city"] = "北京" });
Console.WriteLine(weatherContent.ToString());
- 輸出:
烤鴨,滷煮,老北京炸醬麪,炒肝等
- 擴展
既然Kernel對象提供了根據對象實例創建插件的方案,那麼就可以我們最喜歡的依賴注入獲取的服務做插件的實例,這一點非常的重要,在以後項目實戰中很實用。
依賴注入舉例
IServiceCollection services = new ServiceCollection();
services.AddSingleton<FinefoodPlugin>();
var rootProvider = services.BuildServiceProvider();
FinefoodPlugin finefoodPlugin = rootProvider.GetRequiredService<FinefoodPlugin>();
kernel.ImportPluginFromObject(finefoodPlugin);
根據 Kernelfunction 創建對象的實例
SK 提供了幾個根據 Kernelfunction 來創建Plugins的方案,這就用到Kernel對象創建 kernel functions的擴展方法。
關於Kernel Function的創建有兩種常用的形式第一種是根據Prompts來創建Semantic function也可以叫Prompts function,第二種是根據 C#的Delegate來創建Kernel Function。
第一種方案之前的文章中有講過,有興趣可以瀏覽一下深入學習 Semantic Kernel:創建和配置 prompts functions,這裏不過多介紹。
第二種在這裏我們重點講一下,根據委託來創建Kernel Function
- 源碼一覽
public static KernelFunction CreateFunctionFromMethod(
this Kernel kernel,
Delegate method,
string? functionName = null,
string? description = null,
IEnumerable<KernelParameterMetadata>? parameters = null,
KernelReturnParameterMetadata? returnParameter = null)
{
Verify.NotNull(kernel);
Verify.NotNull(method);
return KernelFunctionFactory.CreateFromMethod(method.Method, method.Target, functionName, description, parameters, returnParameter, kernel.LoggerFactory);
}
在之前的文章介紹過,所有創建Kernelfunction基本上都是利用KernelFunctionFactory的function工廠創建的,其實插件的創建也是一樣通過KernelPluginFactory插件plugin工廠創建的。
創建一個根據城市名獲取遊玩地點的插件
- 創建 Kernel Function
var kernelfunction = kernel.CreateFunctionFromMethod((string city) => { return $"{city} 好玩的地方有八達嶺長城,故宮,恭王府等"; },
functionName: "GetTourismClassic", description: "獲取城市的經典",
[
new KernelParameterMetadata(name:"city") {
Description="城市名"
}]);
- 註冊插件並調用
kernel.ImportPluginFromFunctions("TourismClassicPlugin", [kernelfunction]);
var getTourismClassic = kernel.Plugins.GetFunction("TourismClassicPlugin", "GetTourismClassic");
var weatherContent = await getTourismClassic.InvokeAsync(kernel, new() { ["city"] = "北京" });
Console.WriteLine(weatherContent.ToString());
- 輸出
北京 好玩的地方有八達嶺長城,故宮,恭王府等
擴展
上面介紹的都是在Sk中創建Native Plugins常用的方法,還有一些用法,比如
ImportPluginFromApiManifestAsyncOpenAPI 功能相關
ImportPluginFromOpenAIAsync通過 OpenAI 的 ChatGPT 格式為 OpenAI 插件創建一個插件CreatePluginFromOpenApiAsync從 OpenAPI v3 端點創建插件ImportPluginFromGrpcFile從 gRPC 文檔導入- 其他
最後
本章我們學習了在 Semantic Kernel 中使用 Native Plugins 原生函數插件的方法,包括通過函數定義插件和根據對象創建插件的步驟。我們探討了不同的創建插件的方式,以及如何註冊插件並進行調用。通過這些方法,我們可以擴展 Semantic Kernel 的功能,增強模型的能力。
參考文獻
- 開啓大模型的技能之門 - Plugins
示例代碼
本文源代碼