关于 Vearch 在大模型中使用的一些实践
背景
这两年来大模型及其热门,不仅各大厂家的模型层出不穷,各类 RGA、Agent 应用也花样繁多。这也带火了一批基础设施,比如 Langchain、向量数据库(也叫矢量数据库-Vector Database)等。现在市场上的向量库种类特别繁多,但主要还是分为两类,一类是在原有数据库基础上增加了向量相似性检索的能力,比如 ES、Redis 等等;还有一类就是生而为向量库,比较有名的比如 Qdrant、Pinecone 等等。最近我们在开发一个基于大模型的测试用例生成的应用,检索采用向量库+知识图谱的混合检索方式。在调研向量数据库时,发现公司有类似的产品,也就是 Vearch。并且这款产品开源比较早,也比较成熟,目前已集成到 Langchain 框架中,所以我们也采用了集团部署的 Vearch。这样可以免去部署的烦恼,最重要的是不需要我们去找 GPU 资源😩(向量计算 GPU 更为高效,Vearch 也支持 CPU 计算)。
浅引
Vearch 诞生之初,主要是用在深度学习上,可以进行海量数据的近似检索。后来大模型开始流行,问答机器人此类应用变得广泛。使用时,只要将问题 &答案或者一段文本录入库中,通过检索问题文本向量,即可返回近似文本内容。关于 Vearch 的底层架构及原理,这里不再讲述(之前 Vearch 的元老在神灯已经写了很多文章了,感兴趣的可自行搜索)。Vearch 的核心存储及检索引擎是 Gamma(哎?看到这个是不是很眼熟哇,那个模型叫 Gemma,不是一个东西哈),主要负责向量的存储,索引与检索。它是基于 Faiss(脸书的向量聚类库)中的 SIMD 指令实现(这是 Vearch 的先驱们写的原始论文 https://arxiv.org/abs/1908.07389)。相比于 Faiss,Vearch 最大的能力是在于对分布式的支持,所用的算法称为分布式最邻近搜索,它在原始 KNN 基础上集成了更多的能力(可参考: https://towriting.com/blog/2021/10/07/vearch/ )。关于更底层使用的余弦计算、KNN(最邻近搜索)等概念,就不在本篇范围内了。
这里再简单说两句,大模型为什么要用向量检索库(一个点铺开都有很多内容😢)。最近有一种项目比较流行,就是知识库,它是基于大模型能力的一种扩展。因为目前大模型存在两个问题,其一对于专属领域的知识理解不好,容易幻觉举个栗子,你问 GPT 关于京东营销中心的业务,它就只能自己捏造了;其二,它的训练数据存在滞后性,做不到对最新知识的理解。当然你要是有资源,也可以用这些知识去对模型进行微调,但对于我们这种一点资源没有的用户来说,这不是最优解。所以聪明的人们就整出了一套叫 RAG 的技术(检索增强生成),通过预检索提前录入的向量化知识,将检索的内容嵌入到问题的提示词模板中,这样传给大模型后,以更准确的获取答案。这里又涉及到一个概念了-嵌入(Embedding),这里不细说了,因为涉及到向量化,后面会简单说明,本篇主要还是讲 Vearch 的使用。
项目简述
大模型火热了这么久,我们也在积极研究如何应用到测试上,并给测试提效。结合我们营销中心、策略等系统繁杂业务的特性,希望有一种可以一键输出测试用例的能力,这样可以帮助我们节省用例编写的时间。而这之前,我们先需要完成知识库(业务知识、测试经验、系统上下)的建立,包括知识文档的整理、知识的录入与检索,知识图谱的创建等等。有了 RGA,我们就可以根据知识库以及给定的需求文档,进行测试用例生成。

目前我们的项目还在开发中,所以本篇的目的在于借助该项目介绍其中的一块--向量数据库 Vearch 的使用。
集群库创建
Vearch 架构,它由三部分组成 Master、Router、Ps。Master 负责集群元数据的管理和资源的协调分配;Router 负责请求路由转发及结果合并;Ps 用于存储和检索向量。Vearch 目前已经集成到泰山,在使用前需要先申请一个集群库,从集群列表中可以看到,每个部分默认有三台机器,确保高可用。

然后它有两个地址,一个 Master 地址,一个 Router 地址。
Master 地址:用于库表维度的创建、删除等
Router 地址:用于数据维度的插入、删除、检索等,不过现在也已兼容旧版本的 Master,所以表操作直接用 Router 也没问题。
需要知道的是,目前 Vearch 暂未支持表结构修改能力,但新版本已经在支持中。
功能导入
因为我们的项目使用 Langchain 开发,而且 Vearch 以及集成进去了,所以刚开始我们使用的就是 Langchain 的版本
这个版本比最新开源的 SDK 版本略旧,只支持固定字段,但是最新的开源版本已经兼容多字典。跟 Vearch 的同学讨论后,决定还是直接导入 Github 上开源的最新 SDK,将下面这个文件内容复制到项目工程目录下就行。

然后从本地的 Vearch 文件引用即可。
表空间创建
Vearch 将操作全都封装成了接口,所以并不需要写类似 SQL 那样的语句。我们现在要创建一个名为 delta_llm_embedding 的表,可以通过两种方式:
自定义建表
可以在泰山的操控台进行操作,或在你的本地 dos/MACshell 的中控台进行操作。这里不分别截图演示了,毕竟不是写操作手册。本地建表语句如下:
上面的字段意思官方文档里都有(https://vearch.readthedocs.io/zh-cn/latest/),这里就不一一解释了。需要重点说的是两点,一点是字段名,我们定义了两个字段,一个是文本字段 text,一个是向量字段 text_embedding。至于为什么用这两个名称也是踩过的坑,才知道有多深,稍后说。另外一点就是 dimension,这个是向量维度,理论上来讲维度越高,召回越精准。但这个数据完全依赖于你的嵌入模型所能输出的维数,因为我们用的 Openai 的 Embeddings 模型:text-embedding-ada-002,看下图

我们再说下为什么那两个字段名(文本字段 text,向量字 text_embedding)要这么取,先看下 Vearch 的 SDK 源码,在插入数据的那段是这么写的:
可以看到两个字段名是写死的,这也是一开始我们建表的字段名跟这个并不一致,导致我们花了不少时间来跟 Vearch 的同学排查问题的原因。至于 SDK 里为什么会这么写,原因是基于已有 Vearch SDK 以及 Langchain 的规定,必要字段被指定,其他字段可根据用户需要自适应设置。
vearch_cluster 初始化
如果你一开始不去自行建表,而是直接在工程代码中使用 SDK 的初始化能力,则可以采用该种方式,这种方式你并不需要关注表结构,vearch_cluster 会自行初始化一个表,你只需要告诉它表名即可。
如果自行建表,我们可以任意建字段,想存什么就存什么,但是带来的问题就是没法使用 vearch_cluster 进行初始化检索,除非你的字段是一致的。如果你预建好了表,字段也正确,那么 vearch_cluster 在初始化时,它会跳过建表这一步,直接插入数据,或进行检索。至于 vearch_cluster 初始化时,建表字段为什么只有这两个,那是因为早期这个 SDK 是给问答机器人使用的,那时候并没有考虑到后面在其他地方的使用,当然现在新版本已经在路上了。好了,创建就说这么多吧,至于删除,可以自行查询官方文档,进行操作。
数据存储
现在我们知道建表时有两个字段,一个是文本字段,一个是 Embedding 字段,也就是向量数据字段。在浅引里已经说过,Vearch 本身只提供存储及检索能力,所以向量化是需要依赖外部工具来完成的。过程就是:文本块>Embedding>存储>检索。当然这之前,我们需要对文档进行切割,将文档按照一定的规则切割成文本块。这部分本篇就不细说了,不然就跑题了。
我们项目使用的是 Openai 的 Embeddings 模型,从上面的 vearch_cluster 初始化对象中可以看出,我们使用的模型是 Openai 的 text-embedding-ada-002。在初始化时,它会调用 OpenAIEmbeddings 这个类完成对 texts 文本的向量化,并进行建表落库。OpenAIEmbeddings 是 Langchain 集成的 Openai 调用的能力。当然你也可以不使用 vearch_cluster 的 from_documents 方法,自己定义一个向量化方法,当然这会带来额外的工作量,需要自己写数据落库的方法(调 Vearch 的相关接口)。
比如,现在有一小段文本:营销中心, 将它嵌入后 Openai 的 Embeddings 模型会返回一个长度是 1536 的数组:
然后调用 Vearch 的数据写入接口(这里如果使用 SDK 的初始化,就不用自己写存储了,vearch_cluster 都帮你做了)。落库时「营销中心」写入 text 字段,数组写入 text_embedding。这里需要注意的是,数组的长度要跟建表时的维度一致,否则数据写入失败。如果写入成功,我们会收到这样的返回:
这里的_id,就是记录的唯一 id 了,我们可以通过它检索到这条详细的数据。在中控台里执行这个接口:
这里简单拓展下 Embedding,翻译过来是嵌入,或者词嵌入。这是个有点让人头秃的名词。之前有人说过“没有思考过 Embedding,不足以谈 AI”,可见它在 AI 领域的重要性。当然如果不理解,也不影响我们的使用。
关于这个词,维基的解释是指把一个维数为所有词的数量的高维空间嵌入到一个维数低得多的连续向量空间中,每个单词或词组被映射为实数域上的向量。
好吧,更不好理解了。这句话的核心是将高维的对象映射到低维的空间,Embedding 就是将一个离散的词映射成一个 N 维的数组向量,这组向量表示的是一个连续的数值空间中的点,也就是空间位置。说白点,就是将自然词通过向量化,嵌入到计算机的语言模型中,这个模型是它对人类语言对象的理解。鄙人能力有限,就不做继续深入了。
人工智能的奥义是「万物皆可 Embedding」,不管是图片、文本、对象还是什么,都可以嵌入。这个技术它主要用在机器学习以及自然语言处理中,因为自然语言语意复杂多变,要想让计算机理解人类语言却不是一件简单的事。词与词之间的相关性通过距离进行量化,我们可以想象一堆词语,计算机在空间维度上对其进行聚类,词义相近的放一起,不相近的远离,所有词语之间都有一个方向和距离。最后检索时,通过这些向量进行余弦计算,得出排序分数。
数据检索
现在我们将文档「营销运营策略业务全景介绍」录入知识库中,我们需要根据问题进行内容检索。Vearch 目前支持两种检索方式,文本检索、向量检索。
文本检索
这里我们使用了官方提供的 similarity_search 方法进行检索
我们看下这个方法,通过传入需要检索的问题内容,先对其进行向量化,然后再调了向量化的检索方法 similarity_search_by_vector,通过计算向量的余弦值,对文本块做一个整体的排序,然后召回前 k 个文本。
因为每次检索时,都是一次余弦计算,而维度越多,则计算消耗越大。
检索后,获得了如下内容:
营销运营策略是基于商品、券、内容等多维度的调控策略平台,支持各种营销活动。目前主要包含商品调控策略、权益调控策略、百补风控策略和内容调控策略...
注意这里检索的内容只是从 Vearch 中检索到的内容,并非大模型返回的内容。我们拿到这个检索的文本后,还需要将它嵌到提示词模板中,进行模板格式化后传给大模型,达到对大模型进行知识补充的目的。
向量检索
向量检索调用,跟上面的文本检索就类似了,只是使用的方法是 similarity_search_by_vector,这也是上面文本检索中所调用的方法,当然参数也就变成了向量化的文本。
关于这个方法,这边就不细说了,属于 Vearch 的核心能力,想研究的可以看源代码,自行查询(https://github.com/vearch/vearch/blob/master/sdk/integrations/langchain/vearch.py)。
总结
以上主要就是我们在该项目中所使用的 Vearch 主要能力,即存储跟检索。从整体使用感受来讲,功能基本满足要求,性能也不差,上手难度也不高,关键还开源。但是相比于外面已经完全实现平台化的商业产品来说,因为 Vearch 所有的能力都是接口封装的,写数查询这些日常操作略有麻烦,对于咱们用惯了关系数据库的新手来说稍有不适。
另外在调研 Vearch 时,发现已有不少业务团队将 Vearch 用于业务能力上,比如推荐、查重等。虽然目前营销中心的业务模块并未用到该产品,但对于我们来说是一种知识与技能拓展,并对后续的测试给出新的视野和思路。
作者:京东零售 倪绍峰
来源:京东云开发者社区
版权声明: 本文为 InfoQ 作者【京东科技开发者】的原创文章。
原文链接:【http://xie.infoq.cn/article/b02380ec30004aca2dc373847】。文章转载请联系作者。
评论