首页 > 其他分享 >dotnet SemanticKernel 入门 自定义变量和技能

dotnet SemanticKernel 入门 自定义变量和技能

时间:2023-09-02 11:12:12浏览次数:50  
标签:变量 自定义 dotnet input SemanticKernel 输入 技能

本文将告诉大家如何在 SemanticKernel 框架内定义自定义的变量和如何开发自定义的技能

本文属于 SemanticKernel 入门系列博客,更多博客内容请参阅我的 博客导航

自定义变量是一个非常有用的技能,自定义变量可以让炼丹师和程序员进行并行工作。由炼丹师对 AI 模型进行训练,从而找到对某项问题比较好的解决方案,炼丹师此时不需要关注具体所解决的问题,可以大量使用占位符代替用户的实际输入。而程序员则可以用到炼丹师的成果进而替换占位符为具体的用户输入,从而实现功能。下面举一个具体的例子

比如说对 GPT 进行 prompt 炼丹,最后炼出一个分类器,这个分类器可以根据用户的输入内容进行分类。但是在炼丹的过程炼丹师是不会也不可能拿到所有用户可能的输入的,用户可能的输入是在炼丹师完成炼丹工作之后,程序员开发人机交互应用最后才能拿到用户的实际输入内容。这个时候自定义变量的功能相信大家就能知道了,通过自定义变量的功能,让炼丹师可以方便插入占位符,从而程序员进行对接

更进一步,自定义变量还可以更加方便技能的导入,由于许多技能都可以输入不止一个的输入内容,在有自定义变量的辅助之下,即可完成更加复杂的管道逻辑。比如说在经过某个技能之后,可以进行多变量输入和多变量输出,于是就可以传递更多丰富的信息给到后续的步骤。比如说 GPT 的分类功能,可以在分类之后对不同类别输出不同的输入要求,从而满足对接后续的技能。举一个具体的例子

比如说训练 GPT 可以输出用户的输入内容,将用户的输入类型分类为 1. 总结文本内容 2. 根据文字生成图片 等,通过对接自定义变量功能时。可以让炼丹师不需要关注特定的输入,而是统一采用 input 变量当成用户的输入,然后在完成之后,注入用户输入类型作为 type 变量。如果用户是总结文本内容的需求,则再添加 text 变量。如果是根据文字生成图片,则注入 request 变量和 size 尺寸变量。于是程序员可以编程开发,给 SemanticKernel 框架先设置 input 变量,这个 input 变量就是用户输入的文本内容。接着执行 GPT 的智能逻辑,再读取自定义变量 type 拿到用户期望执行的类型,分别调用不同的技能函数。比如说总结文本技能就需要用到 text 变量作为输入,而根据文字生成图片则需要 request 变量和 size 尺寸变量,这些都可以在一个顺序之中完成

看到这里,大家是不是想要试试看 SemanticKernel 框架赋予 AI 的强大能力了?放心,本文现在还不涉及到任何 AI 相关的逻辑,依然还在探索 SemanticKernel 框架的过程

先和大家介绍一下如何在 SemanticKernel 框架里面注入自定义变量。在 SemanticKernel 框架里面默认将所有的输入当成了 input 变量,也就是后续介绍到的 SemanticKernel 的 SK 函数里面,如果只有一个默认参数,那么这个参数将会被同时赋给 input 变量

在 SemanticKernel 注入自定义变量的方法可以是先新建 ContextVariables 对象,通过变量上下文对象进行类似字典的方式赋值。默认给到 ContextVariables 构造函数的就是后续会被当成 input 的变量,如以下代码。下面代码将演示在没有任何 AI 参与的情况下,输出今天的日期

var variables = new ContextVariables("今天是: ");
variables.Set("day", DateTime.Now.ToString(CultureInfo.CurrentCulture));

如以上的代码就定义了 input 是 "今天是: " 而 day 变量就是通过 Set 方法设置为 DateTime.Now.ToString(CultureInfo.CurrentCulture) 的返回值

也就是说如果有逻辑能够将 input 和 day 拼接在一起,就能够完成一句话。当然,更多的时候变量是用来提供给到 AI 使用的。现在咱还不想使用魔法,先看看如果是纯写传统代码的情况下,如何完成这个功能

在聊到自定义变量的时候,就肯定会聊到自定义技能功能了。在之前的博客里面,大家也看到了调用框架自带的技能的方法,接下来我将和大家介绍如何自定义技能

自定义技能是 SemanticKernel 框架所强大的地方,通过自定义技能即可将 AI 和传统编程联系在一起,下面让咱编写一个技能,这个技能的用途是将日期追加到输入字符串里面

自定义技能的做法是创建一个方法且标记 SKFunction 特性,可选的加上描述信息。这个描述信息现在也只是给程序员看的,据说后面微软将准备出一个 GUI 设计器,这时候对技能的描述就可以更加方便给非编程的工程师进行开发 AI 功能

class StaticTextSkill
{
    [SKFunction, Description("追加 day 变量到字符串")]
    public static string AppendDay
    (
        [Description("准备被追加的文本")] string input,
        [Description("追加到文本后面的字符串")]
        string day
    )
        => input + day;
}

以上的 AppendDay 方法里面的参数将会被 SemanticKernel 框架使用反射的方式进行注入,注入的就是参数名对应的变量。简单来说就是从 ContextVariables 里面尝试通过参数名获取到参数。如果没能从 ContextVariables 里读取到和参数名对应的变量,则会记录一个错误信息,例如当技能函数里面丢失了一个名为 xx 的变量时的输出如下

Missing value for parameter 'xx'

在一个类型里面可以定义许多个技能函数,此时就可以通过导出技能类然后使用技能类里面的多个技能方法,如下面代码定义一个非静态的技能方法在 StaticTextSkill 类型里面

