跳到主要内容
Open on GitHub

向量存储

先决条件
注意

本概念性概述为求简洁,侧重于基于文本的索引和检索。然而,嵌入模型可以是多模态的,并且向量存储可用于存储和检索除文本之外的各种数据类型。

概述

向量存储是专门的数据存储,支持基于向量表示的索引和信息检索。

这些向量,称为嵌入,捕获了已嵌入数据的语义。

向量存储常用于搜索非结构化数据(如文本、图像和音频),以基于语义相似性而非精确关键词匹配来检索相关信息。

Vector stores

集成

LangChain 拥有大量的向量存储集成,允许用户轻松切换不同的向量存储实现。

请参阅LangChain 向量存储集成的完整列表

接口

LangChain 提供了一个与向量存储交互的标准接口,允许用户轻松切换不同的向量存储实现。

该接口包含用于在向量存储中写入、删除和搜索文档的基本方法。

关键方法有

  • add_documents:向向量存储添加文本列表。
  • delete:从向量存储中删除文档列表。
  • similarity_search:搜索与给定查询相似的文档。

初始化

LangChain 中的大多数向量在初始化向量存储时接受嵌入模型作为参数。

我们将使用 LangChain 的 InMemoryVectorStore 实现来演示 API。

from langchain_core.vectorstores import InMemoryVectorStore
# Initialize with an embedding model
vector_store = InMemoryVectorStore(embedding=SomeEmbeddingModel())

添加文档

要添加文档,请使用 `add_documents` 方法。

此 API 适用于`Document` 对象列表。`Document` 对象都具有 `page_content` 和 `metadata` 属性,这使其成为存储非结构化文本和相关元数据的一种通用方式。

from langchain_core.documents import Document

document_1 = Document(
page_content="I had chocolate chip pancakes and scrambled eggs for breakfast this morning.",
metadata={"source": "tweet"},
)

document_2 = Document(
page_content="The weather forecast for tomorrow is cloudy and overcast, with a high of 62 degrees.",
metadata={"source": "news"},
)

documents = [document_1, document_2]

vector_store.add_documents(documents=documents)
API 参考:Document

通常,您应该为您添加到向量存储的文档提供 ID,这样您就可以更新现有文档,而不是多次添加相同的文档。

vector_store.add_documents(documents=documents, ids=["doc1", "doc2"])

删除

要删除文档,请使用 `delete` 方法,该方法接受要删除的文档 ID 列表。

vector_store.delete(ids=["doc1"])

向量存储会嵌入并存储所添加的文档。如果我们传入一个查询,向量存储将嵌入该查询,对嵌入的文档执行相似性搜索,并返回最相似的文档。这涉及到两个重要概念:首先,需要一种方法来衡量查询与任何嵌入文档之间的相似性。其次,需要一种算法来有效地对所有嵌入文档执行此相似性搜索。

相似性度量

嵌入向量的一个关键优势是可以使用许多简单的数学运算进行比较

  • 余弦相似度:测量两个向量之间夹角的余弦值。
  • 欧几里得距离:测量两点之间的直线距离。
  • 点积:测量一个向量在另一个向量上的投影。

相似性度量的选择有时可以在初始化向量存储时进行。请参阅您正在使用的特定向量存储的文档,以了解支持哪些相似性度量。

延伸阅读
  • 请参阅 Google 关于嵌入的相似性度量需要考虑的文档
  • 请参阅 Pinecone 关于相似性度量的博客文章
  • 请参阅 OpenAI 关于与 OpenAI 嵌入一起使用的相似性度量的常见问题

给定一个相似性度量来衡量嵌入式查询与任何嵌入式文档之间的距离,我们需要一种算法来高效地搜索所有嵌入式文档,以找到最相似的文档。有多种方法可以做到这一点。例如,许多向量存储实现了HNSW (分层可导航小世界),这是一种基于图的索引结构,可实现高效的相似性搜索。无论底层使用何种搜索算法,LangChain 向量存储接口都为所有集成提供了 `similarity_search` 方法。该方法将接收搜索查询,创建嵌入,查找相似文档,并将其作为`Document` 列表返回。

query = "my query"
docs = vectorstore.similarity_search(query)

许多向量存储支持通过 `similarity_search` 方法传递搜索参数。请参阅您正在使用的特定向量存储的文档,以了解支持哪些参数。例如,Pinecone 有几个重要的通用参数:许多向量存储支持`k`,它控制返回的文档数量,以及 `filter`,它允许按元数据过滤文档。

  • query (str) - 用于查找相似文档的文本。
  • k (int) - 返回的文档数量。默认为 4。
  • filter (dict | None) - 用于根据元数据进行过滤的参数字典。
延伸阅读
  • 有关如何使用 `similarity_search` 方法的更多详细信息,请参阅操作指南
  • 有关可以传递给特定向量存储的 `similarity_search` 方法的参数的更多详细信息,请参阅集成页面

元数据过滤

尽管向量存储实现了搜索算法来高效地搜索所有嵌入的文档以找到最相似的文档,但许多向量存储也支持基于元数据进行过滤。元数据过滤通过应用特定条件(例如从特定来源或日期范围检索文档)来帮助缩小搜索范围。这两个概念很好地协同工作

  1. 语义搜索:直接查询非结构化数据,通常通过嵌入或关键词相似性。
  2. 元数据搜索:对元数据应用结构化查询,过滤特定文档。

向量存储对元数据过滤的支持通常取决于底层向量存储的实现。

以下是 Pinecone 的示例用法,展示了我们如何过滤所有元数据键 `source` 值为 `tweet` 的文档。

vectorstore.similarity_search(
"LangChain provides abstractions to make working with LLMs easy",
k=2,
filter={"source": "tweet"},
)
延伸阅读

高级搜索和检索技术

尽管 HNSW 等算法在许多情况下为高效相似性搜索提供了基础,但可以采用其他技术来提高搜索质量和多样性。例如,最大边际相关性 (MMR) 是一种用于使搜索结果多样化的重新排序算法,它在初始相似性搜索之后应用,以确保结果集更加多样化。第二个例子是,一些向量存储提供了内置的混合搜索,结合了关键词和语义相似性搜索,这结合了两种方法的优点。目前,LangChain 向量存储没有统一的方法来执行混合搜索,但它通常作为随 `similarity_search` 传入的关键词参数公开。有关更多详细信息,请参阅此混合搜索操作指南

名称何时使用描述
混合搜索当结合基于关键词和语义相似性时。混合搜索结合了关键词和语义相似性,结合了两种方法的优点。论文
最大边际相关性 (MMR)当需要使搜索结果多样化时。MMR 旨在使搜索结果多样化,以避免返回相似和冗余的文档。