当前位置: 首页 > news >正文

【AI原生开发实战专栏】5.5 RAG高级技巧:从Naive RAG到生产级系统

学习目标

  • 理解RAG的三种技术范式演进
  • 掌握Query Rewriting、Hybrid Search、Reranking等核心技巧
  • 能够在实际项目中实现高级RAG Pipeline
  • 理解Chunk策略对检索效果的影响
  • 为构建生产级RAG系统奠定基础

一、RAG技术范式演进

1.1 从Naive到Advanced的演进

RAG技术经历了三个发展阶段:

┌─────────────────────────────────────────────────┐ │ RAG范式演进 │ ├─────────────────────────────────────────────────┤ │ Naive RAG → Advanced RAG → Modular RAG │ │ 2020 2023-2024 2025-2026 │ ├─────────────────────────────────────────────────┤ │ • 简单检索 • 预检索优化 • 模块可插拔 │ │ • 直接拼接 • 后检索优化 • 多模态支持 │ │ • 效果一般 • 质量提升 • Agent集成 │ └─────────────────────────────────────────────────┘

1.2 Naive RAG痛点

问题表现影响
检索不准语义匹配差答非所问
上下文丢失大块截断关键信息遗漏
幻觉严重LLM乱编信任度下降
效率低下检索慢用户体验差

二、预检索优化(Pre-Retrieval)

2.1 Query Rewriting

将用户模糊/口语化的query重写为更适合检索的形式。

fromlangchain.chat_modelsimportChatOpenAIfromlangchain.promptsimportChatPromptTemplatefromlangchain.schemaimportStrOutputParser# Query重写Promptrewrite_prompt=ChatPromptTemplate.from_template(""" 你是一个查询优化专家。将用户的问题改写为更适合向量检索的形式。 原始问题:{query} 要求: 1. 提取核心关键词 2. 去除口语化表达 3. 补充必要的上下文 4. 可以生成2-3个相似查询 改写结果: """)# 重写链rewrite_chain=rewrite_prompt|ChatOpenAI(temperature=0)|StrOutputParser()# 使用示例original_query="那篇讲transformer的论文讲的啥来着"rewritten=rewrite_chain.invoke({"query":original_query})# 输出可能:# - Transformer论文的核心内容# - Attention is All You Need主要贡献# - BERT和GPT的基础架构

2.2 HyDE(Hypothetical Document Embeddings)

用LLM生成"假设答案",用假设答案去检索。

fromlangchain.chainsimportHypotheticalDocumentEmbedderfromlangchain.embeddingsimportOpenAIEmbeddings# HyDE嵌入器hyde_embeddings=HypotheticalDocumentEmbedder.from_llm(llm=ChatOpenAI(temperature=0),base_embeddings=OpenAIEmbeddings(),prompt_key="web_search"# 指定生成假设文档的prompt)# 应用到向量存储vectorstore=Chroma.from_documents(documents=chunks,embedding=hyde_embeddings# 使用HyDE)# 检索时使用假设答案results=vectorstore.similarity_search(query,k=5)

2.3 Hybrid Search

结合BM25(关键词搜索)和向量搜索的优势。

fromlangchain.retrieversimportEnsembleRetrieverfromlangchain_community.retrieversimportBM25Retrieverfromlangchain.vectorstoresimportChroma# 1. BM25检索器bm25_retriever=BM25Retriever.from_texts(texts=chunk_texts,metadatas=chunk_metadatas)bm25_retriever.k=5# 2. 向量检索器vectorstore=Chroma.from_texts(texts=chunk_texts,embedding=OpenAIEmbeddings())vector_retriever=vectorstore.as_retriever(search_kwargs={"k":5})# 3. 集成检索器ensemble_retriever=EnsembleRetriever(retrievers=[vector_retriever,bm25_retriever],weights=[0.6,0.4]# 向量搜索权重更高)# 4. 使用集成检索器results=ensemble_retriever.invoke("transformer架构详解")

三、检索优化(Retrieval)

3.1 Multi-Query Retrieval

从多个角度生成查询变体,扩大召回范围。

fromlangchain.retrievers.multi_queryimportMultiQueryRetriever# 自动生成多个查询multi_query_retriever=MultiQueryRetriever.from_llm(retriever=base_retriever,llm=ChatOpenAI(temperature=0),include_original=True# 保留原始查询)# 检索results=multi_query_retriever.get_relevant_documents("Transformer中的Positional Encoding是如何工作的?")

3.2 Parent Document Retriever

保持父子文档关系,平衡检索精度和上下文完整性。