class StaticTextSkill
{
    [SKFunction, Description("将所有的文本字符串修改为大写")]
    public string Uppercase([Description("准备修改为大写的文本")] string input) =>
        input.ToUpperInvariant();

    [SKFunction, Description("追加 day 变量到字符串")]
    public static string AppendDay
    (
        [Description("准备被追加的文本")] string input,
        [Description("追加到文本后面的字符串")]
        string day
    )
        => input + day;
}

接下来需要做的就是将 ContextVariables 放入到 SemanticKernel 框架,通过管道方式调用 StaticTextSkill 技能,如以下代码

IKernel kernel = new KernelBuilder().Build();
var text = kernel.ImportSkill(new StaticTextSkill(), "text");

var variables = new ContextVariables("今天是: ");
variables.Set("day", DateTime.Now.ToString(CultureInfo.CurrentCulture));

SKContext result = await kernel.RunAsync(variables,
    text["AppendDay"],
    text["Uppercase"]);

Console.WriteLine(result);

执行以上代码,即可看到输出了今天的时间

本文的代码放在githubgitee 欢迎访问

可以通过如下方式获取本文的源代码,先创建一个空文件夹,接着使用命令行 cd 命令进入此空文件夹,在命令行里面输入以下代码,即可获取到本文的代码

git init
git remote add origin https://gitee.com/lindexi/lindexi_gd.git
git pull origin 84c1e073be77bee177607596b5e03cabb0c0a719

以上使用的是 gitee 的源,如果 gitee 不能访问,请替换为 github 的源。请在命令行继续输入以下代码

git remote remove origin
git remote add origin https://github.com/lindexi/lindexi_gd.git
git pull origin 84c1e073be77bee177607596b5e03cabb0c0a719

获取代码之后,进入 SemanticKernelSamples\Example03_Variables 文件夹

标签:变量,自定义,dotnet,input,SemanticKernel,输入,技能
From: https://www.cnblogs.com/lindexi/p/17673351.html

相关文章

  • uniapp项目实践总结(六)自定义顶部导航栏
    本篇主要讲述如何自定义顶部导航栏,有时候默认导航栏不足以满足我们的需求,这时候就需要自定义导航栏来解决这个问题。目录默认导航修改配置自定义顶部默认导航自带的默认顶部导航设置的内容有限,不容易扩展修改,因此如果有更加个性化的需求,则需要自定义顶部导航。配置如下......
  • uniapp的u-album组件自定义删除功能
    加是否显示删除按钮图片字段删除按钮删除方法删除按钮样式代码<template><viewclass="u-album"><viewclass="u-album__row"ref="u-album__row"v-for="(arr,index)inshowUrls"......
  • 博客园如何设置自定义主题?
    作者:西瓜程序猿主页传送门:https://blog.51cto.com/kimiliucn前言写博客也有一个月了,发现博客园自带的主题都不太好看,然后搜索了一下发现这款主题【Cnblogs-Theme-SimpleMemory】界面还挺好看的,也是开源的。那[西瓜程序猿]就以这个主题来介绍一下如何在博客园中进行配置,跟着一起来操......
  • uniapp 如何自定义导航栏并自适应机型
    Uniapp是一款跨平台开发框架,可以同时开发出可以在多个平台(如微信小程序、H5、App等)上运行的应用。在开发过程中,我们常常需要自定义导航栏来满足UI设计的需求。本文将介绍如何在Uniapp中自定义导航栏并自适应不同机型的屏幕大小。1.使用nav-bar组件自定义导航栏Uniapp提......
  • 直播开发app,Xcode如何添加字体,自定义字体
    直播开发app,Xcode如何添加字体,自定义字体1.网上搜索字体文件(后缀名为.ttf,或.odf) 2.把字体库导入到工程的resouce中 3.在程序viewdidload中加载一下一段代码 NSArray*familyNames=[UIFontfamilyNames];for(NSString*familyNameinfamilyNames){  printf("Famil......
  • naiveui | select下拉选择自定义选项渲染
    <n-selectv-model:value="selectValue"placeholder="请选择数据":options="sourceOption"clearablefilterable:render-label="renderReportsLabel"......
  • dbeaver Community :自定义内部 dashboard 模版
    dbeaver的官方文档并没说明怎么去自定义内部的dashboard模版。但是,他是开源的,有源代码可查的。而且,他是java的,即使没有源代码,你也可以简单的去反编译class来读取源代码!#==========================================================以下是我的一点研究。#=================......
  • Skywalking 9.5 +Net6 SkyDotNet的简单使用
    官方下载地址 Downloads|ApacheSkyWalkingjdk12.2解压找到bin/startup目录启动,不连接数据库,采用内存记录webapp\application.yml可以更改web程序启动端口config\application.yml更改配置,具体百度上面这两个可以默认设置,不更改启动后界面 然后Net6......
  • js_通过js主动触发原生事件, 以及通过js注册自定义事件并手动触发
    现实情景:在对博客园的样式进行修改时,需要对博客园的中某些DOM的绑定事件进行手动触发主动触发原生事件,以click为例constoBtn2=document.querySelector('#btn2')oBtn2.addEventListener('click',()=>{console.log('click')})constevObj=document.createEv......
  • Log4j输出到多个自定义文件
     引入:log4j的强大功能无可置疑,但实际应用中免不了遇到某个功能需要输出独立的日志文件的情况,怎样才能把所需的内容从原有日志中分离,形成单独的日志文件呢?其实只要在现有的log4j基础上稍加配置即可轻松实现这一功能。 实例: 对于log4j的简单配置,可以参见log4j文档说明,这里先来看一......