用小学一年级练习来理解RAG的上下文相关性挑战

通过一年级阅读理解练习案例,来研究如何测量检索增强生成系统中的上下文相关性。

由 Leonie Monigatti [1] 发布于 Towards Data Science [2]

用小学一年级练习来理解RAG的上下文相关性挑战-2

一个一年级阅读理解练习作为检索增强生成(RAG)示例,展示上下文相关性

检索到的上下文与用户输入的相关性在 检索增强生成(RAG)管道 [3] 的性能中起关键作用。然而,检索相关上下文本身就面临一系列挑战,更具挑战性的是如何有效地衡量上下文的相关性。

本文将探讨检索相关上下文和衡量上下文相关性的挑战,并通过以下一年级文本理解示例进行阐述。

text = """Lisa is at the park. Her dog Bella, is with her.   Lisa rides her bike and plays with Bella. They race each other in the sun.   Then Lisa goes to the pond to see the ducks.   She thinks they are so cute and funny."""    questions = [      "Where is Lisa?",      "What is Lisa's dog's name?",      "What does Lisa do in the park?",      "Why does Lisa go to the pond?"  ]

需要注意的是,诸如 gpt-3.5-turbo 等最先进的LLM可以轻松回答这类一年级的练习题,因为它只有六句话长。

from openai import OpenAI  openai = OpenAI()  for question in questions:      prompt_template = f"""      Based on the provided context, answer the following question:      Context: {text}      Question: {question}      Answer:      """      response = openai.chat.completions.create(          model="gpt-3.5-turbo",          messages=[              {"role": "user", "content": prompt_template},          ],          temperature=0,      )      print(f"Question: {question}nAnswer: {response.choices[0].message.content}n")

Question: Where is Lisa?  Answer: Lisa is at the park.  Question: What is Lisa's dog's name?  Answer: Lisa's dog's name is Bella.  Question: What does Lisa do in the park?  Answer: In the park, Lisa rides her bike, plays with her dog Bella, races with Bella in the sun, and goes to the pond to see the ducks.  Question: Why does Lisa go to the pond?  Answer: Lisa goes to the pond to see the ducks because she thinks they are cute and funny.

但是请注意,在实际的RAG系统中,您将进行的问题回答任务涉及更大的文档,您不一定希望或可以将整个文档传递给大型语言模型(LLM)的上下文窗口。因此,此简单的文本理解练习旨在展示RAG系统中检索部分的一些核心思想和挑战。

分块

第一个重要的考虑是将文档分割成较小的信息片段。尽管每个新LLM都声称具有更大的上下文窗口,但研究表明,将整个文档传递给LLM会降低其回答问题的效果。

例如,要回答“Lisa在哪里?”这个问题,您只需要“Lisa is at the park.”这条信息,其余的文本对于这个问题是无关的。

用小学一年级练习来理解RAG的上下文相关性挑战-3

RAG的分块技术:按句子分割

然而,简单地将整个文档分割成单句可能不是最好的方法,因为上下文可能包含的信息太少。以“Lisa的狗叫什么名字?”为例,尽管名字的信息在句子“Her dog Bella, is with her.”中,但单独这一句没有提供“她”指的是谁的信息。在这种情况下,最好有一个两句的较大块,使检索到的上下文为“Lisa is at the park. Her dog Bella, is with her.”

用小学一年级练习来理解RAG的上下文相关性挑战-4

RAG的分块技术:分割成两句的较大块

如您所见,块大小是需要调整以提高RAG系统性能的参数。可以在 生产就绪的RAG应用程序指南 [4] 中阅读更多内容。

此外,已经出现了更高级的分块和检索策略。例如,在 sentence window retrieval [5] 技术中,文档被分割成单句,但与较大的上下文窗口一起存储,检索后用更大的上下文替换单句以提供更多上下文。

您可以尝试多种不同的技术来对文档进行分区。流行的编排框架,如 LangChain [6] 和 LlamaIndex [7] ,提供了多种现成的分块策略。但最好的分块策略是什么?这是一个独立的话题,因为有许多不同的方法。

如何分块文本数据——对不同方法的比较分析 [8]

幸运的是,您不需要完美地分块,因为最先进的LLM,如 gpt-3.5-turbo ,能够处理包含无关信息的较大上下文。对于此示例,将文本分成两句的块可能就足够了。

检索

在构建RAG管道时,下一个重要的问题是:您应该检索多少块?

