[LangChain]Semantic search
0 Useful Docs
1 Setup
1 |
|
2 Documents and Document Loaders
LangChain实现了Document abstraction,旨在表示文本单元及其相关元数据。它包含三个属性:
page_content
: 字符串形式的内容;metadata
: 包含任意元数据的字典;id
: (可选)文档的字符串标识符。
metadata
属性可以捕捉关于文档来源、与其他文档的关系及其他信息。需要注意的是,单独的Document
对象通常代表较大文档中的一个chunk。
LangChain ecosystem实现了与数百种常见数据源集成的文档加载器。
API Reference: Document
Loading documents
在LangChain仓库中here,有一个样本PDF——这是耐克公司2023年的10-K报表。可以查阅LangChain文档来了解可用的PDF文档加载器。这里选择使用相对轻量级的PyPDFLoader。
1 |
|
PyPDFLoader为每个PDF页面加载一个Document对象。对于每一个对象,可以访问:
- 页面的字符串内容;
- 包含文件名和页码的元数据。
以下是如何访问并打印第一个文档对象的前200个字符的内容以及其元数据的示例代码:
1 |
|
splitting
在信息检索和下游问答任务中,将页面作为单独的表示单位可能过于粗糙。最终目标是检索能够回答输入查询的文档对象,进一步拆分PDF文件有助于确保文档相关部分的意义不会被周围文本“冲淡”。
为此,可以使用文本分割器。这里采用基于字符的简单分割方法。具体来说,将文档分割成1000个字符的块,并且相邻块之间有200个字符的重叠。这种重叠有助于减少将陈述与其重要上下文分离的可能性。
使用RecursiveCharacterTextSplitter,它会递归地使用常见分隔符(如换行符)分割文档,直到每个块达到合适的大小。对于通用文本用例,推荐使用此文本分割器。
通过设置add_start_index=True
,可以保留每个分割后Document对象在其原始文档中的起始字符索引,并将其作为元数据属性”start_index”保存。
参考here以获取更多关于处理PDF文件的详细信息,包括如何从特定部分和图像中提取文本。
API Reference: RecursiveCharacterTextSplitter
1 |
|
3 Embeddings
向量搜索是一种常见的存储和搜索非结构化数据(如非结构化文本)的方法。其核心思想是存储与文本关联的数字向量。给定一个查询,我们可以将其嵌入为相同维度的向量,并使用向量相似度指标(如余弦相似度)来识别相关的文本。
LangChain 支持来自数十个供应商的嵌入模型。这些模型定义了如何将文本转换为数字向量。
这里选择HuggingFace模型。
1 |
|
4 Vector stores
LangChain的VectorStore对象包含了向存储中添加文本和Document对象的方法,并支持使用多种相似度度量进行查询。这些对象通常与embedding模型一起初始化,以确定文本数据如何转换为数值向量。
LangChain提供了一系列基于不同向量存储技术的integrations 。一些向量存储由供应商托管(例如,不同的云服务提供商),并需要特定的凭据才能访问;有些(如Postgres)则可以在独立的基础设施上运行,既可本地部署也可通过第三方实现;还有些可以在内存中运行,适用于轻量级工作负载。
这里选择In-memory类型。
1 |
|
在实例化了我们的向量存储之后,现在可以对文档进行索引。
1 |
|
需要注意的是,大多数向量存储实现允许连接到现有的向量存储——例如,通过提供客户端、索引名称或其他信息进行连接。有关特定integration的更多详情,请参阅相关文档。
一旦我们实例化了一个包含文档的VectorStore,就可以对其进行查询。VectorStore提供了多种查询方法:
- 同步与异步查询;
- 通过字符串查询和向量查询;
- 支持返回或不返回相似度分数;
- 按相似度以及maximum marginal relevance(在检索结果的相关性和多样性之间取得平衡)进行查询。
这些方法通常在其输出中包含一个Document对象列表。
Usage
嵌入通常将文本表示为“密集”向量,使得具有相似意义的文本在几何空间中彼此接近。
下面的代码示例展示了如何根据与字符串查询的相似度来检索文档:
1 |
|
异步查询:
1 |
|
返回分数:
1 |
|
根据向量查询:
1 |
|
更多信息:
5 Retrievers
LangChain的VectorStore对象并不继承自Runnable接口,而LangChain的检索器(Retrievers)是实现了Runnable接口的,因此它们支持一系列标准方法,如同步和异步 invoke
及 batch
操作。我们可以从vector stores构建检索器,检索器也支持与非向量存储的数据源接口交互,比如外部API。
即便不直接继承Retriever类,我们也能创建一个简单的版本。只要定义了用于检索文档的方法,就可以轻松创建一个可运行的对象。下面的例子将围绕similarity_search
方法来构建:
1 |
|
API Reference: Document | chain
向量存储(VectorStore)实现了as_retriever
方法,可以生成一个专门的VectorStoreRetriever。这类检索器包含特定的search_type
和search_kwargs
属性,用于指定调用底层向量存储的哪些方法及其参数化方式。
1 |
|
VectorStoreRetriever
支持多种搜索类型,包括默认的”similarity”(相似性)、”mmr”(最大边际相关性)以及”similarity_score_threshold”。我们可以使用”similarity_score_threshold”根据相似度分数对检索器输出的文档进行阈值设定,从而控制返回结果的相关性程度。
检索器可以轻松集成到更复杂的应用程序中,例如结合特定问题与检索上下文以生成提示给语言模型(LLM)的 retrieval-augmented generation (RAG)应用。
6 更多信息
Retrieval strategies can be rich and complex. For example:
- We can infer hard rules and filters from a query (e.g., “using documents published after 2020”);
- We can return documents that are linked to the retrieved context in some way (e.g., via some document taxonomy);
- We can generate multiple embeddings for each unit of context;
- We can ensemble results from multiple retrievers;
- We can assign weights to documents, e.g., to weigh recent documents higher.
The retrievers section of the how-to guides covers these and other built-in retrieval strategies.
It is also straightforward to extend the BaseRetriever class in order to implement custom retrievers. See our how-to guide here.
For more on document loaders:
For more on embeddings:
For more on vector stores:
For more on RAG, see: