Skip to content

大模型外挂知识库优化——如何利用大模型辅助召回?

来源:AiGC面试宝典
作者:宁静致远
日期:2024年03月19日 22:30


目录


一、为什么需要使用大模型辅助召回?

我们可以通过向量召回的方式从文档库里召回和用户问题相关的文档片段,同时输入到 LLM 中,增强模型回答质量。

常用的方式是直接用用户的问题进行文档召回。但是很多时候,用户的问题是十分口语化的,描述的也比较模糊,这样会影响向量召回的质量,进而影响模型回答效果。

📝通俗解释:这就好像你去图书馆找书,如果你只说"我想找一本关于那个经常出现在电视上的叫什么的美国总统的书",管理员可能很难理解你要找什么。但如果你说"我想找关于拜登的书",图书馆系统就能更准确地找到相关书籍。大模型的作用就是帮助把用户模糊的问题"翻译"成更清晰、更容易被检索系统理解的形式。


策略一:HYDE

📝通俗解释:HYDE 的全称是 "Hypothetical Document Embeddings",中文意思是"假设性文档嵌入"。它的核心思想是"以答代问"——不直接用用户的问题去检索,而是让大模型先猜一个答案,然后用这个答案去检索。

1. HYDE 思路介绍

HYDE 的工作流程如下:

  1. 用 LLM 根据用户 query 生成 k 个"假答案"

    📝通俗解释:这里的"假答案"是指大模型自己编造的答案,可能包含错误信息。我们并不真正使用这个答案的内容,而是利用它来理解用户可能想要什么。生成时采用 sample 模式,保证生成的 k 个答案不一样。

  2. 利用向量化模型,将生成的 k 个假答案和用户的 query 变成向量

  3. 将 k+1 个向量取平均

    📝通俗解释:公式中 dk 为第 k 个生成的答案,q 为用户问题,f 为向量化操作。平均后的向量既包含了用户问题的信息,也包含了"看起来像正确答案"的信息。

$$ \hat{\mathbf{v}}{q{ij}} = \frac{1}{N+1} [\sum_{k=1}^{N} f(\hat{d}k) + f(q)] $$

  1. 利用融合向量 v 从文档库中召回答案

    📝通俗解释:融合向量中既有用户问题的信息,也有"理想答案"的模式信息,这样可以增强召回效果。就像是既知道用户想问什么,又知道符合需求的文档大概长什么样,两者结合能找到更准确的结果。


2. HYDE 问题分析

该方法在结合微调过的向量化模型时,效果就没那么好了,非常依赖辅助 LLM 的能力。

原始的该模型并未在 TREC DL19/20 数据集上训练过。模型有上标 FT 指的是向量化模型在 TREC DL 相关的数据集上微调过的。

📝通俗解释:表中黄色框是 baseline(不用 HYDE 技术),绿色框是未微调的向量化模型使用 HYDE 的结果,红色框是微调过的向量化模型使用 HYDE 的结果。指标是 NDCG@10(衡量搜索排序质量的指标,越高越好)。

ModelDL19DL20
Contriever44.542.1
ContrieverFT62.163.2
HyDE
w/ Contriever
  w/ Flan-T5 (11b)48.952.9
  w/ Cohere (52b)53.853.8
  w/ GPT (175b)61.357.9
w/ ContrieverFT
  w/ Flan-T5 (11b)60.262.1
  w/ Cohere (52b)61.463.1
  w/ GPT (175b)67.463.5

关键发现:

  • 对于没有微调过的向量化模型(zero-shot 场景),HYDE 非常有帮助,且随着 LLM 模型增大,效果不断变好
  • 对于微调过的向量化模型,如果使用比较小的 LLM 生成假答案(小于 52B 参数量),HYDE 技术甚至会带来负面影响

📝通俗解释:这就像是一个"半吊子助手"——如果你的检索系统已经很专业了(微调过),让一个能力一般的大模型来帮忙反而可能帮倒忙。但如果你的检索系统本身就不太行(没微调过),让一个强大的大模型来"猜"答案,反而能显著提升效果。


策略二:FLARE

📝通俗解释:FLARE 的全称是 "Active REtrieval Augmented Generation",中文意思是"主动检索增强生成"。它的核心思想是在生成内容的过程中多次、主动地检索相关知识,而不是只在一开始检索一次。


1. 为什么需要 FLARE?

对于大模型外挂知识库,大家通常的做法是根据用户 query 一次召回文档片段,让模型生成答案。

📝通俗解释:这就像写一篇很长的文章,只在开始时查一次资料,然后凭记忆写完整篇文章。这样很容易出现"写到后面忘了前面"或者"编造事实"(幻觉)的问题。

只进行一次文档召回在长文本生成的场景下效果往往不好,生成的文本过长,更有可能扩展出和 query 相关性较弱的内容,如果模型没有这部分知识,容易产生模型幻觉问题。

一种解决思路是:随着文本生成,多次从向量库中召回内容。

📝通俗解释:FLARE 的做法就像是边写边查资料。写一段,查一下相关资料;再写一段,再查一下。这样可以确保每写的重要内容都有据可查,减少幻觉。


2. FLARE 召回策略

已有的多次召回方案:

  1. 每生成固定的 n 个 token 就召回一次
  2. 每生成一个完整的句子就召回一次
  3. 用户 query 一步步分解为子问题,需要解答当前子问题时候,就召回一次