虽然问题“Lisa的狗叫什么名字?”只需要一条上下文,

Context 1: "Lisa is at the park. Her dog Bella, is with her."

问题“Lisa在公园里做什么?”则需要两条上下文——假设我们将文本分割成两句的块:

Context 1: "Lisa rides her bike and plays with Bella. They race each other in the sun."  Context 2: "Then Lisa goes to the pond to see the ducks. She thinks they are so cute and funny."

用小学一年级练习来理解RAG的上下文相关性挑战-5

检索上下文的数量

回答检索多少条上下文的问题并不简单。这取决于问题、可用信息和块大小。理想情况下,您应该进行一些实验,以找到块大小和检索上下文数量之间的最佳平衡。

评估

在进行实验以找到RAG管道的最佳设置时,需要量化系统的性能,以判断当前实验是否优于基线。本节将讨论与RAG应用程序中上下文检索相关的不同指标。具体来说,本节讨论如何量化检索到的上下文对用户输入的相关性。

相似性或距离指标

尽管上下文可以从不同类型的数据库中存储和检索,但检索组件最常见的是通过相似性搜索来检索上下文。

为此,文档块会被嵌入或转换为所谓的嵌入模型生成的向量嵌入。在查询时,对搜索查询也进行相同操作。由于向量嵌入能够以数值形式捕捉语义意义,因此可以通过在向量空间中检索离搜索查询最近的数据对象来检索与搜索查询相似的数据对象。相似性由常见的 向量搜索距离指标 [9] 计算,例如余弦相似度、点积、L1或L2。

下图是使用PCA对问题和文档块进行2维可视化(使用OpenAI的 text-embedding-3-small 嵌入模型)。在此向量空间中,可以看到最接近问题“为什么Lisa去池塘?”的上下文块是“Then Lisa goes to the pond to see the ducks. She thinks they are so cute and funny.”,这是用户查询最相关的上下文。

用小学一年级练习来理解RAG的上下文相关性挑战-6

上下文与问题在二维向量空间中的接近度

然而,“相似”并不总是意味着“相关”。例如,下面是文档块到问题“Lisa在公园里做什么?”的余弦距离:

What does Lisa do in the park?  1. Lisa is at the park. Her dog Bella, is with her. (Distance: 0.40)  2. Then Lisa goes to the pond to see the ducks. She thinks they are so cute and funny. (Distance: 0.45)  3. Lisa rides her bike and plays with Bella. They race each other in the sun. (Distance: 0.51)

可以看到,最接近或最相似的上下文并没有回答问题,因此是无关的。

因此,使用距离指标来衡量上下文的相关性是不够的。

搜索和排序指标

评估RAG系统性能的一种简单方法是使用 经典的搜索和排序指标 [10] ,例如:

Precision@K: 检索到的上下文中有多少是相关的?

Recall@K: 检索到了多少总相关上下文?(可以帮助您调整检索上下文的适当数量。)

平均倒数排序(MRR): 系统将第一个相关结果放在排序列表中的位置如何。(如果您知道只有一个相关上下文,这是一个很好的指标。)

归一化折扣累积增益(NDCG): 考虑所有结果的相关性及其位置。(在搜索和推荐系统中最受欢迎。)

虽然这些是经过验证并推荐的指标,但一个缺点是它们需要真实的标签(ground truth labels):上下文是相关的还是不相关的?在NDCG指标的情况下,您甚至需要提供相关性的某种粒度( 上下文有多相关?在什么尺度上衡量相关性?“相关”、“有些相关”、“相关”或按0到10的尺度打分 )。随着数据集规模的增长,为验证数据集收集真实标签可能会变得昂贵。

RAG评估框架中的上下文相关性指标

在这个领域,一个有趣的发展正在RAG评估框架中发生:许多不同的RAG评估框架,如 Ragas [11] 、 TruLens [12] 和 DeepEval [13] 等,包含一个称为上下文相关性的“无参考指标”。

上下文相关性 指标衡量提供的上下文与用户查询的相关性。这在许多RAG评估框架中被称为“无参考”指标,因为它不需要任何真实标签,而是使用LLM来计算。

上下文相关性 指标旨在衡量提供的上下文与用户查询的相关性。

由于这个指标相对较新,不同框架中的上下文相关性计算方式目前有所不同。本节旨在给您一个关于Ragas、TruLens和DeepEval框架中上下文相关性指标的初步直观理解。

