引言:很多人都知道chatpdf,然后因此也许也听说过矢量存储器。那么今天我们就了解一下背后的原理。LangChain,不止懂“构建索引”,更擅长“Retriever”。
那为了更好的理解其意义,我们得理解一下Retriever的基本接口。LangChain 中的BaseRetriever是这样的:
from abc import ABC, abstractmethod
from typing import List
from langchain.schema import Document
class BaseRetriever(ABC):
@abstractmethod
def get_relevant_documents(self, query: str) -> List[Document]:
"""Get texts relevant for a query.
Args:
query: string to find relevant texts for
Returns:
List of relevant documents
"""
这简直是“灵活百搭”啊!从命名不难看出,get_relevant_documents
这个方法的实现方式可以根据您的意愿自由发挥。
而当然,我们更专注于构建“有用”的Retriever类型,其中最明显的一个就是 Vectorstore retriever。让我们开始探究一下它。
那么,为了理解vectorstore retriever,重要的是要理解什么是vectorstore。我们来看一下。
默认情况下,LangChain使用“Chroma”作为向量库来索引和搜索嵌入。所以,为了通过本教程,请先安装chromadb。
pip install chromadb
下面的例子展示了如何问答。我们特别选择了这个例子,因为它正好集合了许多不同的元素(Text splitters、embeddings、vectorstores),再加上它演示了如何在langchain中使用它们。
问答可分成四步:
- 创建索引
- 从该索引创建Retriever
- 创建问答链
- 提问!
每个步骤都有多个子步骤以及众多配置项。但是我们本篇主要介绍第一步。我们通过一行代码快速创建索引,但是我们将分解代码背后的过程。
首先,让我们导入一些通用类,我们肯定会用到的。
from langchain.chains import RetrievalQA
from langchain.llms import OpenAI
然后,在通用设置中,让我们指定我们想要使用的文档加载程序。您可以在这里下载state_of_the_union.txt文件。
from langchain.document_loaders import TextLoader
loader = TextLoader('../state_of_the_union.txt', encoding='utf8')
来吧!一行python代码,助您轻松创建索引
为了更快地开始使用,我们可以使用 VectorstoreIndexCreator。
from langchain.indexes import VectorstoreIndexCreator
index = VectorstoreIndexCreator().from_loaders([loader])
LangChain 提供了一个十分好的接口,可以直接运行Chroma。使用DuckDB内存作为数据库。所以,数据只是短暂存储而已。
那么,现在您已经成功地创建了索引,我们可以使用它轻松查询!请注意,实际上这个方法背后发生了更多,但是放心,我们将在本篇文章中一步一步讲解。
query = "What did the president say about Ketanji Brown Jackson"
index.query(query)
输出:
"The president said that Ketanji Brown Jackson is one of the nation's top legal minds, a former top litigator in private practice, a former federal public defender, and from a family of public school educators and police officers. He also said that she is a consensus builder and has received a broad range of support from the Fraternal Order of Police to former judges appointed by Democrats and Republicans."
query = "What did the president say about Ketanji Brown Jackson"
index.query_with_sources(query)
输出:
{
'question': 'What did the president say about Ketanji Brown Jackson',
'answer': " The president said that he nominated Circuit Court of Appeals Judge Ketanji Brown Jackson, one of the nation's top legal minds, to continue Justice Breyer's legacy of excellence, and that she has received a broad range of support from the Fraternal Order of Police to former judges appointed by Democrats and Republicans.n",
'sources': '../state_of_the_union.txt'
}
从 VectorstoreIndexCreator 返回的是 VectorStoreIndexWrapper,它提供了这些 query
和 query_with_sources
功能。如果您想直接访问 vectorstore,也可像下面这样:
index.vectorstore
输出:
<langchain.vectorstores.chroma.Chroma at 0x119aa5940>
那接下来,如果我们想访问 VectorstoreRetriever 的话,那就可以使用了!
index.vectorstore.as_retriever()
输出:
VectorStoreRetriever(vectorstore=<langchain.vectorstores.chroma.Chroma object at 0x119aa5940>, search_kwargs={})
步骤解释
那么,到底发生了什么?那实际的创建过程是什么?
有大量的魔力都隐藏在 VectorstoreIndexCreator 中,它的作用那就是…
在加载文档后,主要分了三步:
- 将文档分成块。
- 为每个文档创建嵌入。
- 将文档和嵌入存储在 vectorstore 中。
那接下来,我们通过代码具体说明:
documents = loader.load()
接下来,我们将把文档分成块。
from langchain.text_splitter import CharacterTextSplitter
text_splitter = CharacterTextSplitter(chunk_size=1000, chunk_overlap=0)
texts = text_splitter.split_documents(documents)
接着,我们选择要使用的嵌入。
from langchain.embeddings import OpenAIEmbeddings
embeddings = OpenAIEmbeddings()
然后我们创建要用作索引的 vectorstore 本体。
from langchain.vectorstores import Chroma
db = Chroma.from_documents(texts, embeddings)
同时我们使用本地API直接运行 Chroma,数据将会被存储在 DuckDB 内存当中,时间并不会太长。
如果我们只想要直接访问 vectorstore,我们可以使用以下代码段:
retriever = db.as_retriever()
那么接下来,就像我们之前一样,我们可以创建一个链并使用它来回答问题!
qa = RetrievalQA.from_chain_type(llm=OpenAI(), chain_type="stuff", retriever=retriever)
query = "What did the president say about Ketanji Brown Jackson"
qa.run(query)
输出:
"The President said that Judge Ketanji Brown Jackson is one of the nation's top legal minds, a former top litigator in private practice, a former federal public defender, and from a family of public school educators and police officers. He said she is a consensus builder and has received a broad range of support from organizations such as the Fraternal Order of Police and former judges appointed by Democrats and Republicans."
VectorstoreIndexCreator 仅仅是所有逻辑的一个简单封装。它涵盖了文本分割器的使用、使用哪种嵌入以及使用哪种 vectorstore。如果您想进行配置方面的修改,可以按以下方式进行:
index_creator = VectorstoreIndexCreator(
vectorstore_cls=Chroma,
embedding=OpenAIEmbeddings(),
text_splitter=CharacterTextSplitter(chunk_size=1000, chunk_overlap=0)
)
今天简单介绍了创建索引背后的逻辑,明天继续连载。