引言

上一章我们熟悉了一下 Semantic Kernel 的理论知识,Kernel 创建以及简单的Sample熟悉了一下 SK 的基本使用。在Semantic Kernel中的 kernel functions由两部分组成第一部分是prompts functions(提示函数),第二部分Native function(原生函数), kernel functions是构成插件(Plugins)的核心,一个插件代表一个或者多个的kernel functions,今天我们重点了解一下第一部分prompts functions(提示函数)。

kernel functions 基础

我们知道跟大语言模型(LLM)交互靠的是提示(prompts),有效的提示设计对于使用 LLM AI 模型实现预期结果至关重要。提示工程,也称为提示设计,是一个新兴领域,需要创造力和对细节的关注。它涉及选择正确的单词、短语、符号和格式,以指导模型生成高质量和相关的文本。

提示工程的深入学习是用好大语言模型的关键。

创建提示函数

Semantic Kernel中提供了多种通过Prompts创建KernelFunction的扩展方法,底层本质上都是调用KernelFunctionFromPromptCreate方法来完成提示函数的创建。

    public static KernelFunction Create(
IPromptTemplate promptTemplate,
PromptTemplateConfig promptConfig,
ILoggerFactory? loggerFactory = null)
{
Verify.NotNull(promptTemplate);
Verify.NotNull(promptConfig); return new KernelFunctionFromPrompt(
template: promptTemplate,
promptConfig: promptConfig,
logger: loggerFactory?.CreateLogger(typeof(KernelFunctionFactory)) ?? NullLogger.Instance);
}

这里面其实只有第二个参数PromptTemplateConfig是我们需要关心的,第一个参数promptTemplate是根据第二个参数 promptConfigTemplate属性来构造的,接下来我们重点了解一下PromptTemplateConfig的配置。

PromptTemplateConfig的属性

public sealed class PromptTemplateConfig
{
private string? _templateFormat;
private string _template = string.Empty; [JsonPropertyName("name")]
public string? Name { get; set; } [JsonPropertyName("description")]
public string? Description { get; set; }
public static string SemanticKernelTemplateFormat => "semantic-kernel"; [JsonPropertyName("template_format")]
[AllowNull]
public string TemplateFormat
{
get => this._templateFormat ?? SemanticKernelTemplateFormat;
set => this._templateFormat = value;
} [JsonPropertyName("template")]
public string Template
{
get => this._template;
set
{
Verify.NotNull(value);
this._template = value;
}
} [JsonPropertyName("input_variables")]
public List<InputVariable> InputVariables
{
get => this._inputVariables ??= [];
set
{
Verify.NotNull(value);
this._inputVariables = value;
}
} [JsonPropertyName("output_variable")]
public OutputVariable? OutputVariable { get; set; } [JsonPropertyName("execution_settings")]
public Dictionary<string, PromptExecutionSettings> ExecutionSettings
{
get => this._executionSettings ??= [];
set
{
Verify.NotNull(value);
this._executionSettings = value;
}
} [Experimental("SKEXP0001")]
[JsonPropertyName("allow_unsafe_content")]
public bool AllowUnsafeContent { get; set; } = false;
}

为了方便展示我们只保留PromptTemplateConfig的核心属性,这个类非常的重要,包括我们要定义配置模版也是基于此类的字段来配置。

下面我们对PromptTemplateConfig的属性进行简单的讲解

我们可以把PromptTemplateConfig可以看做是对一个函数的表述,带着这个理解来解读这个配置类更容易理解,如用 C#定义一个函数

[Description("无参无返回值的静态函数")]
static void SampleFunction()
{
Console.Write("无参无返回值函数");
}

Name属性

Name属性是在PromptTemplateConfig中用来获取或设置在使用此配置创建提示函数(Prompts functions)时使用的默认函数名称。

类型可空,如果不设置创建函数时将动态生成一个随机名称。命名规则:利用 GUID 生成一个不含连字符的随机字符串,并将其格式化为以"func"为前缀的函数名称

    private static string CreateRandomFunctionName() => $"func{Guid.NewGuid():N}";

Name 类似与我们在 C#中的函数名

Description 属性

Description属性是用于表示一个函数的描述信息,如果在创建prompts functions时候没有显示指定函数描述信息,那会采用Description 属性的描述。

结合我们定义的 C#自定义函数中Description来理解这个属性,其实就是给方法配置一个描述信息,提示方法也是一种特殊的方法。