声明:本节不打算对所提到的框架进行广泛的比较,也不打算推荐使用哪个框架。它仅旨在提供框架的概述和上下文相关性指标的直观理解。

下面,我们将使用两组小示例。第一个DataFrame包含来自示例练习表的问题和我们定义为相关的上下文。

用小学一年级练习来理解RAG的上下文相关性挑战-7

包含问题、相关上下文和答案的DataFrame

第二个DataFrame包含问题“为什么Lisa去池塘?”的不同上下文。前三个上下文都包含相关信息,但有不同量的“杂乱”信息。最后一个上下文与问题完全无关。

用小学一年级练习来理解RAG的上下文相关性挑战-8

包含问题、不相关上下文和答案的DataFrame

import pandas as pd  # Replace with your examples here  df = pd.DataFrame({'question': [ ...],                      'contexts': [[...], ...],                      'answers': [...]})

同时,确保您在环境变量中设置了OpenAI API密钥,因为以下所有框架都使用OpenAI的LLM来评估上下文相关性指标。

import os  os.environ["OPENAI_API_KEY"] = "sk..."

**Ragas** [14] 使用以下公式来计算上下文相关性:

用小学一年级练习来理解RAG的上下文相关性挑战-9

Ragas文档中的截图

您可以使用以下代码在Ragas中计算上下文相关性指标。框架需要信息 question 和 contexts 来计算上下文相关性。

# !pip install ragas  from datasets import Dataset  from ragas.metrics import ContextRelevancy  # Bring dataframe into right format  dataset = Dataset.from_pandas(df)  # Set up context relevancy metric  context_relevancy = ContextRelevancy()  # Calculate metric  results = context_relevancy.score(dataset)

下图显示了我们标记为相关的上下文的上下文相关性指标。

用小学一年级练习来理解RAG的上下文相关性挑战-10

相关上下文示例的Ragas上下文相关性得分

上下文相关性得分范围在0.5到1之间,尽管我们将所有上下文分类为相关。由于Ragas将其认为相关的句子数量除以提供的上下文中的句子总数,如果底层LLM没有将句子评分为相关,这可能会导致较低的得分。

下图显示了不相关上下文的上下文相关性指标。

用小学一年级练习来理解RAG的上下文相关性挑战-11

不相关上下文示例的Ragas上下文相关性得分

可以看到,对于前三个示例,包含更多杂乱信息的上下文相关性降低。此外,最后一个完全不相关的上下文得分为0。

DeepEval [15] 使用以下公式来计算上下文相关性:

用小学一年级练习来理解RAG的上下文相关性挑战-12

DeepEval文档中的截图

您可以使用以下代码在DeepEval中计算上下文相关性指标。框架需要信息 question 、 contexts 和 answers 来计算上下文相关性。

# ! pip install deepeval  from deepeval import evaluate  from deepeval.metrics import ContextualRelevancyMetric  from deepeval.test_case import LLMTestCase  context_relevancy = []  for _, row in df.iterrows():      # Define metric      metric = ContextualRelevancyMetric(          threshold=0.5,          model="gpt-3.5-turbo", #alternatively use "gpt-4"      )      # Define test case      test_case = LLMTestCase(          input = row.question,          actual_output = row.answers,          retrieval_context = row.contexts.tolist(),      )      # Calculate metric      metric.measure(test_case)      context_relevancy.append(metric.score)

下图显示了我们标记为相关的上下文的上下文相关性指标。

用小学一年级练习来理解RAG的上下文相关性挑战-13

相关上下文示例的DeepEval上下文相关性得分

可以看到,大多数结果的上下文相关性为1,只有一个示例的上下文相关性为0.5。

下图显示了不相关上下文的上下文相关性指标。

用小学一年级练习来理解RAG的上下文相关性挑战-14

不相关上下文示例的DeepEval上下文相关性得分

有趣的是,我们没有看到包含更多杂乱信息的上下文相关性得分的差异。然而,最后一个完全不相关的上下文得分为0。

而目前TruLens 并未在其文档中提供有关上下文相关性计算的详细信息。

您可以使用以下代码在TruLens中计算上下文相关性指标。框架需要信息 question 、 contexts 和 answers 来计算上下文相关性。

