QAnything架构学习

QAnything系统的工作流程主要包含三个环节:

  • 索引(indexing):文本索引的构建包括以下步骤:文档解析、文本分块、Embedding向量化和创建索引。先将不同格式的原始文件解析转换为纯文本,再把文本切分成较小的文本块。通过Embedding为每一个文本块生成一个向量表示,用于计算文本向量问题向量之间的相似度。创建索引将原始文本块和Embedding向量以键值对的形式存储,以便将来进行快速和频繁的搜索。

  • 检索(Retrieval):使用Embedding模型将用户输入问题转换为向量,计算问题的Embedding向量语料库中文本块Embedding向量之间的相似度,选择相似度最高的前K个文档块作为当前问题的增强上下文信息。

  • 生成(Generation):将检索得到的前K个文本块和用户问题一起送进大模型,让大模型基于给定的文本块来回答用户的问题。

检索器

期望检索器达到的效果

  1. 具备将不同语种的翻译文本做关联的能力(跨语种检索能力)
  2. 具备将长原文和短摘要进行关联的能力
  3. 具备将不同表述但相同语义的文本做关联的能力
  4. 具备将表述不同但意图相同的问题进行关联的能力
  5. 具备将问题和可能的答案文本进行关联的能力
  6. 检索出尽可能多的相关片段,并且真正有用的片段应该在更靠前的位置

RAG中检索的业务目标是,找出用户问题相关的片段,此时不仅要检索该问题的答案相关的片段,也要检索该问题相似问题,因为相似问题的上下文常常含有原问题的答案相关内容。所以训练过程中,需要将RAG需要检索的目标设置为正例(这个目标可能是相似问题,可能是对应答案,可能是短摘要对应的原长文,也可能是相关的推理过程)。

为什么QAnything要训练自己的Embedding模型?

  1. 开源的Embedding模型效果并不如宣传的那么好,它们在MTEB榜单上可能分数很高,但是这并不能反映真实的效果

  2. 网易有道的业务场景有很多混合语言的情况,比如知识库里存放的是英文文档,但是用户希望得到中文回复,这种跨语种的能力,现有模型支持不好

  3. 单纯的Embedding在检索排序上天花板比较低,所以需要在Embedding基础上增加Reranker,共享同样的底座,但是head不一样。

效果比对:在网易有道的场景下(客服问答以及一些toB客户的场景),openai的ada2 embedding的检索准确率只有60%,而经过训练的BCEmbedding检索准确率可以达到95%。

实验现象:数据标签的构建对模型的效果影响非常大。
在机器学习中,模型性能上不去的时候,大多是因为一些例子比较难,模型训练时见的少,多挖掘一些难例给模型,就能提升模型的性能。但是在训练Embedding模型时,发现难例挖掘反而会降低模型的性能。

猜测原因:Embedding模型本身的能力有限,不应该给过难的任务。

  1. 很多难负样本只有细微差异,“相似程度”很高,强行让Embedding模型区分只会让它感到困惑。
  2. 在大量语料库中,自动化地进行难负样例挖掘而不经过人工校验,难免会“挖到正例”,这会毒害模型训练。
  3. 所谓的“正例”和“难负样例”需要根据业务定义,RAG场景下之前人们认为的难负样例可能就成了正例。

实际操作时,QAnything的向量库采用milvus的混合检索(BM25 + 向量检索),不设置阈值,返回top100的结果。

为什么需要Reranker模块?

Embedding阶段尽可能召回用户问题所需的相关文本片段,而Reranker的目标是越相关的、对回答问题越有帮助的片段应该在越靠前的位置,过滤低质量片段。

因为Embedding模型是dual-encoder(在这种架构中,有两个独立的编码器分别对输入的两个部分进行编码),query和passage在“离线”地语义向量提取时没有信息交互,全靠模型将query和passages“硬”编码到语义空间中,再去语义检索。而rerank的阶段,cross-encoder可以让两个文本片段一开始就在BERT模型各层中通过self-attention进行交互,充分交互query和passage信息,识别更加准确的语义关系,潜力大的多。所以我们定了目标,embedding尽可能提高召回,reranker尽可能提高精度。

此外,QAnything在产品实践中发现,当知识库语料增大时,里面会充斥很多干扰信息,Embedding模型由于其能力有限,通过语义向量检索到的相关片段整体质量变差,导致LLM回答效果变差。采用二阶段方式时,精排Reranker可以对检索到的相关片段进行进一步重排和过滤,可以显著提升最终检索的质量,实现数据越多问答效果越好的愿景。

对于RAG系统,如果喂给大模型的输入是相近且容易混淆的话,对正确性的影响是很大的。比如,问题是“大连医科大学怎么样”,可能会匹配到“大连理工大学XXX怎么样”,看起来和用户问题非常像,Embedding给它打了比较高的分数。而类似“大连医科大学师资介绍”这样的片段相关性就稍微低了些。文本片段与query的相似性和文本片段是否包含query的答案(相关性)是两回事。RAG中非常重要的矛盾点在于,检索召回的片段比较多,但是LLM的输入token是有限制的,所以必须把能回答query问题的片段(和问题最相关)给LLM。