TemplateFormat属性

TemplateFormat属性用于对prompts提示模板的格式配置,默认值为 "semantic-kernel"

对于prompts的模版格式化引擎 用的有两种,第一种就是 Semantic Kernel 自带的处理格式"semantic-kernel";第二种则是handlebars

Template属性

Template 属性用于存储和管理用于定义prompts模板字符串。在设置模板字符串时,会进行空值验证,以确保模板字符串不为 null,从而保证在生成prompts提示时模板内容有有效可用。

InputVariables 属性

InputVariables属性用于prompts提示模板中使用的输入变量集合。

InputVariable 对象包含的属性:

  • Name:变量的名称,用于标识输入变量。
  • Description:变量的描述,提供关于输入变量的说明。
  • Default:变量的默认值。
  • IsRequired:指示变量是否为必需的,默认为 true。
  • JsonSchema:描述变量的 JSON 模式。
  • AllowUnsafeContent:指示是否允许不安全内容,默认为 false。

OutputVariable 属性

OutputVariable 属性用于定义和管理prompts提示模板中的输出变量。

参考我们c#定义函数 这个我理解的就是对我们函数返回值参数的一个描述

ExecutionSettings属性

ExecutionSettings属性用于获取或设置提示模板使用的执行设置集合;类型为Dictionary<string, PromptExecutionSettings>,表示一个键值对集合,其中键为服务 ID,值为执行设置。

      ExecutionSettings =
{
{
OpenAIPromptExecutionSettings.DefaultServiceId,
new OpenAIPromptExecutionSettings()
{
MaxTokens = 1000,
Temperature = 0
}
},
{
"gpt-3.5-turbo", new OpenAIPromptExecutionSettings()
{
ModelId = "gpt-3.5-turbo-0613",
MaxTokens = 4000,
Temperature = 0.2
}
}
}

执行的配置为 PromptExecutionSettings.DefaultServiceId默认值是"default",因为Semantic Kernel都是基于.Net 8 的键值依赖注入Keyed,所以 default 就是获取的上面默认的执行配置,

kernel.GetRequiredService<ITextGenerationService>();
kernel.GetRequiredService<ITextGenerationService>("gpt-3.5-turbo");

从代码处理解就容易多了,可以通过ServiceKey去获取不同大模型的实例。

OpenAIPromptExecutionSettings 配置

这个配置是大模型的进行请求时的参数配置,是PromptExecutionSettings提示执行设置的子类,OpenAI 的配置就是OpenAIPromptExecutionSettings,Google的大模型有自己的实现比如GeminiPromptExecutionSettings 核心参数其实都差不多,现在我们用OpenAI的提示词执行设置熟悉下配置的参数。

  • MaxTokens:指定在生成文本或完成请求时允许生成的最大标记数,大多数模型的上下文长度为 2048 个标记(支持 4096 的 davinci-codex 除外)。
  • Temperature: 控制完成结果的随机性。默认是 1.0,通常取值范围在0-1.0之间。较高的温度会增加生成文本的随机性,使得生成的文本更加多样化和创新性,而较低的温度则会减少随机性,使得生成的文本更加稳定和可预测。

    对于更具创意的应用程序,请尝试 0.9,对于具有明确答案的应用程序,请尝试 0(argmax 采样)。

  • TopP: 用于控制完成结果的多样性。默认是1.0。通过设置不同的值可以调整生成文本的多样性程度。较高的 TopP 值会导致生成的文本更加多样化,而较低的值则可能使生成的文本更加稳定和集中。

    使用温度进行采样的替代方法,称为核采样,其中模型考虑具有 top_p 概率质量的标记的结果。因此,0.1 表示仅考虑包含前 10% 概率质量的代币。我们通常建议改变这个或温度,但不要同时改变两者。

  • PresencePenalty: 属性接受介于-2.0和2.0之间的数字。默认是0。正值将根据新标记是否在文本中出现来对其进行惩罚,从而增加模型谈论新主题的可能性。

    新标记:模型尝试引入新的内容或概念,以增加生成文本的多样性和创新性

  • FrequencyPenalty:属性用于控制模型生成文本时对重复内容的处理方式。默认是0。它接受介于-2.0 和 2.0 之间的数字,其中正值表示根据标记在文本中的现有频率对其进行惩罚,以降低模型直接重复相同内容的可能性。通过设置较高的 FrequencyPenalty 值,模型更有可能避免直接重复相同内容,从而降低生成文本中重复内容的频率.

  • StopSequences:属性用于指定一个字符串列表,其中包含模型在生成文本时遇到指定序列时应停止生成进一步标记。

    例如,如果设置 StopSequences 为[""],则当模型生成文本时遇到"<END>"序列时,生成过程将停止。

  • ChatSystemPrompt:属性用于指定在使用聊天模型生成文本时要使用的系统提示。默认值是:"Assistant is a large language model."。这个系统提示可以影响生成文本的方向和内容,帮助模型更好地理解生成任务的背景和要求。通过合理设置 ChatSystemPrompt 属性,可以定制生成文本时使用的系统提示,以获得符合预期的生成结果。

  • ToolCallBehavior:属性用于获取或设置如何处理工具调用的行为。

          // Enable auto function calling
    OpenAIPromptExecutionSettings openAIPromptExecutionSettings = new()
    {
    ToolCallBehavior = ToolCallBehavior.AutoInvokeKernelFunctions
    };

    1.EnableKernelFunctions:会向模型提供内核的插件函数信息,但不会自动处理函数调用请求。模型需要显式发起函数调用请求,并系统会传播这些请求给适当的处理程序来执行。

     OpenAIPromptExecutionSettings settings = new() { ToolCallBehavior = ToolCallBehavior.EnableKernelFunctions };
    var chatHistory = new ChatHistory();
    ChatMessageContent result = await chat.GetChatMessageContentAsync(chatHistory, settings, kernel);
    //手动调用
    IEnumerable<FunctionCallContent> functionCalls = FunctionCallContent.GetFunctionCalls(result);

    EnableKernelFunctions:需要通过 FunctionCallContent 手动调用

    2.AutoInvokeKernelFunctions:除了向模型提供内核的插件函数信息外,还会尝试自动处理任何函数调用请求。模型发起函数调用请求后,系统会自动执行相应的操作,并将结果返回给模型,而无需模型显式处理函数调用的过程。