# !pip install trulens_eval  from trulens_eval import Select, Tru  from trulens_eval.tru_virtual import VirtualApp, TruVirtual, VirtualRecord  from trulens_eval.feedback.provider import OpenAI  from trulens_eval.feedback.feedback import Feedback  # Define virtual app  virtual_app = VirtualApp()   retriever = Select.RecordCalls.retriever  virtual_app[retriever] = "retriever"  # Initialize provider class  provider = OpenAI()  # Define context_call  context_call = retriever.get_context # The selector for a presumed context retrieval component's call to `get_context`.  context = context_call.rets[:] # Select context to be used in feedback. We select the return values of the virtual `get_context` call in the virtual `retriever` component.  # Define feedback function for context relevance  f_context_relevance = (      Feedback(provider.context_relevance_with_cot_reasons)      .on_input()      .on(context)  )  # Define virtual recorder  virtual_recorder = TruVirtual(      app_id="SmallTests",      app=virtual_app,      feedbacks=[f_context_relevance],  )  # Define test cases  for _, row in df.iterrows():      record = VirtualRecord(      main_input = row.question,      main_output= row.answers,      calls=          {              context_call: dict(                  rets=row.contexts.tolist()              ),          }      )      virtual_recorder.add_record(record)  # Calculate metric  tru = Tru()  tru.run_dashboard(force=True)  tru.start_evaluator()

请注意,TruLens在仪表板中提供结果。以下结果从仪表板中复制回DataFrame,以保持本文中结果可视化的一致性。

下图显示了我们标记为相关的上下文的上下文相关性指标。

用小学一年级练习来理解RAG的上下文相关性挑战-15

相关上下文示例的TruLens上下文相关性得分

可以看到,TruLens将所有相关上下文的得分在0.85到1之间。

下图显示了不相关上下文的上下文相关性指标。

用小学一年级练习来理解RAG的上下文相关性挑战-16

不相关上下文示例的TruLens上下文相关性得分

有趣的是,TruLens似乎并未惩罚额外的杂乱信息:所有包含相关信息的上下文得分为0.9或更高。与Ragas和DeepEval相反,TruLens将不包含回答问题信息的上下文评分为相对较高的0.4。

总结

本文探讨了为RAG应用程序检索上下文和评估其相关性的问题。通过简单的一年级阅读理解练习,展示了检索上下文和衡量其相关性所面临的挑战。

在索引阶段,您必须决定适合的分块策略和块大小。在检索阶段,您需要平衡块大小和检索上下文的数量。最后,在评估阶段,您需要决定适合的指标来评估检索到的上下文的质量。

此外,本文探讨了许多现代RAG评估框架中可用的“无参考”上下文相关性指标。探讨了Ragas、TruLens和DeepEval框架对两个示例集的评分:这些框架如何评分人类标识为相关的上下文,以及这些框架如何评分人类标识为不相关的上下文。

参考链接

[1]

Leonie Monigatti: https://medium.com/@iamleonie?source=post_page-----e362f6eaed34--------------------------------

[2]

Towards Data Science: https://towardsdatascience.com/?source=post_page-----e362f6eaed34--------------------------------

[3]

检索增强生成(RAG)管道: https://towardsdatascience.com/retrieval-augmented-generation-rag-from-theory-to-langchain-implementation-4e9bd5f6a4f2

[4]

生产就绪的RAG应用程序指南: https://towardsdatascience.com/a-guide-on-12-tuning-strategies-for-production-ready-rag-applications-7ca646833439

[5]

sentence window retrieval: https://docs.llamaindex.ai/en/stable/examples/node_postprocessor/MetadataReplacementDemo/

[6]

LangChain: https://python.langchain.com/v0.1/docs/modules/data_connection/document_transformers/

[7]

LlamaIndex: https://docs.llamaindex.ai/en/v0.10.19/api_reference/service_context/node_parser.html

[8]

如何分块文本数据——对不同方法的比较分析: https://towardsdatascience.com/how-to-chunk-text-data-a-comparative-analysis-3858c4a0997a?source=post_page-----e362f6eaed34--------------------------------

[9]

向量搜索距离指标: https://weaviate.io/blog/distance-metrics-in-vector-search

[10]

经典的搜索和排序指标: https://weaviate.io/blog/retrieval-evaluation-metrics

[11]

Ragas: https://docs.ragas.io/en/latest/index.html

版权声明:
作者:clash
链接:https://www.shadowrocket6.top/180.html
来源:Shadowrocket官网
文章版权归作者所有,未经允许请勿转载。

THE END
分享
二维码
< <上一篇
下一篇>>