向量数据库:高效检索与大语言模型的融合

857 阅读13分钟

简介

上一篇文章中,我们探讨了大语言模型的局限性,其中很重要的一点就是大语言模型对 tokens 的限制,这个限制使得我们在开发大语言模型应用时面临很多顾虑。

有问题就有答案,向量数据库就是解决这个问题的方式之一。

什么是向量数据库?

img.png

在数学中,向量是一个有序的数值序列。例如,二维平面中的一个点的位置可以用两个实数的向量(x, y)来表示。同理,三维空间中的点可以用(x, y, z)表示。 而在计算机科学中,这些点可以表示为事务的特征或属性,向量数据库就是用来存储这些点的特征或属性的。

向量数据的来源

我们刚才说了,向量数据库存储的这些"点"其实是事务的特征,那么具体是指什么呢?

假设我们是一个犬类动物爱好者,我们可以通过体型大小、毛发长度、鼻子长短等特征为狗狗分类,那么如果将犬类的体型大小、毛发长度用二维向量记录下来,就是下面这个样子:

img_1.png

X轴表示犬类体型,取值范围从大到小为0到1。

再加上毛发长度的Y轴,就是下面的样子:

img_2.png

接下来,我们再延伸到三维坐标系,将犬类鼻子的长短记录到Z轴,便得到了下面的三维向量数据:

img_3.png

于是乎我们就得到了基于犬类体型大小、毛发长度等鼻子长短等特征的三维向量特征点,也就是x、y、z轴的坐标,这些数据便是向量数据,存储到向量数据库。

向量数据库有了这些数据,便可以提供向我们的向量检索。例如,我们想养一只与哈士奇相似的狗,那么会推荐金毛(0.6,0.65,0.66), 而不会推荐泰迪(0.1,0.45,0.23)。

更高维度的向量数据

当然了,我们不能只根据三个特征就推荐你养哪只狗狗,很明显这样不够精确。那么我们可以将犬类更多的特征,例如眼睛大小、服从性、攻击性等用向量数据记录下来。

也许你很难想象这些数据记录到四维、五维空间会是什么样子,但这不重要,我们只需要知道这些特征换成向量数据就是在向后面追加数字即可,例如:(0.53,0.4,0.75,0.11,0.23,……)

img_4.png

我们可以用这种方式表示所有事物,不管是具象的还是抽象的,例如,一段话、一张照片、喜怒哀乐、悲欢离合。而且数据的维度越高,描述的数据就越精确。

img_5.png

如上图,OpenAI 的文本向量模型 text-embedding-ada-002 可以输出 1536 维的数据。实际上在真实的生产环境中,上千的向量维度和上亿的向量数据都是正常的。

向量数据的检索算法

ANN算法

ANN(相似最近邻搜索)算法是一种用于在大规模数据集中快速找到一个或多个近似最近邻的技术。ANN算法的类型很多,它们采用不同的技术实现和策略来在大规模数据集中加速最近邻搜索。

例如:Flat、k-means、LSH等等。相似最近邻搜索问题是向量数据库产品的核心,一个成熟的向量数据库通常集成了多种ANN算法,并在搜索时综合各种指标选择最合适的策略来利用这些算法。

Flat

关于搜索我们首先能想到的就是遍历搜索,遍历比较目标点,最终找个你想要的数据,这种方式就是 Flat 的实现逻辑,即:暴力搜索、平推遍历。 Flat 虽然很精确,但它的短板也很明显,那就是因为要遍历比较数据,它的检索速度非常慢,在海量数据线我们一般不会使用它。

我们会考虑另外一种算法:聚类算法

k-means

聚类算法的原理是:将数据集中的样本划分为若干组,使得同一组内的样本彼此相似,而不同组之间的样本差异较大。

聚类算法的种类有很多,k-means 是其中最常见的算法。k-means 对数据的处理如下图,在搜索时我们只需要找出查询向量最近的哪个质心, 然后在这个质心的簇中查找数据即可,达到缩小搜索范围的目的。

img_12.png

就像Flat算法,聚类算法k-means也有自己的缺点,例如下图:虽然查询的向量距离他最近的向量点在质心B的簇里,但由于它距离质心近A更近,这种情况下就只能搜索到A簇的数据。

img_13.png

解决上面的问题的方式很多,例如:K-Means++ 初始化、谱聚类、层次聚类、DBSCAN 等。

或者我们换一个算法 -- 位置敏感Hash算法来改善查询。

LSH

