分块和向量化
分块
文档分块的原因:
Transformer 模型输入的长度是固定的,能够表达的语义信息也是固定的,粒度小的文本内容(一句话或者几句话),生成的向量更能够表达文本的含义
分块的大小是需要考量的参数。
- 影响因素:模型的选择,及模型 token 的容量。比如 Bert-based Sentence Transforms 模型最可以有
512 个token,而 OpenAI ada-002 可以接受 8191 个token。 - 需要在“获取到足够的上下文信息以供 LLM 生成回答”和“确保文本嵌入足够具体,以便有效地执行检索”之间找到平衡 。
向量化
将文本块转化成向量的过程就是 Embedding。
向量可以理解为文本块的特征数据信息。
搜索索引构建
包括五种构建方式:
1. 向量存储索引
2. 层次索引
3. 假设问题和HyDE
4. 丰富上下文
5. 融合检索或混合搜索
向量存储索引
搜索索引 AG pipeline 中的关键组成部分,用于存储前面文本块向量化后的数据。
搜索索引类型:
- 平面索引(flat index):最简单的实现,可以通过计算查询文本的向量和所有文本块向量的距离,来获取最相关的查询结果。
- 向量索引(vector index):在1万个元素的量级上可以进行高效检索,基于近似最近邻居算法,如聚类、树结构或 HNSW
算法。这类索引有: faiss、nmslib 或 annoy。 - 托管服务:如 OpenSearch、ElasticSearch 和向量数据库,它们自动处理前文提到的数据摄取流程,例如
Pinecone、Weaviate 和 Chroma。
可以将文本的元数据与向量存储到一起,使用元数据过滤器可以按照日期或来源等条件进行信息检索。
层次索引
场景:
需要从有许多文档中进行高效的检索,找到相关的信息,然后整合到一个答案中,并带有参考来源。
实现:
创建两个索引:
- 一个索引由文档摘要构成
- 一个索引由文本块构成
分两步搜索:
- 先从文档摘要索引中过滤相关文档
- 在这些文档的范围内,在文本块中进行搜索
假设问题和 HyDE
假设问题法:
- 使用 LLM 为每个文本块生成一个问题,然后将问题 embedding 为向量
- 搜索时,先使用问题搜索,找到相似问题的索引
- 然后找到这些问题对应的文本块,使用文本块作为上下文发送给 LLM 来获取答案。
优点:
查询和假设问题之间的语义相似度更好,对比直接搜索文本块,该方法的质量更高。
另外一种方法叫 HyDE,与假设问题方法逻辑相反:
- 根据输入问题生成回答,然后使用回答文本的向量和问题向量来提高搜索的质量。
丰富上下文
主要有两点:
- 检索较小的文本块来获得更好的搜索质量
- 增加文本块周围的上下文供 LLM 推理
有两种方式:
- 增加文本块周围的句子来扩展文本
- 通过递归的的方式,将文本分割为具有父子关系的大小块。
句子窗口检索
- 每个句子独立 embedding,可以提供很高的查询准确性。
- 获得到最相关的句子,并在句子前后扩展 K 个句子
- 将扩展后的内容做为上下文提供给 LLM。
自合并检索器(即父文档检索器)
- 将文档分割成为具有父子关系的大小文本块,较小的子文本块引用较大的父文本块,只对子文本块进行 embedding
- 搜索较小子文本块,如果前 k 个检索结果中超过 n 个结果属于同一父文本块,就使用该父文本块作为上下文提供给 LLM。
融合检索/混合搜索
现代检索方法有:语义或者向量搜索方法
可以将传统和现代方法结合起来,将两种类方法的结果整合成一个检索结果。
参考引用
用户最终获得的回答来自于多个源:
复杂查询:使用多个子查询检索获得的上下文整合为一个回答
单个查询:从各种文档中检索到的相关上下文合并成一个回答
问题:如何准确回溯回答内容的来源
方法:
1、将内容引用的任务增加到 prompt 中,让 LLM 来提示内容引用来源的 id
2、将生成的回答与检索到的文本块匹配。
对话引擎
RAG 系统,只有单次查询是不够的。一个优秀的 RAG 系统需要支持对话逻辑,在查询的时候能够将对话的上下文考虑在内
- 将对话历史和用户查询语句一并考虑
查询路由
1、由 LLM 支持的决策步骤
2、 用来决定根据用户的查询,下面要做什么事情。通常有以下任务:
- 内容总结
- 从某个数据源检索数据(关系型数据库,图数据库,向量数据库等)
- 执行多个不同的路由,并将各个路由的执行结果合并,提供给 LLM生成回答