ResponseFormat属性

ResponseFormat的属性,用于获取或设置用于完成操作的响应格式。可选值包括:"json_object""text",以及 ChatCompletionsResponseFormat 对象,可以选择不同的值来指定响应的格式类型,例如使用 JSON 对象、纯文本等不同的响应格式

ResultsPerPrompt属性

ResultsPerPrompt 属性用于确定每个提示生成的完成次数。默认值:默认为 1,即每个提示只生成一个完成结果。在自然语言处理中,一个提示(prompt)是输入给模型的文本或问题,而完成(completion)是模型生成的对应输出。通过设置 ResultsPerPrompt 属性,您可以指定每个提示应该生成多少个完成结果。

Seed属性

Seed属性的作用是为了控制采样的确定性,通过指定种子值,可以在一定程度上确保相同种子和参数下的重复请求返回相同的结果。然而,由于确定性并不是完全保证的,结果仍可能有一定程度的变化

User属性

通过为每个最终用户分配一个唯一的标识符,OpenAI 可以更好地跟踪和管理用户的行为,同时也可以更有效地监控系统是否受到滥用。

prompts functions 实战

Semantic Kernel 有几个 Kernel 对象的扩展方法用于prompts提示词模版来创建KernelFunction,总的来说可以有三类:

我们继续用我们上一章的 OneApi 代理星火讯飞 V3.5 方式来对接 Semantic Kernel 具体配置可以找我上一篇文章

基于 String 字符串创建 prompts functions

实战

//基于String模版创建kernel functions
Console.WriteLine("====>基于String模版创建kernel functions<=====");
{
string prompt = "What is the intent of this request? {{$request}}";
var kernel = Kernel.CreateBuilder().AddOpenAIChatCompletion(modelId: config.ModelId,
apiKey: config.ApiKey,
httpClient: client).Build();
var kernelFunction = kernel.CreateFunctionFromPrompt(prompt); string request = "I want to send an email to the marketing team celebrating their recent milestone."; // Create a kernel arguments object and add the request
var kernelArguments = new KernelArguments
{
{ "request", request }
};
var functionResult = await kernelFunction.InvokeAsync(kernel, kernelArguments); Console.WriteLine(functionResult?.ToString() ?? string.Empty);
}

当然 SK 也提供了更加简单的方法,直接传prompts string 模版

    var functionResult = await kernel.InvokePromptAsync(prompt, kernelArguments);

