logo
Loading...

關於資料顆粒大小評估的補充 - RAG技術: 智能助手開發實戰 - Cupoy

Reference:2312.10997 (arxiv.org) 使用 LlamaIndex 評估 RAG 系統的理想塊大小 介紹 檢索增強生成 (RAG) 引入了一種創新方法,該方法將搜索系統的廣...

Reference:2312.10997 (arxiv.org) 使用 LlamaIndex 評估 RAG 系統的理想塊大小 介紹 檢索增強生成 (RAG) 引入了一種創新方法,該方法將搜索系統的廣泛檢索功能與 LLM 融合在一起。在實施 RAG 系統時,控制系統效率和性能的一個關鍵參數是 。如何辨別無縫檢索的最佳數據塊大小?這就是 LlamaIndex 可以派上用場的地方。在這篇補充文章中,我們將指導您完成使用 LlamaIndex 的模組確定最佳方法的步驟。 我們將針對所謂的"處理資料顆粒度"分成四的指標評估他的狀態: 1.chunk_sizeResponse  2.Evaluationchunk  3.sizeResponse  4.EvaluationResponse 為什麼數據塊大小很重要 選擇正確的決策是一項關鍵決策,可以通過多種方式影響RAG系統的效率和準確性:chunk_size 相關性和粒度:小的 ,如 128,會產生更精細的塊。但是,這種粒度存在風險:重要資訊可能不在檢索到最多的 chunk 中,尤其是在設置限制為 2 時。相反,512 的chunk大小可能包含前chunk中的所有必要資訊,確保查詢的答案隨時可用。為了解決這個問題,我們採用了 Faithfulness 和 Relevancy 量度。這些分別根據查詢和檢索到的上下文來衡量沒有 「幻覺 」和回答的 「相關性」。chunk_sizesimilarity_top_k 回應生成時間:隨著時間的增加,直接進入 LLM 以生成答案的資訊量也會增加。雖然這可以確保更全面的上下文,但也可能會減慢系統的速度。確保增加的深度不會影響系統的回應能力至關重要。chunk_size 從本質上講,確定最佳方案就是要取得平衡:在不犧牲速度的情況下捕獲所有重要資訊。對各種大小進行全面測試以找到適合特定用例和數據集的配置至關重要。chunk_size 對於選擇正確的 進行實際評估,您可以在此 Google Colab Notebook 上訪問並運行以下設置。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' 下載數據 我們將使用 2021 年的 Uber 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_sizechunk_sizesDatasetGenerator data_generator = DatasetGenerator.from_documents(documents) eval_questions = data_generator.generate_questions_from_nodes() 設置 Evaluator 我們正在設置 GPT-4 模型作為評估實驗期間生成的回應的支柱。兩個計算機 和 使用 .FaithfulnessEvaluatorRelevancyEvaluatorservice_context Faithfulness Evaluator (忠實度評估器) — 它可用於測量回應是否是幻覺,以及測量來自查詢引擎的回應是否與任何源節點匹配。 相關性評估器 — 它可用於測量回應是否實際回答了查詢,以及測量回應 + 源節點是否與查詢匹配。 # We will use GPT-4 for evaluating the responses gpt4 = OpenAI(temperature=0, model="gpt-4") # Define service context for GPT-4 for evaluation service_context_gpt4 = ServiceContext.from_defaults(llm=gpt4) # Define Faithfulness and Relevancy Evaluators which are based on GPT-4 faithfulness_gpt4 = FaithfulnessEvaluator(service_context=service_context_gpt4) relevancy_gpt4 = RelevancyEvaluator(service_context=service_context_gpt4) 數據塊大小的回應評估 我們根據 3 個指標評估每個chunk_size。 平均回應時間。 平均忠誠。 平均相關性。 下面是一個函數 ,它只執行具有以下操作:evaluate_response_time_and_accuracy VectorIndex 創建。 構建查詢引擎。 Metrics Calculation(指標計算)。 # Define function to calculate average response time, average faithfulness and average relevancy metrics for given chunk size # We use GPT-3.5-Turbo to generate response and GPT-4 to evaluate it. def evaluate_response_time_and_accuracy(chunk_size, eval_questions): """ Evaluate the average response time, faithfulness, and relevancy of responses generated by GPT-3.5-turbo for a given chunk size. Parameters: chunk_size (int): The size of data chunks being processed. Returns: tuple: A tuple containing the average response time, faithfulness, and relevancy metrics. """ total_response_time = 0 total_faithfulness = 0 total_relevancy = 0 # create vector index 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 ) # build query engine query_engine = vector_index.as_query_engine() num_questions = len(eval_questions) # Iterate over each question in eval_questions to compute metrics. # While BatchEvalRunner can be used for faster evaluations (see: https://docs.llamaindex.ai/en/latest/examples/evaluation/batch_eval.html), # we're using a loop here to specifically measure response time for different chunk sizes. 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' # Download Data !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' # Load Data reader = SimpleDirectoryReader("./data/10k/") documents = reader.load_data() # To evaluate for each chunk size, we will first generate a set of 40 questions from first 20 pages. eval_documents = documents[:20] data_generator = DatasetGenerator.from_documents() eval_questions = data_generator.generate_questions_from_nodes(num = 20) # We will use GPT-4 for evaluating the responses gpt4 = OpenAI(temperature=0, model="gpt-4") # Define service context for GPT-4 for evaluation service_context_gpt4 = ServiceContext.from_defaults(llm=gpt4) # Define Faithfulness and Relevancy Evaluators which are based on GPT-4 faithfulness_gpt4 = FaithfulnessEvaluator(service_context=service_context_gpt4) relevancy_gpt4 = RelevancyEvaluator(service_context=service_context_gpt4) # Define function to calculate average response time, average faithfulness and average relevancy metrics for given chunk size def evaluate_response_time_and_accuracy(chunk_size): total_response_time = 0 total_faithfulness = 0 total_relevancy = 0 # create vector index 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 # Iterate over different chunk sizes to evaluate the metrics to help fix the chunk size. 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}") 結果 上表表明,隨著塊大小的增加,Average Response Time (平均響應時間) 會略有增加。有趣的是,平均忠實度似乎在1024時達到頂峰,而平均相關性則顯示出更大的塊大小的持續改進,也在1024處達到峰值。這表明 1024 的塊大小可能會在響應時間和回應質量之間取得最佳平衡,以忠實度和相關性來衡量。chunk_size 結論 確定RAG系統的最佳塊大小既需要經驗證據,也需要直覺。使用 LlamaIndex 的模組,您可以嘗試各種大小並根據具體數據做出決策。在構建RAG系統時,請始終記住這是一個關鍵參數。投入時間仔細評估和調整您的數據塊大小,以獲得無與倫比的結果。Response Evaluationchunk_size 大家也可以看這篇論文: 2401.07883 (arxiv.org) 那其實Chroma Research也有針對估計對切割chunk去做檢索方面的策略研究。 "Evaluating Chunking Strategies for Retrieval" 儘管文檔分塊作為預處理步驟幾乎無處不在,但很少有工作來研究它對檢索性能的影響。這部分是由於常用資訊檢索基準的結構,這些基準針對的是整個文檔的檢索任務。 在這項工作中,提出了一種評估方法,該方法考慮了token級別的相關性,並允許評估幾種流行的文檔分塊策略。 證明,分塊策略的選擇會對檢索性能產生重大影響,一些策略的召回率比其他策略高出 9%。 分塊是攝取文檔以在 AI 應用程式上下文中進行檢索時常用的預處理步驟。分塊用於將文檔劃分為資訊單元,其語義內容適合 LLM 基於嵌入的檢索和處理。 此技術報告的目的是評估分塊策略的選擇對檢索性能的影響,以代表分塊和檢索在 AI 應用程式上下文中的使用方式。 雖然 LLM 上下文長度已經增加,並且可以將整個文檔甚至文本語料庫插入上下文視窗,但在實踐中這樣做通常效率低下,並且會分散模型的注意力。對於任何給定的查詢,只有文本語料庫的一小部分可能是相關的,但上下文視窗中的所有標記都會針對每個推理進行處理。理想情況下,對於每個查詢,LLM 只需要處理相關令牌,因此 AI 應用程式中檢索系統的主要目標之一是僅識別和檢索給定查詢的相關令牌。 MTEB 等常用基準測試採用傳統的資訊檢索 (IR) 方法,其中檢索性能通常是根據整個文檔的相關性進行評估的,而不是在段落或標記的級別進行評估,這意味著它們不能考慮分塊。 在 AI 應用程式中,可以在許多文件中或跨多個文件中找到包含與查詢相關的所有標記的摘錄。塊可以同時包含相關和不相關的標記,並且相關摘錄可以拆分為多個塊。 傳統的 IR 基準測試通常也關注檢索到的文檔的相對排名,但在實踐中,LLM 對相關訊息在上下文視窗中的位置相對不敏感。此外,與給定查詢相關的資訊可能分佈在多個文檔中,這使得文檔之間相對排名的評估變得不明確。 在這些限制的激勵下,提出了一種新的評估策略,在代幣級別評估檢索性能。他們的評估使用 LLM 從任何給定的文字語料庫中生成並隨後過濾一組查詢和相關的相關摘錄,然後根據檢索到的標記通過精度、召回率和交集(Jaccard 索引)評估檢索性能。