位置敏感Hash算法(LSH)使用一组哈希函数将相似向量映射到“桶”中,从而使相似向量具有相同的哈希值,这样,就可以通过比较哈希值来判断向量之间的相似度。

img_7.png

LSH 算法也有它的不足,例如在大型数据集中使用随机投影算法获取hash值时,生成质量好的随机的投影矩阵计算成本会很高。

其他算法

此外还有很多算法,他们有各自的优点和短板,例如:

ANN-基准

ANN-基准是一种用于评估各种向量数据库和近似最近邻(ANN)算法性能的工具。

  • 数据集和参数规格:ANN 基准提供大小、类型、维度不同数据集。每套数据集匹配一套参数,如:检索的最近邻数量、使用的距离计算公式等。
  • 计算召回率(search recall):ANN 基准计算召回率,即返回的 k 个近邻中包含真正最近邻的比例。召回率是用于评估系统向量检索准确性的重要指标。
  • 计算 RPS:ANN 基准还可以计算 RPS(或者也叫 QPS,query per second),即向量数据库和 ANN 算法处理 query(查询请求)的速度。RPS 是用于评估系统速度和可扩展性的重要指标。

我们可以使用 ANN 基准,在同一条件下比较不同向量数据库和 ANN 算法的性能,从而更快速找到最合适的选择。

小结

从上面的例子我们可以看出,算法并非解决问题的"银弹",每种算法都有自己的优势的短板,我们在使用时需要根据实际情况加以区分。 此外ANN算法也是向量数据库产品的核心,你可以用ANN-基准来对向量数据库做评估,找到你需要的产品。

向量数据库产品

img_9.png

随着这一轮人工智能的热潮,向量数据库的热度也从年初一直延续直径。目前市面上的向量数据库产品以及很丰富了。

我们可以将它们”向量化“做一个比较分类,直观的看一下他们的特征。

将他们按照本地部署和云部署分类如下:

img_8.png

按照实现方式、开源程度可以做如下区分:

img_10.png

每种向量数据库支持的搜索算法也不尽相同:

img_11.png

除此之外,在实际的业务场景中,向量数据库选型中,你还需要关注如下问题:

  • 分布式能力:CAP如何取舍的,可用性和稳定性如何。
  • 支持的数据类型和维度:确保向量数据库支持你的数据类型和维度。有些数据库可能更适合特定类型的数据,如文本、图像或数值型数据。
  • 可扩展性: 确认向量数据库的可扩展性。考虑到项目可能的增长,确保数据库可以有效地处理大量的数据和查询请求。
  • API和集成: 评估数据库的API和集成能力。确保数据库可以轻松地集成到你的应用程序中,并且提供方便易用的API。
  • 安全性: 安全性是任何数据库选择的一个关键因素。确保向量数据库提供适当的安全性特性,如数据加密、数据隔离、访问控制和身份验证。
  • 社区和支持: 考察数据库的社区支持和文档。一个活跃的社区通常能够提供更好的支持和解决问题的资源。
  • 成本: 评估数据库的总体成本,包括许可费、运维成本以及可能的扩展成本。确保数据库符合你的预算和资源限制。

关于向量数据库产品更详细的内容,我这里就不展开了。如果你没有接触过向量数据库,建议了解下以下几款产品。

  • 专业的向量数据库产品: chromadbmilvuspinecone
  • 具有向量数据库能力的产品:PostgreSQL & pgvectorElasticSearch 8.0 +

向量数据库与LLMs的融合

市场前景

你可能看过 Zilliz 的融资新闻,这家向量数据库公司借着这轮大语言模型的东风,拿到了B+轮融资6000万美元, 融资规模达到了1.13 亿美元,Zilliz 的开源向量数据库产品,就是我们上面提到的 milvus

可以看出,向量数据库应用的前景市场还是认可的。

向量数据库与 LLM 的对接

我们上一篇文章讲到了 LangChain,并以ChromeDB为例,演示了如何用LangChain对接向量数据,做一个本地的文档知识库。

在这篇文章里,我们在开发本地文档知识库时做了如下几件事情: 1.配置环境、Python、LangChain、ChatGLM2、 chromadb等 2.将本地数据切片向量化:Docs -> Embeddings -> chromadb 3.编码对接ChatGLM2、chromadb等,完成开发。

接下来我们讲一下步骤二:将本地数据切片向量化,这是向量数据库与LLM对接的核心

分词(tokenization)

img_15.png

