SemanticKernel/C#:实现接口,接入本地嵌入模型

前言

本文通过Codeblaze.SemanticKernel这个项目,学习如何实现ITextEmbeddingGenerationService接口,接入本地嵌入模型。

项目地址:https://github.com/BLaZeKiLL/Codeblaze.SemanticKernel

实践

SemanticKernel初看以为只支持OpenAI的各种模型,但其实也提供了强大的抽象能力,可以通过自己实现接口,来实现接入不兼容OpenAI格式的模型。

Codeblaze.SemanticKernel这个项目实现了ITextGenerationService、IChatCompletionService与ITextEmbeddingGenerationService接口,由于现在Ollama的对话已经支持了OpenAI格式,因此可以不用实现ITextGenerationService和IChatCompletionService来接入Ollama中的模型了,但目前Ollama的嵌入还没有兼容OpenAI的格式,因此可以通过实现ITextEmbeddingGenerationService接口,接入Ollama中的嵌入模型。

查看ITextEmbeddingGenerationService接口:

image-20240806081346110

代表了一种生成浮点类型文本嵌入的生成器。

再看看IEmbeddingGenerationService<string, float>接口:

[Experimental("SKEXP0001")]
public interface IEmbeddingGenerationService<TValue, TEmbedding> : IAIService where TEmbedding : unmanaged
{Task<IList<ReadOnlyMemory<TEmbedding>>> GenerateEmbeddingsAsync(IList<TValue> data, Kernel? kernel = null, CancellationToken cancellationToken = default(CancellationToken));
}

再看看IAIService接口:

image-20240806081733336

说明我们只要实现了

Task<IList<ReadOnlyMemory<TEmbedding>>> GenerateEmbeddingsAsync(IList<TValue> data, Kernel? kernel = null, CancellationToken cancellationToken = default(CancellationToken));IReadOnlyDictionary<string, object?> Attributes { get; }

这个方法和属性就行。

学习Codeblaze.SemanticKernel中是怎么做的。