这个方法内部实际上就是调用了CreateFunctionFromPrompt创建了kernel functions,目的是简化提示函数创建的过程

基于PromptTemplateConfig对象创建 prompts functions

经过上面的介绍我们已经对PromptTemplateConfig的参数设置已经有了一个大致的认识,要实现这个要求需要借助到我们的 kernel.CreateFunctionFromPrompt这个扩展方法,下面我们来实操一下:

实战

string request = "I want to send an email to the marketing team celebrating their recent milestone.";
{
var kernel = Kernel.CreateBuilder().AddOpenAIChatCompletion(modelId: config.ModelId,
apiKey: config.ApiKey,
httpClient: client).Build(); var kernelFunctions = kernel.CreateFunctionFromPrompt(new PromptTemplateConfig()
{
Name = "intent",
Description = "use assistant to understand user input intent.",
TemplateFormat = PromptTemplateConfig.SemanticKernelTemplateFormat,//此处可以省略默认就是"semantic-kernel"
Template = "What is the intent of this request? {{$request}}",
InputVariables = [new() { Name = "request", Description = "The user's request.", IsRequired = true }],
ExecutionSettings = new Dictionary<string, PromptExecutionSettings>() {
{
OpenAIPromptExecutionSettings.DefaultServiceId ,//"default"
new OpenAIPromptExecutionSettings()
{
MaxTokens = 1024,
Temperature = 0
}
},
}
});
var kernelArguments = new KernelArguments
{
{ "request", request }
};
var functionResult = await kernelFunctions.InvokeAsync(kernel, kernelArguments); Console.WriteLine(functionResult?.ToString() ?? string.Empty);
}

运行效果

基于pluginDirectory从指定的插件目录中创建插件

此方法是创建插件的方法之一,之前有介绍过插件就是一组kernel functions的集合,通过定义文件夹模版可以生成prompts functions,这部分内容等学习到Semantic KernelPlugins在着重讲解吧。

最后

在本章中,我们深入探讨了 Semantic Kernel 中的 kernel functions,重点关注了第一部分的 prompts functions(提示函数)。我们学习了如何基于不同方法创建这些提示函数,包括基于字符串模板和 PromptTemplateConfig 对象的创建方式,以及如何从指定的插件目录中创建插件。

通过详细讲解 PromptTemplateConfig 的属性,我们理解了如何配置和管理提示模板,以及如何调整执行设置来影响提示函数的生成结果。我们还实际操作了创建 kernel functions 的过程,加深了对提示工程的实际运用。

最后,我们展望了未来的学习方向,即 Semantic KernelPlugins 部分,这将为我们提供更多关于插件的创建和应用方法,进一步扩展我们的知识和应用领域。

通过本章的学习,相信您对 prompts functions 的创建和配置有了更深入的了解,为进一步探索和应用 Semantic Kernel 打下了坚实的基础。如果您有任何疑问或需要进一步帮助,请随时向我提问。感谢阅读!

参考资料

configure-prompts

本文示例源代码

本文源代码

欢迎关注笔者公众号一起学习交流,获取更多有用的知识~

