如何通过SK集成chatGPT实现DotNet项目工程化?

智能助手服务

以下案例将讲解如何实现天气插件

当前文档对应src/assistant/Chat.SemanticServer项目

首先我们介绍一下Chat.SemanticServer的技术架构

SemanticKernel 是什么?

Semantic Kernel是一个SDK,它将OpenAI、Azure OpenAI和Hugging Face等大型语言模型(LLMs)与传统的编程语言如C#、Python和Java集成在一起。Semantic Kernel通过允许您定义可以在几行代码中链接在一起的插件来实现这一目标。

如何集成使用SemanticKernel

以下是添加IKernel,OpenAIOptions.ModelOpenAIOptions.Key在一开始使用了builder.Configuration.GetSection("OpenAI").Get<OpenAIOptions>();绑定。对应配置文件,OpenAIChatCompletion则是用于直接请求OpenAI。

"OpenAI": {"Key": "","Endpoint": "","Model": "gpt-3.5-turbo"}
builder.Services.AddTransient<IKernel>((services) =>
{var httpClientFactory = services.GetRequiredService<IHttpClientFactory>();return Kernel.Builder.WithOpenAIChatCompletionService(OpenAIOptions.Model,OpenAIOptions.Key,httpClient: httpClientFactory.CreateClient("ChatGPT")).Build();
}).AddSingleton<OpenAIChatCompletion>((services) =>
{var httpClientFactory = services.GetRequiredService<IHttpClientFactory>();return new OpenAIChatCompletion(OpenAIOptions.Model, OpenAIOptions.Key,httpClient: httpClientFactory.CreateClient("ChatGPT"));
});

在项目中存在plugins文件夹,这是提供的插件目录,在BasePlugin目录下存在一个识别意图的插件。

config.json对应当前插件的一些参数配置,

{"schema": 1,"type": "completion","description": "获取用户的意图。","completion": {"max_tokens": 500,"temperature": 0.0,"top_p": 0.0,"presence_penalty": 0.0,"frequency_penalty": 0.0},"input": {"parameters": [{"name": "input","description": "用户的请求。","defaultValue": ""},{"name": "history","description": "对话的历史。","defaultValue": ""},{"name": "options","description": "可供选择的选项。","defaultValue": ""}]}
}

skprompt.txt则是当前插件使用的prompt

加载插件

在这里我们注入了IKernel

    private readonly IKernel _kernel;private readonly IHttpClientFactory _httpClientFactory;private readonly RedisClient _redisClient;private readonly ILogger<IntelligentAssistantHandle> _logger;private readonly OpenAIChatCompletion _chatCompletion;public IntelligentAssistantHandle(IKernel kernel, RedisClient redisClient,ILogger<IntelligentAssistantHandle> logger, IHttpClientFactory httpClientFactory,OpenAIChatCompletion chatCompletion){_kernel = kernel;_redisClient = redisClient;_logger = logger;_httpClientFactory = httpClientFactory;_chatCompletion = chatCompletion;_redisClient.Subscribe(nameof(IntelligentAssistantEto),((s, o) => { HandleAsync(JsonSerializer.Deserialize<IntelligentAssistantEto>(o as string)); }));}

然后准备加载插件。


//对话摘要  SK.Skills.Core 核心技能
_kernel.ImportSkill(new ConversationSummarySkill(_kernel), "ConversationSummarySkill");// 插件根目录
var pluginsDirectory = Path.Combine(Directory.GetCurrentDirectory(), "plugins");// 这个是添加BasePlugin目录下面的所有插件,会自动扫描
var intentPlugin = _kernel.ImportSemanticSkillFromDirectory(pluginsDirectory, "BasePlugin");// 这个是添加Travel目录下面的所有插件,会自动扫描
var travelPlugin = _kernel.ImportSemanticSkillFromDirectory(pluginsDirectory, "Travel");// 这个是添加ChatPlugin目录下面的所有插件,会自动扫描
var chatPlugin = _kernel.ImportSemanticSkillFromDirectory(pluginsDirectory, "ChatPlugin");// 这个是添加WeatherPlugin类插件,并且给定插件命名WeatherPlugin
var getWeather = _kernel.ImportSkill(new WeatherPlugin(_httpClientFactory), "WeatherPlugin");

