让你的RAG应用更加智能!引入自我反思的大模型 RAG 框架(Self-RAG) 原创
Self-RAG 出现的背景
经典的RAG模型通过提供与问题相关的上下文信息来支持LLM在回答知识密集型问题。然而,这种方法存在两个主要问题:
- 过度检索:RAG系统并不针对用户意图进行精细的判断,而是对每次输入都执行top-k的知识检索,可能导致引入不必要或偏离主题的信息,从而影响输出的质量。例如,当用户仅是打招呼时(如 "hello"),理想的做法是直接利用LLM的能力来回答,而不需要查询知识库
- 输出一致性问题:无法百分百确定回答的内容就是完全参考检索到的上下文还是来自模型自己的生成,因为大模型本身不能保证绝对的遵循,更何况知识的相关性也会存疑。
在实际应用RAG时,我们常常通过精细化的工作流程设计和创新性的Prompt调整来尽量缓解上述问题。具体来说:
- 我们可以利用LLM的能力,在执行检索步骤之前先判断是否真的需要进行检索。
- 在给出Prompt指令时,我们可以确保LLM严格按照找到的参考知识来形成答案。
- 我们还可能依赖LLM的强大能力对答案进行评估,经过多轮迭代优化,以提升答案的质量。
然而这些方案往往比较复杂,并可能引入一些难以控制的潜在问题。Self-RAG则是另一种解决这些挑战的方案。
什么是Self-RAG
Self-RAG是由来自华盛顿大学、IBM人工智能研究院等机构技术专家提出的一种增强的RAG范式, Self-RAG 的论文地址可以看SELF-RAG: LEARNING TO RETRIEVE, GENERATE, AND CRITIQUE THROUGH SELF-REFLECTION。它主要是在模型层面的微调,让大模型本身直接具备了判断按需检索与自我评判的能力,并进而通过与应用层的配合,达到提升生成准确性与质量的问题。Self-RAG的运作流程如下:
基本流程
Self-RAG的基本工作流程用网上的这张图进行说明:
从图上我们可以看出Self-RAG相比经典RAG有以下几点不同:
- 按需检索
- 如果无需检索(比如”hello“),则由模型直接生成
- 如果需要检索(比如”what is new features of iphone15“),则执行检索
- 并行生成:使用检索出的K个相关知识与输入问题组装Prompt,并行生成K个输出。而传统的RAG则是把K个知识一起和输入问题组成Prompt只生成1个输出。
- 评估和选择:先对生成的多个响应进行评分,然后选择上一步其中一个响应作为输出
仔细研究上面的流程可以看出,有两个环节需要借助LLM进行评判:
- 用户的问题是否需要进行知识检索
- 如果进行检索,如何对多个输出计算评分
那么我们应该如何进行评判呢?常规的方式是借助LLM与Prompt来判断,这种方式的好处是完全在应用层实现,但缺点是:
- 过多的LLM交互会带来响应性能下降与tokens成本升高
- 生成的评判指标只能定性的判断,难以量化
Self-RAG采用了一种不同的方法:通过微调训练LLM,让LLM在推理过程中实现自我反省,直接输出一些特殊的Tokens,一般称之为“Reflection Token”。我们可以利用这些特殊的Token来进行不同的操作。下面我们会对上面需要LLM进行评判的两个环节做详细说明。
按需检索
Self-RAG 开始使用 LLM 对问题进行生成时,会输出 Retrieve
类型的 Reflection Token。Reflection Token有三种可能的值,分别代表不同的行动指示:
- "Retrieval":表示需要查找更多相关信息。
- "No Retrieval":表示无需进一步检索,模型应该根据已有的知识或信息回答问题。
- "Continue to Use Evidence":表示模型应继续利用先前检索到的信息进行问题的解答。
来看几个例子,首先是一个不需要检索的例子:
Question: Write a essay of your best summer vacation.
Answer: Sure![No Retrieval]As an AI, I don't have personal experiences or memories, but I can write about the importance and significance of summer vacations for individuals and families.[No Retrieval]......
在返回结果中我们可以看到包含了[No Retrieval]
关键字,表示这个问题不需要检索,可以直接返回结果。
我们再问一个需要检索的问题:
Question: How did US statues get their names?
Answer: A number of them.[Retrieval]<paragraph>[Irrelevant]Some were named for the people who originally sponsored them, some were named for events or issues that they represented, and some were named for mythological figures.[Utility:4]
在返回结果中我们可以看到包含了[Retrieval]<paragraph>
关键字,表示这个问题需要补充外部知识,即需要检索。
在没有Self-RAG之前,我们可以首先使用 LLM(Language Model)确定查询问题是否需要检索。如果无需检索,那么直接用 LLM 生成最终答案。这种方式的一个缺点是,如果查询问题实际上不需要检索,那么标准的 RAG 模型将需要进行两次 LLM 调用。而 Self-RAG 模型则更高效,即便在此类情况下也只需调用一次 LLM。可以看到在不需要检索的这个分支上,Self-RAG的效率更高。
检索和生成
在这个阶段,Self-RAG LLM会生成三种类型的Reflection Token:
- IsREL: 检查检索到的文档是否为查询提供了有用信息,值为
[Relevant]
和[Irrelevant]
表示相关性。 - IsSUP:检查检索到的文档是否都为生成的答案提供了支持,它的值有
[Fully supported]
,[Partially supported]
,[No support / Contradictory]
,表示支持的程度 - IsUSE: 表示生成的答案是否对查询有帮助,值[Utility:5]
、
[Utility:4]、
[Utility:3]、
[Utility:2]、
[Utility:1]`,表示答案的质量,数字越大表示质量越高,表示答案的质量,数字越高表示质量越高。
我们来看下 Self-RAG 在这个阶段的生成结果,问题和输出结果示例如下:
Question: What mysterious object did Loki use in his attempt to conquer Earth?
Answer1: [Relevant]The mysterious object that Loki used in his attempt to conquer Earth was the Tesseract, which is a powerful energy source of unknown potential.[Fully supported][Utility:5]
Answer2: [Relevant]Thanos used the Time Stone to dodge Loki's attack.[No support / Contradictory][Utility:5]
可以看到,在每个生成结果中,基本上都包含了以上 3 种 Reflection Token,这些 Token 会在后面的评估阶段进行使用,评估得分最高的文档被选作最终结果。
评估算法
我们看到的标记tokens并非量化指标,因此这里需要借助到LLM推理输出结果的一个字段:logprobs(对数),我们来了解一下这个字段和相对应的算法。
LLM的工作方式是通过连续预测并生成token,直到整个文本生成完毕。它并不是事先确定下一个token,而是通过复杂的计算和神经网络处理来推测下一个可能的词元。输出结果是一个包含多个可能词元及其相应概率的列表,从中LLM选择概率最高的词元进行输出。可以参考下图简单理解下:
LLM最后从多个候选tokens中选择“机器”这个词输出,并将其附加到输入提示,进入下一次生成。而logprobs就是用来保存这里每一步预测时的多个可能的token概率(取对数,所以叫对数概率).
我们再来看下 OpenAI API 返回的一个结果示例:
{
"id": "copl-6yE4TGqItUpYJ6xYcIzY6",
"object": "text_completion",
"created": 1723073722,
"model": "davinci",
"choices": [
{
"text": " I'm good, thanks!",
"index": 0,
"logprobs": {
"tokens": [" I'm", " good", ",", " thanks", "!"],
"token_logprobs": [-0.1, -0.05, -0.2, -0.3, -0.15],
"top_logprobs": [
{
" I'm": -0.1,
" I am": -2.3,
" I": -3.1
},
{
" good": -0.05,
" fine": -1.5,
" great": -2.0
},
{
",": -0.2,
".": -2.5,
"!": -3.0
},
{
" thanks": -0.3,
" thank you": -1.8,
" thank": -2.6
},
{
"!": -0.15,
".": -1.9,
"?": -2.7
}
],
"text_offset": [5, 9, 14, 15, 21]
},
"finish_reason": "length"
}
],
"usage": {
"prompt_tokens": 5,
"completion_tokens": 5,
"total_tokens": 10
}
}
在这个示例中,logprobs 参数的输出如下:
- tokens:生成的 token 列表 [" I’m", " good", ",", " thanks", "!"]
- token_logprobs:每个生成的 token 的对数概率值 [-0.1, -0.05, -0.2, -0.3, -0.15]
- top_logprobs:每个生成的 token 的前几名候选 token 的对数概率值及其对应的 token,例如第一个 token
I’m
的前几名候选 token 及其对数概率值为{" I’m": -0.1, " I am": -2.3, " I": -3.1}
- text_offset:每个 token 在生成文本中的偏移量 [5, 9, 14, 15, 21]
在Self-RAG中,评估函数使用logprobs参数来计算IsREL、IsSUP和IsUSE反射标记的分数。这里给出计算公式,数学不好的可以跳过:
- 知识相关度:s(ISREL) = p(ISREL = RELEVANT) / (p(ISREL = RELEVANT) + p(ISREL = IRRELEVANT)),即用“relevant”token的概率占本类型两种token的概率和的比例
- 响应支持度:s(ISSUP) = p(ISSUP = FULLY) / S + 0.5 * p(ISSUP = PARTIALLY) / S,即用“fully supported”token的概率占本类型三种类型token概率和的比例,加上“partially supported”token的概率所占比例。但后者要乘以权重0.5
- 响应有效性:s(ISUSE) = (∑i wi * p(ISUSE = i)) / S,用本类型的5种类型token的概率占总概率的比例乘以对应的权重(分别为从-1到1不等),然后求和
好了,Self-RAG 基本的原理就先分享到这,下一篇文章会分享如何实现一个真正的Self-RAG应用。
本文转载自公众号AI 博物院 作者:longyunfeigu
原文链接:https://mp.weixin.qq.com/s/8A6SSjAx07KBDFKmENvjxA