文章背景
Langchain-Chatchat项目是一种利于langchain思想实现的基于本地知识库的问答应用,是一个可以实现完全本地化推理的知识库增强方案,具有重点解决数据安全保护,私域化部署的企业痛点的能力。
本文主要对构建一个基于Langchain-Chatchat的知识库问答系统,可能存在的问题以及相关改进方案的说明。
项目地址:https://github.com/chatchat-space/Langchain-Chatchat
项目更多详情:https://github.com/chatchat-space/Langchain-Chatchat/wiki/
构建知识库
将七月近两年整理的大厂面试题PDF文件作为源文件来进行知识库的构建。
默认使用RapidOCRPDFLoader作为文档加载器。RapidOCR是目前已知运行速度最快、支持最广,完全开源免费并支持离线快速部署的多平台多语言OCR。由于PaddleOCR工程化不是太好,RapidOCR为了方便大家在各种端上进行OCR推理,将PaddleOCR中的模型转换为ONNX格式,使用Python/C++/Java/Swift/C# 将它移植到各个平台。
更多详情参考:https://rapidai.github.io/RapidOCRDocs/docs/overview/
资源及相关配置
本次主要对 V0.2.6 版本进行测试,资源及相关默认配置如下:
- 显卡:Tesla P100,16G(显存)
- 分词器:ChineseRecursiveTextSplitter
- chunk_size:250
- embedding模型:m3e-base
- LLM模型:chatglm2-6b
- 向量库:faiss
相关问题
检索问题
检索结果不准确
问题描述
会出现检索出的部分结果与问题相关性不大的情况,甚至还会出现对某些问题检索不到的情况。
比如问一个面试题:用通俗的语言介绍下强化学习
检索得到的内容如下:
出处 [1] 2022Q2大厂面试题共92题(含答案及解析).pdf
CART 树算法的核心是在生成过程中用基尼指数来选择特征。 4、用通俗的语言介绍下强化学习(Reinforcement Learning)监督学习的特点是有一个“老师”来“监督”我们,告诉我们正确的结果是什么。在我们在小的时候,会有老师来教我们,本质上监督学习是一种知识的传递,但不能发现新的知识。对于人类整体而言,真正(甚至唯一)的知识来源是实践——也就是强化学习。比如神农尝百草,最早人类并不知道哪些草能治病,但是通 过尝试,就能学到新的知识。学习与决策者被称为智能体,与智能体交互的部分则称为环境。智能体与环境不断进行交互,具体而言,这一交互的过程可以看做是多个时刻,每一时刻,智能体根据环境的状态,依据一定的策略选择一个动作(这
出处 [2] 2021Q3大厂面试题共107题(含答案及解析).pdf
20.2 集成学习的方式,随机森林讲一下,boost 讲一下, XGBOOST 是怎么回事讲一下。 集成学习的方式主要有 bagging,boosting,stacking 等,随机森林主要是采用了 bagging 的思想,通过自助法(bootstrap)重采样技术,从原始训练样本集 N 中有放回地重复随机抽取 n 个样本生成新的训练样本集合训练决策树,然后按以上步骤生成 m 棵决策树组成随机森林,新数据的分类结果按分类树 投票多少形成的分数而定。 boosting是分步学习每个弱分类器,最终的强分类器由分步产生的分类器组合而成,根据每步学习到的分类器去改变各个样本的权重(被错分的样本权重加大,反之减小) 它是一种基于 boosting增强策略的加法模型,训练的时候采用前向分布算法进行贪婪的学习,每次迭代
出处 [3] 2022Q2大厂面试题共92题(含答案及解析).pdf
特征工程可以并行开发,大大加快开发的速度。 训练速度较快。分类的时候,计算量仅仅只和特征的数目相关。 缺点:准确率欠佳。因为形式非常的简单,而现实中的数据非常复杂,因此,很难达到很高的准确性。很难处理 数据不平衡的问题。 3、介绍下决策树算法常见的决策树算法有三种:ID3、C4.5、CART 树 ID3 算法的核心是在决策树的每个节点上应用信息增益准则选择特征,递归地构架决策树。C4.5 算法的核心是在生成过程中用信息增益比来选择特征。 CART 树算法的核心是在生成过程中用基尼指数来选择特征。4、用通俗的语言介绍下强化学习(Reinforcement Learning)
可以看出,第一个检索结果和问题是相关的,第二个检索结果和问题是完全没关系的,而第三个检索结果的最后一句话是和问题相关的。
比如问一个面试题:Bert的预训练过程是什么
检索得到的内容如下:
出处 [1] 2021Q2大厂面试题共121题(含答案及解析).pdf
成. 15.6 bert 的改进版有哪些 参考答案: RoBERTa:更强大的 BERT 加大训练数据 16GB -> 160GB,更大的batch size,训练时间加长 不需要 NSP Loss: natural inference 使用更长的训练 SequenceStatic vs. Dynamic Masking 模型训练成本在 6 万美金以上(估算) ALBERT:参数更少的 BERT一个轻量级的 BERT 模型 共享层与层之间的参数 (减少模型参数)
出处 [2] 2022Q1大厂面试题共65题(含答案及解析).pdf
可以从预训练方法角度解答。
… 20
5、RoBERTa 相比 BERT 有哪些改进?
…
20 6、BERT 的输入有哪几种 Embedding?出处 [3] 2022Q2大厂面试题共92题(含答案及解析).pdf
保证模型的训练,pre-norm 显然更好一些。 5、GPT 与 Bert 的区别 1) GPT
是单向模型,无法利用上下文信息,只能利用上文;而 BERT 是双向模型。 2) GPT 是基于自回归模型,可以应用在 NLU 和 NLG两大任务,而原生的 BERT 采用的基于自编码模 型,只能完成 NLU 任务,无法直接应用在文本生成上面。 6、如何加速 Bert模型的训练 BERT 基线模型的训练使用 Adam with weight decay(Adam 优化器的变体)作为优化器,LAMB 是一款通用优化器,它适用于小批量和大批量,且除了学习率以外其他超参数均无需调整。LAMB 优化器支持自
而在文档中的结果如下:
可以看出,是没有检索到的相关内容的。
原因分析
使用默认配置时,虽然上传文档可以实现基础的问答,但效果并不是最好的,通常需要考虑以下几点原因。
- 文件解析及预处理:对于PDF文件,可能出现解析不准确的情况,导致检索召回率低;
- 文件切分:不同的chunk_size切分出来的粒度不一样。如果设置的粒度太小,会出现信息丢失的情况;如果设置的粒度太大,又可能会造成噪声太多,导致模型输出的结果明显错误。且单纯根据chunk_size切分比较简单粗暴,需要根据数据进行针对性优化;
- embedding 模型效果:模型效果不好也会影响检索结果。
优化方法:
- 文件解析及预处理:一方面可以尝试不同的PDF解析工具,解析更加准确;另一方面可以考虑将解析后的内容加上标题,并保存成Markdown格式,这样可以提高召回率;
- 文件切分:基于策略:对于特定的文档,比如有标题的,可以优先根据标题和对应内容进行划分,再考虑chunk_size;基于语义分割模型:还可以考虑使用语义分割模型。
- 模型效果:尝试使用更多embedding模型,获得更精确的检索结果。如:piccolo-large-zh 或 bge-large-zh-v1.5等等。可以参考榜单:https://huggingface.co/spaces/mteb/leaderboard
- 向量库:如果知识库比较庞大(文档数量多或文件较大),推荐使用pg向量数据库;如果文件中存在较多相似的内容,可以考虑分门别类存放数据,减少文件中冲突的内容。
- 多路召回:结合传统方法进行多路召回。
- 精排:对多路召回得到的结果进行精排。
LLM问题
LLM回答错误、遗漏或多余
问题描述
LLM问题主要有以下几点:
1、LLM的回答会出现遗漏信息或补充多余信息的情况。
2、chatglm2-6b还会出现回答明显错误的情况。
3、在检索到和问题相关的文本块的情况下,模型也会根据自己已有的知识进行回答。
比如我们还用上面的一个面试题:用通俗的语言介绍下强化学习
LLM基于知识库给的答案如下:
强化学习是一种人工智能技术,它通过不断地试错和学习,使机器逐步掌握如何在特定环境中实现某种目标。与监督学习不同,强化学习没有一个“老师”来指导机器,而是通过与环境的交互来不断学习。
在强化学习中,机器作为一个智能体,与环境的交互过程可以看作是多个时刻的循环。在每个时刻,机器根据当前的环境状态,依据一定的策略选择一个动作,然后接着得到一个反馈(如得分或奖励)。机器通过不断试错和学习,逐渐提高自己的策略,以最大化累积的奖励。
强化学习算法主要有三种:ID3、C4.5和CART树。其中,ID3算法通过信息增益准则来选择特征,C4.5算法则用信息增益比来选择特征,而CART树算法则是用基尼指数来选择特征。这些算法都在决策树的生成过程中应用某种准则来选择特征,以达到提高模型性能的目的。
而在文档中的结果如下:
可以看出,LLM并没有完全根据文档内容来回答,而是基于自己的知识进行了相应回答,而对于回答的第三段话,强化学习算法主要有三种:ID3、C4.5和CART树。可以看出,这段话的表达是完全错误的。
而如果换用Chatglm3-6b,则没有出现这种明显错误的情况,如下:
强化学习是一种通过不断尝试、学习并调整行动来获得奖励或惩罚的方法,让智能体在与环境的交互中不断学习和成长。它可以看做是一种“trial-and-error”的过程,通过尝试不同的行动来获得反馈,并根据反馈调整自己的行动,以获得最大的奖励。 example:比如,一个智能体想要通过一个迷宫来获得出口,它先尝试向左走,如果向左走后没有找到出口,它会向右走,如果向右走也没有找到出口,它会再向左走,这样不断尝试直到找到出口。这一过程就是强化学习。在强化学习中,智能体根据当前状态选择一个行动,然后根据行动的结果获得反馈,并根据反馈调整自己的选择,直到达到预期的目标。
下面看一个检索出来的结果和问题是相关的,但LLM还是会根据自己的知识进行回答的例子。
比如问一个问题:greedy search 和 beam search 的区别
Chatglm2-6b的回答如下:
Greedy search 和 beam search 都是 word2vec 中常用的搜索策略,它们的主要区别在于搜索空间的变化方式上。
Greedy search 是一种简单的搜索策略,它通过每一步都选择概率最大的单词来生成整个句子。这种方法虽然计算速度较快,但往往只能得到全局最优解,因为只考虑了每一步的最优解,往往里全局最优解差距很大。
Beam search 是一种在全局搜索和贪婪搜索之间的策略。它使用 beam size参数来限制在每一步保留下来的可能性词的数量。Beam search 的搜索空间比 greedy search更具有多样性,因为它允许在每一步保留更多的可能性词,从而可以更好地探索搜索空间,得到更全局的最优解。
具体来说,beam search 在每一步都选择当前可能性词中最优的词,并在后续的步骤中使用 dissimilarity项来避免全局最优解和局部最优解的累积误差。而 greedy search则是在每一步都选择概率最大的词,并在后续的步骤中逐渐减少搜索空间,只保留 beam size 个最大的取值路径。
总的来说,beam search 相对于 greedy search更具有探索性和可扩展性,可以得到更全局的最优解,但需要更多的计算资源。而 greedy search
则更加简单,计算速度更快,但往往只能得到局部最优解。
知识匹配结果如下:
知识库匹配结果
出处 [1] 2022Q2大厂面试题共92题(含答案及解析).pdf
3、word2vec 有几种方式 word2vec 有 CBOW 模型和 Skip-Gram 模型。 CBOW模型:输入是某一个特征词的上下文相关的词对应的词向量,而输出就是这特定的一个词的词向 量。(Continuous Bag-of-Word)Skip-Gram 模型:输入是特定的一个词的词向量,而输出是特定词对应的上下文词向量。 有两种改进方式: 一种是基于Hierarchical Softmax 的,另一种是基于 Negative Sampling 的。 4、greedy search 和beam search 的区别 greedy search 比较简单,就是贪婪式的搜索,每一步都选择概率最大的单词输出,最后组成整个句子输出。这种方法给出的结果一般情况结果比较差,因为只考虑了每一步的最优解,往往里全局最优解差距很大。
出处 [2] 2022Q2大厂面试题共92题(含答案及解析).pdf
1、Beam Search 生成的句子基本都一样,是否有方法扩展生成句子的多样性 解决方法:通过分组加入相似性惩罚,具体可以参考论文Diverse beam search: https://arxiv.org/pdf/1610.02424.pdf。 具体方法:选择Beam size 为 B,然后将其分为 G 组,每一组就有 B/G 个 beam,每个单独的组内跟 beam search很像,不断延展序列,同时引入一个 dissimilarity 项来保证组与组之间有差异。 组内与 beam search 很像:从 t-1到 t 时刻,不断的减少搜索空间(如同 beam search 一样)。 组间差异:对于 t=4 时刻,我们先对第一组输出y(t=4),然后我们开始对第二组输出 y(t=4),但
出处 [3] 2022Q2大厂面试题共92题(含答案及解析).pdf
出。这种方法给出的结果一般情况结果比较差,因为只考虑了每一步的最优解,往往里全局最优解差距很大。 优点:计算速度快,每次取概率最大的词。缺点:局部最优并不等于全局最好的,而且一旦选错了,后 续生成的内容很可能也是错误的,具有错误的累加效果。 第 35 页 共 46 页beam search 是介于全局搜索和贪婪搜索之间。使用 beam size 参数来限制在每一步保留下来的可能性 词的数量。beam search 是在测试阶段为了获得更好准确性而采取的一种策略,在训练阶段无需使用。相比暴力搜索的全局最优解,降低时间复杂度的方法就是寻找次优解,具体就是把搜索空间中的 N 减下 来,每一步计算完只保留 K 个(beam size)最大的取值路径,这样时间复杂度降为 O(KNT),K 取值一般比
优化方法
- 优化prompt,可能会有一定效果的。但由于随机性,结果并不能得到保证。
- 优先使用最新的6B/7B模型:ChatGLM3-6B、Baichuan2-7B、Qwen-7B,如果资源可以支持48G以上的显卡,可以考虑使用Qwen-14B-Chat 或 Baichuan-13B-Chat,13B的模型通常好于6B/7B模型。
优化方案
PDF文档解析优化方案
Langchian-Chatchat中对于不同类型的文件提供了不同的处理方式,从项目server/knoledge_base/utils.py文件中可以看到对于不同类型文件的加载方式,大体有HTML,Markdown,json,PDF,图片及其他类型等。
LOADER_DICT = {"UnstructuredHTMLLoader": ['.html'],
"UnstructuredMarkdownLoader": ['.md'],
"CustomJSONLoader": [".json"],
"CSVLoader": [".csv"],
# "FilteredCSVLoader": [".csv"], # 需要自己指定,目前还没有支持
"RapidOCRPDFLoader": [".pdf"],
"RapidOCRLoader": ['.png', '.jpg', '.jpeg', '.bmp'],
"UnstructuredFileLoader": ['.eml', '.msg', '.rst',
'.rtf', '.txt', '.xml',
'.docx', '.epub', '.odt',
'.ppt', '.pptx', '.tsv'],
}
这里,我们重点关注PDF文件的解析方式,并探究其可能的优化方案。从上面的文件加载字典中可以看出,PDF文件使用的加载器为RapidOCRPDFLoader,该文件的方法在项目document_loaders/mypdfloader.py中。
处理方法:
- 首先使用fitz(即pyMuPDF)的open方法解析PDF文件;
- 对于每一页的文本内容,通过get_text方法进行获取,而对于图片内容通过get_images方法进行获取,获取后通过RapidOCR对图片中的文本内容进行提取;
- 最后将从图片中提取的文本和原始的文本内容进行拼接,得到最终的所有文本内容。然后进行下一步的分词和文本切割。
这种方式的优点简单粗暴,基本上对于任何排版的PDF文件都能够提取到有效信息。但缺点也很明显,就是无差别,比如我们的文档本身就有较好结构,提取出来的内容也无法将结构反映出来。所以,通常情况下需要根据文档的具体情况对解析后的文档做进一步定制化处理。
以七月在线大厂面试题PDF文档为例,有以下特点:
- 文档具有书签,可以直接根据书签对应到具体的页码
- 文档结构不复杂,共有两级标题,一级标题表示一个大的章节,二级标题表示面试题的问题,文本内容为每道面试题对应的答案;
- 每道面试题是独立的,和其前后的面试题并没有明显的相关性。
- 面试题题目的长度长短不一,短的有几个词组成,长的基本一句话。
- 文档中除中文外,还有大量模型或算法英文词,且文档中包含部分公式和代码。
因此,可以考虑根据文档的标题进行分割,即将文档中的标题和标题对应的内容分为一块,在放入向量库的时候可以尝试两种方式,一种是只将题目进行向量化表示存入向量库,另一种是将题目和答案一起进行向量化表示存入向量库。
文档解析过程中存在的问题:
1、书签中的标题内容和文档中的标题内容并不完全一致,这种情况可能是解析后出现多余的空格导致的;
2、需要考虑一道面试题可能存在跨页的情况,一般是会出现一道面试题出现在两页的情况,但也需要考虑一道面试跨三页或多页的情况。
3、由于一级标题是有分页符的,每个一级标题会另起一页,因此在处理时也需要考虑此种情况。
4、解析的文本中带有页脚,如:第 4 页 共 46 页,由于页脚的内容对面试题是没有意义的,因此也需要考虑去掉。
解决方案:
1、对于书签中的标题内容和文档中的标题内容并不完全一致的问题,一种方式有考虑去除文档中标题的空格,实现困难在于无法精确定位,如果全去掉就会出现一些英文单词拼接在一块的情况,可能对语义或后续的检索产生影响;一种方式是不去除,如果出现这种情况,则将标题所在页的信息都提取出来;
2、对于一道面试题可能存在跨页的情况,可以通过设置起始页和终止页,对相邻标题(主要是下一个标题)所在页进行判断的方式来处理;
3、对于每个一级标题会另起一页的情况,可以通过添加对特殊字符“1、”判断的方式来处理;
4、对于页脚,可以使用正则表达式进行匹配去除。
参考
基于LLM+向量库的文档对话痛点及解决方案:https://zhuanlan.zhihu.com/p/651179780
RAG检索增强的比赛参考方案:
https://github.com/MetaGLM/FinGLM
https://www.kaggle.com/competitions/kaggle-llm-science-exam/discussion
https://tianchi.aliyun.com/competition/entrance/532154?spm=a2c22.12281957.0.0.605a3b74yOyo0b
大模型外挂知识库优化:https://www.zhihu.com/people/zhan-shi-jin-27/posts
多向量检索器与查询转换:https://www.datalearner.com/blog/1051698375259477
LLM+Embedding构建问答系统的局限性及优化方案:https://zhuanlan.zhihu.com/p/641132245
与传统方法结合的多路召回:https://github.com/FlagOpen/FlagEmbedding/issues/17