dotnet 简单控制台使用 KernelMemory 向量化文本嵌入生成和查询

news/2024/10/4 19:24:25

本文将和大家简单介绍一下如何在控制台里面使用 Microsoft.KernelMemory 调用 TextEmbedding 对一些文本知识库内容生成向量化信息,以及进行向量化查询

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

根据 new bing 对 Microsoft.KernelMemory 的如下介绍,可以知道 KernelMemory 的基础功能

Microsoft.KernelMemory 是一个开源的服务和插件,专门用于通过自定义的连续数据混合管道对数据集进行高效的索引。它的目标是模拟人类大脑如何存储和检索关于世界的知识。其中,嵌入(Embeddings) 是一项关键功能,用于创建语义映射,将概念或实体表示为高维空间中的向量。

嵌入是一种强大的工具,用于帮助软件开发人员处理人工智能和自然语言处理。它们通过将单词表示为高维向量而不是简单的字符字符串,以更复杂的方式帮助计算机理解单词的含义。嵌入通常以数值向量的形式存在,例如由数百个浮点数组成的列表。这些向量通过将每个已知的标记(token)映射到高维空间中的一个点来工作。设计这个空间和标记词汇表的目的是使具有相似含义的单词位于彼此附近。这使得算法能够在不需要显式规则或人工监督的情况下识别单词之间的关系,例如同义词或反义词。

在开始之前,期望大家已经有了 Azure 的 AI 账号权限,如果现在还没有权限,请填写 https://aka.ms/oai/access 进行申请。网上有很多申请攻略,如果大家不知道如何填写的话,还请自行参考网上大佬们写的攻略

先进入到 https://ai.azure.com/ 进行部署项目,如果大家现在没有权限但只是想测试一下,可以找我要借账号给你自己测试一下

由于 AzureAI 的界面更新比较快,本文以下截图都是在 2024.06 截图的,如果你阅读本文的时间距离本文编写时间过长,那可能界面很多都会不一样,但相信大家看界面还是会创建模型的

先点击创建部署按钮,如下图

接着在选择模型这里选择 TextEmbedding 模型,本文这里选择的是 text-embedding-ada-002 模型,这是当前总体表现都很好的模型

创建模型时需要给模型命名,这个命名将在后续咱的代码里面调用。我这里的部署名称使用的是 Embedding 名称,完成部署之后的界面内容大概如下

完成以上准备工作之后,接下来可以开始新建控制台编写代码了。先新建一个 .NET 8 框架的控制台,当然了,这个时间点你要是激进一些也可以创建 .NET 9 框架的

先按照 .NET 的惯例安装 Microsoft.KernelMemory.Core 这个库,安装之后的 csproj 项目文件的代码大概如下

<Project Sdk="Microsoft.NET.Sdk"><PropertyGroup><OutputType>Exe</OutputType><TargetFramework>net8.0</TargetFramework><ImplicitUsings>enable</ImplicitUsings><Nullable>enable</Nullable></PropertyGroup><ItemGroup><PackageReference Include="Microsoft.KernelMemory.Core" Version="0.62.240605.1" /></ItemGroup></Project>

先引用命名空间

using Microsoft.KernelMemory;

接着初始化进行一些配置,配置代码如下

var endpoint = "https://lindexi.openai.azure.com/"; // 请换成你的地址
var apiKey = File.ReadAllText(@"C:\lindexi\CA\Key"); // 请换成你的密钥var kernel = new KernelMemoryBuilder().WithSimpleFileStorage("Folder").WithoutTextGenerator().WithAzureOpenAITextEmbeddingGeneration(new AzureOpenAIConfig(){Endpoint = endpoint,APIKey = apiKey,Deployment = "Embedding",APIType = AzureOpenAIConfig.APITypes.EmbeddingGeneration,Auth = AzureOpenAIConfig.AuthTypes.APIKey}).Build();

以上代码里面的 endpoint 和 apiKey 和 Deployment 分别换成你的地址和你的密钥以及你的部署名称

本文只是演示如何调用文本嵌入向量化,不涉及到文本生成,于是加上了 WithoutTextGenerator 配置,加上了此配置之后,后续的 Ask 系列方法将不能调用。本文这里为了方便起见,将知识库向量化之后存放到本地文件夹里面,即通过 .WithSimpleFileStorage("Folder") 配置存放到相对工作路径的 Folder 文件夹。大家可以尝试运行项目之后看看你的这个文件夹里面的内容

拿到了 IKernelMemory 类型的 kernel 对象之后,接下来就可以导入知识库的知识了。如以下我导入了一些我的博客内容作为知识

