向量存储
为了简化,本概念概述主要关注基于文本的索引和检索。 然而,嵌入模型可以是多模态的, 并且向量存储可以用于存储和检索文本以外的各种数据类型。
概述
向量存储是专门的数据存储,能够基于向量表示进行索引和检索信息。
这些向量,称为embeddings,捕捉了已被嵌入数据的语义含义。
向量存储经常用于搜索非结构化数据,如文本、图像和音频,以基于语义相似性而非精确的关键字匹配来检索相关信息。
集成
LangChain 拥有大量的向量存储集成,允许用户轻松地在不同的向量存储实现之间切换。
接口
LangChain 提供了一个标准接口用于与向量存储工作,允许用户轻松地在不同的向量存储实现之间切换。
该接口包含用于在向量存储中写入、删除和搜索文档的基本方法。
关键方法有:
add_documents
: 将一系列文本添加到向量存储中。delete_documents
: 从向量存储中删除一系列文档。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 chocalate 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)
通常,您应该为您添加到向量存储中的文档提供ID,这样您就可以更新现有文档,而不是多次添加相同的文档。
vector_store.add_documents(documents=documents, ids=["doc1", "doc2"])
删除
要删除文档,请使用delete_documents
方法,该方法接受要删除的文档ID列表。
vector_store.delete_documents(ids=["doc1"])
搜索
向量存储嵌入并存储添加的文档。 如果我们传入一个查询,向量存储将嵌入该查询,对嵌入的文档执行相似性搜索,并返回最相似的文档。 这抓住了两个重要的概念:首先,需要有一种方法来衡量查询与任何 嵌入文档之间的相似性。 其次,需要有一种算法来高效地在所有嵌入文档中执行这种相似性搜索。
相似性度量
嵌入向量的一个关键优势是它们可以使用许多简单的数学操作进行比较:
- 余弦相似度: 测量两个向量之间角度的余弦值。
- 欧几里得距离: 测量两点之间的直线距离。
- 点积: 测量一个向量在另一个向量上的投影。
相似度度量的选择有时可以在初始化向量存储时选择。请参考您正在使用的特定向量存储的文档,以查看支持哪些相似度度量。
相似性搜索
给定一个相似性度量来测量嵌入查询和任何嵌入文档之间的距离,我们需要一个算法来高效地搜索所有嵌入文档以找到最相似的文档。
有多种方法可以实现这一点。例如,许多向量存储实现了HNSW(分层可导航小世界),这是一种基于图的索引结构,允许进行高效的相似性搜索。
无论底层使用何种搜索算法,LangChain向量存储接口都有一个similarity_search
方法用于所有集成。
这将获取搜索查询,创建嵌入,找到相似的文档,并将它们作为Documents列表返回。
query = "my query"
docs = vectorstore.similarity_search(query)
许多向量存储支持通过similarity_search
方法传递搜索参数。请参阅您正在使用的特定向量存储的文档,以了解支持哪些参数。
例如,Pinecone有几个重要的通用概念参数:
许多向量存储支持the k
,它控制返回的文档数量,以及filter
,它允许通过元数据过滤文档。
query (str) – 要查找相似文档的文本。
k (int) – 要返回的文档数量。默认为4。
filter (dict | None) – 用于过滤元数据的参数字典
元数据过滤
虽然向量存储实现了一种搜索算法,可以高效地搜索所有嵌入的文档以找到最相似的文档,但许多也支持对元数据进行过滤。 这允许使用结构化过滤器来减少相似性搜索空间的大小。这两个概念很好地结合在一起:
- 语义搜索: 直接查询非结构化数据,通常通过嵌入或关键字相似性进行。
- 元数据搜索: 对元数据应用结构化查询,筛选特定文档。
向量存储对元数据过滤的支持通常依赖于底层向量存储的实现。
以下是使用Pinecone的示例用法,展示了我们如何过滤所有具有元数据键source
且值为tweet
的文档。
vectorstore.similarity_search(
"LangChain provides abstractions to make working with LLMs easy",
k=2,
filter={"source": "tweet"},
)
- 参见Pinecone的文档,了解如何使用元数据进行过滤。
- 查看支持元数据过滤的LangChain向量存储集成列表。
高级搜索和检索技术
虽然像HNSW这样的算法在许多情况下为高效的相似性搜索提供了基础,但可以采用额外的技术来提高搜索质量和多样性。
例如,最大边际相关性是一种用于多样化搜索结果的重新排序算法,它在初始相似性搜索之后应用,以确保结果集更加多样化。
作为第二个例子,一些向量存储提供了内置的混合搜索,以结合关键字和语义相似性搜索,从而结合了两种方法的优点。
目前,使用LangChain向量存储执行混合搜索没有统一的方法,但它通常作为一个关键字参数与similarity_search
一起传递。
有关更多详细信息,请参阅此混合搜索指南。
名称 | 何时使用 | 描述 |
---|---|---|
Hybrid search | 当结合基于关键字和语义相似性时。 | 混合搜索结合了关键字和语义相似性,融合了两种方法的优点。论文。 |
Maximal Marginal Relevance (MMR) | 当需要多样化搜索结果时。 | MMR尝试多样化搜索结果,以避免返回相似和冗余的文档。 |