測試不同的RAG技術以找到最佳方案
檢索增強生成(RAG)技術通過結合大型語言模型(LLMs)與外部數據檢索能力,能夠提供準確且富含上下文的答案。無論是構建客戶支持聊天機器人還是研究助手,RAG都能通過從數據庫中提取相關信息來增強AI的性能。然而,不同的RAG技術在性能上存在差異,選擇最佳技術需要進行測試。本文將全面探討各類RAG技術,包括基礎方法和高級手段,并對它們進行評估,以幫助您根據需求選擇最合適的技術。
什么是RAG及其測試的重要性
想象一下,向AI提問:“如何解決智能手機上的登錄問題?”標準的大型語言模型可能會給出通用或過時的回答。而RAG技術通過檢索相關數據(例如來自產品手冊)并將其輸入到大型語言模型中,從而生成精確的答案,以此改善了這一情況。這使得RAG非常適用于需要最新或特定信息的應用場景,如技術支持或醫療咨詢。
測試RAG技術至關重要,因為每種方法在文檔索引、檢索或生成的方式上各有不同,會對準確性、速度和成本產生影響。通過比較這些技術,我們可以為特定的使用場景找到最佳設置。
RAG系統的核心組件
RAG流程主要包含三個階段:
- 索引:將文檔分割成塊,將其轉換為數值向量(嵌入),并存儲在向量數據庫中。
- 檢索:在數據庫中搜索與查詢相關的塊。
- 生成:使用大型語言模型將檢索到的數據與查詢結合起來生成答案。
RAG技術列表
以下是我們將要比較的主要RAG技術:
- 樸素RAG(基準)
- 分塊策略(固定大小、基于句子、語義)
- 重排序
- 查詢轉換(查詢重寫、多查詢、HyDE)
- 圖RAG(GraphRAG)
- RAG融合(RAG-Fusion)
- 上下文壓縮
- 自查詢檢索
- 多文檔代理
- 動態檢索
- 遞歸檢索
- 父文檔檢索
1. 樸素RAG(基準)
這是最簡單的方法:將文檔分割成固定大小的塊,對其進行嵌入處理(例如使用BERT),存儲在向量數據庫(例如FAISS)中,并根據查詢相似度檢索前k個塊。
示例:對于查詢“如何解決智能手機上的登錄問題?”,樸素RAG將手冊分割成500字的塊,并檢索前5個塊。
代碼片段(使用LlamaIndex):
from llama_index import VectorStoreIndex, SimpleDirectoryReader
from llama_index.llms import OpenAI
documents = SimpleDirectoryReader("manuals/").load_data()
index = VectorStoreIndex.from_documents(documents)
query_engine = index.as_query_engine()
response = query_engine.query("How do I fix a login issue on my smartphone?")
print(response)輸出:“要解決登錄問題,請嘗試通過‘忘記密碼’鏈接重置密碼或清除設置中的應用緩存。”
優點:簡單、快速。
缺點:可能會遺漏上下文或檢索到不相關的塊。
2. 分塊策略
分塊會影響檢索質量。分塊方式包括:
- 固定大小:按詞數分割(例如500詞)。
- 基于句子:按句子分割以保證語義連貫性。
- 語義:使用AI將相關句子分組。
示例:基于句子的分塊將登錄查詢的故障排除部分完整保留。
代碼片段(語義分塊):
from llama_index import SemanticSplitter
splitter = SemanticSplitter(chunk_size=512)
chunks = splitter.split_documents(documents)
index = VectorStoreIndex.from_documents(chunks)
response = index.as_query_engine().query("How do I fix a login issue?")
print(response)輸出:“通過設置>應用清除緩存。如果問題仍然存在,請重置密碼。”
優點:更好地保留上下文。
缺點:語義分塊計算密集。
3. 重排序
重排序使用交叉編碼器或大型語言模型對檢索到的塊進行重新排序,以對查詢-塊相關性進行評分。
示例:重排序會優先考慮有關登錄故障排除的塊,而不是通用設置的塊。
代碼片段(使用Cohere):
from cohere import Client
cohere_client = Client("YOUR_COHERE_API_KEY")
chunks = index.retrieve("How do I fix a login issue?")
reranked = cohere_client.rerank(query="How do I fix a login issue?", documents=[chunk.text for chunk in chunks])
top_chunks = [chunks[i] for i in reranked.results[:5]]輸出:“清除緩存;使用‘忘記密碼’鏈接。”
優點:提高相關性。
缺點:增加計算開銷。
4. 查詢轉換
增強查詢以改進檢索:
- 查詢重寫:重新表述模糊的查詢(例如將“登錄問題”改為“解決智能手機登錄失敗”)。
- 多查詢:生成多個相關查詢。
- HyDE(假設文檔嵌入):創建用于檢索的假設答案。
示例:HyDE生成類似“清除緩存或重置密碼”的假答案,并檢索匹配的塊。
代碼片段(HyDE):
from llama_index import HyDEQueryTransform
hyde = HyDEQueryTransform()
transformed_query = hyde.transform("How do I fix a login issue?")
response = index.as_query_engine().query(transformed_query)
print(response)輸出:“檢查設置>應用>清除緩存;重置密碼。”
優點:捕捉細微的意圖。
缺點:增加延遲。
5. 圖RAG(GraphRAG)
使用知識圖譜捕獲實體關系,適用于復雜查詢。
示例:對于“什么導致登錄問題?”,圖RAG檢索與“應用緩存”和“用戶憑據”相關聯的塊。
工作流程:
- 提取實體和關系。
- 構建圖數據庫(例如FalkorDB)。
- 查詢圖形并將結果輸入大型語言模型。
優點:擅長多步驟推理。
缺點:設置復雜。
6. RAG融合(RAG-Fusion)
將查詢擴展到多個視角,執行并行搜索,并對結果進行重排序。
示例:生成“清除應用緩存”、“重置密碼”等查詢,并檢索不同的塊。
優點:覆蓋全面。
缺點:計算成本高。
7. 上下文壓縮
壓縮檢索到的塊,專注于最相關的部分,在生成前減少噪音。
示例:對于登錄查詢,壓縮從較長的塊中僅提取有關緩存清除和密碼重置的句子。
代碼片段(使用LlamaIndex):
from llama_index import ContextualCompressionRetriever
retriever = ContextualCompressionRetriever(base_retriever=index.as_retriever())
response = retriever.query("How do I fix a login issue?")
print(response)輸出:“通過設置>應用清除應用緩存;通過‘忘記密碼’重置密碼。”
優點:減少不相關內容。
缺點:需要額外處理。
8. 自查詢檢索
使用大型語言模型將復雜查詢解析為結構化數據庫查詢,適用于富含元數據的數據集。
示例:對于“顯示2025年Android設備的登錄問題”,大型語言模型生成一個過濾Android和2025年元數據的查詢。
代碼片段:
from llama_index import SelfQueryRetriever
retriever = SelfQueryRetriever(index=index, metadata_fields=["device_type", "year"])
response = retriever.query("Show login issues for Android devices in 2025")
print(response)輸出:“對于2025年的Android設備,通過設置>應用清除緩存或重置密碼。”
優點:處理復雜的結構化查詢。
缺點:需要富含元數據的數據。
9. 多文檔代理
使用多個代理,每個代理專門處理文檔的子集,以處理不同的數據源。
示例:一個代理處理Android手冊,另一個處理iOS手冊,將結果結合起來回答登錄查詢。
代碼片段:
from llama_index import MultiDocumentAgent
agents = [VectorStoreIndex.from_documents(docs).as_query_engine() for docs in [android_docs, ios_docs]]
agent = MultiDocumentAgent(agents)
response = agent.query("How do I fix a login issue?")
print(response)輸出:“在Android上,清除緩存;在iOS上,通過設置重置密碼。”
優點:可擴展到不同的數據集。
缺點:協調復雜。
10. 動態檢索
根據查詢復雜度動態調整檢索參數(例如top-k、相似度閾值)。
示例:簡單查詢使用前3個塊;復雜查詢使用前10個塊。
代碼片段:
from llama_index import DynamicRetriever
retriever = DynamicRetriever(index=index, complexity_estimator=lambda q: len(q.split()))
response = retriever.query("How do I fix a login issue?")
print(response)輸出:“清除緩存或重置密碼。”
優點:適應查詢需求。
缺點:需要調優。
11. 遞歸檢索
通過基于初始結果生成后續查詢來迭代優化檢索。
示例:在檢索到有關“登錄問題”的塊后,查詢“緩存清除步驟”以加深上下文。
代碼片段:
from llama_index import RecursiveRetriever
retriever = RecursiveRetriever(base_retriever=index.as_retriever())
response = retriever.query("How do I fix a login issue?")
print(response)輸出:“通過設置>應用清除緩存;詳細步驟:進入設置,選擇應用,選擇該應用,然后清除緩存。”
優點:為復雜查詢加深上下文。
缺點:增加延遲。
12. 父文檔檢索
檢索較小的塊,但返回其父文檔,以便在生成過程中獲得更豐富的上下文。
示例:檢索有關登錄問題的句子,但向大型語言模型提供完整的故障排除部分。
代碼片段:
from llama_index import ParentDocumentRetriever
retriever = ParentDocumentRetriever(index=index, parent_splitter=lambda x: x.split("\n\n"))
response = retriever.query("How do I fix a login issue?")
print(response)輸出:“在設置>應用中清除緩存;必要時重置密碼。完整部分:[詳細故障排除指南]。”
優點:平衡精度和上下文。
缺點:需要分層文檔結構。
測試與評估
為了找到最佳技術,我們將使用智能手機手冊數據集對所有12種技術進行測試,評估指標包括:
- 檢索精度:檢索到的相關塊的百分比。
- 答案相似度:與參考答案的得分(0-5)。
- 延遲:檢索和生成的時間。
- 成本:計算資源。
演示設置
我們將使用LlamaIndex、OpenAI的GPT-3.5、FAISS和Cohere進行重排序。查詢為“如何解決智能手機上的登錄問題?”
分析
- HyDE和遞歸檢索在精度和答案質量上得分最高,但速度較慢。
- 樸素RAG和動態檢索速度最快,但準確性較低。
- 重排序和父文檔檢索在準確性和速度之間取得平衡。
- 多文檔代理在處理不同數據集時表現出色,但速度最慢。
- 自查詢對于結構化數據非常有用,但需要元數據。
選擇最佳技術
最佳技術取決于您的優先級:
- 速度:樸素RAG、動態檢索。
- 準確性:HyDE、遞歸檢索、重排序。
- 復雜查詢:圖RAG、多文檔代理、自查詢。
- 資源限制:樸素RAG、語義分塊、上下文壓縮。
- 豐富上下文:父文檔檢索、圖RAG。
示例場景:對于客戶支持聊天機器人,重排序或父文檔檢索提供了良好的平衡。對于具有復雜查詢的研究工具,圖RAG或遞歸檢索是理想的。
挑戰與提示
- 幻覺:使用清晰的提示使大型語言模型基于檢索到的數據生成內容。
- 數據質量:整理數據集以減少噪音。
- 可擴展性:使用FAISS或FalkorDB等向量數據庫。
- 元數據:為自查詢或多文檔代理提供支持。
總結一下
對廣泛的RAG技術的探索表明,每種技術都有其優缺點。樸素RAG是一個很好的起點,因為它簡單且設置快速,非常適合快速項目。另一方面,像HyDE、圖RAG、遞歸檢索等高級方法在需要更準確和詳細的答案時表現出色,特別是對于復雜或特定的任務。通過測試這些方法,人們可以找出最適合自己需求的方法,無論優先考慮的是速度、精度還是處理棘手問題的能力。























