101 使用LlamaIndex评估RAG系统的理想分块大小

使用LlamaIndex评估RAG系统的理想分块大小

引言

检索增强生成(RAG)引入了一种创新方法,将搜索系统的强大检索能力与大型语言模型(LLM)相结合。在实现RAG系统时,一个关键参数是chunk_size,它决定了系统的效率和性能。如何确定最佳的分块大小以实现无缝检索?这就是LlamaIndex响应评估模块发挥作用的地方。在本篇博客中,我们将指导您使用LlamaIndex的响应评估模块来确定最佳分块大小。如果您不熟悉响应评估模块,建议在继续之前查看其文档。

为什么分块大小很重要

选择合适的chunk_size是一个关键决策,它可以通过以下几个方面影响RAG系统的效率和准确性:

相关性和粒度

  • 小分块大小(如128):产生更细粒度的分块。然而,这种粒度存在风险:重要信息可能不在前几个检索到的分块中,特别是当similarity_top_k设置为2时。
  • 大分块大小(如512):更有可能在顶部分块中包含所有必要信息,确保查询的答案随时可用。

为了解决这个问题,我们使用**忠实度(Faithfulness)相关性(Relevancy)**指标。这些指标分别测量响应中“幻觉”的缺失和响应基于查询和检索上下文的相关性。

响应生成时间

随着chunk_size的增加,进入LLM以生成答案的信息量也会增加。虽然这可以确保更全面的内容,但也可能减慢系统速度。确保增加的深度不会牺牲系统的响应速度至关重要。

本质上,确定最佳chunk_size是关于平衡:捕捉所有必要信息而不牺牲速度。通过使用各种大小进行彻底测试,找到适合特定用例和数据集的配置至关重要。

设置

在开始实验之前,我们需要确保所有必需的模块都已导入:

import nest_asyncio
nest_asyncio.apply()

from llama_index import (
    SimpleDirectoryReader,
    VectorStoreIndex,
    ServiceContext,
)
from llama_index.evaluation import (
    DatasetGenerator,
    FaithfulnessEvaluator,
    RelevancyEvaluator
)
from llama_index.llms import OpenAI

import openai
import time
openai.api_key = 'OPENAI-API-KEY'

下载数据

我们将使用Uber 2021年的10K SEC文件进行此实验。

!mkdir -p 'data/10k/'
!wget 'https://raw.githubusercontent.com/jerryjliu/llama_index/main/docs/examples/data/10k/uber_2021.pdf' -O 'data/10k/uber_2021.pdf'

加载数据

让我们加载文档。

documents = SimpleDirectoryReader("./data/10k/").load_data()

问题生成

为了选择合适的chunk_size,我们将计算不同chunk_size的平均响应时间、忠实度和相关性指标。DatasetGenerator将帮助我们从文档中生成问题。

data_generator = DatasetGenerator.from_documents(documents)
eval_questions = data_generator.generate_questions_from_nodes()

设置评估器

我们将使用GPT-4模型作为实验中生成响应的评估基础。两个评估器,FaithfulnessEvaluatorRelevancyEvaluator,使用service_context进行初始化。

gpt4 = OpenAI(temperature=0, model="gpt-4")
service_context_gpt4 = ServiceContext.from_defaults(llm=gpt4)
faithfulness_gpt4 = FaithfulnessEvaluator(service_context=service_context_gpt4)
relevancy_gpt4 = RelevancyEvaluator(service_context=service_context_gpt4)

分块大小的响应评估

我们根据以下三个指标评估每个chunk_size

  1. 平均响应时间
  2. 平均忠实度
  3. 平均相关性

以下是一个函数evaluate_response_time_and_accuracy,它实现了这些功能:

def evaluate_response_time_and_accuracy(chunk_size, eval_questions):
    total_response_time = 0
    total_faithfulness = 0
    total_relevancy = 0

    llm = OpenAI(model="gpt-3.5-turbo")
    service_context = ServiceContext.from_defaults(llm=llm, chunk_size=chunk_size)
    vector_index = VectorStoreIndex.from_documents(
        eval_documents, service_context=service_context
    )
    query_engine = vector_index.as_query_engine()
    num_questions = len(eval_questions)

    for question in eval_questions:
        start_time = time.time()
        response_vector = query_engine.query(question)
        elapsed_time = time.time() - start_time
        
        faithfulness_result = faithfulness_gpt4.evaluate_response(
            response=response_vector
        ).passing
        
        relevancy_result = relevancy_gpt4.evaluate_response(
            query=question, response=response_vector
        ).passing

        total_response_time += elapsed_time
        total_faithfulness += faithfulness_result
        total_relevancy += relevancy_result

    average_response_time = total_response_time / num_questions
    average_faithfulness = total_faithfulness / num_questions
    average_relevancy = total_relevancy / num_questions

    return average_response_time, average_faithfulness, average_relevancy

