先祝大家 2025 新年好。

在 2024 年落地的 LLM 应用来看,基本上都是结合 RAG 技术来使用的。因为绝大多数人跟公司是没有 fine-turning 的能力的。不管是在难度还是成本的角度看 RAG 技术都友好的多。

在 RAG(Retrieval-Augmented Generation)中,向量的意义在于将文本数据转换为高维向量表示,以便进行高效的相似性搜索和信息检索。具体来说,向量在 RAG 中的作用包括:

文本嵌入:将文本数据(如用户查询、文档内容)转换为向量表示。这些向量捕捉了文本的语义信息,使得相似的文本在向量空间中距离较近。

相似性搜索:通过计算向量之间的距离(如余弦相似度),可以快速找到与查询向量最相似的文档向量,从而实现高效的信息检索。

增强生成:在生成式模型(如 GPT)生成文本时,利用检索到的相关文档向量作为辅助信息,提高生成结果的相关性和准确性。

使用 SK 对向量进行存储与检索

如果要使用 RAG 技术,基本上离不开对向量进行存储,检索等基础操作。好在 SK 已经为我们全都封装好了。以下让我们看看如何使用 SK 来玩转向量。

定义 User Model 类

定义 User Model 类用来描述数据结构。使用 VectorStoreRecordKeyAttribute 指示 key 字段,使用 VectorStoreRecordDataAttribute 指示数据字段,VectorStoreRecordVector 指示向量字段。

        public class UserModel
{
[VectorStoreRecordKey]
public string UserId { get; set; } [VectorStoreRecordData]
public string UserName { get; set; } [VectorStoreRecordData]
public string Hobby { get; set; } public string Description => $"{UserName}'s ID is {UserId} and hobby is {Hobby}"; [VectorStoreRecordVector(1024, DistanceFunction.CosineDistance, IndexKind.Hnsw)]
public ReadOnlyMemory<float>? DescriptionEmbedding { get; set; } }

SK 为我们提供了 IVectorStore 接口。这样各种向量存储的方案只要实现这个接口就可以了。 SK 为我们提供了很多 out-of-the-box 的库,比如:InMemory, Redis, Azure Cosmos, Qdrant, PG。只要通过 nuget 安装就可以使用了。

下面我们使用 Redis 作为向量数据库给大家演示。

使用 docker 安装 redis stack server

默认 redis 是不支持向量搜索的,我们需要使用 redis/redis-stack-server:latest 这个镜像。

docker run -d --name redis-stack-server -p 6379:6379 redis/redis-stack-server:latest

初始化 RedisVectorStore

 var vectorStore = new RedisVectorStore(
ConnectionMultiplexer.Connect("localhost:6379").GetDatabase(),
new() { StorageType = RedisStorageType.HashSet });

初始化 collection

创建一个 collection 来存储用户信息。collection 可以认为就是关系数据库里的 表。

  // init collection
var collection = vectorStore.GetCollection<string, UserModel>("ks_user");
await collection.CreateCollectionIfNotExistsAsync();

初始化 EmbeddingGenerationService

以下还是使用本地的 ollama 服务提供 embedding generation 服务。这个服务是所有 text to vector 的核心。

 // init embedding serivce
var ollamaApiClient = new OllamaApiClient(new Uri(ollamaEndpoint), modelName);
var embeddingGenerator = ollamaApiClient.AsTextEmbeddingGenerationService();

Vector CRUD

以下代码演示了如何把 User 的 Description 字段转成 vector 后进行最基本的 Insert、Update、Delete、Get 操作。

// init user infos and vector
var users = this.CreateUserModels();
foreach (var user in users)
{
user.DescriptionEmbedding = await embeddingGenerator.GenerateEmbeddingAsync(user.Description);
}
// insert or update
foreach (var user in users)
{
await collection.UpsertAsync(user);
} // get
var alice = await collection.GetAsync("1");
Console.WriteLine(alice.UserName);
var all = collection.GetBatchAsync(users.Select(x=>x.UserId));
await foreach(var user in all)
{
Console.WriteLine(user.UserName);
} // delete
await collection.DeleteAsync("1");

Vector Search

以下演示了如何进行向量相识度搜索。先把问题的文本进行一次向量生成,然后使用这个向量进行搜索。搜索的时候可以配置匹配的字段,以及取前几个结果。

// search
var vectorSearchOptions = new VectorSearchOptions
{
VectorPropertyName = nameof(UserModel.DescriptionEmbedding),
Top = 3
};
var query = await embeddingGenerator.GenerateEmbeddingAsync("Who hobby is swimming?");
var searchResult = await collection.VectorizedSearchAsync(query,vectorSearchOptions);
await foreach (var user in searchResult.Results)
{
Console.WriteLine(user.Record.UserName);
Console.WriteLine(user.Score);
}

总结

以上我们演示了如何把数据模型向量化后配合 redis 进行 CRUD 的基本操作。同时还演示了把文本问题的向量化搜索,也就是相似的检索。虽然以上演示是配合 redis 运行的,但是 SK 还给我们提供了非常多的选择,你可以快速的选择你喜欢的向量数据库进行存储。比如:Azure Cosmos, Qdrant, PG, SQLite 等等。好了,也没啥可以多说的了,希望这篇文章能帮助到大家学习 SemanticKernel, 谢谢。

示例代码已上传到 github

https://github.com/kklldog/SKLearning

