大家好,我是雨飞。最近一直在尝试 检索增强生成(RAG) 相关的一些任务,最近尝试利用小说的文本信息构建一个知识库,然后让用户进行提问。

在实际操作时遇到了挺多问题,有的解决了,有的还没有解决。在此,记录下自己的思考,希望对大家有帮助。

RAG 的整个流程,我在之前的文章中已经提到过了,有不清楚的或者新入门想学习 RAG 的同学可以点击下面的链接进行查看,本次只分享一些信息增量的部分。
juejin.cn/post/735604…

一、需求和问题定义

需求:针对小说数据构建一个问答系统,用于提供给用户,让用户和大模型进行对话获取小说的相关知识

小说数据一般都是文本,整体格式相对比较固定,分章节,处理起来相对比较容易。结合我们之前提到的父子索引以及多向量索引相关的内容,在对小说数据做切分的时候,需要根据实际情况进行如下考虑。

就是我们的这个 APP 能给用户提供哪些问答的功能,比如是回答小说的男女主,故事梗概还是针对某一些章节或者小说细节内容进行回答。根据用户的问题不同,可以主要分为下面几大类:

L1:只需要小说的梗概和摘要就能回答的简单问题,比如小说的男女主是谁、这篇小说主要讲了什么内容等

L2:需要对小说的章节进行概括就可以回答的较难问题,比如小说第X章讲了一件什么样的事,第X章中发生了什么事

L3:需要对小说的章节细节进行阅读才能回答的困难问题,比如在第X章中男女主角引起误会的原因,女主角是从那一集出现的

根据,我们的实际情况和能力,一般应用对 L1 的问题,回答都比较容易,在数据处理上也比较简单。

而 L2 类问题,则需要考虑借助大模型的能力对文本进行总结。

对于 L3 类问题,基本很难回答,并且回答效果和基座大模型的能力强相关,而主流的可以供使用的开源大模型一般以 13B 为主,这个大小的大模型很难搞定。

二、切片策略和文本增强

针对 L1 级的问题,可以考虑直接把小说的摘要信息进行向量化。由于向量模型本身的局限性,直接用向量召回,小说的摘要信息和问题的相似度可能不会很高,因此采用计算问题相似度的策略会更好,我们把这种方法称为文本增强。

具体来说,提取生成一些对小说摘要提问的问题,可以人工生成,也可以用 ChatGPT 生成。然后,将这些问题向量化后进行存储在用户进行提问时,优先和这些预设的问题计算相似度如果相似度高于阈值,则将摘要作为最相似的内容进行返回。这个技巧可以提高用户对 L1 问题的命中率,而且用户通常都会询问L1类问题,能明显提高用户体验。

针对 L2 级的问题,需要对小说的每个章节进行总结,然后进行向量化。由于,小说的每一章节至少几千字,直接进行向量编码比较困难,因此需要分片段进行摘要总结,在这里可以考虑几种生成摘要的方式。

第一种,类似 MapReduce 的思想,将小说的文本进行切片,生成片段 1,片段 2,片段 n。先讲片段 1 输入到大模型中进行总结,然后将总结的结果和片段 2 一起输入到大模型继续总结。依次类推,只到将所有的片段都总结完毕。

第二种,如果大模型可以支持更长的上下文,比如 GPT-4 128k。可以不需要进行切片,直接将小说的一章输入到大模型中进行总结。

针对 L3 级的问题,需要小说的细节,强烈建议使用父子索引的方式去构建,即对小说文本进行细粒度的切片去构建向量,然后这些细粒度的切片都映射到一个粗粒度的小说段落。在实际使用大模型去做回答的时候,使用粗粒度的段落。

三、向量数据库选型和索引选择

建议使用现成的向量数据库去构建 APP,如果人员充足也可以考虑使用 faiss。我们在选型时,考虑了通用性,开发成本和上手难度等方面,最终使用了 milvus 作为向量数据库。由于低版本的 milvus 会将数据全部加载到内存里,如果将大批量的数据都插入到 milvus 的索引里,会导致内存溢出

为此,我们配合使用了 mongo,将文本数据和索引ID存储到 mongo 里。在实际使用时,会首先查询 milvus 获取索引 ID,然后通过索引 ID 查询 mongo 得到文本数据,最终将文本数据作为上下文拼接为提示词输入到大模型。整体流程会偏长,但是避免了内存溢出的问题。

Milvus 里面有多种索引类型可供选择,不同的索引类型所消耗的空间和检索效率都有差异。常见的索引类型主要有 FLAT、INV_FLAT、IVF_PQ、HNSW 等,比较常用的类型有 FLAT 以及 HNSW。

在我们的实际使用中,由于数据量比较小,直接使用了 FLAT 的索引,当数据量比较大的时候,HNSW 或者一些量化后的索引都是可以选择使用的。

一个简单的原则就是,如果内存占用比较紧张,建议使用 INV_FLAT 的格式,内存比较富裕,建议使用 HNSW 的格式,如果内存成为瓶颈,考虑使用 PQ 量化后的索引,后面也会单独针对索引的选择出一期新的文章。

四、多路召回

我们采用 BGE 作为基础的向量模型,只使用向量召回的方法,很难做到满足用户的效果。可以增加多路召回的措施去增加召回效果,然后增加重排序的部分,提高召回上下文的质量。

常见的召回方法主要有,BM25、关键词召回。Milvus 里面支持添加数值类型和字符串类型的值,为我们进行关键词召回提供了便利。如果使用其他向量数据库,可能需要考虑与 ES 等传统搜索引擎工具的联动,相对会更复杂一点。

此外,可以使用 BGE-reranke r去对召回的结果进行重排序,根据我们的实测:增加 reranker 之后,能明显提高召回率。但实际还需要各位在自己数据集上进行实验才可以,有的数据集上 reranker 会表现不佳。

微调 bge 的embedding,根据反馈绝大部分情况会降低准确率,目前还在验证这一点。

五、提示词优化

在文本增强和调用大模型进行输出的时候,需要构建提示词指导大模型的输出。我们目前使用的提示词如下,供各位参考。

文本增强

请根据以下三个反引号中的知识片段,按照以下要求生成3个高质量的问题及答案:
```
{context}
```
## 要求
1.生成的问题和答案不要超出反引号中信息的范围。
2.请确保所有生成的问题都能在知识片段中找到明确的答案。
3.生成的答案必须尊重知识片段的事实和描述,不允许添加编造成分或进行推理。
4.问题部分以"Question:"开始,答案部分以"Answer:"开始。
5.使用中文进行输出。

大模型回答问题

已知信息:
"""
{context}
"""
根据上述已知信息,简洁和专业的来回答用户的问题。如果无法从中得到答案,请说 “根据已知信息无法回答该问题” 或 “没有提供足够的相关信息”,不允许在答案中添加编造成分,答案请使用中文。 
问题是:{question}

雨飞同行

  • 雨飞
  • 主业是推荐算法
  • 希望通过自媒体开启自己不上班只工作的美好愿景
  • 微信:1060687688
  • 欢迎和我交朋友

好了,我写完了,有启发的欢迎点赞评论。新的一天,愿阳光洒在你的脸上。