探索Native Plugins:開啟大模型的技能之門

董瑞鹏發表於2024-06-07

前言

上一章節我們瞭解了一下Semantic KernnelPlugins外掛的概念以及學習了的 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 中定義函式外掛,需要用到兩個特性KernelFunctionDescription
KernelFunction特性把函式標記為一個SKNative functionDescription給函式和引數以及返回值加描述,方便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基本上都是利用KernelFunctionFactoryfunction工廠建立的,其實外掛的建立也是一樣透過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常用的方法,還有一些用法,比如

  • ImportPluginFromApiManifestAsync OpenAPI 功能相關
  • ImportPluginFromOpenAIAsync 透過 OpenAI 的 ChatGPT 格式為 OpenAI 外掛建立一個外掛
  • CreatePluginFromOpenApiAsync 從 OpenAPI v3 端點建立外掛
  • ImportPluginFromGrpcFile 從 gRPC 文件匯入
  • 其他

最後

本章我們學習了在 Semantic Kernel 中使用 Native Plugins 原生函式外掛的方法,包括透過函式定義外掛和根據物件建立外掛的步驟。我們探討了不同的建立外掛的方式,以及如何註冊外掛並進行呼叫。透過這些方法,我們可以擴充套件 Semantic Kernel 的功能,增強模型的能力。

參考文獻

  • 開啟大模型的技能之門 - Plugins

示例程式碼

本文原始碼

相關文章