在使用向量数据库时,分词(tokenization)的意义与处理自然语言文本的相关任务密切相关。分词是将连续的文本数据切分成词(或称为单词)的过程。 对于自然语言处理(NLP)和文本检索等任务,分词是一个重要的预处理步骤,因为它将文本数据转化为更易于处理的语言单元,每个语言单元可以是一个字母、数个词或一句话。

在LangChain中,我们可以通过 tiktoken 分词器对文档进行拆分,tiktoken 是由 OpenAI 开源的快速 BPE 分词器。

# 根据token拆分文本
text_splitter = CharacterTextSplitter.from_tiktoken_encoder(
    chunk_size=100, chunk_overlap=0
)
texts = text_splitter.split_text(state_of_the_union)

嵌入(Embeddings)

img_14.png

Embeddings(嵌入):向量数据库存储的是向量数据,我们的本地语料需要通过Embeddings的方式将自然语言转成成向量,也就是将数据映射到低维空间的表示形式。

最常见的例子是词嵌入(Word Embeddings),它是将单词映射到实数向量的表示。词嵌入模型(如 Word2Vec、GloVe、FastText)通过学习大量文本语料库中的上下文关系, 将每个单词映射到一个固定维度的实数向量。这样的词嵌入向量能够捕捉到单词之间的语义关系,使得在向量空间中相似的词语距离更近。

在LangChain中,我们可以使用OpenAIEmbeddings将文档转换成向量,并存储到向量数据库。

# 初始化 openai 的 embeddings 对象
embeddings = OpenAIEmbeddings()
# 将 document 通过 openai 的 embeddings 对象计算 embedding 向量信息并临时存入 Chroma 向量数据库,用于后续匹配查询
docsearch = Chroma.from_documents(split_docs, embeddings)

对接LLM

最终我们通过 LangChain 的问答链实现与用户的交互

# 初始化 openai embeddings
embeddings = OpenAIEmbeddings()

# 将数据存入向量存储
vector_store = Chroma.from_documents(documents, embeddings)
# 通过向量存储初始化检索器
retriever = vector_store.as_retriever()

system_template = """
Use the following context to answer the user's question.
If you don't know the answer, say you don't, don't try to make it up. And answer in Chinese.
-----------
{question}
-----------
{chat_history}
"""

# 构建初始 messages 列表,这里可以理解为是 openai 传入的 messages 参数
messages = [
  SystemMessagePromptTemplate.from_template(system_template),
  HumanMessagePromptTemplate.from_template('{question}')
]

# 初始化 prompt 对象
prompt = ChatPromptTemplate.from_messages(messages)

# 初始化问答链
qa = ConversationalRetrievalChain.from_llm(ChatOpenAI(temperature=0.1,max_tokens=2048),retriever,condense_question_prompt=prompt)

chat_history = []
while True:
  question = input('问题:')
  # 开始发送问题 chat_history 为必须参数,用于存储对话历史
  result = qa({'question': question, 'chat_history': chat_history})
  chat_history.append((question, result['answer']))
  print(result['answer'])

实现效果

img_16.png

更多的Embeddings

我们之前有提到文本向量可以通过 OpenAI 的 text-embedding-ada-002 模型生成,相似的:

  • 图像向量可以通过 clip-vit-base-patch32 模型生成,
  • 音频向量可以通过 wav2vec2-base-960h 模型生成。
  • 还有一些对中文支持更好的,例如:shibing624/text2vec-base-chinese

这些向量都是通过 AI 模型生成的,所以它们都是具有语义信息的。

总结与展望

在本文中,我们探讨了向量数据库及其在解决大语言模型(LLM)应用中的局限性的重要性。我们了解了向量数据库的基本概念、数据存储方式以及如何进行向量数据的检索, 同时介绍了一些常见的ANN算法,如Flat、k-means、LSH等,以及它们在向量数据库中的应用。

我们还详细介绍了向量数据库的产品分类、市场前景以及与LLMs的融合。通过对接LLMs,我们能够将自然语言的语义信息嵌入到向量数据库中, 从而实现更智能、更灵活的数据检索与分析。通过示例展示了LangChain在向量数据库与LLMs的对接过程,包括分词、嵌入、以及与用户的交互。

最后,我们提到了更多类型的Embeddings,包括图像、音频等领域的向量表示,这些向量都能够通过相应的AI模型生成,为不同领域的应用提供更多可能性。

在未来,随着向量数据库技术的不断发展和LLMs的广泛应用,我们可以期待更多创新性的解决方案和应用场景的涌现。同时,对于开发者和研究者来说, 需要根据具体问题的特点选择合适的向量数据库产品和相应的ANN算法,以实现更高效、更精准的数据处理与分析。