await kernel.ImportTextAsync("本文记录在 WPF 项目里面设置 IncludePackageReferencesDuringMarkupCompilation 属性为 False 导致了项目所安装的分析器不能符合预期工作 设置 IncludePackageReferencesDuringMarkupCompilation 属性为 false 将配置 WPF 在构建 XAML 过程中创建的 tmp.csproj 过程中将不引用依赖的 nuget 包。分析器默认也是通过 nuget 包方式安装的,这就导致了分析器项目没有被 tmp.csproj 项目正确使用到 如果项目里面有代码依赖分析器生成的影响语义的代码,那这部分代码将会构建不通过");await kernel.ImportTextAsync("在 dotnet 6 时,官方为了适配好 Source Generators 功能,于是默认就将 WPF 的 XAML 构建过程中,引入第三方库的 cs 文件,这个功能默认设置为开启。刚好源代码包为了修复在使用 dotnet 6 SDK 之前,在 WPF 的构建 XAML 过程中,不包含第三方库的代码文件,从而使用黑科技将源代码包加入到 WPF 构建 XAML 中。在 VisualStudio 升级到 2022 版本,或者是升级 dotnet sdk 到 dotnet 6 版本,将会更新构建调度,让源代码包里的代码文件被加入两次,从而构建失败\r\n构建失败的提示如下\r\n\r\n```\r\nC:\\Program Files\\dotnet\\sdk\\6.0.101\\Sdks\\Microsoft.NET.Sdk\\targets\\Microsoft.NET.Sdk.DefaultItems.Shared.targets(190,5): error NETSDK1022: 包含了重复的“Compile”项。.NET SDK 默认包含你项目目录中的“Compile”项。可从项目文件中删除这些项;如果希望将其显式包含在项目文件中,可将“EnableDefaultCompileItems”属性设置为“false”。有关详细信息,请参阅 https://aka.ms/sdkimplicititems。重复项为: \r\n```重复的原因是 WPF 在 .NET SDK 里修复了在 XAML 构建过程中,没有引用 NuGet 包里面的文件。而源代码包许多都是在此修复之前打出来的,源代码包为了修复在 XAML 里面没有引用文件,就强行加上修复逻辑引用文件。而在 dotnet 6 修复了之后,自然就会导致引用了多次 修复方法很简单,在不更改源代码包的前提下,可以在 csproj 项目文件里加入以下代码```xml\r\n    <IncludePackageReferencesDuringMarkupCompilation>False</IncludePackageReferencesDuringMarkupCompilation>\r\n```");await kernel.ImportTextAsync("默认情况下的 WPF 项目都是带 -windows 的 TargetFramework 方式,但有一些项目是不期望加上 -windows 做平台限制的,本文将介绍如何实现不添加 -windows 而引用 WPF 框架 对于一些特殊的项目来说,也许只是在某些模块下期望引用 WPF 的某些类型,而不想自己的项目限定平台。这时候可以去掉 `-windows` 换成 FrameworkReference 的方式 通过 `<FrameworkReference Include=\"Microsoft.WindowsDesktop.App.WPF\" />` 即可设置对 WPF 程序集的引用,也就是仅仅只是将 WPF 的程序集取出来当成引用,而不是加上 WPF 的负载");await kernel.ImportTextAsync("dotnet 如何访问到 UNO 框架里面的 internal 不公开成员? 核心原理是基于 UNO 框架里面的 InternalsVisibleToAttribute 程序集特性,指定给到 SamplesApp 等程序集可见。因此只需要新建一个程序集,设置 AssemblyName 为 SamplesApp 即可");

以上的导入逻辑将会调用上文部署的 text-embedding-ada-002 模型,将文本内容进行向量化,将向量化之后的结果存放到本地的文件里面,使用本地文件系统作为知识数据库。后续的查询逻辑即可读取本地文件的向量进行向量距离对比,支持语义化查询

传统的查询大部分都是关键词进行字符串比较,而通过 text-embedding-ada-002 等 TextEmbedding 模型,即可进行语义化查询。核心原理是计算出查询字符串的向量值,与知识数据库里面存放的知识的向量进行比较,从而获取到向量距离较近的知识,向量距离越近表示约有相关性。通过此方法可以更好的进行查询知识,特别是处理海量知识库信息查询的时候

建立知识库步骤只需要做一次调用 TextEmbedding 模型,不需要每次查询数据都重新对整个知识库进行调用 TextEmbedding 模型。因为调用一次之后,就获取到 TextEmbedding 模型返回的向量化信息。之后只需要对查询的信息的内容调用 TextEmbedding 模型获取查询信息的向量化信息,再将查询信息的向量化信息与知识库里面的各个知识的向量化信息进行比较即可,即可找到查询信息与各个知识的相关性