使用插件,首先我们创建了一个ContextVariablesinput则是GetIntent插件中的的{{$input}}options则对应{{$options}}getIntentVariables则将替换对应的prompt中响应的参数。

var getIntentVariables = new ContextVariables{["input"] = value,["options"] = "Weather,Attractions,Delicacy,Traffic" //给GPT的意图,通过Prompt限定选用这些里面的};
string intent = (await _kernel.RunAsync(getIntentVariables, intentPlugin["GetIntent"])).Result.Trim();

plugins/BasePlugin/GetIntent/skprompt.txt内容

{{ConversationSummarySkill.SummarizeConversation $history}}
用户: {{$input}}---------------------------------------------
提供用户的意图。其意图应为以下内容之一: {{$options}}意图: 

意图识别完成以后,当执行完成GetIntentintent相应会根据options中提供的参数返回与之匹配的参数,

然后下面的代码将根据返回的意图进行实际上的操作,或加载相应的插件,比如当intent返回Weather,则首先从chatPlugin中使用Weather插件,并且传递当前用户输入内容,在这里将提取用户需要获取天气的城市。

完成返回以后将在使用MathFunction = _kernel.Skills.GetFunction("WeatherPlugin", "GetWeather")的方式获取WeatherPlugin插件的GetWeather方法,并且将得到的参数传递到_kernel.RunAsync执行的时候则会掉用GetWeather方法,这个时候会由插件返回的json在组合成定义的模板消息进行返回,就完成了调用。

            ISKFunction MathFunction = null;SKContext? result = null;//获取意图后动态调用Funif (intent is "Attractions" or "Delicacy" or "Traffic"){MathFunction = _kernel.Skills.GetFunction("Travel", intent);result = await _kernel.RunAsync(value, MathFunction);}else if (intent is "Weather"){var newValue = (await _kernel.RunAsync(new ContextVariables{["input"] = value}, chatPlugin["Weather"])).Result;MathFunction = _kernel.Skills.GetFunction("WeatherPlugin", "GetWeather");result = await _kernel.RunAsync(newValue, MathFunction);if (!result.Result.IsNullOrWhiteSpace()){if (result.Result.IsNullOrEmpty()){await SendMessage("获取天气失败了!", item.RevertId, item.Id);return;}var weather = JsonSerializer.Deserialize<GetWeatherModule>(result.Result);var live = weather?.lives.FirstOrDefault();await SendMessage(WeatherTemplate.Replace("{province}", live!.city).Replace("{weather}", live?.weather).Replace("{temperature_float}", live?.temperature_float).Replace("{winddirection}", live?.winddirection).Replace("{humidity}", live.humidity), item.RevertId, item.Id);return;}}else{var chatHistory = _chatCompletion.CreateNewChat();chatHistory.AddUserMessage(value);var reply = await _chatCompletion.GenerateMessageAsync(chatHistory);return;}

Weather的prompt

我会给你一句话,你需要找到需要获取天气的城市,如果存在时间也提供给我:
{{$input}}仅返回结果,除此之外不要有多余内容,按照如下格式:
{"city":"","time":""
}

WeatherPlugin获取天气插件


/// <summary>
/// 获取天气插件
/// </summary>
public class WeatherPlugin
{private static List<AdCode>? _codes;static WeatherPlugin(){var path = Path.Combine(AppContext.BaseDirectory, "adcode.json");if (File.Exists(path)){var str = File.ReadAllText(path);_codes = JsonSerializer.Deserialize<List<AdCode>>(str);}_codes ??= new List<AdCode>();}private readonly IHttpClientFactory _httpClientFactory;public WeatherPlugin(IHttpClientFactory httpClientFactory){_httpClientFactory = httpClientFactory;}[SKFunction, Description("获取天气")][SKParameter("input", "入参")]public async Task<string> GetWeather(SKContext context){var weatherInput = JsonSerializer.Deserialize<WeatherInput>(context.Result);var value = _codes.FirstOrDefault(x => x.name.StartsWith(weatherInput.city));if (value == null){return "请先描述指定城市!";}var http = _httpClientFactory.CreateClient(nameof(WeatherPlugin));var result = await http.GetAsync("https://restapi.amap.com/v3/weather/weatherInfo?key={高德天气api的key}&extensions=base&output=JSON&city=" +value.adcode);if (result.IsSuccessStatusCode){return await result.Content.ReadAsStringAsync();}return string.Empty;}
}public class WeatherInput
{public string city { get; set; }public string time { get; set; }
}public class AdCode
{public string name { get; set; }public string adcode { get; set; }public string citycode { get; set; }
}

效果图

以上代码可从仓库获取

项目开源地址

体验地址:https://chat.tokengo.top/ (可以使用Gitee快捷登录)
Github : https://github.com/239573049/chat
Gitee: https://gitee.com/hejiale010426/chat

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/163309.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

MyBatis--多案例让你熟练使用CRUD操作

目录 一、前期准备 二、两种实现CRUD方式 三、增加数据&#xff08;INSERT&#xff09; 四、删除数据&#xff08;DELETE&#xff09; 五、查询数据&#xff08;SELECT&#xff09; 六、更新数据&#xff08;UPDATE&#xff09; 一、前期准备 1.创建maven项目并在pom文件…

【计算机网络笔记】计算机网络性能(1)——速率、带宽、延迟

系列文章目录 什么是计算机网络&#xff1f; 什么是网络协议&#xff1f; 计算机网络的结构 数据交换之电路交换 数据交换之报文交换和分组交换 分组交换 vs 电路交换 系列文章目录速率带宽延迟/时延(delay或latency) 下面介绍一些计算机网络中常用的性能指标。在本篇中涉及速…

ELK架构Logstash的相关插件:grok、multiline、mutate、date的详细介绍

文章目录 1. grok (正则捕获插件)1.1 作用1.2 正则表达式的类型1.2.1 内置正则表达式1.2.2 自定义正则表达式 2. mutate (数据修改插件&#xff09;2.1 作用2.2 常见配置选项2.3 应用实例 3. multiline &#xff08;多行合并插件&#xff09;3.1 作用3.2 常用配置项及示例3.2.1…

Looper分析

Looper分析 在 Handler 机制中&#xff0c;Looper 的作用是提供了一个消息循环 ( message loop ) 的机制&#xff0c;用于处理和分发消息。 Looper 是一个线程局部的对象&#xff0c;每个线程只能有一个 Looper 对象。它通过一个无限循环来不断地从消息队列中取出消息&#x…

Linux搭建文件服务器

搭建简单文件服务器 基于centos7.9搭建http文件服务器基于centos7.9搭建nginx文件服务器基于ubuntu2204搭建http文件服务器 IP环境192.168.200.100VMware17 基于centos7.9搭建http文件服务器 安装httpd [rootlocalhost ~]# yum install -y httpd关闭防火墙以及selinux [roo…

【软考-中级】系统集成项目管理工程师 【15 信息 (文档) 和配置管理】

持续更新。。。。。。。。。。。。。。。 【第十五章】信息&#xff08;文档&#xff09;和配置管理 知识精讲考点 1:软件文档一般分为三类:开发文档、产品文档、管理文档。考点 2:文档的质量可以分为四级:考点 3:配置管考点 4:考点 5:考点6:考点 7:配置项版本号:考点 8:考点9…

36张图详解网络基础知识

下午好&#xff0c;我的网工朋友。 在网工这行&#xff0c;只要是面试&#xff0c;一般都难逃网络协议相关的问题吧。 不管是OSI还是TCP/IP&#xff0c;这都是非常重要、基础的知识&#xff0c;很多知识点都是以它们为基础去串联的。 作为网络世界的底层技术&#xff0c;掌握…

Docker安装ES7.14和Kibana7.14(无账号密码)

一、Docker安装ES7.14.0 1、下载镜像 docker pull elasticsearch:7.14.0 2、docker安装7.14.0 mkdir -p /usr/local/elasticsearch/config mkdir -p /usr/local/elasticsearch/data chmod 777 -R /usr/local/elasticsearch/ echo "http.host: 0.0.0.0" >> /u…

Java 多线程案例

文章目录 1. 多线程案例1.1 单例模式1.2 阻塞式队列 2. 定时器3. 线程池 1. 多线程案例 1.1 单例模式 单例模式&#xff08;Singleton Pattern&#xff09;是一种常用的软件设计模式&#xff0c;该模式的主要目标是确保一个类只有一个实例&#xff0c;并提供一个全局访问点。…

关于网络协议的若干问题(五)

1、DH 算法会因为传输随机数被破解吗&#xff1f; 答&#xff1a;DH 算法的交换材料要分公钥部分和私钥部分&#xff0c;公钥部分和其他非对称加密一样&#xff0c;都是可以传输的&#xff0c;所以对于安全性是没有影响的&#xff0c;而且传输材料远比传输原始的公钥更加安全。…

Apache Jmeter测压工具快速入门

Jmeter测压工具快速入门 一、Jmeter介绍二、Jmeter On Mac2.1 下载2.2 安装2.2.1 环境配置2.2.2 初始化设置 2.3 测试2.3.1 创建JDBC Connection Configuration2.3.2 创建线程组2.3.3 创建JDBC Request2.3.4 创建结果监控2.3.5 运行结果 2.4 问题记录2.4.1 VM option UseG1GC异…

小程序技术在信创操作系统中的应用趋势:适配能力有哪些?

小程序技术在信创操作系统中的应用前景非常广阔&#xff0c;但也面临着一些挑战和问题。开发者需要积极应对这些挑战和问题&#xff0c;为信创操作系统的发展和推广做出贡献。同时&#xff0c;开发者也需要关注小程序技术在信创操作系统中的应用趋势&#xff0c;积极探索新的应…

视频剪辑SDK,实现高效的移动端视频编辑

为了满足企业对视频编辑的需求&#xff0c;美摄提供了iOS/Android端视频编辑SDK技术开发服务&#xff0c;帮助企业快速高效地制作高质量视频。本文将详细介绍美摄的视频编辑SDK的优势和特点&#xff0c;以及如何为企业提供技术解决方案。 随着智能手机的普及和移动互联网的发展…

Java实现业务异步的几种方案

背景&#xff1a; 在java中异步线程很重要&#xff0c;比如在业务流处理时&#xff0c;需要通知硬件设备&#xff0c;发短信通知用户&#xff0c;或者需要上传一些图片资源到其他服务器这种耗时的操作&#xff0c;在主线程里处理会阻塞整理流程&#xff0c;而且我们也不需要等…

Zookeeper集群 + Kafka集群的详细介绍与部署

文章目录 1. Zookeeper 概述1.1 简介1.2 Zookeeper的工作机制1.3 Zookeeper 主要特点1.4 Zookeeper 数据结构1.5 Zookeeper的相关应用场景1.5.1 统一命名服务1.5.2 统一配置管理1.5.3 统一集群管理1.5.4 服务器动态上下线1.5.5 软负载均衡 1.6 Zookeeper 选举机制1.6.1 第一次启…

Jmeter 之接口测试(http 接口测试)

基础知识储备 一、了解 jmeter 接口测试请求接口的原理 客户端 -- 发送一个请求动作 -- 服务器响应 -- 返回客户端 客户端 -- 发送一个请求动作 --jmeter 代理服务器 --- 服务器 --jmeter 代理服务器 -- 服务器 二、了解基础接口知识&#xff1a; 1、什么是接口&#xff1a…

uniapp 小程序优惠劵样式

先看效果图 上代码 <view class"coupon"><view class"tickets" v-for"(item,index) in 10" :key"item"><view class"l-tickets"><view class"name">10元优惠劵</view><view cl…

centos7 部署oracle完整教程(命令行)

centos7 部署oracle完整教程&#xff08;命令行&#xff09; 一. centos7安装oracle1.查看Swap分区空间&#xff08;不能小于2G&#xff09;2.修改CentOS系统标识 (由于Oracle默认不支持CentOS)2.1.删除CentOS Linux release 7.9.2009 (Core)&#xff08;快捷键dd&#xff09;&…

python爬取boss直聘数据(selenium+xpath)

文章目录 一、主要目标二、开发环境三、selenium安装和驱动下载四、主要思路五、代码展示和说明1、导入相关库2、启动浏览器3、搜索框定位创建csv文件招聘页面数据解析(XPATH)总代码效果展示 六、总结 一、主要目标 以boss直聘为目标网站&#xff0c;主要目的是爬取下图中的所…

EV SSL数字证书贵吗

EVSSL证书通常适用于具有高需求的网站和企业&#xff0c;特别是涉及在线交易、金融服务、电子商务平台等需要建立用户信任的场景。大型企业、金融机构、电子商务平台等可以受益于使用EV证书来提升品牌形象和安全性。 申请EVSSL证书&#xff08;Extended Validation SSL certifi…