RAG
其全称为Retrieval-Augmented Generation,即检索增强生成,它结合了检索和生成的能力,为文本序列生成任务引入外部知识。RAG将传统的语言生成模型与大规模的外部知识库相结合,使模型在生成响应或文本时可以动态地从这些知识库中检索相关信息。这种结合方法旨在增强模型的生成能力,使其能够产生更为丰富、准确和有根据的内容,特别是在需要具体细节或外部事实支持的场合。
RAG 的工作原理可以概括为几个步骤。
- 检索:对于给定的输入(问题),模型首先使用检索系统从大型文档集合中查找相关的文档或段落。这个检索系统通常基于密集向量搜索,例如ChromaDB、Faiss这样的向量数据库。
- 上下文编码:找到相关的文档或段落后,模型将它们与原始输入(问题)一起编码。
- 生成:使用编码的上下文信息,模型生成输出(答案)。这通常当然是通过大模型完成的。
RAG 的一个关键特点是,它不仅仅依赖于训练数据中的信息,还可以从大型外部知识库中检索信息。这使得RAG模型特别适合处理在训练数据中未出现的问题。
文档加载
RAG的第一步是文档加载。LangChain 提供了多种类型的文档加载器,以加载各种类型的文档(HTML、PDF、代码),并与该领域的其他主要提供商如 Airbyte 和 Unstructured.IO 进行了集成。
文本转换
加载文档后,下一个步骤是对文本进行转换,而最常见的文本转换就是把长文档分割成更小的块(或者是片,或者是节点),以适合模型的上下文窗口。LangChain 有许多内置的文档转换器,可以轻松地拆分、组合、过滤和以其他方式操作文档。
文本分割器
把长文本分割成块听起来很简单,其实也存在一些细节。文本分割的质量会影响检索的结果质量。理想情况下,我们希望将语义相关的文本片段保留在一起。
LangChain中,文本分割器的工作原理如下:
- 将文本分成小的、具有语义意义的块(通常是句子)。
- 开始将这些小块组合成一个更大的块,直到达到一定的大小。
- 一旦达到该大小,一个块就形成了,可以开始创建新文本块。这个新文本块和刚刚生成的块要有一些重叠,以保持块之间的上下文。
因此,LangChain提供的各种文本拆分器可以帮助你从下面几个角度设定你的分割策略和参数:
- 文本如何分割
- 块的大小
- 块之间重叠文本的长度
文本嵌入
文本块形成之后,我们就通过LLM来做嵌入(Embeddings),将文本转换为数值表示,使得计算机可以更容易地处理和比较文本。OpenAI、Cohere、Hugging Face 中都有能做文本嵌入的模型。
Embeddings 会创建一段文本的向量表示,让我们可以在向量空间中思考文本,并执行语义搜索之类的操作,在向量空间中查找最相似的文本片段。
存储嵌入
计算嵌入可能是一个时间消耗大的过程。为了加速这一过程,我们可以将计算出的嵌入存储或临时缓存,这样在下次需要它们时,就可以直接读取,无需重新计算。
缓存存储
CacheBackedEmbeddings是一个支持缓存的嵌入式包装器,它可以将嵌入缓存在键值存储中。具体操作是:对文本进行哈希处理,并将此哈希值用作缓存的键。
要初始化一个CacheBackedEmbeddings,主要的方式是使用from_bytes_store。其需要以下参数:
- underlying_embedder:实际计算嵌入的嵌入器。
- document_embedding_cache:用于存储文档嵌入的缓存。
- namespace(可选):用于文档缓存的命名空间,避免与其他缓存发生冲突。
向量数据库(向量存储)
更常见的存储向量的方式是通过向量数据库(Vector Store)来保存它们。LangChain支持非常多种向量数据库,其中有很多是开源的,也有很多是商用的。比如Elasticsearch、Faiss、Chroma和Qdrant等等。
索引
在本节课的最后,我们来看看LangChain中的索引(Index)。简单的说,索引是一种高效地管理和定位文档信息的方法,确保每个文档具有唯一标识并便于检索。
知识点很多的一节课哎。。。。加油!