RAG 检索增强生成:详细原理 + Python 完整实战

张开发
2026/4/20 10:42:37 15 分钟阅读

分享文章

RAG 检索增强生成:详细原理 + Python 完整实战
RAGRetrieval-Augmented Generation检索增强生成是当前解决大模型 “幻觉、知识过时、隐私泄露” 三大核心问题的主流技术本质是让大模型 “查资料再回答”而非仅靠训练数据 “闭卷考试”。下面从原理深度解析、核心架构、完整实战、优化方案四方面全面讲解。一、RAG 深度原理为什么需要 RAG1.1 纯 LLM 的三大致命缺陷知识截止模型训练数据有时间上限如 GPT-4 截止 2024 年 10 月无法回答最新数据、私有文档。幻觉问题模型为保证语句流畅会编造不存在的事实、数据、引用企业场景完全不可用。隐私风险私有数据企业文档、客户信息上传至公共 LLM 会泄露无法满足合规。1.2 RAG 核心思想不让模型 “记住” 所有知识而是给它 “专属知识库”回答时先检索相关资料再基于资料生成答案。优势零微调、低成本、实时更新、数据本地存储、答案可溯源、幻觉率降低 90%。对比RAG vs 微调 vs 纯 LLM| 方案 | 知识更新 | 成本 | 幻觉率 | 隐私 | 适用场景 ||------|----------|------|--------|------|----------|| 纯 LLM | 不能 | 0 | 极高 | 差 | 通用对话 || 微调 | 难重训 | 极高 | 中 | 中 | 固定领域 ||RAG| 易增删文档 | 极低 | 极低 | 优 | 企业知识库、私有问答 |1.3 RAG 标准工作流程RAG 分两大阶段离线索引构建在线检索生成。阶段 1离线索引数据入库一次构建文档加载读取 PDF/Word/Excel/ 网页 / 数据库等数据源。文本切分长文本拆成小块chunk适配模型上下文窗口。向量化用 Embedding 模型将文本块转为高维向量。向量存储向量存入向量库FAISS/Chroma/Milvus建立索引。阶段 2在线检索生成用户提问实时执行查询向量化用户问题转为同维度向量。相似度检索向量库匹配最相关的文本块Top-K。上下文拼接检索结果 用户问题 → 生成 Prompt。LLM 生成模型基于参考资料生成精准答案。1.4 RAG 核心组件详解Document Loader文档加载器支持 50 格式PyPDFLoader、Docx2txtLoader、WebBaseLoader。Text Splitter文本切分器RecursiveCharacterTextSplitter 最优控制 chunk_size/chunk_overlap。Embedding Model向量模型文本→向量可选在线通义千问 Embedding、文心 Embedding本地BGE-small、m3e、Ollama 本地模型Vector Store向量数据库负责存储与快速检索。Retriever检索器控制召回数量、相似度阈值、混合检索。LLM大语言模型负责最终生成通义千问、DeepSeek、Llama 3、Ollama。Prompt Template提示词模板约束模型 “只参考资料、不编造”。二、Python LangChain 完整实战本地 / 在线双版本2.1 环境准备安装依赖bash运行# 核心框架 pip install langchain langchain-community langchain-core # 向量库轻量本地 pip install faiss-cpu chromadb # 文档加载 pip install pypdf python-docx beautifulsoup4 # 在线 Embedding/LLM通义千问替代OpenAI pip install dashscope # 本地方案Ollama完全离线 pip install langchain-ollama方案选择在线版通义千问 API免费额度足够测试本地版Ollama 本地模型无需 API、完全隐私2.2 实战 1在线版 RAG通义千问步骤 1准备知识库test_knowledge.txtplaintextRAG全称Retrieval-Augmented Generation即检索增强生成用于解决大模型幻觉、知识过时问题。 LangChain是Python开发LLM应用的主流框架提供文档加载、切分、检索全链路工具。 LangGraph是LangChain生态的流程编排工具支持RAG的条件判断、重试、多跳检索。 向量数据库用于存储文本向量实现高效语义相似度检索常用FAISS、Chroma、Milvus。 Embedding模型将文本转为高维向量是RAG检索的核心基础。步骤 2完整代码实现python运行import os from langchain_community.document_loaders import TextLoader from langchain_text_splitters import RecursiveCharacterTextSplitter from langchain_community.vectorstores import FAISS from langchain_community.embeddings import DashScopeEmbeddings from langchain_community.llms import Tongyi from langchain.prompts import PromptTemplate from langchain.chains import RetrievalQA # 1. 配置 API Key通义千问 os.environ[DASHSCOPE_API_KEY] 你的通义千问API Key # 官网申请 # 初始化向量模型 LLM embeddings DashScopeEmbeddings(modeltext-embedding-v1) llm Tongyi( model_nameqwen-turbo, temperature0.01, # 低温度低幻觉 max_tokens1024 ) # 2. 构建索引离线 # 1. 加载文档 loader TextLoader(test_knowledge.txt, encodingutf-8) documents loader.load() # 2. 文本切分核心参数 text_splitter RecursiveCharacterTextSplitter( chunk_size300, # 每块300字符 chunk_overlap50, # 重叠50字符保证语义连贯 separators[\n\n, \n, 。, , ] # 按语义拆分 ) text_chunks text_splitter.split_documents(documents) print(f切分后文本块数量{len(text_chunks)}) # 3. 构建向量库 vectorstore FAISS.from_documents(text_chunks, embeddings) # 持久化保存下次直接加载 vectorstore.save_local(faiss_rag_db) # 4. 创建检索器召回最相关3条 retriever vectorstore.as_retriever( search_typesimilarity, search_kwargs{k: 3} ) # 3. 构建 RAG 链 # 关键严格 Prompt禁止编造 prompt_template 你是专业AI助手请严格按照以下参考资料回答问题。 规则 1. 只使用参考资料中的信息不添加任何外部知识 2. 资料中无答案直接回复未找到相关信息 3. 回答简洁准确标注来源 参考资料 {context} 用户问题{question} PROMPT PromptTemplate( templateprompt_template, input_variables[context, question] ) # 构建检索问答链 rag_chain RetrievalQA.from_chain_type( llmllm, chain_typestuff, # 直接拼接检索结果 retrieverretriever, chain_type_kwargs{prompt: PROMPT}, return_source_documentsTrue # 返回来源文档可溯源 ) # 4. 测试 RAG if __name__ __main__: # 测试问题1有答案 query1 LangGraph是什么 result1 rag_chain.invoke({query: query1}) print(*50) print(f问题{query1}) print(f答案{result1[result]}) print(来源文档) for doc in result1[source_documents]: print(f- {doc.page_content[:100]}...) # 测试问题2无答案 query2 Python是谁发明的 result2 rag_chain.invoke({query: query2}) print(*50) print(f问题{query2}) print(f答案{result2[result]})运行结果plaintext 问题LangGraph是什么 答案LangGraph是LangChain生态的流程编排工具支持RAG的条件判断、重试、多跳检索。 来源文档 - LangGraph是LangChain生态的流程编排工具支持RAG的条件判断、重试、多跳检索。... 问题Python是谁发明的 答案未找到相关信息2.3 实战 2本地离线版 RAGOllama无需 API Key、数据完全本地适合隐私场景。步骤 1安装 Ollama官网下载https://ollama.com/命令行拉取模型bash运行ollama pull qwen:7b # LLM ollama pull m3e:base # Embedding模型步骤 2本地版代码python运行from langchain_community.document_loaders import TextLoader from langchain_text_splitters import RecursiveCharacterTextSplitter from langchain_community.vectorstores import FAISS from langchain_ollama import OllamaEmbeddings, ChatOllama from langchain.prompts import PromptTemplate from langchain.chains import RetrievalQA # 1. 本地模型初始化 # 本地Embedding embeddings OllamaEmbeddings(modelm3e:base) # 本地LLM llm ChatOllama( modelqwen:7b, temperature0.01, max_tokens1024 ) # 2. 索引构建同在线版 loader TextLoader(test_knowledge.txt, encodingutf-8) documents loader.load() text_splitter RecursiveCharacterTextSplitter(chunk_size300, chunk_overlap50) text_chunks text_splitter.split_documents(documents) vectorstore FAISS.from_documents(text_chunks, embeddings) retriever vectorstore.as_retriever(search_kwargs{k: 3}) # 3. RAG 链同在线版 prompt_template 严格按参考资料回答无答案则回复未找到相关信息 参考资料{context} 问题{question} PROMPT PromptTemplate(templateprompt_template, input_variables[context, question]) rag_chain RetrievalQA.from_chain_type( llmllm, chain_typestuff, retrieverretriever, chain_type_kwargs{prompt: PROMPT}, return_source_documentsTrue ) # 4. 测试 if __name__ __main__: query RAG解决什么问题 result rag_chain.invoke({query: query}) print(f问题{query}) print(f答案{result[result]})三、RAG 进阶LangGraph 工业级流程带重试 / 判断基础 RAG 是线性流程LangGraph可实现条件检索、多轮重试、答案校验适合生产环境。3.1 核心代码基于上文python运行from typing import List, TypedDict from langchain.schema import Document from langgraph.graph import StateGraph, START, END # 1. 定义图状态 class GraphState(TypedDict): question: str documents: List[Document] answer: str # 2. 定义节点函数 # 节点1检索 def retrieve(state: GraphState): question state[question] docs retriever.invoke(question) return {documents: docs} # 节点2生成 def generate(state: GraphState): question state[question] docs state[documents] context \n.join([d.page_content for d in docs]) prompt PROMPT.format(contextcontext, questionquestion) answer llm.invoke(prompt) return {answer: answer} # 节点3答案校验无答案则重试检索 def check_answer(state: GraphState): answer state[answer] if 未找到相关信息 in answer: return retrieve # 回到检索 else: return END # 3. 构建 LangGraph 流程 workflow StateGraph(GraphState) workflow.add_node(retrieve, retrieve) workflow.add_node(generate, generate) # 流程连接 workflow.add_edge(START, retrieve) workflow.add_edge(retrieve, generate) # 条件边有效→结束无效→重试 workflow.add_conditional_edges( generate, check_answer, {retrieve: retrieve, END: END} ) # 编译 app workflow.compile() # 4. 运行 if __name__ __main__: inputs {question: LangChain用来做什么} output app.invoke(inputs) print(f答案{output[answer]})四、RAG 生产级优化提升准确率核心4.1 检索优化准确率 70% 来源切分优化chunk_size200~500 字符匹配模型上下文chunk_overlap50~100 字符避免语义断裂按语义拆分优先段落、句子、标点。检索策略混合检索相似度 关键词BM25重排序Rerank召回后用 BGE-rerank 模型二次筛选。扩大 k 值k5~10再重排序取 Top3。向量库选择小规模FAISS、Chroma本地大规模Milvus、Pinecone分布式。4.2 生成优化低温度temperature0.01~0.1减少随机性。严格 Prompt明确禁止编造、要求引用来源。上下文截断避免超出模型窗口如 4k/8k。4.3 工程优化向量库持久化避免重复构建缓存高频问题Redis 缓存答案异步接口提升并发日志监控记录检索准确率、响应时间五、总结RAG 本质给 LLM 加 “专属知识库 搜索引擎”解决幻觉、过时、隐私问题。核心流程索引加载→切分→向量化→存储→ 检索生成查询→匹配→拼接→生成。实战落地LangChain 快速搭建LangGraph 实现复杂流程本地 / 在线双方案可选。优化关键检索精度 Prompt 约束 模型选择。

更多文章