添加OllamaBase类:

 public interface IOllamaBase{Task PingOllamaAsync(CancellationToken cancellationToken = new());}public abstract class OllamaBase<T> : IOllamaBase where T : OllamaBase<T>{public IReadOnlyDictionary<string, object?> Attributes => _attributes;private readonly Dictionary<string, object?> _attributes = new();protected readonly HttpClient Http;protected readonly ILogger<T> Logger;protected OllamaBase(string modelId, string baseUrl, HttpClient http, ILoggerFactory? loggerFactory){_attributes.Add("model_id", modelId);_attributes.Add("base_url", baseUrl);Http = http;Logger = loggerFactory is not null ? loggerFactory.CreateLogger<T>() : NullLogger<T>.Instance;}/// <summary>/// Ping Ollama instance to check if the required llm model is available at the instance/// </summary>/// <param name="cancellationToken"></param>public async Task PingOllamaAsync(CancellationToken cancellationToken = new()){var data = new{name = Attributes["model_id"]};var response = await Http.PostAsJsonAsync($"{Attributes["base_url"]}/api/show", data, cancellationToken).ConfigureAwait(false);ValidateOllamaResponse(response);Logger.LogInformation("Connected to Ollama at {url} with model {model}", Attributes["base_url"], Attributes["model_id"]);}protected void ValidateOllamaResponse(HttpResponseMessage? response){try{response.EnsureSuccessStatusCode();}catch (HttpRequestException){Logger.LogError("Unable to connect to ollama at {url} with model {model}", Attributes["base_url"], Attributes["model_id"]);}}}

注意这个

public IReadOnlyDictionary<string, object?> Attributes => _attributes;

实现了接口中的属性。

添加OllamaTextEmbeddingGeneration类:

#pragma warning disable SKEXP0001public class OllamaTextEmbeddingGeneration(string modelId, string baseUrl, HttpClient http, ILoggerFactory? loggerFactory): OllamaBase<OllamaTextEmbeddingGeneration>(modelId, baseUrl, http, loggerFactory),ITextEmbeddingGenerationService{public async Task<IList<ReadOnlyMemory<float>>> GenerateEmbeddingsAsync(IList<string> data, Kernel? kernel = null,CancellationToken cancellationToken = new()){var result = new List<ReadOnlyMemory<float>>(data.Count);foreach (var text in data){var request = new{model = Attributes["model_id"],prompt = text};var response = await Http.PostAsJsonAsync($"{Attributes["base_url"]}/api/embeddings", request, cancellationToken).ConfigureAwait(false);ValidateOllamaResponse(response);var json = JsonSerializer.Deserialize<JsonNode>(await response.Content.ReadAsStringAsync().ConfigureAwait(false));var embedding = new ReadOnlyMemory<float>(json!["embedding"]?.AsArray().GetValues<float>().ToArray());result.Add(embedding);}return result;}}

注意实现了GenerateEmbeddingsAsync方法。实现的思路就是向Ollama中的嵌入接口发送请求,获得embedding数组。

为了在MemoryBuilder中能用还需要添加扩展方法:

#pragma warning disable SKEXP0001public static class OllamaMemoryBuilderExtensions{/// <summary>/// Adds Ollama as the text embedding generation backend for semantic memory/// </summary>/// <param name="builder">kernel builder</param>/// <param name="modelId">Ollama model ID to use</param>/// <param name="baseUrl">Ollama base url</param>/// <returns></returns>public static MemoryBuilder WithOllamaTextEmbeddingGeneration(this MemoryBuilder builder,string modelId,string baseUrl){builder.WithTextEmbeddingGeneration((logger, http) => new OllamaTextEmbeddingGeneration(modelId,baseUrl,http,logger));return builder;}       }

开始使用

 public async Task<ISemanticTextMemory> GetTextMemory3(){var builder = new MemoryBuilder();var embeddingEndpoint = "http://localhost:11434";var cancellationTokenSource = new System.Threading.CancellationTokenSource();var cancellationToken = cancellationTokenSource.Token;builder.WithHttpClient(new HttpClient());builder.WithOllamaTextEmbeddingGeneration("mxbai-embed-large:335m", embeddingEndpoint);IMemoryStore memoryStore = await SqliteMemoryStore.ConnectAsync("memstore.db");builder.WithMemoryStore(memoryStore);var textMemory = builder.Build();return textMemory;}
  builder.WithOllamaTextEmbeddingGeneration("mxbai-embed-large:335m", embeddingEndpoint);

实现了WithOllamaTextEmbeddingGeneration这个扩展方法,因此可以这么写,使用的是mxbai-embed-large:335m这个向量模型。

我使用WPF简单做了个界面,来试试效果。

找了一个新闻嵌入:

image-20240806090946822

文本向量化存入数据库中:

image-20240806091040483

现在测试RAG效果:

image-20240806091137623

image-20240806091310159

image-20240806091404424

回答的效果也还可以。

大模型使用的是在线api的Qwen/Qwen2-72B-Instruct,嵌入模型使用的是本地Ollama中的mxbai-embed-large:335m。

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

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

相关文章

近似算法:求Π的近似值(迭代法)

问题&#xff1a;请用正多边形逼近法求Π的近似值。 算法&#xff1a;圆的周长 正多边形的边长 * 边数。设圆的半径为1&#xff0c;则2Π i * x 。其中 i 为正多边形边数&#xff0c;x 为边长。 因为圆的半径 内接于此圆的正六边形的边长&#xff0c;故从六边形开始计算。参…

git系统学习

git系统学习 git命令行获取git 版本号 创建初始版本库创建git库初始化用户名和密码查看用户名和邮箱修改用户名和密码 将文件添加到版本库中删除暂存文件提交代码查看提交信息查看更加详细的信息查看提交差异版本库内文件的删除和重命名删除库里的文件重命名库里的文件 打标签查…

重启人生计划-大梦方醒

&#x1f973;&#x1f973;&#x1f973; 茫茫人海千千万万&#xff0c;感谢这一刻你看到了我的文章&#xff0c;感谢观赏&#xff0c;大家好呀&#xff0c;我是最爱吃鱼罐头&#xff0c;大家可以叫鱼罐头呦~&#x1f973;&#x1f973;&#x1f973; 从今天开始&#xff0c;我…

MybatisPlus——扩展功能(一)

扩展功能 1.代码生成 在使用MybatisPlus以后&#xff0c;基础的Mapper、Service、PO代码相对固定&#xff0c;重复编写也比较麻烦。因此MybatisPlus官方提供了代码生成器根据数据库表结构生成PO、Mapper、Service等相关代码。只不过代码生成器同样要编码使用&#xff0c;也很麻…

软考高级:真实的程序、核心程序、小型基准程序、合成基准程序

一、AI 讲解 这段内容描述了在软件测试或性能测试中&#xff0c;不同类型程序的测试精确度排名。 测试类型说明精确度排名真实的程序直接测试实际运行的软件或系统&#xff0c;能够反映真实的使用场景1核心程序测试系统或应用的核心模块或功能&#xff0c;虽然范围较小但仍具…

使用Selenium调试Edge浏览器的常见问题与解决方案

背景介绍 在当今互联网时代&#xff0c;网页爬虫已经成为数据获取的重要手段。而Selenium作为一款功能强大的自动化测试工具&#xff0c;被广泛应用于网页爬取任务中。虽然Chrome浏览器是Selenium用户的常见选择&#xff0c;但在某些工作环境中&#xff0c;我们可能需要使用Ed…

运行时数据区

运行时数据区 方法区 Method Area&#xff0c;用于存储已被虚拟机加载的类信息&#xff08;、、&#xff09;、常量、静态变量、即时编译后的代码等数据线程公用类信息 类型信息&#xff1a;类class、接口interface、注解annotation、枚举enum域Field信息&#xff1a;字段名称、…

某MDM主数据管理系统与微软Dynamic CRM系统(新加坡节点)集成案例

一、项目背景 某客户需要将物料和配件等主数据和海外系统进行对接&#xff0c;由SAP PO在中间对接海外系统&#xff0c;进行主数据的下发&#xff0c;方便两端系统之间进行对接&#xff0c;集团统一性管理国内海外数据&#xff0c;提高整体业务效率&#xff0c;保证数据的时…

基于Java中的SSM框架实现在线收银系统项目【项目源码+论文说明】

基于Java中的SSM框架实现在线收银系统演示 摘要 科技的力量总是在关键的地方改变着人们的生活&#xff0c;不仅如此&#xff0c;我们的生活也是离不开这样或者那样的科技改变&#xff0c;有的消费者没有时间去商场购物&#xff0c;那么电商和快递的结合让端口到消费者的距离不…

气膜建筑的抗风与防火性能:保障仓储的安全—轻空间

气膜建筑以其独特的结构和材料优势&#xff0c;为仓储设施提供了可靠的安全保障。在应对自然灾害特别是强风和火灾时&#xff0c;气膜建筑展示了优异的抗风和防火性能。轻空间将详细探讨这些性能及其在实际应用中的表现。 气膜建筑的抗风能力源于其特殊的结构设计和高性能材料。…

ZLM+wvp-pro使用错误记录

这里千万不要写127.0.0.1 在同步国标同步的时候&#xff0c;会出现接口不可达。以下是抓包工具抓的内容 这个时候就很奇怪了&#xff0c;这是为什么呢&#xff0c;这个时候我们通过telnet来判断一下&#xff0c;会发现端口占用&#xff0c;那么这个时候为什么说端口不可达。。。…

一站搞定原型链:深入理解JavaScript的继承机制

目录 一站搞定原型链&#xff1a;深入理解JavaScript的继承机制 一、基本概念 1. 对象与原型 2. 构造函数 二、原型链 三、原型链的终点 四、原型链的构造 1. 创建对象 2. 原型对象的原型 五、继承 1. 原型继承 2. Class 语法糖 六、总结 作者&#xff1a;watermel…

冥想第一千二百四十八天(12478)

1.今天周日&#xff0c;被今天的天气治愈了&#xff0c;空气特别的好。 2.先去游泳了1个小时&#xff0c;中午和家人一起吃饭。 3.下午没再出去了。给溪溪桐桐洗了澡。 4.感谢父母&#xff0c;感谢朋友&#xff0c;感谢家人&#xff0c;感谢不断进步的自己。

Linux应用层开发(7):网络编程

互联网对人类社会产生的巨大变革&#xff0c;大家是有目共睹的&#xff0c;它几乎改变了人类生活的方方面面。互联网通信的本质是数字通信&#xff0c;任何数字通信都离不开通信协议的制定&#xff0c;通信设备只有按照约定的、统一的方式去封装和解析信息&#xff0c;才能实现…

STM32的USB接口介绍

STM32 USB接口是STM32微控制器系列中集成的一种通信接口&#xff0c;它允许STM32微控制器与外部设备或计算机进行高速的数据传输和通信。以下是STM32 USB接口的简要介绍&#xff1a; 1. 接口类型 STM32的USB接口通常支持USB 2.0标准&#xff0c;部分高端型号可能还支持USB 3.…

LVS负载均衡集群部署之—NAT模式的介绍及搭建步骤

一、环境准备 1.准备三台rhel9服务器 服务器名称 主机名 ip地址备注LVS调度服务器lvs.timinglee.org eth0:172.25.254.100&#xff08;外网&#xff09; eth1:192.168.0.100(内网) 关闭selinux和防火墙webserver2网站服务器webserver1.timinglee.orgeth0&#xff1a;192.168.…

一行实现88个群智能算法优化混合核极限学习机HKELM的多特征输入单输出的数据回归预测Matlab程序全家桶

一行实现88个群智能算法优化混合核极限学习机HKELM的多特征输入单输出的数据回归预测Matlab程序全家桶 文章目录 前言一行实现88个群智能算法优化混合核极限学习机HKELM的多特征输入单输出的数据回归预测Matlab程序全家桶 一、HKELM模型1. 极限学习机&#xff08;ELM&#xff0…

【exgcd 扩展欧几里得算法】[ABC340F] S = 1 题解

题意 给定 ( X , Y ) (X,Y) (X,Y)&#xff0c;其中 X , Y X,Y X,Y 为整数。求整数 A , B A,B A,B 使得由 ( 0 , 0 ) , ( X , Y ) , ( A , B ) (0,0),(X,Y),(A,B) (0,0),(X,Y),(A,B) 三个点构成的三角形面积为 1 1 1。 思路 将 ( X , Y ) , ( A , B ) (X,Y),(A,B) (X,Y)…

DC-3靶机打靶练习!!!!

先开始还是老样子我的思路&#xff1a; 外网渗透 信息收集 我们在发现了靶机的ip以及靶机开放了80端口&#xff0c;然后收集到了cms 然后去访问页面发现了是有登录口的&#xff0c;win10虚拟机进行后台目录扫描&#xff0c;主机进行弱口令爆破&#xff0c;kali在使用msf模块进…

Basic‘ attribute type should not be a container解决方法

在使用Spring Data JPA的时候&#xff0c;实体类中定义一个用List修饰的成员ip&#xff0c;IDEA会提示Basic‘ attribute type should not be a container错误&#xff0c;导致编译不通过。 查阅一些博客和文档说是Spring Data JPA这个框架会把实体类的属性当做是MySQL数据库中…