实际操作时,reranker的阈值设置在0.35。


在实际使用中,因为rerank比embedding慢得多,所以一般用两阶段检索。速度慢不是cross-encoder的模型比dual-encoder的模型速度慢。关键在于,dual-encoder可以离线计算海量文本块的向量化表示,把它们暂存在向量数据库中,在问答检索的时候只需要计算一个query的向量化表示就可以了。拿着query的向量表示去库里找最相似的文本即可。

但是cross-encoder需要实时计算两个文本块的相关度,如果候选文本有几万条,每一条都需要和query一起送进BERT模型中算一遍,需要实时算几万次。这个成本是非常巨大的。

所以,我们可以把检索过程分为两个阶段:召回(粗排)和重排:

  • 第一个阶段的目标是尽可能多的召回相似的文本片段,这个阶段的文本得分排序不是特别靠谱,所以候选的topK可以设置大一些,比如topK=100;
  • 第二个阶段的目标是对100个粗排的候选文本片段进行重新排序,用cross-encoder计算100个候选文本和query的相关度得分;

两阶段检索结合可以兼顾效果和效率。

LLM模型微调

QAnything在Qwen-7B的基础上,通过精心构建的中英文高质量指令数据进行微调得到Qwen-7B-QAnything。通过在优秀的开源大型语言模型的基础上进行后续训练,包括继续预训练、指令微调(SFT)和偏好对齐等工作,可以更有效地满足RAG应用对大模型的特定需求,从而实现高性价比的模型优化。

为什么需要微调?

RAG技术结合了知识检索和生成模型,通过从外部知识源检索信息,并将这些信息与用户问题整合成完整的Prompt输入到大模型中,以便根据这些参考信息回答问题。然而,当面对含有专业术语或者通俗缩写的开放性问题时,直接使用开源Chat模型可能会导致模型回答不准确。此外,为了最大化利用大模型的上下文窗口,RAG应用倾向于保留尽可能多的检索信息,这可能会使模型的注意力分散,降低其遵循指令的能力,进而引发回答中的重复内容、关键信息丢失等问题。为了提高大模型在参考信息不足时的诚实度,加入与用户问题关联度低的负样本进行微调训练变得必要。

在指令微调时,采用了结构化指令模板,以增强模型在实际应用中的指令遵循能力。

微调过程

  1. 指令微调数据构造

    网易有道团队构造了丰富的指令微调数据集,涵盖了多种类型的数据,包括基于参考信息的结构化问答数据(单文档/多文档的事实问答、多文档的归纳总结/推理类问答、信息抽取)、多轮对话查询重写、段落摘要、开放域问答、中英文翻译以及跨学科问答等。

  2. 指令微调模型训练

    首先采用LoRA方法进行微调探索,待实验条件稳定后,再转向全参数微调。LoRA微调配置如下:使用8张A40显卡的单机环境,初始学习率设为3e-5,每张卡的批量大小为2,采用16步的梯度累积,同时利用bfloat16精度训练以避免溢出并增强稳定性。此外,我们采用QLoRA + DeepSpeed Zero2 + FlashAttention配置以节约训练所需的显存。QLoRA通过4比特量化技术压缩预训练语言模型,使用NormalFloat4数据类型存储基模型权重,冻结基模型参数,并以低秩适配器(LoRA参数)形式添加少量可训练参数。在微调阶段,QLoRA将权重从NormalFloat4数据类型反量化为bfloat16进行前向和后向传播,仅更新bfloat16格式的LoRA参数权重梯度。

  3. 指令微调模型问答效果评估

    参考了Benchmarking Large Language Models in Retrieval-Augmented Generation这篇文章,使用开源Benchmark的事实型文档问答测试集,对微调之后的LLM做质量评估。相比于Qwen-7B和Qwen-7B-Chat,微调之后的模型对检索外部知识源包含不相关信息的鲁棒性更好。

    此外,团队内部针对业务场景构造700条问答对作为评测集,覆盖多种文档类型和问题,其中相关参考信息由BCE Embedding和Rerank模型检索重排序得到,参考答案由GPT4生成,结合人工修正得到。结合Ragas评测框架实现对LLM的自动化评测。评测指标采用answer_correctness,通过计算LLM回答内容answer和参考答案的factual correctnesssemantic similarity加权和得到,其中factual correctness(权重系数0.75)利用GPT4根据answer和参考答案生成TP/FN/FP表述计算得分,semantic similarity(权重系数0.25)利用BCE Embedding计算answer和参考答案的语义相似度。

【参考文献】

  1. QAnything

  2. 有道QAnything背后的故事—-关于RAG的一点经验分享

  3. QAnything之BCEmbedding技术路线