RAG从入门到实践:原理拆解、本地部署与避坑指南
发布时间:2026/10/1 22:52:45 锦皓数字建站

2025年7月15日我花了一整天把RAG从听说过到亲手跑通这篇笔记就是当天学习wow-rag项目时整理出来的完整记录——从RAG到底解决了什么问题到经典链路里每个环节的职责再到本地部署时那些网上教程不会告诉你的参数细节最后还聊了聊RAG知识库、RAG瓶颈这些概念背后真正的含义。无论是刚接触RAG检索增强的小白还是已经跑过demo但总觉得效果不稳定的入门者这篇笔记应该都能给你一些可参考的东西。1. RAG到底是什么先说清它解决的三个问题很多人一上来就背定义RAG是检索增强生成。但光背定义没用你得先搞清楚它到底在解决什么。我当时学wow-rag项目时最大的感触是标题里的名词背后其实是一串非常具体的问题。1.1 大模型的两块短板幻觉和知识过期大模型本质上是背课文长大的它的所有知识都锁死在训练时见过的数据里。这带来两个非常现实的问题。第一是幻觉。模型不知道答案时它不会老实说我不知道而是会基于概率编一个看起来合理的答案。就像一个人考试时遇到不会的题硬着头皮写了个答案字迹工整、逻辑通顺但内容全错。在企业场景里这种幻觉是致命的——比如让模型回答公司报销流程它可能一本正经地告诉你一个根本不存在的审批环节。第二是知识过时。模型训练完成后就处于封存状态2024年训练完的模型不可能知道2025年的新政策。很多公司投入大量成本做微调Fine-tuning但微调有几个难题数据准备周期长、每次知识更新都要重新训练、成本随模型规模剧增。而且你没法保证微调后模型依然稳定很可能学新忘旧。除了这两点还有一个常被忽略的问题——知识割裂。公司内部的知识散落在各种文档、表格、聊天记录里今天修订的SOP可能和新版产品手册相矛盾而模型本身并不知道哪个才是最新版本。RAG知识库要解决的其实正是这种知识割裂把散落的文档拉通成统一可检索的知识库。1.2 RAG的核心思想开卷考试理解RAG最快的方式是把它想成闭卷考试和开卷考试的区别。传统方式纯LLM生成是闭卷考试。模型靠记忆答题记不清就编遇到没学过的直接交白卷。RAG是开卷考试。每次答题前先给你一本指定教材知识库允许你翻书找到相关内容再结合参考材料来作答。具体拆开看RAG的流程分三步先做检索Retrieval把用户的问题拿去知识库里找最相关的段落再做增强Augmented把找到的段落和原始问题组装成一个完整的提示词最后生成Generation把组装好的提示词交给大模型让它基于给定材料回答问题。这个流程看起来简单但它带来一个巨大的优势知识可以随时更新。你不需要重新训练模型只要往知识库里丢新文档模型下一次回答时就能检索到最新内容。这也是为什么RAG框架RAG检索这些词这几年在技术圈和业务圈同时火起来——它把大模型的脑子和企业自己的资料库解耦了。1.3 wow-rag项目一个把整条链路串起来的入门项目我学习用的wow-rag项目本质上就是这条标准流程的最小可用实现。它把文档处理、文本切分、向量化、向量存储、相似度检索、提示词组装、模型生成这七个环节全部串起来跑通之后你就能直观看到一条RAG管道长什么样。这类入门项目的价值在于上手快、链路完整、出了问题好排查。调参时有太多失败方式但你先得有一条能跑通的基准线才知道每一步调参到底在调什么。接下来我按这个思路把整个RAG项目的技术链路逐层拆开。2. 从wow-rag的实际结构看RAG完整链路索引与检索生成这一节是全文的核心。我把wow-rag项目的各个模块分别对应到RAG的标准流程里这样你学完一个项目就能举一反三看懂市面上其他RAG框架。2.1 第一段管道文档加载与切分RAG的第一步是把知识库里的文档PDF、Word、Markdown、HTML等加载进系统。wow-rag里用了一个统一的文档加载器把各种格式统一转成纯文本。这一步看着不起眼实际坑很多比如PDF里表格会乱、扫描件需要OCR、Markdown里的代码块会被切碎。加载之后是切分Chunking。这是决定RAG效果的第一关键环节。文档是不能直接整篇塞进提示词的——一个大模型上下文窗口有限而且就算有足够空间塞进无关内容反而会干扰回答。所以要先把长文档切成多个片段检索时只取最相关的几个片段。切分不是越短越好。片段太长检索到的内容可能只有一小段相关其余全是噪音片段太短又会丢失上下文比如该方案成本1800元和该方案出现在两个相邻片段里单看哪一段都信息不完整。wow-rag默认用的是按固定字符数切分比如512字符 重叠窗口比如80字符。重叠的意义在于让相邻片段之间保留交叉信息避免一句话刚好被拦腰截断。2.2 第二段管道向量化与向量存储切出来的每个片段接下来要被翻译成计算机能比较的格式。RAG里用的标准翻译工具是Embedding模型也叫向量化模型。它把一段文字映射成一组浮点数向量比如768维、1024维核心特性是语义相近的文本向量距离也更近。苹果好吃和苹果营养丰富在向量空间里距离很近哪怕它们没有一个字是重复的而苹果好吃和汽车保养距离就很远。这个语义表达的能力是RAG检索能超越关键词匹配的根本原因。向量化之后这些向量连同原文一起存入向量数据库。常见的向量库有FAISS、Chroma、Milvus、Weaviate等。wow-rag默认用的是Chroma——一个轻量级本地向量库对入门来说最友好不需要部署单独的服务一个文件夹就能存所有数据。向量数据库除了能存向量还实现了高效的相似度搜索。普通的数据库做不了找最相似的向量这种操作向量库底层用了近似最近邻检索ANN能在海量向量里快速找到距离最近的TopK个。这里提醒一句千万不要自己用Python逐条算余弦相似度几百条数据还凑合上万条就慢到怀疑人生向量库存在的意义就是把这个检索做到毫秒级。2.3 第三段管道检索、组装与生成说完索引侧再来看查询侧。用户提一个问题系统要做三件事。第一步是查询向量化把用户问题用同一个Embedding模型转成向量。注意这里必须和索引阶段用同一个模型否则向量空间的坐标系不一致检索结果会完全失真——这是新手最容易踩的坑之一。第二步是相似度检索在向量库中搜索与查询向量最相似的TopK个片段K通常是3~5。wow-rag里还支持简单的元数据过滤比如只检索某个指定目录下的文档。第三步是提示词组装把检索到的片段按一定格式拼接连同原始问题一起构造出一个完整的Prompt。你是知识库助手。请基于以下资料回答问题如果资料中没有相关信息请明确说明根据现有资料无法回答。 参考资料 [1] 文档A第3页《公司报销流程》 员工报销需填写报销单经部门负责人审批后提交财务部审核... [2] 文档B第5节差旅费用标准 国内出差住宿标准为每晚400元超过部分自理... 用户问题公司差旅住宿的报销标准是多少最后把Prompt交给大模型生成答案再返回给用户。到这里一条完整体验的RAG流程就走完了。现在你再看任何RAG框架Spring AI RAG、LangChain4j、LangChain等的文档骨架其实都是一样的——无非是加载器不同、切分策略不同、用的Embedding模型不同、向量库不同、编Prompt的模板不同。wow-rag的价值就是把这个通用骨架具象化了让我从知道概念变成看得见每一个环节的输入和输出。3. 本地部署实操用ollama跑通一个最小RAG知识库概念清楚了接下来是动手。我是在一台没有NVIDIA显卡的普通笔记本上完成的全部实操靠的是CPU推理和本地模型所以下面这套流程对绝大多数零基础读者都是可复制的。整体选型是ollama 本地嵌入模型 Chroma 本地LLM全程不需要联网调用任何付费API。3.1 环境准备与工具选型先说工具选型这是很多教程讲不清楚的地方。整个RAG链路里有三个模型角色Embedding模型负责把文本转向量、LLM对话模型负责最终生成、重排序模型可选负责对检索结果二次打分。我用了以下组合Embedding模型选nomic-embed-text约500MB支持1024维向量中文效果尚可资源占用极小。LLM对话模型选qwen2.5:7b约4.7GB中文能力在线CPU推理速度虽慢但可接受。向量数据库用Chroma无需单独服务直接本地文件存储。文档处理用LangChain社区里现成的加载器配合正则清理做文本清洗。安装ollama之后拉取模型只需两条命令# 拉取Embedding模型和对话模型 ollama pull nomic-embed-text ollama pull qwen2.5:7b这里我踩了一个比较影响体验的坑初版我图省事直接用了qwen2.5:7b自带的嵌入能力结果检索效果惨不忍睹。原因是对话模型虽然能输出向量但输出维度、语义质量和专门的Embedding模型差距很大尤其是对短查询的匹配能力很差。Embedding模型和对话模型必须是分开的两个模型这是新手最容易埋下的隐患。3.2 文档加载与切分参数到底怎么选我准备了一份约20页的Markdown文档内容是某个内部系统的操作手册。用LangChain的Markdown加载器读入后开始切分。切分我先后试了三组参数记录如下切分策略chunk_sizechunk_overlap检索效果目测固定长度200字符40字符答案碎片化严重上下文断裂固定长度512字符80字符基本可用偶尔信息不全按标题/段落语义切分动态无效果最好但依赖文档结构规范第三组方案其实依赖LangChain里的MarkdownHeaderTextSplitter——按文档的#、##、###标题级别自动分段每个标题下的内容成为一个独立片段。对于有清晰章节结构的文档这种方式远胜固定字符数切分因为它天然保留了语义边界。如果你的文档结构不规范那再退回到固定长度并把重叠窗口设在chunk_size的10%~20%之间。一个小技巧切分完之后先打印几个片段看看。如果片段里含有……未完接下一段这种上下文断裂感强或者出现了半个表格、半个代码块就说明参数需要调整。这一步十分钟的检查能省掉后面一小时的排错。3.3 向量化入库你的第一个本地知识库接下来把片段向量化并存入Chroma。代码大致是这个流程from langchain_community.embeddings import OllamaEmbeddings from langchain_community.vectorstores import Chroma embedding OllamaEmbeddings(modelnomic-embed-text) vectorstore Chroma.from_documents( documentssplit_chunks, embeddingembedding, persist_directory./chroma_db )执行这个脚本后本地会生成一个chroma_db目录里面就是你的知识库。这里我犯过一个蠢错每次启动脚本都执行Chroma.from_documents()直接把旧库覆盖掉了结果前一天导入的文档第二天全没了。正确做法是先判断库是否存在存在就加载不存在才重建import os if os.path.exists(./chroma_db): vectorstore Chroma(persist_directory./chroma_db, embedding_functionembedding) else: vectorstore Chroma.from_documents(documentssplit_chunks, embeddingembedding, persist_directory./chroma_db)另外一个很多教程没提的问题同一个知识库里只能用同一个Embedding模型。如果你今天用nomic-embed-text建库明天换了个模型检索结果会全部错乱因为向量空间对不上。要么删库重建要么一开始就固定好模型。3.4 检索与生成联调把RAG管道接起来入库完成后我写了一个简单的查询脚本把之前的三个环节串起来question 如何重置用户密码 retrieved vectorstore.similarity_search_with_score(question, k3) context \n\n.join([doc.page_content for doc, score in retrieved]) prompt f基于以下资料回答问题资料不足就直说不知道 {context} 问题{question} # 调用ollama本地模型生成第一次联调时我发现一个问题检索得分很差的片段居然也被塞进了上下文。后来把k3调成k5答案质量反而下降了因为多出来的两个片段里有一个是不相关的内容模型的注意力被带偏。这说明不是检索得越多越好。对大部分场景TopK取3~4是性价比最高的值如果你的文档质量高且问题明确K甚至可以再小一点。联调跑通后我顺手测了几个不同角度的问题覆盖完全在文档里部分在文档里完全不在文档里三类情况。第三类情况最能检验Prompt写得好不好——如果Prompt没写资料不足就直说模型极有可能开始自由发挥编答案这本质上还是幻觉。所以Prompt里那句如果资料中没有相关信息请明确说明无法回答不是可有可无的装饰是RAG系统的安全底线。4. 实测中的三个坑切分、命中率与上下文污染RAG入门阶段真实遇到的坑往往记录在案的人不多。我自己从下午踩到晚上总结了三个典型问题每一个都能显著影响最终效果。4.1 切分不合理召回率从根上就输了先说我最初用200字符切分时踩的坑。当时我检索快递费用谁负责系统返回的片段里只有一句快递费用由发起人承担但上下文里明明还写着如需加急费用由申请人个人承担——因为这句话被切到了下一个片段里没被检索到。这就是RAG圈子里常说的召回率问题。切分粒度直接决定了召回率的上限。片段切得太碎一条完整信息被拆进两个片段检索时只能召回一半切得太粗有效信息淹没在无关文字里相似度被拉低同样召不回来。我后面改用语义切分按标题这个问题就大幅缓解了。建议你拿到一份新文档时先人工扫一遍结构如果章节标题清晰就优先用语义切分没有结构的文本至少把chunk_overlap设置在80~120字符。另外如果你的检索经常漏内容可以在入库时额外保存每个片段对应的源文档名和章节号这样召回后即便内容不完整也能根据元数据定位到原文去复核。4.2 RAG命中率Hit Rate低先从这三个点排查命中率低是RAG最头疼的现象之一。你问它一个问题它答非所问或直接说不知道。我在排查时用的顺序基本是固定的先查检索是否命中打印出TopK的片段人工看看有没有相关内容。如果TopK片段里压根没有相关内容说明问题出在Embedding模型或切分方式上属于索引侧缺陷。这一步可以临时用关键词匹配做对比测试确认到底是语义检索没生效还是知识库根本没收录。再查检索到了但生成效果差说明问题出在Prompt组装或模型能力上。此时把Prompt打印出来直接喂给模型如果同样答错就可以断定生成侧的问题。这里最常见的是上下文放得太多有效信息占比太低片段之间风格冲突导致模型困惑。最后查知识库本身。确认文档真的入库了、没有被覆盖或漏发。我前面提过的from_documents覆盖旧库的坑就属于这一类——知识库本身就已经是空的了检索自然零命中。另外可以聊一下 Hit Rate 这个指标的含义它统计的是有多少次提问能在检索结果里找到正确答案。参考基准是一个有合理切分和Embedding的RAG系统Hit Rate通常在70%~90%。如果你的命中率远低于这个数老老实实按上面的顺序排查而不是去调K值碰运气。4.3 上下文污染检索到的不该全塞进Prompt跑通之后我做了个粗鲁的实验把TopK从3改成10把检索到的所有片段一股脑塞给模型。结果答案质量直线下降甚至出现了编造文档里根本没有的细节的情况。这里涉及RAG里的上下文污染概念。大模型面对大量文本时注意力是有限的。当你塞入10个片段其中只有2个相关另外8个就是噪音噪音会在生成时干扰模型的判断让它错误地借用了无关信息。更隐蔽的是片段间矛盾。如果切分粒度不合理检索到的片段可能来自同一流程的不同版本一个片段说先审批后报销另一个片段说先报销后审批模型夹在中间无所适从。应对手段就是在User Query里明确如果资料之间矛盾以标注了最新日期或最高版本号的内容为准。这个设计极其有效本质上是把文档的时效性判断交给了模型。所以上下文组装的原则是少而精而不是多而全。宁可只给3个相关片段也不要给10个混着噪音的片段。这也是为什么现在有专门的上下文压缩重排序Reranker技术——先用向量检索粗筛再用重排序模型精排把最相关的片段筛出来再进Prompt。本地部署如果性能允许强烈推荐加一个rerank环节效果提升立竿见影。5. RAG进阶方向从朴素RAG到图谱RAG与Agentic RAG跑通wow-rag只是起点。我翻热搜时看到RAG瓶颈ontologk RAGGraphRAGAgentic RAG这些词当时觉得是噱头但深入了解后发现它们其实是同一个问题的不同解法。5.1 朴素RAG的瓶颈到底在哪教科书式的朴素RAGNaive RAG核心问题有三个。一是跨文档推理能力弱。我问比较A方案和B方案的优缺点朴素RAG检索到的片段可能只覆盖A方案因为B方案的描述换了措辞和罐装名词向量检索没能把它们关联起来。这种知识割裂问题在跨文档场景尤其严重。二是多跳问题处理能力差。所谓多跳Multi-hop就是要回答这个问题需要先找到X再通过X找到Y。比如负责A项目的那个人他之前参与过的项目里哪个是盈利最多的朴素RAG检索是单轮的没法做到这种推理式查找。三是不确定性管理和全局理解弱。朴素RAG擅长定位一段信息却很难回答整个文档库的主题和骨架是什么这类全局性问题。这三个瓶颈正好催生了两个重要的RAG演进方向。5.2 图谱RAG与本体RAG从向量距离走向关系GraphRAG的思想是不只把文档切成碎片存向量而是从文档里抽取出实体公司、人物、产品和关系A负责B、B属于C构建出知识图谱。查询时先在图谱上定位相关实体再顺着关系找到关联信息之后再用来引导检索。这么做的好处很直观解决跨文档和多跳问题。因为图谱把A方案和B方案连到了同一个概念的上下位关系里哪怕它们出现在完全不同的文档段落中图谱检索也能把它们捞回来。Ontology RAG比GraphRAG更进一步它在图谱之上构建了一层本体——相当于定义了领域里的概念体系、类别层次和属性关系。比如医疗领域的本体里感冒是呼吸道疾病的子类发热是症状属性。有了本体模型对知识的理解就不再是纯字符串或纯向量而是有语义骨架的概念网络。这听着学术化但实际效果是它能更好地区分含义相同但说法不同的表达减少检索偏差。5.3 Agentic RAG让检索变成自主决策如果说GraphRAG是改进了索引与检索的底层结构Agentic RAG则是改写了利用检索结果的方式。朴素RAG是固定流程用户问→检索→拼接→生成一步到位中间没有判断。Agentic RAG里则有一个决策者Agent它会根据问题自主规划行动——先检索一波看结果够不够回答不够再换个关键词或换个数据源检索多个数据源都要查时还会并行检索再汇总。整个过程像是一个懂得检索技巧的人在工作而不是一个只会翻同一本书的机械流程。中文技术社区里也有人讨论 RAG as a Service 的趋势也就是把RAG能力封装成标准的服务接口让上层业务直接调用不再每家自己搭管道。这个方向背后其实暗示着一个行业判断RAG会像数据库一样成为一种基础设施能力。我的看法是作为学习者先别急着追这些新名词把朴素RAG每一个环节的为什么吃透再往图谱RAG和Agentic RAG方向顺路延伸会比较稳。回到wow-rag这个项目本身它最大的贡献不是功能有多强而是把RAG是什么从概念变成了一条可以亲手跑通、逐步调优的管道。我最后想分享的一个建议是跑通之后一定要自己动手改一个地方比如把固定长度切分改成语义切分把TopK从3改成5把Embedding模型换一个然后记录前后差别。只要动手改过一次参数你对RAG的理解就会比读十篇论文都深刻。
锦
锦皓数字建站
深耕本土企业品牌数字化升级,专注原创端正雅致商务官网,从视觉设计到稳定运维全程保驾护航。