AI 伴学笔记9 检索增强生成

119 阅读6分钟

检索增强生成:Retrieval-Augmented Generation,RAG,结合检索和生成的能力,为文本序列生成任务引入外部知识

RAG 不仅仅依赖于训练数据中的信息,还可以从大型外部知识库中检索信息,特别适合处理在训练数据中未出现的问题,通常可以概括为三个步骤:

  1. 检索:根据输入的问题,使用检索系统从文档集合中查找相关片段。检索系统常基于密集向量搜索,如 ChromaDB、Faiss 等向量数据库
  2. 上下文编码:将检索的文档段落与原始问题输入一起编码
  3. 生成:使用编码的上下文信息,模型生成输出,通常由 LLM 完成

文档加载

LangChain 提供各种文档加载器,并与 Airbyte、Unstructured.IO 等供应商集成

名称说明加载类
TextLoader加载文本文档TextLoader
CSVLoader加载CSV 文档CSVLoader
HTMLLoader加载HTML文档UnstructuredHTMLLoader
JSONLoader加载JSON 文档JSONLoader
MarkdownLoader加载Markdown 文档UnstructuredMarkdownLoader
PDFLoader加载 PDF 文档PyPDFLoader

文本转换

将文本拆分成更小的块(片,节点等)

文本文档

文本分割器工作原理为:

  1. 将文本分成小的、具有语义意义的块(通常是句子)
  2. 将小块组合成一个更大的块,直到达到一定的大小
  3. 生成新文本块时要和上一个块有一定的重叠,保持块之间的上下文
分割器说明
字符分割器
CharacterTextSplitter
基于单个字符进行分割,默认的分隔符为 \n\n,分块大小为字符数。
递归字符分割器
RecursiveCharacterTextSplitter
用一个分隔符列表进行分割,按照顺序逐个尝试列表中的分割符直到块足够小为止。默认的分隔符列表是 ["\n\n","\n","",“"]
Markdown 标题分割器
MarkdownHeaderTextSplitter
根据指定的标题标记来分割 Markdown 文件,如 ###
令牌分割器
TokenTextSplitter
SpacyTextSplitterSentence
TransformersTokenTextSplitter
NLTKTextSplitter
在分割文本时考虑令牌数量,如 TokenTextSplitter 使用 TikToken 估计分割后的令牌数量
分割器和分片策略主要考虑以下因素:
  • LLM Token 限制,还要预留一定数量的 Token 作为输入提示
  • 考虑任务类型
    • 需要细致查看文本的任务,最好使用较小的分块:需要识别文本中的单个单词或字符,分析类任务,关键字提取任务等
    • 需要全面了解文本的任务,则使用较大的分块:需要理解文本的整体含义,识别文本中不同部分之间的关系,创意写作等
  • 所分割的文本的性质,文本结构很强(HTML,代码等)的需要较大的块

其他文件

  • 过滤冗余的文档:EmbeddingsRedundantFilter 工具可以识别相似的文档并过滤掉冗余信息,节省存储空间并提高检索效率。
  • 翻译文档:通过与工具 doctran 进行集成,可以将文档从一种语言翻译成另一种语言。
  • 提取元数据:通过与工具 doctran 进行集成,可以从文档内容中提取关键信息(日期、作者、关键字等)存储为元数据,更有效地管理、分类和检索文档。
  • 转换对话格式:通过与工具 doctran 进行集成,可以将对话式的文档内容转化为问答(QA)格式,更容易地提取和查询特定的信息或回答,在处理访谈、对话或其他交互式内容时非常有用。

文本嵌入

嵌入 Embeddings 将一段文本转换为向量表示,在向量空间中查找最相似的文本片段,由 LLM 完成。

LangChain 提供 Embeddings 类表示 LLM 文本嵌入功能的接口

  • embed_documents:接收多个文本作为输入,一次性将多个文档转换为向量表示
  • embed_query:查询创建嵌入,只接收一个文本作为输入

存储嵌入

存储计算后的嵌入结果

缓存存储

LangChain 提供 CacheBackedEmbeddings 将嵌入缓存在键值存储中,通常使用 from_bytes_store(<embedder>, <cache>, <namespace>) 创建

  • embedder:Embeddings 类的实现类,实际计算嵌入的嵌入器
  • cache:存储文档嵌入的缓存,可用内置缓存工具
    • InMemoryStore:内存缓存
    • LocalFileStore:本地文件系统存储
    • 其他数据库,如 RedisStore 或其他向量数据库
  • namespace:可选,文档缓存的命名空间,避免冲突

向量数据库

根据具体需求选择

  1. 数据规模和速度需求:考虑你的数据量大小以及查询速度的要求
  2. 持久性和可靠性:根据你的应用场景,确定你是否需要数据的高可用性、备份和故障转移功能
  3. 易用性和社区支持:考虑向量数据库的学习曲线、文档的完整性以及社区的活跃度
  4. 成本:考虑总体拥有成本,包括许可、硬件、运营和维护成本
  5. 特性:考虑你是否需要特定的功能,例如多模态搜索等
  6. 安全性:确保向量数据库符合你的安全和合规要求

数据检索

检索器 Retriever 是数据检索模块的核心入口,通过非结构化查询返回相关文档

最常用的检索器是向量存储检索器,使用 VectorstoreIndexCreator 创建,通过 vectorstore 类的 as_retriever 方法直接作为检索器

LangChain中还提供很多种其他的检索工具

索引

索引:Index,一种高效地管理和定位文档信息的方法,确保每个文档具有唯一标识并便于检索。

  • 避免重复内容:确保你的向量存储中不会有冗余数据。
  • 只更新更改的内容:能检测哪些内容已更新,避免不必要的重写。
  • 省时省钱:不对未更改的内容重新计算嵌入,从而减少了计算资源的消耗。
  • 优化搜索结果:减少重复和不相关的数据,从而提高搜索的准确性。

LangChain 使用记录管理器 RecordManager 跟踪写入向量存储的文档,通过哈希处理确保每个文档都有一个唯一的标识

  • 文档哈希:基于文档内容和元数据计算出的唯一标识。
  • 写入时间:记录文档何时被添加到向量存储中
  • 源 ID:这是一个元数据字段,表示文档的原始来源

记录管理器确保了即使文档经历了多次转换或处理,也能够精确地跟踪它的状态和来源,确保文档数据被正确管理和索引。