📝通俗解释:这些方案都比较"被动"——策略 a、b 并不能准确判断什么时候真的需要召回,可能在不需要时频繁召回,或者该召回时没有召回。策略 c 需要精心设计 prompt,通用性较差。

作者在本文里提出了两种更主动的多次召回策略,让模型自己决定什么时候触发召回操作。


2.1 策略一:主动召回标识

📝通俗解释:这个策略的核心是让模型学会在需要查资料时主动"喊停",生成一个特殊的标记来表示"我需要查一下这个"。

2.1.1 策略一思路

通过设计 prompt 以及提供示例的方式,让模型知道当遇到需要查询知识的时候,提出问题,并按照格式输出,和 Toolformer 的模式类似。

  1. 提出问题的格式[Search("模型自动提出的问题")](称其为主动召回标识)。利用模型生成的问题去召回答案。

  2. 召回出答案后,将答案放到用户 query 的前边,然后去掉主动召回标识之后,继续生成。

  3. 当下一次生成主动召回标识之后,将上次召回出来的内容从 prompt 中去掉。

📝通俗解释:这个流程就像:

  • 模型说:"[Search(拜登在哪里上学)]"
  • 系统去查资料,找到"拜登毕业于宾夕法尼亚大学"
  • 模型继续生成:"拜登毕业于宾夕法尼亚大学,在那里获得了..."
  • 模型又说:"[Search(拜登获得了什么学位)]"
  • 系统再查资料,找到"拜登获得了法学博士学位"
  • 模型继续生成:"法学博士学位。"

下图展示了生成拜登相关答案时,触发多次召回的例子:

Input: "Generate a summary about Joe Biden."

Generation 过程:
  y₁: "Joe Biden attended"
  q₂: [Search("Joe Biden University")] → Retriever → "D₍q₂₎: University of Pennsylvania"
  y₂: "the University of Pennsylvania, where he earned"
  q₃: [Search("Joe Biden degree")] → Retriever → "D₍q₃₎: law degree"
  y₃: "a law degree."

2.1.2 策略一缺陷
  1. LLM 不愿意生成主动召回标识

    • 解决方法:对 "[" 对应的 logit 乘 2,增加生成 "[" 的概率
  2. 过于频繁的主动召回可能会影响生成质量

    • 解决方法:在刚生成一次主动召回标识、得到召回后的文档、去掉主动召回标识之后,接下来生成的几个 token 禁止生成 "["
  3. 不微调该方案不太可靠

    • 很难通过 few-shot 的方式让模型生成这种输出模式

📝通俗解释:策略一的主要问题是模型可能"不听话",不肯主动生成那个特殊的标记。这需要通过微调才能让模型很好地配合。


2.2 策略二:置信度触发召回

📝通俗解释:这个策略更加巧妙——它通过判断模型对自己生成内容的"自信程度"来决定什么时候该查资料。如果模型生成某个词时自己都不太确定,那就说明可能需要查一下资料了。

2.2.1 策略二思路

策略一存在的第 3 点缺陷比较严重。因此作者提出了策略二。该策略基于一个假设:模型生成的词对应该的概率能够表现生成内容的置信度

📝通俗解释:当你让模型生成"拜登毕业于..."时,如果模型生成"宾夕法尼亚大学"的概率很高,说明它对这个答案比较自信;如果生成某个词的概率很低,说明它自己也不太确定这个内容对不对。

工作流程:

  1. 根据用户的 query,进行第一次召回,让模型生成答案

  2. 之后,每生成 64 个 token,用 NLTK 工具包从 64 个 token 里边找到第一个完整句子,当作"假答案",切掉多余的 token

    📝通俗解释:和 HYDE 的思想一样,利用 LLM 生成符合回答模式的"假答案"来帮助检索

  3. 如果"假答案"里有任意一个 token 对应的概率,低于某一阈值,那么就利用这个句子进行向量召回

    📝通俗解释:模型在生成某些词时概率很低,说明它对这些内容没把握,需要查资料确认

  4. 触发召回的"假答案"很可能包含事实性错误,降低召回准确率。设计了两种方法解决这个问题:

    • 方法1(隐式查询):将"假答案"中生成概率低于某一阈值的 token 扔掉(低概率的 token 很可能存在错误信息),然后再进行向量召回
    • 方法2(显式查询):利用大模型能力,对"假答案"中置信度低的内容进行提问,生成一个问题,用生成的问题进行向量召回
  5. 利用召回出来的文本,重新生成新的"真答案",然后进行下一个句子的生成

📝通俗解释:举个例子,模型生成了"拜登毕业于 [某概率很低的词]"。方法1会把这个不确定的词去掉,变成"拜登毕业于",然后去检索。方法2会问"拜登毕业于哪所学校?",然后用这个问题去检索。

处理流程示意:

原始文本: "Joe Biden attended the University of Pennsylvania, where he earned a law degree."

方法1 (implicit query by masking):
  → "Joe Biden attended ___, where he earned ___."

方法2 (explicit query by question generation):
  → "What university did Joe Biden attend?"
  → "What degree did Joe Biden earn?"

参考资料

  1. HYDE 论文
  2. FLARE 论文
  3. 知识星球:AiGC面试宝典

📝通俗解释:总结一下这两种策略的核心区别:

  • HYDE:在检索之前,先让大模型猜一个答案,用这个"假答案"去检索
  • FLARE:在生成过程中,根据需要多次检索,分为主动标识和置信度触发两种方式
  • 两种方法都是为了解决"用户问题太模糊"或"生成内容太长容易出错"的问题,只是介入的时机不同

基于 MIT 许可发布