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接口:

代表了一种生成浮点类型文本嵌入的生成器。
再看看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接口:

说明我们只要实现了
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 SKEXP0001
public 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 SKEXP0001
public 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简单做了个界面,来试试效果。
找了一个新闻嵌入:

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

现在测试RAG效果:



回答的效果也还可以。
大模型使用的是在线api的Qwen/Qwen2-72B-Instruct,嵌入模型使用的是本地Ollama中的mxbai-embed-large:335m。
SemanticKernel/C#:实现接口,接入本地嵌入模型的更多相关文章
- 循序渐进BootstrapVue,开发公司门户网站(5)--- 使用实际数据接口代替本地Mock数据
在我们开发一些门户网站功能的时候,有时候我们需要快速的创建数据模型来进行数据展示,因为数据结构可能处于不断的修正变化之中,因此服务端的接口我们可以暂时不开发,当我们基本完成数据结构和界面展示的时候,就 ...
- 微信SDK开发——接口接入
园子里面很多关于微信接口开发的文章,Github也一堆的开源代码. 官方文档地址:http://mp.weixin.qq.com/wiki/home/index.html 接下来主要以代码为主,接口说 ...
- ACM MM | 中山大学等提出HSE:基于层次语义嵌入模型的精细化物体分类
细粒度识别一般需要模型识别非常精细的子类别,它基本上就是同时使用图像全局信息和局部信息的分类任务.在本论文中,研究者们提出了一种新型层次语义框架,其自顶向下地由全局图像关注局部特征或更具判别性的区域. ...
- webpack正式、测试环境接口地址本地运行及打包命令配置
声明:本文由w3h5原创,转载请注明出处:<webpack正式.测试环境接口地址本地运行及打包命令配置> https://www.w3h5.com/post/521.html 为了方便开发 ...
- 配置交换机Trunk接口流量本地优先转发(集群/堆叠)
组网图形 Eth-Trunk接口流量本地优先转发简介 在设备集群/堆叠情况下,为了保证流量的可靠传输,流量的出接口设置为Eth-Trunk接口.那么Eth-Trunk接口中必定存在跨框成员口.当集群/ ...
- 华为S5300交换机配置基于接口的本地端口镜像
配置思路 1. 将Ethernet0/0/20接口配置为观察端口(监控端口) 2. 将Ethernet0/0/1----Ethernet0/0/10接口配置为镜像端口 配置步骤 1. 配置观察端 ...
- xddpay.com 个人支付接口接入流程
作为一个独立开发者产品需要支付接口是挺麻烦的,支付宝微信都不对个人开放,注册公司维护成本太高,市面上各种收款工具要么手续费太高,要么到账很慢,体验很不好. 看到 「小叮当支付」 这个收款工具,挺有意思 ...
- php短信验证码接口接入流程及代码示例
对于绝大部分企业来说,所使用的短信验证码接口都是第三方短信服务商所提供,目前市场上短信服务商有很多,在此向大家推荐一家动力思维乐信,运营13年,值得信赖! 就拿动力思维乐信短信验证码接口为例,详细介绍 ...
- BufPay.com 个人收款接口 接入步骤
作为独立开发者产品需要收款是非常麻烦的,注册公司维护成本太高,市面上各种收款工具要么手续费太高,要么到账很慢,体验很不好. 看到 「BufPay.com 个人收款」 这个收款工具,挺有意思的.原理是监 ...
- 用PHP调用证件识别接口识别本地图片
前置条件 在开始前,请作如下准备:1.学会用PHP输出“Hello World” 2.去聚合数据申请证件识别专用的KEY:https://www.juhe.cn/docs/api/id/153 操作步 ...
随机推荐
- Jenkins发布服务报错Fatal error: put encountered an exception while uploading磁盘空间不足处理 No space left on device
Jenkins发布服务报错Fatal error: put encountered an exception while uploading磁盘空间不足处理 No space left on devi ...
- jqurey基础知识和常用事件方法
样式文件不需要<style>标签 引用style文件的方法 <link href="main.css" rel="stylesheet" st ...
- Springcloud开发之OpenFeign调用和认证
SpringCloud开发cloud具有巨大的灵活性. 在调用其它服务的时候有多种方式,虽然本质一样,但是细节还是有所差异. 一.概述 当a服务调用b服务的时候有多种方式进行: 1.通过openFei ...
- STM32 学习:IAP有关介绍
--- title: mcu-stm32-IAP-0-about date: 2020-05-27 08:51:58 categories: tags: - iap - stm32 - about - ...
- 福利来了!MoneyPrinterPlus可以自动配置环境和自动运行了
之前开源了MoneyPrinterPlus,可以实现批量混剪视频,一键生成视频和自动发布视频的功能. 但是经常会看到小伙伴在安装过程中遇到很多问题.所以这篇文章的目的就是告诉大家怎么使用MoneyPr ...
- P9576 题解
赛时没仔细想,赛后才发现并不难. 将 \(l,r\) 与 \(l',r'\) 是否相交分开讨论. 假若不相交,那么 \(l',r' < l\) 或者 \(l',r' > r\) 并且 \( ...
- Redis常见的16个使用场景
1.缓存 String类型 例如:热点数据缓存(例如报表.明星出轨),对象缓存.全页缓存.可以提升热点数据的访问数据. 2.数据共享分布式 String 类型,因为 Redis 是分布式的独立服务,可 ...
- Nginx常用操作
Nginx Nginx的最重要的几个使用场景 静态资源服务,通过本地文件提供服务 反向代理服务,延伸出包括缓存,负载均衡等 API服务,OpenResty 相关概念 简单请求和非简单请求 请求方法是H ...
- docker-compose创建haproxy教程
本文主要讲解通过docker-compose创建haproxy并进行代理 一.haproxy简介 HAProxy是一款基于事件驱动.单进程模型设计的四层与七层负载均衡器,它能够在TCP/UDP层面以及 ...
- react-devtools安装以及使用中的问题
使用react框架开发的小伙伴肯定都想使用想vue-devtools开发工具一样,可以看见组件的状态,和当前组件里的props,data等等. 当然react也有一个开发者工具,现在废话少说,开始安装 ...