
大模型圈子这两年最热的话题除了参数和评测榜就是 RAG 了。RAG 全称 Retrieval-Augmented Generation中文一般叫检索增强生成。我见过不少刚入行的朋友把它当成某种新模型架构也有人觉得 RAG 就是外挂一个向量数据库这些理解都不够准确。它本质上是给大模型配了一套随取随用的资料库和检索系统让模型在回答问题时先查资料、再动笔。这篇就把 RAG 和大模型之间到底是什么关系、系统怎么搭、瓶颈在哪一次讲清楚适合正在做知识库问答、文档助手、企业私有化部署的工程师和产品同学参考。1. 大模型的天生短板RAG 到底在给模型补什么要理解 RAG 的价值先得承认一个事实大模型再强它也不是一个数据库更不是一个活的知识系统。很多人第一次用 ChatGPT 或开源模型时都会有一个错觉——它什么都知道。实际上这个知道有严格边界而且这些边界恰好是 RAG 要补的短板。1.1 知识截止日期模型知道的是过去时大模型的训练过程是把互联网上海量文本压缩进权重里。这个过程成本极高一次预训练动辄数百万美元所以没有任何团队会天天重新训练模型。结果是模型的知识停留在训练数据截止的那个时间点。今天发布的新闻、这个月的新政策、你公司内部刚更新的产品手册模型一概不知。如果你直接问大模型我们公司最新的报销流程是什么它要么一本正经地给出一个过时的流程要么直接说不知道。这不是模型笨而是它脑子里压根没有这个信息。RAG 的解决办法很直接把最新文档存进检索系统回答前先查出来把相关内容塞进上下文。1.2 幻觉问题模型会自信地胡说幻觉Hallucination是所有大模型使用者的噩梦。模型本质上是一个概率系统它在生成每个 token 时按概率挑一个看起来合理的延续。当它遇到一个不确定的问题尤其是不在其训练范围内的细节性问题时它不会像人一样承认我不懂而是倾向于编造一个语法流畅、逻辑通顺但内容错误的答案。这也是为什么很多企业把大模型直接接到客服或内部问答系统后会翻车。RAG 不能从根上消灭幻觉但它能把模型的答题范围限制在你提供的资料里。检索到的原文就摆在上下文里模型再胡编的概率大幅下降。说白了RAG 是给模型开卷考试而不是让它闭卷猜。1.3 私有数据不可访问大模型根本不认识你的业务预训练模型只见过公开数据。企业内部的知识库、技术文档、客服工单、研发日志、行业研究报告这些数据天然不在模型的知识范围里。而且这里还有一个现实问题你不可能把核心业务数据发给一个在线 API 去训练这涉及数据安全、合规和成本。RAG 的价值就在这里体现出来了它不需要改变模型的任何参数而是把私有数据放在用户自己的存储系统中本地向量库、文件服务器均可调用模型时只把检索出来的相关内容片段传入上下文。数据不进模型模型只负责读和写。这对企业私有化部署来说是最稳妥的落地路径。1.4 关系的本质模型是大脑RAG 是外接记忆系统把上面几点合起来RAG 和大模型的关系应该这样理解大模型是那个负责阅读理解、推理和生成文字的大脑RAG 是一套外接记忆检索系统。大脑不需要重新学一遍你的资料每次要回答问题的时候记忆系统帮你把相关资料调到眼前大脑基于这些资料组织答案。打个比方大模型就像一个博学但健忘的顾问RAG 就是坐在他旁边的资料员。顾问本身没变但每次咨询前资料员都会把相关的合同、报表、历史记录翻出来递给他。顾问读一眼资料再回答准确率自然比凭记忆瞎说高得多。这就是检索增强四个字的真正含义。2. RAG 系统四大环节拆解从文档到答案的完整链路RAG 的系统架构说复杂也复杂说简单也简单。标准流程可以分成四大环节索引Indexing、检索Retrieval、增强Augmentation、生成Generation。任何一个环节做得粗糙最终回答质量都会大打折扣。我从工程实践角度逐个拆开讲。2.1 索引阶段数据准备才是真正的重头戏很多人以为 RAG 的核心是 Prompt 或模型调用我做了几个项目之后的结论是数据准备决定上限模型只负责在下限之上发挥。索引阶段做了三件事文档解析、分块Chunking、向量化入库。文档解析是把 PDF、Word、Markdown、HTML 等格式的原始文档转成纯文本。这一步的坑非常隐蔽PDF 里的表格解析出来经常是乱的扫描件需要 OCRWord 里的图片无法直接读文字。我见过一个知识库项目因为 PDF 表格没处理好用户问上季度各产品线的销售额对比系统检索出来的是一堆页眉页脚答案自然惨不忍睹。分块是决定检索质量最关键的一步。分块太大混入太多无关信息向量检索的精确度下降分块太小语义不完整模型拿到的上下文零碎。我常用的经验值一般技术文档用 300-500 个 token 的块大小配合 20%-30% 的重叠率。但这个值不是死的要根据文档结构来定。如果文档本身有清晰的小节标题优先按标题切块如果是一段连续的论述文字再按固定长度切。向量化入库就是把每个文本块通过 Embedding 模型转成高维向量存进向量数据库。这里有个容易忽略的点Embedding 模型的选择会直接影响检索效果。中英文混合场景我建议用支持多语言的 Embedding 模型比如 BGE 系列或 OpenAI 的 text-embedding-3 在小规模场景也可以用不要拿着只针对英文训练的模型硬跑中文文档。2.2 检索阶段向量相似度之外还有更多讲究检索阶段的目标是根据用户问题从向量库里找出最相关的几个文本块。最常见的方式是向量相似度检索——把用户的问题也用同一个 Embedding 模型转成向量然后算它和库里面所有向量的余弦相似度取最接近的 Top-K 个。但纯向量检索有已知盲区。关键词匹配的精确性不足比如用户问增值税发票怎么开具如果库里的文档恰好只写开票流程而没有增值税这个词向量检索有可能找偏。所以在工程实践中我更推荐混合检索BM25 稀疏检索基于关键词 向量稠密检索基于语义双路并行取交集或加权融合。这样既能抓到精确关键词又能通过语义找回同义表达。检索完之后还有一个容易被省略但效果提升很明显的环节重排Rerank。向量检索的 Top-K 只是粗筛相关性排序并不精确。用专门的 Rerank 模型对候选片段重新打分把最相关的排到前面最终进入上下文的片段质量会明显提升。我实测过加一个 Rerank 环节答案相关性主观评分平均能提高一到两分满分五分的口径。2.3 增强与生成阶段Prompt 组装里的门道检索出来的文本块不会自己变成答案需要把它和大模型连接起来。这个连接就是 Prompt 组装。一个经典的 RAG Prompt 结构大致是你是一个企业知识库助手。请严格基于以下资料回答用户问题。 如果资料中没有相关信息请明确回答资料库中未找到相关内容不要编造。 【资料片段】 这里放入检索到的 Top-K 文本块 【用户问题】 用户的问题这里的关键词是严格基于和不要编造。一定要在 Prompt 里显式约束模型否则模型还是会依赖自己的预训练知识乱发挥。我见过一个生产事故工程师搭好了 RAG 链路检索回来的资料是 A 产品的手册模型回答时却基于自己的知识把 B 产品的参数也写了进去用户对比时发现了错误。问题根源就是 Prompt 里没写清楚只许引用资料、不许补充外部知识。另外上下文窗口的管理在生成阶段同样重要。一个文本块 500 tokenTop-K 取 5 个就是 2500 token再算上系统提示词和问题如果模型上下文窗口是 8K勉强够用。但一旦要跨多个文档综合回答或需要多轮对话历史上下文很容易撑爆。所以现在很多 RAG 系统会做上下文压缩先让一个小模型把检索结果压缩成精华摘要再把摘要送入大模型。3. RAG 与大模型微调不是二选一是分工协作每次讲 RAG几乎必被问到同一个问题那微调呢我是不是应该微调模型而不是搞 RAG我的回答一贯是先想清楚你要解决的问题是什么再选择工具。RAG 和微调根本不是替代关系它们解决的是不同层面的需求。3.1 一张表看清 RAG 和微调的差异我做了个对比表方便你按场景快速判断对比维度RAG微调Fine-tuning知识更新成本低换文档重新入库即可高每次更新都要重新训练对私有数据的依赖高检索质量取决于数据中训练数据决定学习效果幻觉控制能力较强答案被检索内容约束一般模型仍可能自由发挥推理成本略高多一次检索调用无额外检索成本技能与风格塑造弱主要面向事实问答强可学习特定格式、语气、复杂任务流程数据需求最少只需几十份文档至少几百条高质量样本通常要几千条部署复杂度需要向量库、检索服务训练产物仍是单个模型部署简单从这个表可以看出一道清晰的分界线RAG 适合模型需要知道特定事实的场景比如企业制度问答、产品手册客服、法规政策咨询微调适合模型需要学会某种行为方式的场景比如让模型按固定 JSON 格式输出、模仿客服话术风格、学会执行多步骤工具调用。3.2 最常见的误区一上来就要微调我在社区里看到太多中小团队踩同一个坑知识问答效果不好第一反应是去微调模型。微调一个 7B 甚至 13B 的模型光是数据清洗和标注就要花一到两周训练一张 A100 动辄几十个小时电费训完发现新的知识没记住多少原来会的东西反而退化了——这种现象叫灾难性遗忘。而同一批文档搭一个 RAG 链路快的话一天就能上线效果大概率够用。什么时候才轮到微调我的实践标准是RAG 已上线且效果稳定用户开始提出回答风格太死板希望它更像我们的专家客服这类诉求时再考虑用微调去调说话的姿态。3.3 实际项目里最常用的组合打法大厂和成熟团队的主流做法不是 RAG 排斥微调而是两者叠加。我在一个企业客服项目里的方案是这样基础模型选用一个通用能力较强的开源模型如 Qwen 系列或 LLama 系列的中文变体。微调层用几百条该企业客服的对话样本做轻量微调LoRA 方式让模型学会企业要求的应答语气、称呼习惯和简短的回复风格。RAG 层把产品手册、售后政策、物流规则存入向量库每次客服问答实时检索最新政策放入上下文。这样分层之后微调负责怎么说话RAG 负责说什么事实两者互不干扰、各司其职。这种组合的维护成本也最低——政策变更时换个文档就行不需要重新训练模型。4. 从零搭一套本地 RAG零基础也能复制的实操记录理论讲再多不如手上过一遍。这里我完整还原一次本地 RAG 知识库的搭建过程基于 Ollama 加 Python 脚本完全离线可跑适合个人电脑验证和中小企业私有化部署前的小规模测试。这个流程我在知乎和公众号都分享过很多零基础的朋友照着做也都跑通了。4.1 环境准备先把组件装齐需要准备的东西主要有四样本地大模型运行时Ollama。它可以把开源模型封装成类似 OpenAI 的 API 接口省去手动配置推理服务的痛苦。一个 Embedding 模型用于给文档和问题做向量化。Ollama 生态里自带nomic-embed-text等选项中文场景也可以用bge-m3这类模型。向量数据库小规模测试用 Chroma 或 FAISS 就够了它们是嵌入式库不需要单独起服务生产环境再换成 Milvus 或 Qdrant。Python 环境用于编排整个流程。中间件框架用 LangChain 或 LlamaIndex 都行但我个人觉得刚上手时先不用框架用几十行原生 Python 理解透流程再引入框架不迟。安装命令很简单# 安装 Ollama curl -fsSL https://ollama.com/install.sh | sh # 拉取本地模型7B 参数级别16G 内存的机器可跑 ollama pull qwen2.5:7b # 拉取 Embedding 模型 ollama pull nomic-embed-text # Python 依赖 pip install chromadb sentence-transformers langchain跑这些之前建议确认机器配置纯 CPU 跑 7B 模型也能出结果但速度感人大概每秒几个 token有 NVIDIA 显卡8G 以上显存体验会好很多。没有显卡的朋友也不用灰心用小一点的模型比如qwen2.5:3bCPU 也能凑合完成演示。4.2 文档处理与入库核心代码逐行解释准备三到五篇你手头的技术文档或规章制度存成 txt 或 markdown 格式放在docs/目录下。然后跑下面的脚本完成分块和入库import os from langchain_community.document_loaders import DirectoryLoader, TextLoader from langchain.text_splitter import RecursiveCharacterTextSplitter from langchain_community.embeddings import OllamaEmbeddings from langchain_community.vectorstores import Chroma # 1. 加载文档目录下的所有文本文件 loader DirectoryLoader(./docs, glob**/*.md, loader_clsTextLoader) documents loader.load() # 2. 分块每块 400 个字符重叠 80 个字符 splitter RecursiveCharacterTextSplitter( chunk_size400, chunk_overlap80, separators[\n\n, \n, 。, , , , ] ) chunks splitter.split_documents(documents) print(f共切分了 {len(chunks)} 个文本块) # 3. 向量化并写入 Chroma 本地库 embeddings OllamaEmbeddings(modelnomic-embed-text) vectorstore Chroma.from_documents( documentschunks, embeddingembeddings, persist_directory./chroma_db ) print(向量库写入完成)这里要解释两个重点。第一分块时我自定义了分隔符序列[\n\n, \n, 。, , , , ]目的是让切分器优先按段落、换行、句号这些自然边界来切而不是硬生生把一句话从中间劈开。第二chunk_overlap80是为了避免一个完整知识点恰好被切分边界切断——比如一句话的前半段在上一块、后半段在下一块检索时只命中其中一块就会导致信息残缺。重叠 80 个字符是低成本的保险方案。4.3 检索与问答链路把检索结果送进大模型向量库建好后就到了问答环节。完整的问答调用代码如下from langchain_community.llms import Ollama from langchain.chains import RetrievalQA # 重新加载向量库 vectorstore Chroma(persist_directory./chroma_db, embedding_functionOllamaEmbeddings(modelnomic-embed-text)) # 创建检索器默认返回最相似的 4 个文本块 retriever vectorstore.as_retriever(search_kwargs{k: 4}) # 初始化本地大模型 llm Ollama(modelqwen2.5:7b, temperature0.1) # 使用 LangChain 的标准 RAG 链路 qa_chain RetrievalQA.from_chain_type( llmllm, chain_typestuff, # 把所有检索结果一次性塞入上下文 retrieverretriever, return_source_documentsTrue # 返回引用来源方便追溯 ) # 问一个问题 result qa_chain.invoke(报销单审批流程是什么) print(答案, result[result]) print(\n--- 引用的文档片段 ---) for doc in result[source_documents]: print(doc.page_content[:100])注意两点。第一temperature0.1知识问答场景温度必须调低让模型输出尽量确定、贴近原文。温度调到 0.7 以上模型就会开始创作幻觉率直线上升。第二return_source_documentsTrue非常重要它能让答案附带引用来源。在真实产品里这个来源列表就是用户可验证、可追溯的基础也是排查回答质量问题的抓手。4.4 实测效果与参数调整记录我用三份企业内部制度文档做测试问新员工转正需要满足哪些条件。第一次跑出来模型只回答了其中两条第三条漏了。排查发现是分块把第三部分切到了下一个文本块而 Top-K 检索只回了 4 块漏掉的那块排到了第 6 位。解决方案是把k从 4 调到 6并把chunk_size从 400 降到 300让单个知识点的完整性更好。调整后再测三条都答全了。所以别把参数当一次定死的东西。k值、分块大小、重叠率这些参数必须根据你自己文档的特点反复试。我的调整原则是先看有没有检索到相关内容打开 source_documents 检查再看模型回答是否忠实于内容对照原文看有没有发挥。这两个环节要分开排查不要一上来就怪模型。5. RAG 的瓶颈与避坑实录那些文档里不会写的教训RAG 不是银弹。从 2023 年到现在学术界和工业界对 RAG 的批评和反思越来越多这些批评基本都指向真实落地时的硬伤。这一节我把踩过的坑、见过的事故、排查思路都整理出来。5.1 检索质量瓶颈召回率低是最隐蔽的病根RAG 系统最常见的失败模式不是模型答错而是根本就没检索到对的资料。用户问题换一种说法向量检索就找不到对应文档模型拿不到正确上下文自然给不出正确答案。这种失败非常隐蔽因为回答看起来依然流畅只是内容是错的。排查方法每次回答都把检索命中的片段打印出来人工看一眼。如果发现命中的片段和问题无关问题出在 Embedding 模型或分词方式如果相关的片段排得太靠后没被选中问题出在 Top-K 设置或缺少 Rerank 环节。这里强烈建议在生产环境加一个 Rerank 模块它能把召回率这个慢性病明显缓解。5.2 多轮对话的上下文污染问题RAG 在单轮问答中表现很好一旦进入多轮对话就麻烦。用户在第二轮问那它的价格呢——它指的是第一轮提到的产品。如果系统只把这一轮的问题拿去检索向量库里搜价格两个字根本匹配不到对应内容。行业里常用的方案有两类一是做查询改写把多轮对话的指代消解掉先把用户问题结合历史记录改写成一个独立完整的问句再拿改写结果去检索二是做对话上下文压缩把历史对话中与当前问题相关的部分抽出来拼进检索语句。两类方案都有开源实现LangChain 里的create_history_aware_retriever走的就是第一条路。如果你自己实现的 RAG 又不处理这个场景多轮对话体验会很差。5.3 图片和表格RAG 知识库能不能存图片很多朋友问RAG 知识库能存储图片吗这个问题要拆两层回答。如果你说的是把图片文件本身存进知识库并在回答时返回图片目前主流 RAG 系统都不擅长这件事向量库里存的是文本向量不是图片像素。如果你说的是让 RAG 理解图片里的信息现在有两条可行路径路径一对图片先做 OCR 或调用多模态模型如 Qwen-VL、GPT-4V把图片内容转换成文字描述再把文字描述存入 RAG 向量库。这是目前性价比最高、实现最简单的方案。路径二用多模态 Embedding 模型直接对图片做向量化检索时图片和文本在同一向量空间内匹配。这条路在技术上已经可行但工程复杂度高、资源消耗大中小项目不太划算。表格处理更麻烦。PDF 里的表格被解析成文本后通常是一堆散落的数字和字段名语义完全丢失。我的经验是能转成 Markdown 表格再入库的优先转不能用现成工具的用多模态模型把表格结构描述成文字再入库。纯靠 PDF 解析库硬拿文本表格这一块基本会碎。5.4 文档更新的同步问题知识库是活的文档定期会改。常见的问题是旧文档的向量还在库里新文档也写进去了同一个问题检索时可能同时命中新旧两个版本的内容模型有时答新的、有时答旧的用户投诉答案不稳定。解法不复杂但要在架构里留好接口每个文本块入库时带上文档版本号和时间戳检索时可以按时间或版本过滤。更进一步的做法是做增量入库和删除标记而不是把整个库推倒重建。很多团队第一次做 RAG 都没规划这部分上线三个月后文档一更新就傻眼了。5.5 性能开销RAG 不是零成本增强RAG 每回答一个问题至少要多出三次网络或本地调用Embedding 一次问题向量化、向量库检索一次、还有一次可选的 Rerank。在高并发场景下这一串调用都会成为延迟瓶颈。一个未经优化的 RAG 接口P95 延迟可能到 5 秒以上对于实时客服场景是致命的。优化思路有几个Embedding 结果做缓存相同或相似问题直接复用向量库用 HNSW 这类近似最近邻索引可以有效降低检索耗时把 Rerank 模型量化或用小模型替代。还有一条架构层面的思路对高频问题做静态问答缓存完全不经过 RAG 链路直接命中预设答案。这些优化在我的项目里能把整体延迟砍掉 60% 以上。回头再看 RAG 和大模型的关系我个人的体会是与其说 RAG 是大模型的补丁不如说它是大模型走向工程化的必然条件。模型本身解决的是理解和生成而 RAG 解决的是知识和信任。知识要新、要准、要私有、要可追溯这些需求单靠模型训练解决不现实也不经济。最后分享一个小建议别一上来就追最新的 RAG 框架和模型先把你手头的文档处理好、把检索质量调好RAG 的效果立刻就能上一个台阶。数据质量永远是 RAG 的第一生产力这个判断在我做过的所有项目里都成立。