测试不同分块大小

我们将评估一系列分块大小,以确定哪个分块大小提供最有希望的指标。

chunk_sizes = [128, 256, 512, 1024, 2048]

for chunk_size in chunk_sizes:
  avg_response_time, avg_faithfulness, avg_relevancy = evaluate_response_time_and_accuracy(chunk_size, eval_questions)
  print(f"Chunk size {chunk_size} - Average Response time: {avg_response_time:.2f}s, Average Faithfulness: {avg_faithfulness:.2f}, Average Relevancy: {avg_relevancy:.2f}")

总结

让我们将所有过程汇总:

import nest_asyncio
nest_asyncio.apply()

from llama_index import (
    SimpleDirectoryReader,
    VectorStoreIndex,
    ServiceContext,
)
from llama_index.evaluation import (
    DatasetGenerator,
    FaithfulnessEvaluator,
    RelevancyEvaluator
)
from llama_index.llms import OpenAI

import openai
import time

openai.api_key = 'OPENAI-API-KEY'

# 下载数据
!mkdir -p 'data/10k/'
!wget 'https://raw.githubusercontent.com/jerryjliu/llama_index/main/docs/examples/data/10k/uber_2021.pdf' -O 'data/10k/uber_2021.pdf'

# 加载数据
reader = SimpleDirectoryReader("./data/10k/")
documents = reader.load_data()

# 生成问题
eval_documents = documents[:20]
data_generator = DatasetGenerator.from_documents()
eval_questions = data_generator.generate_questions_from_nodes(num = 20)

# 使用GPT-4进行响应评估
gpt4 = OpenAI(temperature=0, model="gpt-4")
service_context_gpt4 = ServiceContext.from_defaults(llm=gpt4)
faithfulness_gpt4 = FaithfulnessEvaluator(service_context=service_context_gpt4)
relevancy_gpt4 = RelevancyEvaluator(service_context=service_context_gpt4)

# 定义函数以计算给定分块大小的平均响应时间、平均忠实度和平均相关性指标
def evaluate_response_time_and_accuracy(chunk_size):
    total_response_time = 0
    total_faithfulness = 0
    total_relevancy = 0

    llm = OpenAI(model="gpt-3.5-turbo")
    service_context = ServiceContext.from_defaults(llm=llm, chunk_size=chunk_size)
    vector_index = VectorStoreIndex.from_documents(
        eval_documents, service_context=service_context
    )
    query_engine = vector_index.as_query_engine()
    num_questions = len(eval_questions)

    for question in eval_questions:
        start_time = time.time()
        response_vector = query_engine.query(question)
        elapsed_time = time.time() - start_time
        
        faithfulness_result = faithfulness_gpt4.evaluate_response(
            response=response_vector
        ).passing
        
        relevancy_result = relevancy_gpt4.evaluate_response(
            query=question, response=response_vector
        ).passing

        total_response_time += elapsed_time
        total_faithfulness += faithfulness_result
        total_relevancy += relevancy_result

    average_response_time = total_response_time / num_questions
    average_faithfulness = total_faithfulness / num_questions
    average_relevancy = total_relevancy / num_questions

    return average_response_time, average_faithfulness, average_relevancy

# 迭代不同分块大小以评估指标以帮助确定分块大小
for chunk_size in [128, 256, 512, 1024, 2048]:
  avg_time, avg_faithfulness, avg_relevancy = evaluate_response_time_and_accuracy(chunk_size)
  print(f"Chunk size {chunk_size} - Average Response time: {avg_time:.2f}s, Average Faithfulness: {avg_faithfulness:.2f}, Average Relevancy: {avg_relevancy:.2f}")

结果

上述表格显示,随着分块大小的增加,平均响应时间略有上升。有趣的是,平均忠实度在chunk_size为1024时达到顶峰,而平均相关性随着分块大小的增加而持续改善,也在1024时达到峰值。这表明分块大小为1024可能在响应时间和响应质量之间达到最佳平衡。

结论

确定RAG系统的最佳分块大小既需要直觉,也需要实证证据。通过LlamaIndex的响应评估模块,您可以尝试各种大小,并根据具体数据做出决策。在构建RAG系统时,请记住chunk_size是一个关键参数。投入时间仔细评估和调整您的分块大小,以获得无与伦比的结果。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

需要重新演唱

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值