Advanced RAG实战12种优化策略从原理到代码引言在上一篇文章中我们梳理了RAG从Naive到Agentic的完整进化路线。但知道有什么只是第一步知道怎么用才是关键。本文将聚焦Advanced RAG的12种核心优化策略从原理剖析到代码实现手把手教你将RAG系统从勉强能用提升到生产就绪。这12种策略按照RAG管道的三个阶段组织检索前优化4种、检索中优化4种、检索后优化4种。每种策略都配有可运行的代码示例你可以直接复制到自己的项目中使用。一、检索前优化Pre-Retrieval策略1语义分块Semantic Chunking原理传统固定大小分块如每512 token一段容易切断语义边界。语义分块根据文档的自然结构段落、章节、列表进行切分确保每个Chunk包含完整的语义单元。实现fromlangchain.text_splitterimportRecursiveCharacterTextSplitterfromlangchain_experimental.text_splitterimportSemanticChunkerfromlangchain_openaiimportOpenAIEmbeddings# 方案A递归字符分割适合通用场景text_splitterRecursiveCharacterTextSplitter(chunk_size512,chunk_overlap50,separators[\n\n,\n,。,., ,])chunkstext_splitter.split_text(document)# 方案B语义分割适合需要保持语义完整性的场景semantic_splitterSemanticChunker(embeddingsOpenAIEmbeddings(),breakpoint_threshold_typepercentile,breakpoint_threshold_amount95)semantic_chunkssemantic_splitter.create_documents([document])关键参数调优chunk_size太小丢失上下文太大引入噪声。建议范围256-1024chunk_overlap重叠部分保留上下文连贯性。建议chunk_size的10-20%separators按优先级排列的分隔符优先在段落边界切分策略2查询重写Query Rewriting原理用户的原始查询往往简短、模糊或包含口语化表达。查询重写使用LLM将原始查询扩展为更精确、更详细的检索查询。实现fromlangchain_openaiimportChatOpenAIfromlangchain_core.promptsimportChatPromptTemplate llmChatOpenAI(modelgpt-4o-mini,temperature0)rewrite_promptChatPromptTemplate.from_messages([(system,你是一个查询优化专家。请将用户的原始查询重写为更适合检索的格式。 重写规则 1. 将口语化表达转换为正式用语 2. 补充隐含的上下文信息 3. 将模糊指代明确化 4. 生成2-3个不同角度的查询变体 输出格式 主查询[重写后的主要查询] 变体1[角度一的查询] 变体2[角度二的查询]),(user,原始查询{query})])defrewrite_query(query:str)-dict:chainrewrite_prompt|llm responsechain.invoke({query:query})# 解析响应提取主查询和变体returnparse_rewrite_response(response.content)策略3HyDE假设文档嵌入原理HyDEHypothetical Document Embeddings的核心思想是用答案找答案。先让LLM生成一个假设性的答案文档然后将这个假设文档向量化用它在知识库中检索真正相关的文档。这种方法能有效弥合查询-文档之间的语义鸿沟。实现defhyde_retrieval(query:str,vector_store,llm):# 步骤1生成假设文档hyde_promptf请根据以下问题生成一段假设性的回答。 注意你不需要给出正确答案只需要生成一段看起来像答案的文本。 问题{query}假设回答hypothetical_docllm.invoke(hyde_prompt).content# 步骤2用假设文档检索resultsvector_store.similarity_search(hypothetical_doc,k5)returnresults适用场景HyDE特别适合用户查询与文档用词差异较大的场景如技术文档问答、法律文书检索等。策略4查询路由Query Routing原理不同类型的查询适合不同的检索策略。查询路由根据查询的语义特征将其分发到最合适的检索管道。实现fromlangchain_core.runnablesimportRunnableBranch# 定义路由逻辑defroute_query(query:str):# 使用轻量级分类器判断查询类型ifis_factual_query(query):returnkeyword_searchelifis_conceptual_query(query):returnvector_searchelifis_relational_query(query):returngraph_searchelse:returnhybrid_search# 构建路由管道routerRunnableBranch((lambdax:route_query(x)keyword_search,keyword_retriever),(lambdax:route_query(x)vector_search,vector_retriever),(lambdax:route_query(x)graph_search,graph_retriever),hybrid_retriever# 默认)二、检索中优化Retrieval策略5混合检索Hybrid Search原理单一检索策略各有盲区。混合检索同时使用稀疏检索BM25擅长关键词匹配和稠密检索向量相似度擅长语义匹配然后融合两者的结果。实现fromlangchain.retrieversimportBM25Retriever,EnsembleRetrieverfromlangchain_community.vectorstoresimportFAISS# 构建BM25检索器bm25_retrieverBM25Retriever.from_documents(documents)bm25_retriever.k10# 构建向量检索器vector_storeFAISS.from_documents(documents,embeddings)vector_retrievervector_store.as_retriever(search_kwargs{k:10})# 混合检索器ensemble_retrieverEnsembleRetriever(retrievers[bm25_retriever,vector_retriever],weights[0.3,0.7]# BM25权重0.3向量权重0.7)resultsensemble_retriever.invoke(query)权重调优建议精确匹配场景如代码搜索BM25权重调高至0.5-0.6语义理解场景如客服问答向量权重调高至0.8-0.9通用场景使用默认的0.3/0.7策略6多阶段检索Multi-Stage Retrieval原理先用轻量级方法快速召回大量候选再用重量级方法精确排序。这种粗排精排的策略在保证召回率的同时控制了计算成本。实现fromlangchain.retrieversimportContextualCompressionRetrieverfromlangchain_cohereimportCohereRerank# 第一阶段粗排快速召回Top-50coarse_retrievervector_store.as_retriever(search_kwargs{k:50})# 第二阶段精排Cross-Encoder重排序compressorCohereRerank(modelrerank-multilingual-v3.0,top_n10)compression_retrieverContextualCompressionRetriever(base_compressorcompressor,base_retrievercoarse_retriever)resultscompression_retriever.invoke(query)策略7多粒度索引Multi-Granularity Indexing原理同一文档同时维护粗粒度和细粒度索引。检索时先用粗粒度索引定位相关文档再用细粒度索引精确定位相关段落。实现# 粗粒度索引文档级别coarse_splitterRecursiveCharacterTextSplitter(chunk_size2048,chunk_overlap200)coarse_chunkscoarse_splitter.split_documents(documents)coarse_indexFAISS.from_documents(coarse_chunks,embeddings)# 细粒度索引段落级别fine_splitterRecursiveCharacterTextSplitter(chunk_size256,chunk_overlap50)fine_chunksfine_splitter.split_documents(documents)fine_indexFAISS.from_documents(fine_chunks,embeddings)defmulti_granularity_search(query):# 先用粗粒度定位相关文档coarse_resultscoarse_index.similarity_search(query,k3)# 在相关文档范围内用细粒度精确定位doc_idsset([r.metadata[doc_id]forrincoarse_results])fine_resultsfine_index.similarity_search(query,k10,filter{doc_id:{$in:list(doc_ids)}})returnfine_results策略8自查询检索Self-Query Retrieval原理让LLM从用户查询中提取结构化过滤条件如时间范围、文档类型、作者等然后将这些条件应用于向量检索的元数据过滤。实现fromlangchain.retrievers.self_query.baseimportSelfQueryRetrieverfromlangchain.chains.query_constructor.baseimportAttributeInfo# 定义元数据字段metadata_field_info[AttributeInfo(namedate,description文档的发布日期,typestring),AttributeInfo(namecategory,description文档分类技术文档/产品手册/FAQ,typestring),AttributeInfo(nameauthor,description文档作者,typestring)]# 创建自查询检索器self_query_retrieverSelfQueryRetriever.from_llm(llmllm,vectorstorevector_store,document_contents技术文档和产品手册,metadata_field_infometadata_field_info,verboseTrue)# 用户查询2026年发布的技术文档中关于API接口的说明resultsself_query_retriever.invoke(query)# 自动提取过滤条件date2026, category技术文档三、检索后优化Post-Retrieval策略9上下文压缩Context Compression原理检索回来的片段可能包含大量冗余信息。使用LLM对每个片段进行压缩——提取与查询相关的关键信息去除无关内容。实现fromlangchain.retrieversimportContextualCompressionRetrieverfromlangchain.retrievers.document_compressorsimportLLMChainExtractor# 创建压缩器compressorLLMChainExtractor.from_llm(llm)# 创建压缩检索器compression_retrieverContextualCompressionRetriever(base_compressorcompressor,base_retrieverbase_retriever)compressed_docscompression_retriever.invoke(query)策略10重排序Re-ranking原理使用专门的Reranker模型对检索结果重新排序。Reranker模型直接计算查询和文档的相关性分数比向量相似度更精确。实现fromsentence_transformersimportCrossEncoder# 加载Reranker模型rerankerCrossEncoder(BAAI/bge-reranker-v2-m3,max_length512)defrerank_documents(query,documents):# 构建查询-文档对pairs[[query,doc.page_content]fordocindocuments]# 计算相关性分数scoresreranker.predict(pairs)# 按分数排序scored_docslist(zip(documents,scores))scored_docs.sort(keylambdax:x[1],reverseTrue)return[docfordoc,scoreinscored_docs[:5]]策略11上下文组织Context Organization原理检索到的片段来自不同文档直接拼接会导致逻辑混乱。上下文组织按照逻辑顺序重新排列片段提升模型的理解效果。实现deforganize_context(documents):按文档来源和时间顺序组织上下文# 按文档来源分组doc_groups{}fordocindocuments:sourcedoc.metadata.get(source,unknown)ifsourcenotindoc_groups:doc_groups[source][]doc_groups[source].append(doc)# 组内按位置排序organized[]forsource,docsindoc_groups.items():docs.sort(keylambdax:x.metadata.get(chunk_index,0))organized.extend(docs)returnorganized策略12引用增强Citation Enhancement原理在生成的回答中标注信息来源提升可信度和可追溯性。实现citation_prompt基于以下参考资料回答用户问题。在回答中请使用[1]、[2]等标记标注信息来源。 参考资料 {context} 用户问题{query} 请生成带引用的回答defgenerate_with_citations(query,documents):# 构建带编号的上下文context_parts[]fori,docinenumerate(documents):context_parts.append(f[{i1}] 来源{doc.metadata.get(source,unknown)}\nf{doc.page_content})context\n\n.join(context_parts)responsellm.invoke(citation_prompt.format(contextcontext,queryquery))returnresponse.content四、策略组合建议不同场景适合不同的策略组合技术文档问答语义分块 混合检索 重排序 引用增强客服系统查询重写 查询路由 上下文压缩 引用增强法律文书检索HyDE 多粒度索引 重排序 上下文组织企业内部知识库语义分块 自查询检索 多阶段检索 引用增强五、性能评估实施优化策略后建议通过以下指标评估效果检索召回率相关文档是否被检索到检索精确率检索结果中相关文档的比例答案准确率生成的回答是否正确幻觉率回答中编造信息的比例引用准确率引用是否指向正确的来源结语Advanced RAG的12种策略不是全部都要用而是按需选用。每个策略都有其适用场景和成本代价。建议从最简单的策略开始如语义分块和混合检索逐步叠加更复杂的策略每次叠加后评估效果提升和成本增加找到最适合你业务场景的最优组合。RAG优化是一个持续迭代的过程没有一劳永逸的银弹。
网站建设
高端定制
企业官网