如以下代码尝试进行一条查询

var searchResult = await kernel.SearchAsync("如何访问 UNO 不公开成员");

以上查询可以拿到查询结果,一般来说查询结果需要关注其相关性,即 Relevance 属性的值。大部分情况下的业务只取第一条,即最相关的内容

var searchResult = await kernel.SearchAsync("如何访问 UNO 不公开成员");if (searchResult.NoResult)
{Console.WriteLine("没有找到相关项");return;
}foreach (var citation in searchResult.Results)
{// 大部分情况下,只取第一项foreach (var partition in citation.Partitions){Console.WriteLine($"关联性: {partition.Relevance:0.00} 内容: {partition.Text}");}
}

运行以上代码的输出如下

关联性: 0.84 内容: dotnet 如何访问到 UNO 框架里面的 internal 不公开成员? 核心原理是基于 UNO 框架里面的 InternalsVisibleToAttribute 程序集特性,指定给到 SamplesApp 等程序集可见。因此只需要新建一个程序集,设置 AssemblyName 为 SamplesApp 即 可
关联性: 0.66 内容: NET SDK 里修复了在 XAML 构建过程中,没有引用 NuGet 包里面的文件。而源代码包许多都是在此修复之前打出来的,源代码包为了修复在 XAML 里面没有引用文件,就强行加上修复逻辑引用文件。而在 dotnet 6 修复了之后,自然就会导致引用了多次 修复方法很简单,在不更改源代码包的前提下,可以在 csproj 项目文件里加入以下代码```xml
<IncludePackageReferencesDuringMarkupCompilation>False</IncludePackageReferencesDuringMarkupCompilation>`` `
关联性: 0.64 内容: 在 dotnet 6 时,官方为了适配好 Source Generators 功能,于是默认就将 WPF 的 XAML 构建过程中,引入第 三方库的 cs 文件,这个功能默认设置为开启。刚好源代码包为了修复在使用 dotnet 6 SDK 之前,在 WPF 的构建 XAML
过程中,不包含第三方库的代码文件,从而使用黑科技将源代码包加入到 WPF 构建 XAML 中。在 VisualStudio 升级到 2022 版本,或 者是升级 dotnet sdk 到 dotnet 6 版本,将会更新构建调度,让源代码包里的代码文件被加入两次,从而构建失败
构建失败的提示如下` ``
C:\Program Files\dotnet\sdk\6.0.101\Sdks\Microsoft.NET.Sdk\targets\Microsoft.NET.Sdk.DefaultItems.Shared.targets(190,5): error NETSDK1022: 包含了重复的“Compile”项。.NET SDK 默认包含你项目目录中的“Compile”项。可从项目文件中删除这些项;如果希望将其显式包含在项目文件中,可将“EnableDefaultCompileItems”属性设置为“false”。有关详细信息,请参阅 https://aka.ms/sdkimplicititems。重复项为:
` ``重复的原因是 WPF 在 . NET SDK 里修复了在 XAML 构建过程中,没有引用 NuGet
关联性: 0.65 内容: 本文记录在 WPF 项目里面设置 IncludePackageReferencesDuringMarkupCompilation 属性为 False 导致了项目所安装的分析器不能符合预期工作 设置 IncludePackageReferencesDuringMarkupCompilation 属性为 false 将配置 WPF 在构建 XAML 过程中创建的 tmp.
csproj 过程中将不引用依赖的 nuget 包。分析器默认也是通过 nuget 包方式安装的,这就导致了分析器项目没有被 tmp.csproj 项目 正确使用到 如果项目里面有代码依赖分析器生成的影响语义的代码,那这部分代码将会构建不通过
关联性: 0.64 内容: 默认情况下的 WPF 项目都是带 -windows 的 TargetFramework 方式,但有一些项目是不期望加上 -windows 做 平台限制的,本文将介绍如何实现不添加 -windows 而引用 WPF 框架 对于一些特殊的项目来说,也许只是在某些模块下期望引用 WPF  的某些类型,而不想自己的项目限定平台。这时候可以去掉 `-windows` 换成 FrameworkReference 的方式 通过 `<FrameworkReference Include="Microsoft.
WindowsDesktop.App.WPF" />` 即可设置对 WPF 程序集的引用,也就是仅仅只是将 WPF 的程序集取出来当成引用,而不是加上 WPF 的 负载

