1、背景
C#通过Semantic Kernel可以实现向量存储和检索,向量的存储方式有很多(InMemory、各种专门的向量数据库之类),本次实现以Qdrant向量数据库实现,其他的向量数据库都是一样的。
2、步骤
2.1、下载Qdrant数据库
可以参考如下的文章,进行下载:2025年Windows 11系统下Qdrant向量数据库安装与使用全指南
本机的环境是安装的1.14.1
2.2、下载Ollama并下载模型
Ollama的安装教程网上很多,不在此赘述。
本地环境为:ollama的版本是:ollama version is 0.9.3
本地中模型有:
2.3、下载package
因为需要使用到Ollama和Qdrant向量数据库,所以需要安装相应的package
2.4、代码实现
安装完软件后,创建一个控制台程序,然后引入上面的包后,全部代码如下:
using Microsoft.Extensions.AI;
using Microsoft.Extensions.VectorData;
using Microsoft.SemanticKernel;
using Microsoft.SemanticKernel.Connectors.Qdrant;
using OllamaSharp;
using Qdrant.Client;
var kernelBuilder = Kernel.CreateBuilder();
//1、设置嵌入的模型
IEmbeddingGenerator<string, Embedding<float>> embeddingGenerator = new OllamaApiClient(new Uri("http://localhost:11434"),
"all-minilm");
//2、QdrantClient默认使用的gRPC方式联系,因此端口只能是6334,。
//6333那个http的端口,无法使用
var vectorStore = new QdrantVectorStore(new QdrantClient("localhost",6334,false), ownsClient: true, new QdrantVectorStoreOptions
{
EmbeddingGenerator = embeddingGenerator
});
//3、创建一个collection,并进行初始化
var collection = vectorStore.GetCollection<ulong, Movie>("movies");
await collection.EnsureCollectionExistsAsync();
//4、把数据进行初始化
//其中,我们是讲描述进行了向量化,并保存到向量数据库中
var movieData = new List<Movie>()
{
new Movie
{
Key=0,
Title="Lion King",
Description="The Lion King is a classic Disney animated film that tells the story of a young lion named Simba who embarks on a journey to reclaim his throne as the king of the Pride Lands after the tragic death of his father."
},
new Movie
{
Key=1,
Title="Inception",
Description="Inception is a science fiction film directed by Christopher Nolan that follows a group of thieves who enter the dreams of their targets to steal information."
},
new Movie
{
Key=2,
Title="The Matrix",
Description="The Matrix is a science fiction film directed by the Wachowskis that follows a computer hacker named Neo who discovers that the world he lives in is a simulated reality created by machines."
},
new Movie
{
Key=3,
Title="Shrek",
Description="Shrek is an animated film that tells the story of an ogre named Shrek who embarks on a quest to rescue Princess Fiona from a dragon and bring her back to the kingdom of Duloc."
}
};
//5、将描述向量化,并保存到数据库中
foreach (var movie in movieData)
{
movie.Vector = await embeddingGenerator.GenerateVectorAsync(movie.Description);
await collection.UpsertAsync(movie);
}
//6、以上,完成了数据的保存
//从本布开始,进行数据检索。先将查询条件进行向量化
var query = "A family friendly movie";
var queryEmbedding = await embeddingGenerator.GenerateVectorAsync(query);
//7、在向量中查询数据
//SearchAsync方法的第二个参数是,希望能获取几个结果。现在是2个结果
var results = collection.SearchAsync<ReadOnlyMemory<float>>(queryEmbedding, 2);
//8、将结果展示出来
await foreach (var result in results)
{
Console.WriteLine($"Key: {result.Record.Key}, Text: {result.Record.Title}");
}
Console.ReadLine();
//定义数据类型
public class Movie
{
[VectorStoreKey]
public ulong Key { get; set; }
//title和Description是payload
[VectorStoreData]
public string? Title { get; set; }
[VectorStoreData]
public string? Description { get; set; }
[VectorStoreVector(384, DistanceFunction = DistanceFunction.CosineSimilarity, IndexKind = IndexKind.Hnsw)]
public ReadOnlyMemory<float> Vector { get; set; }
}
2.5、实现效果
3、总结
这里面的版本不太稳定,方法变化挺多。调试费劲。