fromlangchain.retrieversimportParentDocumentRetrieverfromlangchain.text_splitterimportRecursiveCharacterTextSplitterfromlangchain.vectorstoresimportChroma# 大块(父文档)parent_splitter=RecursiveCharacterTextSplitter(chunk_size=2000,chunk_overlap=200)# 小块(检索用)child_splitter=RecursiveCharacterTextSplitter(chunk_size=200,chunk_overlap=50)# 父文档检索器parent_retriever=ParentDocumentRetriever(vectorstore=Chroma(),docstore=InMemoryStore(),child_splitter=child_splitter,parent_splitter=parent_splitter,)# 添加文档时会自动切分parent_retriever.add_documents(documents)# 检索时返回父文档(完整上下文)results=parent_retriever.invoke("attention mechanism")

3.3 Reranking

用更精确的模型对初筛结果重排序。

fromsentence_transformersimportCrossEncoder# 1. 初筛:快速向量检索Top-20initial_results=vectorstore.similarity_search(query,k=20)# 2. 重排:用Cross-Encoder精细排序reranker=CrossEncoder('BAAI/bge-reranker-base')pairs=[[query,doc.page_content]fordocininitial_results]scores=reranker.predict(pairs)# 按分数排序ranked_results=[docfor_,docinsorted(zip(scores,initial_results),reverse=True)][:5]# 取Top-5# 3. 使用重排后的结果context="\n\n".join([doc.page_contentfordocinranked_results])

四、Chunk策略优化

4.1 固定窗口Chunk

fromlangchain.text_splitterimportCharacterTextSplitter# 简单但可能切断语义text_splitter=CharacterTextSplitter(separator="\n",chunk_size=500,chunk_overlap=50,length_function=len,)

4.2 语义分块(推荐)

fromlangchain_experimental.text_splitterimportSemanticChunkerfromlangchain_openai.embeddingsimportOpenAIEmbeddings# 基于语义相似度切分semantic_chunker=SemanticChunker(embeddings=OpenAIEmbeddings(),breakpoint_threshold_type="percentile",# 基于百分位breakpoint_threshold_amount=95,# 相似度低于95%分位点时切分)chunks=semantic_chunker.create_documents([long_text])

4.3 Markdown/JSON结构化分块

defchunk_by_markdown(content:str)->list[str]:""" 按Markdown标题层级分块 """lines=content.split('\n')chunks=[]current_chunk=[]current_level=0forlineinlines:ifline.startswith('#'):level=len(line)-len(line.lstrip('#'))# 遇到更高级别标题时保存当前chunkiflevel<current_levelandcurrent_chunk:chunks.append('\n'.join(current_chunk))current_chunk=[]current_level=level current_chunk.append(line)ifcurrent_chunk:chunks.append('\n'.join(current_chunk))return[cforcinchunksifc.strip()]

五、后检索处理

5.1 Contextual Compression

压缩检索结果,保留关键信息。

fromlangchain.retrieversimportContextualCompressionRetrieverfromlangchain_community.document_compressorsimportLLMChainExtractor# 压缩器:用LLM提取关键信息compressor=LLMChainExtractor.from_llm(ChatOpenAI(temperature=0))compression_retriever=ContextualCompressionRetriever(base_retriever=base_retriever,document_compressor=compressor)# 检索时自动压缩compressed_docs=compression_retriever.invoke(query)

5.2 MMR(最大边际相关性)

避免检索结果过于相似,增加多样性。

# 在向量存储中配置MMRvectorstore=Chroma.from_texts(texts,embedding=embeddings)# 检索时使用MMRresults=vectorstore.max_marginal_relevance_search(query,k=5,# 最终返回数量fetch_k=20,# 初始候选数量lambda_mult=0.5# 0=只顾多样性, 1=只顾相关性)

六、完整RAG Pipeline实现

fromtypingimportOptionalfromlangchain.chat_modelsimportChatOpenAIfromlangchain.promptsimportChatPromptTemplatefromlangchain.schemaimportStrOutputParserfrompydanticimportBaseModelclassAdvancedRAGPipeline:def__init__(self,vectorstore,llm:ChatOpenAI,embedder):self.vectorstore=vectorstore self.llm=llm# 1. Query重写self.rewrite_prompt=ChatPromptTemplate.from_template(""" 将这个问题改写为更适合检索的形式: {query} """)self.rewrite_chain=(self.rewrite_prompt|self.llm|StrOutputParser())# 2. HyDE生成假设答案selfhyde_embeddings=HypotheticalDocumentEmbedder.from_llm(llm=self.llm,base_embeddings=embedder)# 3. 集成检索self.bm25_retriever=BM25Retriever.from_texts(...)self.vector_retriever=vectorstore.as_retriever(k=10)self.ensemble_retriever=EnsembleRetriever(retrievers=[self.vector_retriever,self.bm25_retriever],weights=[0.7,0.3])# 4. 重排器self.reranker=CrossEncoder('BAAI/bge-reranker-base')# 5. 生成self.qa_prompt=ChatPromptTemplate.from_template(""" 基于以下上下文回答问题。如果上下文中没有相关信息,请如实说明。 上下文: {context} 问题:{question} """)defretrieve(self,query:str,top_k:int=5)->list:"""检索阶段"""# 重写Queryrewritten=self.rewrite_chain.invoke({"query":query})# 集成检索initial_results=self.ensemble_retriever.invoke(rewritten)# 重排pairs=[[query,doc.page_content]fordocininitial_results]scores=self.reranker.predict(pairs)ranked=sorted(zip(scores,initial_results),reverse=True)return[docfor_,docinranked[:top_k]]defgenerate(self,question:str,context_docs:list)->str:"""生成阶段"""context="\n\n".join([doc.page_contentfordocincontext_docs])chain=self.qa_prompt|self.llm|StrOutputParser()returnchain.invoke({"question":question,"context":context})definvoke(self,query:str)->dict:"""完整RAG Pipeline"""docs=self.retrieve(query)answer=self.generate(query,docs)return{"answer":answer,"source_documents":docs,"retrieval_query":query}