使用 SK 进行向量操作的更多相关文章

  1. OpenMesh 之向量操作

    OpenMesh 提供了许多可供使用的向量操作函数,使用特别方便. 计算距离: 从官方文档可以看到OpenMesh提供了5个函数,分别为 Scalar length() const        // ...

  2. C++ code:向量操作之添加元素

    读入一个文件aaa.txt的数据到向量中,文件中是一些整数(个数未知).要判断向量中的元素有多少个两两相等的数对. 代码如下: #include<iostream> #include< ...

  3. ca75a_c++_标准IO库-利用流对象把文件内容读取到向量-操作文件

    /*ca75a_c++_标准IO库习题练习习题8.3,8.4,8.6习题8.9.8.10 ifstream inFile(fileName.c_str());1>d:\users\txwtech ...

  4. matlab 向量操作作业

    写出下列语句的计算结果及作用 clear    清除所有变量 clc    清屏 A = [2 5 7 1 3 4];    创建行向量并赋值 odds = 1:2:length(A);    冒号操 ...

  5. C++ STL中vector(向量容器)使用简单介绍

    原文:http://www.seacha.com/article.php/knowledge/cbase/2013/0903/2205.html C++ vector(向量容器)是一个线性顺序结构.相 ...

  6. 【转】C++ Vector(向量容器)

    转自:https://blog.csdn.net/studentyyl/article/details/21177445 vector是一个线性顺序结构.相当于数组,但其大小可以不预先指定,并且自动扩 ...

  7. 【足迹C++primer】32、定制操作_2

    版权声明:本文为博主原创文章.未经博主同意不得转载. https://blog.csdn.net/cutter_point/article/details/32301839 定制操作_2 完整的big ...

  8. Eigen子矩阵操作

    1 子矩阵操作简介 子矩阵操作又称块操作,在矩阵运算中,子矩阵的提取和操作应用也十分广泛.因此Eigen中也提供了相关操作的方法.提取的子矩阵在操作过程中既可以用作左值也可以用作右值. 2 块操作的一 ...

  9. [OpenCV-Python] OpenCV 核心操作 部分 III

    部分 III核心操作 OpenCV-Python 中文教程(搬运)目录 9 图像的基础操作 目标 • 获取像素值并修改 • 获取图像的属性(信息) • 图像的 ROI() • 图像通道的拆分及合并几乎 ...

  10. R语言多元素向量

    使用冒号运算带有数值数据(数值的增加为1) # Creating a sequence from 5 to 13. v <- 5:13 print(v) # Creating a sequenc ...

随机推荐

  1. eShopOnContainer 中 unauthorized_client error 登录错误处理

    在准备好 eShopOnContainer 环境,运行起来之后,不幸的是,我遇到了不能登录的错误. 从错误信息中,可以看到 unauthorized_client 的内容.这是为什么呢? 从 eSho ...

  2. Java调用与发布Webservice接口(一)

    ​ 一  准备工作 (一)开发环境 demo以springboot为基础框架,使用到了httpclient.hutool等依赖,详情如下:         springboot版本: org.spri ...

  3. Base64解码、Base64编码、Base64加密解密规则

    转换规则:进行Base64转换的时候,将3个byte(3*8bit = 24bit)的数据,先后放入一个24bit的缓冲区中,先来的byte占高位.数据不足3byte的话,于缓冲器中剩下的bit用0补 ...

  4. trim-all-strings-elements-in-a-complex-object

    package com.xxx.common.util; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.Strin ...

  5. Qt/C++地图导航app/支持qml/手机运行/输入起点终点规划路径/模拟轨迹移动

    一.前言说明 搞Qt地图开发这块,随着研究的深入,用户的需求变化,最近又需要在手机上运行,由于本地图组件依赖浏览器控件,而手机安卓上的Qt并没有带qwebengine控件,怎么办呢,不断的努力验证下, ...

  6. Qt编写安防视频监控系统62-子模块6预置位

    一.前言 预置位功能,只对带有预置位的球机才起作用,有云台的球机未必有预置位,要仔细查看清楚,不清楚可以询问厂家或者查阅手册,在本模块中,可以获取预置位.添加预置位.调用预置位.删除预置位.调用起始位 ...

  7. CSP-J2/S2 2024 游记

    前情提要:CSP-J/S 2023 写这篇文章的时候,心情比较复杂. 哎,结局还算圆满. 初赛 之前那个写的不好再写一遍() 两个都在 WFLS,也就是本校考 qaq. J 在大礼堂考,没啥好说的,太 ...

  8. IM跨平台技术学习(六):网易云信基于Electron的IM消息全文检索技术实践

    本文作者网易云信高级前端开发工程师李宁,本文有修订. 1.引言 在IM客户端的使用场景中,基于本地数据的全文检索功能扮演着重要的角色,最常用的比如:查找聊天记录.联系人等. 类似于IM中的聊天记录查找 ...

  9. JVM实战—10.MAT的使用和JVM优化总结

    大纲 1.线上大促活动导致的老年代内存泄漏和FGC(MAT分析出本地缓存没处理好) 2.百万级数据误处理导致频繁FGC(大数据量加载到内存处理 + String.split()) 3.JVM运行原理和 ...

  10. 重温Go语法笔记 | 结构体

    结构体 多个任意类型聚合成的复合类型 1.字段拥有自己的类型和值 2.字段名必须唯一 3.字段可以是结构体 结构体的定义是一种内存布局的描述 只有实例化才会真正分配内存,必须实例化之后才能使用结构体的 ...