Semantic Kernel 入门系列:💬Semantic Function

image

如果把提示词也算作一种代码的话,那么语义插件所带来的将会是全新编程方式,自然语言编程。

通常情况下一段prompt就可以构成一个Semantic Function,如此这般简单,如果我们提前可以组织好一段段prompt的管理方式,甚至可以不需要写任何的代码,就可以构造出足够多的插件来。

使用文件夹管理Semantic Function

Semantic Kernel恰好就提供了这样一种组织方式,仅需使用文本文件和文件夹就可以管理Semantic Function。文件夹的大致结构如下:

TestPlugin  #<- Plugin
│
└─── SloganMaker  #<- Function
|    |
│    └─── skprompt.txt
│    └─── [config.json]
│   
└─── SummarizeBlurb  #<- Function 
     |
     └─── skprompt.txt
     └─── [config.json]

和自己手动定义的一样,每一个Function 都包含了一个 skprompt.txt 文件,里面就是对应的prompt,还有一个可选文件config.json 用作配置。如果有多个Plugin的话,可以再往上创建一层文件夹将所有的Plugin都放在里面。

然后我们在代码中仅需要将这个插件的文件夹导入到Kernel中即可。

// 这里将所有的Plugin都放在了 PluginCollection 这个文件夹下,直接指定TextPlugin所在的目录
var textPlugin = kernel.ImportPluginFromPromptDirectory("PluginCollection/TextPlugin");

然后还是和往常一样正常调用即可,只不过这里导入得到的是Plugin层级的,所以执行的时候需要从Plugin中获取对应的Function,Function的名字和对应的文件夹名一致。

var input = 
"""
Congratulations! You have imagined a delicious ASK for SK to run to completion. This ASK can be given to the Planner to get decomposed into steps. Although to make the Planner work reliably, you'll need to use the most advanced model available to you. So let's start from writing basic prompts to begin with.
""";


var result = await kernel.InvokeAsync(textPlugin["SummarizeBlurb"], new() { ["input"] = input});

result.GetValue<string>().Dump();
// output:
// The text congratulates the reader on coming up with a delicious ASK project for SK. It suggests using the most advanced model to make the Planner work effectively and advises starting with basic prompts.

扩展自己的Semantic Function管理方式

除了官方提供的方式之外,也可以自行实现一些个性化的方便的管理方式,例如存放在文档数据库上,或者对象存储服务上,甚至使用Git、FTP等方式也不是不可以。

所需要做的只不过是将prompt和配置从远程方式获取到本地,然后通过原生的SemanticFunction创建接口创建出来即可。

一个基本的创建方式如下:


var prompt = "prompt {{$INPUT}}"; // 对应skprompt.txt文件
var promptConfig = new PromptExecutionSettings(); // 执行配置

var functionName = "functionName"; // function名称

var function = kernel.CreateFunctionFromPrompt(prompt,promptConfig,functionName);

通过这种方式创建的Function,可以直接使用,但是并不会注册到Kernel中Plugin中。如果需要注册到Kernel中,可以通过以下方式:

kernel.ImportPluginFromFunctions("pluginName", new[] { function });

只需要根据自己的喜好,处理好当前插件的管理方式,就可以打造出各种各样的个性场景了。

例如为每一个用户分配一个插件池,用户可以自行微调每个插件的相关的参数。

结合后面会提及到的Prompt Template 语法,也可以创造出更多丰富的场景。

Semantic Function的参数配置

除了skprompt.txt ,另外一个需要注意的就是config.json文件,也就对应着 PromptTemplateConfig 这个配置类。

一个典型的配置文件类似这样:

{
  "schema": 1,
  "description": "Automatically generate compact notes for any text or text document.",
  "execution_settings": {
    "default": {
      "max_tokens": 256,
      "temperature": 0.0,
      "top_p": 0.0,
      "presence_penalty": 0.0,
      "frequency_penalty": 0.0
    }
  }
}

其中 schema 目前没啥用, description 提供了Function的功能说明, execution_settings指定了不同的模型参数配置,其中以key:object的形式组织,默认情况下直接使用default即可,如果未指定default而是指定其他的key值,kernel的使用该prompt的时候,将会配置对应ServiceId或者modelId的模型配置。然后其中object就是我们作为常见的 completion配置了。直接参考官方文档即可。

image

更为强大的模板语法

如果仅仅是将OpenAI的接口做了一层封装的话,其实和市面上大多数的OpenAI的sdk差不了多少,

而Semantic Kernel所能提供自然会有更多,其中就Semantic Function部分,SK就提供了一套强大的Prompt Template 语法。

变量

前面已经用到过一个最简单 {{$INPUT}} 就是SK提供的变量语法,所有的变量放在 {{ }} 中, $INPUT 就是默认的输入参数,除此之外,还可以自行定义参数。

例如:

Write me a marketing slogan for my {{$INPUT}} in {{$CITY}} with 
a focus on {{$SPECIALTY}} we are without sacrificing quality.

这里的参数不区分大小写,所以有时会看到$INPUT,有时候会看到$input,都是可以的。

有了参数自然就需要能够传递多个参数进去,需要使用的是KernelArguments进行管理的。

var args = new KernelArguments();
args["BUSINESS"] = "Basketweaving Service";
args.Add("CITY", "Seattle");
args.TryAdd("SPECIALTY", "ribbons");

var myResult = await kernel.InvokeAsync(myPlugin["SloganMakerFlex"],args);

KernelArguments本身是一个Dictionary,所以可以直接使用Dictionary的方法进行参数的添加。包括前面看到的 new (){["input"] = input} 也是Dictionary的初始化方式。

函数调用

除了多个参数之外,SK还提供了类似函数调用的方式,可以在prompt中实现多种插件的组合,而且并不限制是Semantic Function 还是 Native Function。

例如有一个 weather.getForecast 的Native Function可以获取指定 city 的天气,还有一个 time.Date 可以获取今天的日期。

需要根据用户的所在城市,以及相关行程信息撰写一篇旅行日记。就可以这样写prompt:

The weather today is {{weather.getForecast $city}}.
The date is {{time.Date}}.
My itinerary for today is as follows:
===
{{ $itinerary }}
===
Generate a travel diary based on the above content.

除此之外,模板语法的还有一些符号转义的注意事项,可以具体参考Github中的文档Prompt template syntax

至此,Semantic Function的基本配置和使用的掌握的差不多了。


参考资料:

  1. Inline Function Definition
  2. Prompting AI models with Semantic Kernel
  3. Configuring prompts
  4. PromptTemplateConfig.cs
  5. Prompt template syntax
posted @ 2023-04-10 23:10  宵伯特  阅读(1847)  评论(0编辑  收藏  举报