使用 TextEmbedding 查询的好处在于其支持语义化,即换个说法查询也是可以的,比如我换成如下代码进行查询

var searchResult = await kernel.SearchAsync("如何调用非公开方法");

此时依然能够输出如下内容

关联性: 0.77 内容: dotnet 如何访问到 UNO 框架里面的 internal 不公开成员? 核心原理是基于 UNO 框架里面的 InternalsVisibleToAttribute 程序集特性,指定给到 SamplesApp 等程序集可见。因此只需要新建一个程序集,设置 AssemblyName 为 SamplesApp 即 可

在 Microsoft.KernelMemory 里面还添加了 AskAsync 方法,这个 AskAsync 方法里面包含两个步骤的内容。第一步就是执行 SearchAsync 的核心功能,查询到相关的知识。第二步就是调用 TextGenerator 的功能,根据查询到相关的知识让 AI 如 GPT 生成人类更加友好的回答内容

由于本文开始配置里面设置了 WithoutTextGenerator 因此调用以下代码将会抛出异常

var answer = await kernel.AskAsync("为什么分析器和源代码冲突");

如果大家想要测试此功能,还请执行配置

本文代码放在 github 和 gitee 上,可以使用如下命令行拉取代码

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

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

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

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

获取代码之后,进入 SemanticKernelSamples/NekawlaicaYegemwheechijahafea 文件夹,即可获取到源代码

欢迎加入 SemanticKernel 群交流:623349574

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈,一经查实,立即删除!

相关文章

WPF 通过 SetWindowDisplayAffinity 配置禁止对窗口进行截图或录屏

有些应用程序比较机密或隐私,不期望被其他截图软件截图到应用的窗口,或者被录屏软件录制到。简单的方法是通过 SetWindowDisplayAffinity 方法进行配置窗口阻止截图软件对其截图开始之前必须说明的是对抗截图录屏是一个矛和盾的事情,截图和录屏技术方向在千方百计尝试对所有…

[转帖]性能分析之TCP全连接队列占满问题分析及优化过程

https://cloud.tencent.com/developer/article/1558493 前言 在对一个挡板系统进行测试时,遇到一个由于TCP全连接队列被占满而影响系统性能的问题,这里记录下如何进行分析及解决的。 理解下TCP建立连接过程与队列 从图中明显可以看出建立 TCP 连接的时候,有两个队列:syns…

Linux内核版本以及部分参数与性能之二

Linux内核版本以及部分参数与性能之二版本范围 grubby --set-default /boot/vmlinuz-6.9.4-1.el7.elrepo.x86_64 grubby --set-default /boot/vmlinuz-5.4.277-1.el7.elrepo.x86_64 grubby --set-default /boot/vmlinuz-4.19.12-1.el7.elrepo.x86_64 grubby --set-default /boo…

Python实用库--PrettyTable

简介 PrettyTable是一个强大的Python第三方库,专门设计用于从程序中生成美观、易于阅读的ASCII格式表格。 在数据分析、命令行工具开发、脚本编写等领域中,特别是在需要直观呈现数据而又不依赖图形界面的情况下,PrettyTable库显得尤为实用。 其设计灵感来源于PostgreSQL的ps…

随便写的小网页练习

随便写的小网页练习: 👆原视频:十分钟学会写网页【编程前端入门】 本期重做了好几遍,是全新的视角和概念,从浏览器底层渲染原理到实现网站的演示,一节课讲透,必看的一期。后面不管是写小程序还是App,都会用到这一期的概念。 这一期内容是我做完第一章个人网站后更新的,…

golang 同时(一个项目)注册http和GRPC服务

main 里面package mainimport ("fmt""github.com/gin-gonic/gin""github.com/hashicorp/consul/api"grpc "gorm_project/grpc/services""gorm_project/route""gorm_project/utils""log""net/http&…

如何设置word首页封面不出现页眉和编码

方法: 比如说我想让页码从第二页开始编号,那就双击第二页的编号,然后勾取消掉这个链接到前一页(我这里已经勾选掉了),之后直接删除掉第一页的编号就可以了如果数字不对的话,可以在“设置页码格式”中修改一下起始的页码:参考: 设置word中第一页不显示页码,第二页页码…

Paimon笔记

支持高吞吐数据摄入、变更追踪、高效分析的流批数据湖 基于LSM提升写入速度并降低写入消耗;基于有序的SortRun裁剪大部分数据以提升查询性能;支持多种merge引擎实现高性能流表打宽 基于Flink&Paimon实现,提供数据一致性管理能力,解决流式数仓普遍存在的问题 paimon通过…