深入学习Semantic Kernel:创建和配置prompts functions的更多相关文章

  1. Semantic Kernel 知多少 | 开启面向AI编程新篇章

    引言 在ChatGPT 火热的当下, 即使没有上手亲自体验,想必也对ChatGPT的强大略有耳闻.当一些人在对ChatGPT犹犹豫豫之时,一些敏锐的企业主和开发者们已经急不可耐的开展基于ChatGPT ...

  2. Semantic Kernel 入门系列:🔥Kernel 内核和🧂Skills 技能

    理解了LLM的作用之后,如何才能构造出与LLM相结合的应用程序呢? 首先我们需要把LLM AI的能力和原生代码的能力区分开来,在Semantic Kernel(以下简称SK),LLM的能力称为 sem ...

  3. Semantic Kernel 入门系列:💬Semantic Function

    如果把提示词也算作一种代码的话,那么语义技能所带来的将会是全新编程方式,自然语言编程. 通常情况下一段prompt就可以构成一个Semantic Function,如此这般简单,如果我们提前可以组织好 ...

  4. LangChain vs Semantic Kernel

    每当向他人介绍 Semantic Kernel, 会得到的第一个问题就是 Semantic Kernel 类似于LangChain吗,或者是c# 版本的LangChain吗? 为了全面而不想重复的回答 ...

  5. Semantic Kernel 入门系列:🥑Memory内存

    了解的运作原理之后,就可以开始使用Semantic Kernel来制作应用了. Semantic Kernel将embedding的功能封装到了Memory中,用来存储上下文信息,就好像电脑的内存一样 ...

  6. Semantic Kernel 入门系列:📅 Planner 计划管理

    Semantic Kernel 的一个核心能力就是实现"目标导向"的AI应用. 目标导向 "目标导向"听起来是一个比较高大的词,但是却是实际生活中我们处理问题的 ...

  7. Netty学习之客户端创建

    一.客户端开发时序图 图片来源:Netty权威指南(第2版) 二.Netty客户端开发步骤 使用Netty进行客户端开发主要有以下几个步骤: 1.用户线程创建Bootstrap Bootstrap b ...

  8. springmvc学习笔记---idea创建springmvc项目

    前言: 真的是很久没搞java的web服务开发了, 最近一次搞还是读研的时候, 想来感慨万千. 英雄没落, Eclipse的盟主地位隐隐然有被IntelliJ IDEA超越的趋势. Spring从2. ...

  9. thinkphp学习笔记4—眼花缭乱的配置

    原文:thinkphp学习笔记4-眼花缭乱的配置 1.配置类别 ThinkPHP提供了灵活的全局配置功能,ThinkPHP会依次加载管理配置>项目配置>调试配置>分组配置>扩展 ...

  10. OGG学习笔记02-单向复制配置实例

    OGG学习笔记02-单向复制配置实例 实验环境: 源端:192.168.1.30,Oracle 10.2.0.5 单实例 目标端:192.168.1.31,Oracle 10.2.0.5 单实例 1. ...

随机推荐

  1. Git 12 IDEA上传本地项目到远程

    这里以上传 Spring 开源项目到 Gitee 为例: 1.点击 Create Git Repository 2.选择项目目录 3.添加到缓存库 4.提交到本地库 5.复制远程库地址 6.推送到远程 ...

  2. Python将依赖包导出到requirements.txt文件

    代码 # 查询环境中已经安装的库 pip list # 将所有依赖库导出到 requirements.txt 文件 pip freeze > requirements.txt

  3. CentOS8 / CentOS7 yum源最新修改搭建 2022.3.1

    Part I CentOS 8 源更新 ========================================== 2022年过完后,发现公司里面的所有服务器yum都不能用了,一直报错 按照 ...

  4. async/await 贴脸输出,这次你总该明白了

    出来混总是要还的 最近在准备记录一个.NET Go核心能力的深度对比, 关于.NET/Go的异步实现总感觉没敲到点上. async/await是.NET界老生常谈的话题,每至于此,状态机又是必聊的话题 ...

  5. CC1TransformedMap链学习

    跟着看了白日梦组长的视频,记录一下调试学习过程 CC1链学习 TransformedMap链 ObjectInputStream.readObject() AnnotationInvocationHa ...

  6. Web前端 -- 利用Babel来将ES6转化为ES5代码

    一.简介 Babel用来将ES6代码转为ES5代码. 二.安装 安装命令行转码工具 Babel提供babel-cli工具,用于命令行转码.它的安装命令如下: npm install --global ...

  7. -source 1.5 中不支持 diamond 运算符(中文版idea)

    -source 1.5 中不支持 diamond 运算符(中文版idea) 将idea中的各个部分的jdk设为8即可,中文版的如下 1.文件-设置 2.项目上右击-打开模块设置 模块中每一个都要确认是 ...

  8. 用了那么久的Lombok,你知道它的原理么?

    简介: 在写Java代码的时候,最烦写setter/getter方法,自从有了Lombok插件不用再写那些方法之后,感觉再也回不去了,那你们是否好奇过Lombok是怎么把setter/getter方法 ...

  9. 重磅官宣:Nacos2.0 发布,性能提升 10 倍

    简介: 继 Nacos 1.0 发布以来,Nacos 迅速被成千上万家企业采用,并构建起强大的生态.但是随着用户深入使用,逐渐暴露一些性能问题,因此我们启动了 Nacos 2.0 的隔代产品设计,时隔 ...

  10. MaxCompute跨境访问加速解决方案

    简介: MaxCompute联合全球加速服务,为有跨境访问需求的MaxCompute客户提供一套高效稳定的跨境访问加速方案. MaxCompute联合全球加速服务,为有跨境访问需求的MaxComput ...