RAG 核心原理与新手入门实战
RAG 核心原理与新手入门实战这篇文章面向零基础读者不讲复杂的数学公式也不堆砌概念。全程跟着动手从搭环境到跑通第一个能回答问题的 RAG 程序每一步都有具体操作。一、RAG 是什么用图书馆类比理解检索增强生成你直接问一个大模型“我们公司的报销流程是什么”它大概率会给你一个通用答案——因为它根本不知道你们公司内部是怎么规定的。这就是大模型的两个老毛病一是知识有截止日期二是它不知道你的私有数据。RAG 解决这个问题的思路特别像你去图书馆查资料。假设你要写一篇关于“宋朝经济”的论文直接问大模型 凭记忆硬写记不清的地方就编RAG 的做法 先跑到图书馆知识库翻相关书籍检索找到具体段落相关文档然后基于这些材料写论文生成回答RAG 的全称是 Retrieval-Augmented Generation中文叫“检索增强生成”。说白了就是先查资料再回答问题让模型的回答有据可依。整个流程就三步检索用户提问 → 去知识库里找相关的文档片段增强把找到的片段和原始问题拼在一起生成喂给大模型让它基于这些材料给出答案这样做的好处很明显——回答准确了幻觉少了而且你的私有数据全程不用交给模型厂商。二、核心原理解析检索、增强与生成的协作流程把上面那三步拆开来看每一步背后都有具体的技术动作第一步知识库构建离线阶段先把你的文档PDF、Word、Markdown 都行切分成小块然后用 Embedding 模型把每一块文字转成一串数字——这叫“向量”。语义相近的文本向量在空间里也靠得近。最后把这些向量存进向量数据库相当于给每篇文章编了个“索书号”。第二步检索在线阶段用户提问时同样把问题转成向量然后去向量数据库里找最相似的几个文档块。找多少条可以自己定一般取 Top 3 到 Top 8。第三步生成在线阶段把检索到的文档块和用户问题一起拼成 Prompt发给大模型。模型基于这些材料生成答案而不是凭空发挥。把 RAG 想象成“搜索引擎 大模型”的组合——搜索引擎负责找资料大模型负责把资料整理成通顺的回答。三、环境快速搭建零基础安装必要依赖库硬件方面入门阶段 16GB 内存 4 核 CPU 就够用了。如果要用本地大模型建议 32GB 内存 带 NVIDIA 显卡的机器。第一步创建 Python 虚拟环境python-mvenv rag-envsourcerag-env/bin/activate# Windows 用 rag-env\Scripts\activate第二步准备依赖文件在项目根目录新建requirements.txt写入以下内容langchain0.3.26 langchain-huggingface0.3.1 langchain-text-splitters0.3.8 langchain-community0.3.27 faiss-cpu1.7.0 sentence-transformers3.0.0 openai1.86.0 unstructured0.18.11第三步一键安装pipinstall-rrequirements.txt新手避坑faiss-cpu是 CPU 版本的向量检索库入门完全够用。如果后续数据量大了再换 GPU 版本faiss-gpu。另外unstructured用来解析 PDF 和 Word 文档安装时可能会卡住多等一会儿就行。四、数据准备与处理文档加载及文本切片方法文档加载LangChain 的DirectoryLoader可以自动识别文件夹里各种格式的文档。fromlangchain_community.document_loadersimportDirectoryLoader# 把你要喂给 RAG 的文档都放进这个文件夹DATA_PATH./knowledge_base/loaderDirectoryLoader(DATA_PATH,silent_errorsTrue)raw_documentsloader.load()print(f成功加载了{len(raw_documents)}份文档)文本切片Chunking一整篇长文档直接喂给模型效果会很差。需要切成大小适中、语义完整的小块。fromlangchain.text_splitterimportRecursiveCharacterTextSplitter text_splitterRecursiveCharacterTextSplitter(chunk_size500,# 每块 500 个字符chunk_overlap50,# 相邻块重叠 50 个字符separators[\n\n,\n,。,,,,, ,])documentstext_splitter.split_documents(raw_documents)print(f切分后共{len(documents)}个文本块)为什么要重叠假如一段关键信息正好被切在两块的边界上重叠机制能保证信息不丢失。切分参数怎么调初始建议chunk_size设在 300800 个中文字符之间chunk_overlap设为 10%15%。先跑起来效果不好再调。五、向量数据库构建将文本转化为可检索的向量文本切好了接下来要把每一块文字转成向量存进向量数据库。选哪个向量数据库入门阶段推荐 FAISS——本地部署、零依赖、上手快。Chroma 也不错API 更友好。生产环境再考虑 Pinecone 这类托管服务。用 Sentence-Transformers 做嵌入免费、本地运行fromlangchain_huggingfaceimportHuggingFaceEmbeddingsfromlangchain_community.vectorstoresimportFAISS# 用轻量级中文嵌入模型embeddingsHuggingFaceEmbeddings(model_namesentence-transformers/paraphrase-multilingual-MiniLM-L12-v2)# 把文档块转成向量并存入 FAISSvectorstoreFAISS.from_documents(documents,embeddings)# 保存到本地下次直接用vectorstore.save_local(faiss_index)如果你想用 OpenAI 的嵌入模型效果更好但要花钱fromlangchain_openaiimportOpenAIEmbeddingsimportos os.environ[OPENAI_API_KEY]你的API密钥embeddingsOpenAIEmbeddings(modeltext-embedding-3-small)vectorstoreFAISS.from_documents(documents,embeddings)新手避坑嵌入模型的选择非常关键——建库时用的什么模型查询时也必须用同一个否则向量维度对不上检索会完全失效。六、检索器配置实战实现基于语义的精准查询向量数据库建好了现在来配置检索器——也就是“怎么去数据库里找最相关的资料”。# 创建检索器每次返回 Top 3 最相关的文档块retrievervectorstore.as_retriever(search_kwargs{k:3})# 测试一下检索效果query公司报销流程是什么docsretriever.invoke(query)fori,docinenumerate(docs):print(f第{i1}个相关片段)print(doc.page_content[:200]...\n)运行这段代码你就能看到数据库里哪些文档块和“公司报销流程”最相关。检索方式进阶单纯向量检索有时候不够精准可以试试“混合检索”——向量检索 关键词检索BM25组合使用。入门阶段先用向量检索就够了。七、完整链路调用串联检索与大模型生成回答检索没问题了最后一步——把检索到的资料和用户问题一起喂给大模型生成最终答案。方案一用 OpenAI API最简单fromlangchain_openaiimportChatOpenAIfromlangchain.chainsimportRetrievalQAimportos os.environ[OPENAI_API_KEY]你的API密钥# 初始化大模型llmChatOpenAI(modelgpt-3.5-turbo,temperature0)# 构建 RAG 问答链qa_chainRetrievalQA.from_chain_type(llmllm,chain_typestuff,# stuff 模式把所有检索结果一次性塞进 Promptretrieverretriever,return_source_documentsTrue# 返回引用的原始文档方便溯源)# 提问query我们公司的报销流程是什么resultqa_chain.invoke({query:query})print(回答,result[result])print(\n参考来源)fordocinresult[source_documents]:print(-,doc.page_content[:100]...)方案二用本地大模型免费但要自己部署用 Ollama 跑本地模型# 先安装 Ollama然后下载模型ollama pull qwen2:7bfromlangchain_community.llmsimportOllama llmOllama(modelqwen2:7b,temperature0)# 后面的代码和方案一完全一样qa_chainRetrievalQA.from_chain_type(llmllm,retrieverretriever,chain_typestuff)chain_type 选哪个stuff最简单把所有检索结果一股脑塞进 Prompt适合文档量不大的场景。文档多了可以用map_reduce或refine但入门阶段用stuff就够了。八、效果验证示例运行第一个 RAG 问答程序把前面所有代码串起来就是一个完整的 RAG 程序。这里给一个精简版你可以直接复制运行# 1. 加载文档fromlangchain_community.document_loadersimportDirectoryLoaderfromlangchain.text_splitterimportRecursiveCharacterTextSplitterfromlangchain_huggingfaceimportHuggingFaceEmbeddingsfromlangchain_community.vectorstoresimportFAISSfromlangchain_openaiimportChatOpenAIfromlangchain.chainsimportRetrievalQAimportos# 2. 加载并切分文档loaderDirectoryLoader(./knowledge_base/,silent_errorsTrue)raw_docsloader.load()text_splitterRecursiveCharacterTextSplitter(chunk_size500,chunk_overlap50)docstext_splitter.split_documents(raw_docs)# 3. 建向量库embeddingsHuggingFaceEmbeddings(model_namesentence-transformers/paraphrase-multilingual-MiniLM-L12-v2)vectorstoreFAISS.from_documents(docs,embeddings)retrievervectorstore.as_retriever(search_kwargs{k:3})# 4. 配置大模型用 OpenAI 或换成 Ollamaos.environ[OPENAI_API_KEY]你的密钥llmChatOpenAI(modelgpt-3.5-turbo,temperature0)# 5. 创建问答链qa_chainRetrievalQA.from_chain_type(llmllm,retrieverretriever,chain_typestuff)# 6. 开始提问whileTrue:questioninput(\n请输入问题输入 q 退出)ifquestion.lower()q:breakanswerqa_chain.invoke({query:question})print(\n回答,answer[result])把你要问的文档放进./knowledge_base/文件夹运行这个脚本就能跟你的“专属知识库”对话了。九、常见报错排查解决嵌入维度不匹配等难题报错1向量维度不匹配... does not match the dimension of the index 1536建库时用的嵌入模型和查询时用的不是同一个。比如建库用了text-embedding-3-small1536 维查询时换成了别的模型维度不同就会报这个错。解决方法确保建库和查询用完全相同的嵌入模型。最好把嵌入模型固定成一个变量全文复用。报错2ModuleNotFoundError: No module named unstructuredunstructured是解析 PDF、Word 等格式的依赖库。解决方法pip install unstructured[pdf]或pip install unstructured[docx]按需安装对应格式的支持。报错3API 调用超时或连不上调用 OpenAI API 时网络不通或者免费额度用完了。解决方法先用本地模型Ollama Qwen做测试等调通了再切 API。报错4检索结果全是无关内容通常是chunk_size太大或太小导致的——太大则每块信息太杂太小则语义不完整。解决方法从 500 字符开始试根据效果逐步调整。另外检查一下文档内容本身是否跟问题相关。十、进阶优化技巧提升检索准确率与回答质量程序跑通了但效果可能还不够好。下面几个优化方向按优先级从高到低排列1. 调 chunk_size 和 chunk_overlap这是成本最低、见效最快的优化。从chunk_size500, chunk_overlap50开始试观察检索结果质量再逐步调整。2. 增加检索数量Top K默认取 3 条可以试试取 5 条或 8 条。多了会引入噪声少了可能漏掉关键信息。一般建议 38 之间调试。3. 引入重排序Rerank向量检索召回一批文档后用更精细的模型重新排序把最相关的排到前面。这个效果很明显但实现稍复杂入门阶段先跳过。4. 查询改写用户问的可能是口语化、不精确的问题。可以用大模型先把问题改写成更规范的检索语句再去向量库搜索。5. 混合检索向量检索 关键词检索BM25双路召回然后用 Rerank 合并排序。对专有名词产品型号、人名特别有效。6. 元数据过滤给文档块打标签日期、类别、作者等检索时先按元数据过滤缩小搜索范围。比如只搜“2025年的财务报告”而不是搜全部文档。WEB项目地址演示地址安卓APP下载地址演示地址写在最后从理解 RAG 是什么到跑通第一个能回答问题的程序你已经走完了完整的入门路径。记住几个关键点嵌入模型要前后一致、chunk_size 从 500 开始调、先用本地模型跑通再换 API。别追求一步到位——先让程序跑起来再逐步优化检索和生成的质量。把你想问的文档扔进knowledge_base文件夹跑一遍代码试试它能不能回答你的问题吧。