从零搭建 RAG 完整指南LangChain 向量数据库 LLM目录什么是 RAG为什么需要 RAGRAG 核心架构技术栈选型环境准备[极简 RAG 实现纯 Python](#极简-rag 实现纯-python)使用 LangChain 实现完整 RAG更换向量数据库接入真实 LLM文档加载与分块高级优化技巧常见问题完整项目示例什么是 RAGRAGRetrieval-Augmented Generation检索增强生成是一种结合检索和生成的 AI 技术架构。核心流程用户提问 → 检索相关知识 → 组装上下文 → LLM 生成回答通俗理解RAG 就像是给大语言模型配备了一个开卷考试的能力传统 LLM闭卷考试全靠训练时 memorized 的知识RAG 增强的 LLM开卷考试可以查阅参考书后作答为什么需要 RAG大语言模型的三大痛点问题描述案例幻觉问题模型会编造看似合理但错误的信息鲁迅在 2020 年获得诺贝尔奖知识过时训练数据有截止时间不知道最新信息不知道 2024 年的新闻私有数据无法访问企业内部知识库公司文档、产品手册无法利用RAG 的优势✅减少幻觉- 基于真实资料回答有据可查✅支持最新数据- 知识库可随时更新✅利用私有数据- 企业内部文档可用✅回答可溯源- 可以知道答案来自哪份文档✅成本更低- 无需频繁微调模型RAG 核心架构基本架构图┌─────────────────────────────────────────────────────────┐ │ 用户提问 │ │ 公司的年假政策是什么 │ └────────────────────┬────────────────────────────────────┘ ↓ ┌────────────────────────┐ │ 1. 问题向量化 │ │ (Embedding) │ └────────────┬───────────┘ ↓ ┌────────────────────────┐ │ 2. 向量数据库检索 │ │ 查找最相关的文档片段 │ └────────────┬───────────┘ ↓ ┌────────────────────────┐ │ 3. 组装上下文 │ │ 问题 检索到的资料 │ └────────────┬───────────┘ ↓ ┌────────────────────────┐ │ 4. LLM 生成回答 │ │ 基于上下文生成答案 │ └───────────────────────┘ ↓ ┌────────────────────────┐ │ 5. 返回答案 │ │ 根据公司政策... │ └────────────────────────┘核心组件文档处理模块文档加载PDF、Word、Markdown 等文本分块Chunking数据清洗向量化模块Embedding 模型向量生成存储模块向量数据库索引管理检索模块相似度搜索排序过滤生成模块LLM 接入Prompt 工程技术栈选型完整技术栈组件推荐方案备选方案编排框架LangChainLlamaIndex向量数据库ChromaFAISS、Milvus、Qdrant、WeaviateEmbedding 模型OpenAI text-embedding-3-smallBGE、M3E、text2vecLLMGPT-4、Claude通义千问、文心一言、ChatGLM本地 LLMOllamaQwen2.5、Llama3LM Studio新手推荐组合快速入门10 分钟跑通LangChain Chroma OpenAI API完全免费本地运行LangChain Chroma Ollama BGE Embedding企业级部署LangChain Milvus 商业 LLM API环境准备安装依赖# 基础依赖 pip install langchain langchain-community langchain-openai # 向量数据库 pip install chromadb faiss-cpu # 文档处理 pip install pypdf python-docx markdown # 本地模型可选 pip install sentence-transformers完整 requirements.txtlangchain0.1.0 langchain-community0.0.10 langchain-openai0.0.2 chromadb0.4.22 faiss-cpu1.7.4 pypdf4.0.0 python-docx1.1.0 markdown3.5.2 sentence-transformers2.3.1环境变量配置# OpenAI API如果使用 export OPENAI_API_KEYyour-api-key # 或者使用本地模型无需 API Key # 安装 Ollama: https://ollama.ai极简 RAG 实现纯 Python不依赖任何库的 RAG 示例# 1. 构造知识库 knowledge_base [ Python 是一种解释型、高级编程语言。, RAG 是检索增强生成用于让大模型引用外部知识。, 大模型容易产生幻觉RAG 可以减少幻觉。, 向量数据库用于存储文本的向量表示方便快速检索。 ] # 2. 简单检索关键词匹配 def retrieve(query, docs): 检索与查询相关的文档 results [] query_words query.lower().split() for doc in docs: # 检查是否包含查询词 if any(word in doc.lower() for word in query_words): results.append(doc) return results # 3. 模拟生成 def generate_answer(query, context): 根据上下文生成答案 if not context: return 抱歉没有相关资料。 # 简单拼接实际应调用 LLM return f根据资料{context[0]} # 4. RAG 主流程 def rag(query): 完整的 RAG 流程 # 检索 context retrieve(query, knowledge_base) # 生成 return generate_answer(query, context) # 5. 测试 if __name__ __main__: print(问题什么是 RAG) print(答案, rag(什么是 RAG)) print(\n问题Python 是什么) print(答案, rag(Python 是什么))运行结果问题什么是 RAG 答案根据资料RAG 是检索增强生成用于让大模型引用外部知识。 问题Python 是什么 答案根据资料Python 是一种解释型、高级编程语言。使用 LangChain 实现完整 RAG完整代码示例from langchain_community.vectorstores import Chroma from langchain_community.embeddings import FakeEmbeddings from langchain_text_splitters import CharacterTextSplitter from langchain.chains import RetrievalQA from langchain_community.llms import FakeListLLM # 1. 准备数据 documents [ Python 是一种解释型、高级编程语言由 Guido van Rossum 于 1991 年发明。, RAGRetrieval-Augmented Generation是检索增强生成技术。, 大模型容易产生幻觉RAG 可以通过检索外部知识减少幻觉。, 向量数据库专门用于存储和检索向量数据支持相似度搜索。, LangChain 是用于开发大语言模型应用的框架。 ] # 2. 文本分块 text_splitter CharacterTextSplitter( chunk_size100, # 每块 100 字符 chunk_overlap20, # 重叠 20 字符 separator。 # 按句号分割 ) chunks text_splitter.create_documents(documents) # 3. 创建向量数据库 # 使用模拟 Embedding实际使用时替换为真实模型 embedding FakeEmbeddings(size10) # 创建 Chroma 向量库 db Chroma.from_documents( documentschunks, embeddingembedding, persist_directory./chroma_db # 持久化存储 ) # 4. 创建检索器 retriever db.as_retriever( search_typesimilarity, # 相似度搜索 search_kwargs{k: 2} # 返回最相关的 2 条 ) # 5. 创建 LLM # 使用模拟 LLM实际使用时替换为真实 API llm FakeListLLM( responses[ 根据检索到的资料Python 是一种高级编程语言。, RAG 是检索增强生成技术可以减少大模型幻觉。 ] ) # 6. 创建 RAG 链 qa_chain RetrievalQA.from_chain_type( llmllm, chain_typestuff, # 将所有文档拼接到一个 prompt retrieverretriever, return_source_documentsTrue # 返回来源文档 ) # 7. 提问测试 query 什么是 RAG result qa_chain.invoke(query) print(f问题{query}) print(f答案{result[result]}) print(f参考文档{result[source_documents]})使用真实的 OpenAI 模型from langchain_openai import ChatOpenAI, OpenAIEmbeddings # Embedding 模型 embedding OpenAIEmbeddings( modeltext-embedding-3-small, openai_api_keyyour-api-key ) # LLM 模型 llm ChatOpenAI( modelgpt-4, temperature0.7, openai_api_keyyour-api-key ) # 其他代码保持不变...使用本地 Ollama 模型免费from langchain_community.llms import Ollama from langchain_community.embeddings import OllamaEmbeddings # Embedding需要 Ollama 安装 nomic-embed-text 模型 embedding OllamaEmbeddings( modelnomic-embed-text, base_urlhttp://localhost:11434 ) # LLM使用 Qwen2.5 或 Llama3 llm Ollama( modelqwen2.5:7b, base_urlhttp://localhost:11434 )更换向量数据库LangChain 的优势统一接口更换向量数据库只需修改一行代码1. FAISSFacebook AI 相似性搜索from langchain_community.vectorstores import FAISS db FAISS.from_documents(chunks, embedding) # 保存 db.save_local(./faiss_index) # 加载 # db FAISS.load_local(./faiss_index, embedding)特点✅ 速度快✅ 轻量级❌ 不支持持久化需手动保存❌ 不支持分布式2. Milvus企业级向量数据库from langchain_community.vectorstores import Milvus db Milvus.from_documents( chunks, embedding, connection_args{ host: localhost, port: 19530 }, index_params{ metric_type: COSINE, index_type: HNSW } )特点✅ 企业级性能✅ 支持大规模数据✅ 支持分布式❌ 部署复杂3. Qdrant云原生向量数据库from langchain_community.vectorstores import Qdrant db Qdrant.from_documents( chunks, embedding, urlhttp://localhost:6333, api_keyyour-api-key, # 可选 collection_namemy_rag )特点✅ 云原生设计✅ 支持 Docker 部署✅ RESTful API✅ 免费云托管4. Chroma新手友好from langchain_community.vectorstores import Chroma db Chroma.from_documents( documentschunks, embeddingembedding, persist_directory./chroma_db )特点✅ 简单易用✅ 内置持久化✅ 无需额外部署✅ 适合原型开发向量数据库对比数据库易用性性能扩展性适用场景Chroma⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐原型、小项目FAISS⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐本地应用Milvus⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐企业级Qdrant⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐云服务接入真实 LLM方案 1OpenAI APIfrom langchain_openai import ChatOpenAI import os os.environ[OPENAI_API_KEY] sk-... llm ChatOpenAI( modelgpt-4o, # 或 gpt-3.5-turbo temperature0.7, # 创造性 0-1 max_tokens1000 # 最大输出长度 )价格GPT-4o: $2.5 / 1M tokens输入GPT-3.5-turbo: $0.5 / 1M tokens输入方案 2Claude APIAnthropicfrom langchain_anthropic import ChatAnthropic import os os.environ[ANTHROPIC_API_KEY] sk-ant-... llm ChatAnthropic( modelclaude-3-5-sonnet-20241022, temperature0.7, max_tokens1000 )价格Claude 3.5 Sonnet: $3 / 1M tokens输入方案 3国产大模型通义千问阿里云from langchain_community.llms import Tongyi import os os.environ[DASHSCOPE_API_KEY] sk-... llm Tongyi( modelqwen-max, # 或 qwen-plus temperature0.7 )价格免费额度 按量付费文心一言百度from langchain_community.llms import QianfanLLMEndpoint import os os.environ[QIANFAN_AK] your-access-key os.environ[QIANFAN_SK] your-secret-key llm QianfanLLMEndpoint( modelERNIE-Bot-4, temperature0.7 )方案 4本地部署完全免费使用 Ollama# 1. 安装 Ollama # 访问 https://ollama.ai 下载安装 # 2. 下载模型 ollama pull qwen2.5:7b # 通义千问 7B ollama pull llama3:8b # Llama 3 8B ollama pull mistral:7b # Mistral 7B # 3. 运行 ollama run qwen2.5:7bfrom langchain_community.llms import Ollama llm Ollama( modelqwen2.5:7b, base_urlhttp://localhost:11434, temperature0.7 )模型推荐模型大小显存需求速度质量Qwen2.5:7b7B8GB快⭐⭐⭐⭐Llama3:8b8B8GB快⭐⭐⭐⭐Qwen2.5:14b14B16GB中⭐⭐⭐⭐⭐Mistral:7b7B8GB快⭐⭐⭐⭐文档加载与分块加载各种格式文档PDF 文档from langchain_community.document_loaders import PyPDFLoader loader PyPDFLoader(company_handbook.pdf) documents loader.load() print(f加载了 {len(documents)} 页文档)Word 文档from langchain_community.document_loaders import Docx2txtLoader loader Docx2txtLoader(product_manual.docx) documents loader.load()Markdown 文件from langchain_community.document_loaders import UnstructuredMarkdownLoader loader UnstructuredMarkdownLoader(README.md) documents loader.load()批量加载文件夹from langchain_community.document_loaders import DirectoryLoader # 加载目录下所有 PDF loader DirectoryLoader( ./docs/, glob**/*.pdf, loader_clsPyPDFLoader ) documents loader.load()文本分块策略1. 固定长度分块from langchain_text_splitters import CharacterTextSplitter splitter CharacterTextSplitter( chunk_size500, # 每块 500 字符 chunk_overlap50, # 重叠 50 字符 separator\n # 分隔符 ) chunks splitter.split_documents(documents)2. 递归分块推荐from langchain_text_splitters import RecursiveCharacterTextSplitter splitter RecursiveCharacterTextSplitter( chunk_size1000, chunk_overlap200, separators[\n\n, \n, 。, ., ] # 优先级分隔符 ) chunks splitter.split_documents(documents)3. 按 Token 分块更精确from langchain_text_splitters import TokenTextSplitter splitter TokenTextSplitter( chunk_size500, # 500 tokens chunk_overlap50 ) chunks splitter.split_documents(documents)分块大小建议场景chunk_sizechunk_overlap短文本FAQ200-30050一般文档500-800100-200长文档书籍1000-2000200-400代码文件300-50050-100高级优化技巧1. 混合检索关键词 向量from langchain.retrievers import EnsembleRetriever from langchain_community.vectorstores import Chroma from langchain_community.retrievers import BM25Retriever # 向量检索 vector_retriever db.as_retriever(search_kwargs{k: 3}) # 关键词检索BM25 bm25_retriever BM25Retriever.from_documents(chunks) bm25_retriever.k 3 # 混合检索 ensemble_retriever EnsembleRetriever( retrievers[bm25_retriever, vector_retriever], weights[0.3, 0.7] # 权重分配 )2. 重排序Re-rankingfrom langchain.retrievers import ContextualCompressionRetriever from langchain.retrievers.document_compressors import LLMChainExtractor # 使用 LLM 对检索结果重排序 compressor LLMChainExtractor.from_llm(llm) compression_retriever ContextualCompressionRetriever( base_compressorcompressor, base_retrieverdb.as_retriever() )3. 多查询检索from langchain.retrievers.multi_query import MultiQueryRetriever # 让 LLM 生成多个角度的查询 retriever MultiQueryRetriever.from_llm( retrieverdb.as_retriever(), llmllm ) # 会自动生成 3-5 个不同问法合并结果4. 元数据过滤# 添加元数据 for doc in chunks: doc.metadata[source] handbook doc.metadata[category] policy doc.metadata[year] 2024 # 检索时过滤 retriever db.as_retriever( search_kwargs{ k: 3, filter: {category: policy, year: 2024} } )5. 父子文档检索from langchain.retrievers import ParentDocumentRetriever # 大文档用于检索上下文小 chunk 用于向量匹配 retriever ParentDocumentRetriever( vectorstoredb, docstoreInMemoryDocstore(), child_splitterCharacterTextSplitter(chunk_size200), parent_splitterCharacterTextSplitter(chunk_size1000) )6. 对话式 RAG支持多轮对话from langchain.chains import ConversationalRetrievalChain from langchain.memory import ConversationBufferMemory # 添加对话记忆 memory ConversationBufferMemory( memory_keychat_history, return_messagesTrue ) # 创建对话式 RAG 链 conversational_chain ConversationalRetrievalChain.from_llm( llmllm, retrieverdb.as_retriever(), memorymemory, return_source_documentsTrue ) # 多轮对话 result1 conversational_chain({question: 什么是 RAG}) result2 conversational_chain({question: 它有什么好处}) # 能理解它指代 RAG常见问题Q1: RAG 和微调Fine-tuning有什么区别维度RAG微调原理检索外部知识调整模型参数成本低高更新知识容易更新文档困难重新训练可解释性高可溯源低适用场景知识库问答风格适配、任务特化建议优先用 RAG特殊需求再微调Q2: 如何提高检索准确率优化分块- 合理设置 chunk_size增加重叠- chunk_overlap 设为 10-20%混合检索- 关键词 向量重排序- 使用 LLM 重排结果元数据过滤- 添加分类、时间等标签Q3: Embedding 模型选哪个英文OpenAI text-embedding-3-small性价比高BGE-large-en开源最佳中文BGE-large-zhM3E-basetext2vec多语言m3e-baseLaBSEQ4: 向量数据库如何选择快速原型→ Chroma本地应用→ FAISS中小项目→ Qdrant企业部署→ MilvusQ5: 如何处理超长文档# 1. 分段加载 loader PyPDFLoader(book.pdf) pages loader.load_and_split() # 2. 使用 Map-Reduce from langchain.chains import MapReduceDocumentsChain # 3. 增加 chunk_size splitter RecursiveCharacterTextSplitter( chunk_size2000, chunk_overlap400 )Q6: RAG 响应慢怎么办减少检索数量- search_kwargs{k: 3}使用缓存- 缓存常见问题答案异步处理- 先返回正在检索优化模型- 使用更小的 LLMQ7: 如何评估 RAG 效果评估指标检索准确率- 检索到的文档是否相关回答质量- LLM 回答是否准确响应时间- 端到端延迟用户满意度- 点赞/点踩评估方法# 构建测试集 test_questions [ (问题 1, 期望答案要点 1), (问题 2, 期望答案要点 2), ] # 人工评估或使用 LLM 评估完整项目示例项目结构rag_project/ ├── data/ # 文档数据 │ ├── handbook.pdf │ └── faq.md ├── src/ │ ├── __init__.py │ ├── loader.py # 文档加载 │ ├── embeddings.py # 向量化 │ ├── retriever.py # 检索 │ └── rag.py # RAG 主流程 ├── requirements.txt └── main.py # 入口文件loader.py - 文档加载from langchain_community.document_loaders import ( PyPDFLoader, UnstructuredMarkdownLoader, DirectoryLoader ) def load_documents(data_dir: str): 加载指定目录下的所有文档 documents [] # 加载 PDF pdf_loader DirectoryLoader( data_dir, glob**/*.pdf, loader_clsPyPDFLoader ) documents.extend(pdf_loader.load()) # 加载 Markdown md_loader DirectoryLoader( data_dir, glob**/*.md, loader_clsUnstructuredMarkdownLoader ) documents.extend(md_loader.load()) return documentsembeddings.py - 向量化from langchain_community.embeddings import HuggingFaceEmbeddings def get_embedding_model(model_name: str BAAI/bge-large-zh-v1.5): 获取 Embedding 模型 return HuggingFaceEmbeddings( model_namemodel_name, model_kwargs{device: cpu}, encode_kwargs{normalize_embeddings: True} )retriever.py - 检索器from langchain_community.vectorstores import Chroma from langchain_text_splitters import RecursiveCharacterTextSplitter def create_retriever(documents, embedding_model): 创建检索器 # 文本分块 splitter RecursiveCharacterTextSplitter( chunk_size800, chunk_overlap200, separators[\n\n, \n, 。, ., ] ) chunks splitter.split_documents(documents) # 创建向量库 db Chroma.from_documents( documentschunks, embeddingembedding_model, persist_directory./chroma_db ) # 创建检索器 retriever db.as_retriever( search_typesimilarity, search_kwargs{k: 3} ) return retrieverrag.py - RAG 主流程from langchain.chains import RetrievalQA from langchain_community.llms import Ollama def create_rag_chain(retriever, llm_model: str qwen2.5:7b): 创建 RAG 问答链 # 加载 LLM llm Ollama( modelllm_model, base_urlhttp://localhost:11434, temperature0.7 ) # 创建 RAG 链 qa_chain RetrievalQA.from_chain_type( llmllm, chain_typestuff, retrieverretriever, return_source_documentsTrue ) return qa_chainmain.py - 入口文件from src.loader import load_documents from src.embeddings import get_embedding_model from src.retriever import create_retriever from src.rag import create_rag_chain def main(): # 1. 加载文档 print(正在加载文档...) documents load_documents(./data) print(f加载了 {len(documents)} 份文档) # 2. 初始化 Embedding print(正在初始化 Embedding 模型...) embedding get_embedding_model() # 3. 创建检索器 print(正在创建向量数据库...) retriever create_retriever(documents, embedding) # 4. 创建 RAG 链 print(正在初始化 LLM...) rag_chain create_rag_chain(retriever) # 5. 开始问答 print(\n RAG 助手已就绪输入quit退出\n) while True: query input(你).strip() if query.lower() in [quit, exit, 退出]: break result rag_chain.invoke({query: query}) print(f\n助手{result[result]}\n) # 显示来源 if result.get(source_documents): print(参考文档:) for i, doc in enumerate(result[source_documents], 1): print(f {i}. {doc.page_content[:100]}...) print() if __name__ __main__: main()运行项目# 1. 安装依赖 pip install -r requirements.txt # 2. 启动 Ollama如果使用本地模型 ollama serve # 3. 运行项目 python main.py总结RAG 核心要点RAG 检索 增强 生成核心价值- 减少幻觉、支持私有数据、回答可溯源技术栈- LangChain 向量数据库 LLM关键步骤- 文档加载 → 分块 → 向量化 → 检索 → 生成新手学习路径1. 理解 RAG 原理1 小时 ↓ 2. 跑通极简 Python 示例30 分钟 ↓ 3. 使用 LangChain Chroma OpenAI2 小时 ↓ 4. 切换到本地模型 Ollama1 小时 ↓ 5. 加载真实文档数据2 小时 ↓ 6. 优化检索效果持续最佳实践✅ 从简单开始先跑通再优化✅ 选择合适的 chunk_size500-800✅ 使用混合检索提高准确率✅ 添加元数据便于过滤✅ 评估检索效果再调优下一步学习LangChain 官方文档向量数据库原理Prompt 工程Embedding 模型原理RAG 高级技巧HyDE、FLARE 等