七、评估与调优

7.1 RAGAS指标

fromragas.metricsimport(faithfulness,answer_relevancy,context_relevancy,)fromragasimportevaluate# 评估数据集eval_dataset=[{"question":"...","answer":"...","contexts":["..."],}]# 运行评估result=evaluate(eval_dataset,metrics=[faithfulness,answer_relevancy,context_relevancy],)result.to_pandas()

7.2 调优参数

参数调优范围影响
chunk_size200-2000太大丢失精度,太小缺上下文
top_k3-10太多噪声,太少缺信息
retrieval_weight0.3-0.7向量vs BM25的权重
rerank_top_n5-20重排候选数量
mmr_lambda0-1相关性与多样性平衡

八、总结

高级RAG技巧的核心是全流程优化

  1. 预检索:Query Rewriting/HyDE提升召回
  2. 检索层:Hybrid Search + Parent Doc平衡精度
  3. 后处理:Reranking + Compression提升精度
  4. 评估:RAGAS等指标量化效果

实践建议

  • 从Naive RAG开始,逐步迭代
  • 每个优化点单独验证效果
  • 记录不同配置的效果对比

习题

  1. 实现一个支持MMR的RAG系统
  2. 对比不同Chunk策略的检索效果
  3. 使用RAGAS评估现有RAG系统
  4. 尝试组合多种优化技巧

参考文献

  • LangChain RAG文档
  • RAGAS Evaluation Framework
  • BAAI/bge-reranker模型
http://www.jsqmd.com/news/700346/

相关文章:

  • 掌握pmu-tools:大规模分布式系统性能监控的终极解决方案
  • SGPlayer在tvOS上的特殊适配:为大屏体验优化的播放器开发技巧
  • 如何用OpenResume实现简历数据可视化:打造专业简历统计与分析功能
  • 2026届必备的五大降重复率助手实际效果
  • 如何快速构建低延迟智能语音应用:RealtimeSTT实战指南
  • 从 ChatGPT 到 AutoGPT:对话式 AI 向智能体演进的关键转折
  • 图像融合新思路:拆开再拼起来——DeFusion论文精读与代码实战指南
  • 《把 Hermes Agent 养成你的专属帕鲁:从捕捉到满级实战指南》(二)
  • 如何快速上手AtCoder Library:5分钟完成安装与配置
  • 避坑指南:Seurat v4/v5对象互转时,你的差异表达结果还可靠吗?
  • 如何在Windows电脑上直接安装安卓应用:APK安装器完整指南
  • LOOT模组加载优化工具:5分钟掌握完美游戏体验的秘诀
  • 如何将Disque消息代理无缝集成到CI/CD流程:自动化部署与版本管理终极指南
  • innovus LEF/DEF 6.0 语言学习参考(1)
  • 2026家装墙板优选指南:适配全场景,告别后期维修烦恼 - 速递信息
  • Python使用XPath定位元素:动态计算与函数调用
  • MySQL主从复制过程中怎么增加从库_利用mysqldump快速扩容从库.txt
  • Apache Kylin 3.1.3 自动化构建指南:如何用Shell脚本调用REST API定时触发增量构建
  • JVM 学习第五天:类加载机制 + 内存调优实战 + 新面试题全解(无重复)
  • XUnity自动翻译器:如何为Unity游戏实现实时文本翻译
  • Simple Form开源项目安全政策:漏洞披露完整指南
  • Qwen3.5-2B实操手册:WebUI中启用RAG插件连接本地知识库方法
  • RocketMQ 系列文章(高级篇第 2 篇):消息追踪与性能优化实战
  • 终极指南:3分钟快速搭建Kafka可视化管理平台
  • DeepSeek V4写论文不被检测攻略,2026年4月3款工具配 - 我要发一区
  • 终极AI Agent云运行时:如何用E2B构建企业级智能代理协作环境
  • 2026届学术党必备的五大降AI率网站实际效果
  • 儿童近视防控科学指南|赵阳眼科解析系统化护眼核心方案 - 外贸老黄
  • 直接进老年代的大对象指的是shallow还是retained
  • 大语言模型:有趣的小实验