RAG(Retrieval-Augmented Generation,检索增强生成)这两年是真火。从最初给大模型外挂一个“知识库”,到如今各类Agent、行业大模型落地几乎都绕不开它,我手上接到的咨询里,十个有八个都在问怎么搭一套靠谱的RAG系统。这技术本质上不复杂,但工程落地时到处是坑,很多朋友把模型调通了、向量库也跑起来了,一到线上就发现检索结果稀烂、回答胡言乱语,最后回来骂RAG不行。实际上大多数情况不是RAG不行,而是细节没做到位。
这篇东西我不打算写成一板一眼的教程,更想把它当作一次全景复盘:RAG究竟解决什么问题、和微调怎么取舍、为什么单独用向量检索不够、文本切分怎么影响最终效果、重排和评估体系怎么搭。同时结合我实际用过的工具链和踩过的坑,把一轮能直接参考的决策路径整理出来,方便你下次搭RAG时少走弯路。
这轮梳理适合正在做大模型应用开发、想把私域知识塞进聊天机器人、或者在考核RAG方案选型的朋友,属于那种“你看完能直接动手改自己项目”的长度和深度。
1. 基础概念:先搞懂RAG到底在干嘛
1.1 为什么“模型懂得多”不等于“回答得好”
要理解RAG,得先想清楚一个矛盾:大模型的知识截止时间和你的业务数据发布时间永远不同步。模型训练时见过的东西是固定的,哪怕它把常识、代码、理论都学得不错,你问它最近内部系统的新版操作手册,它大概率一本正经地编个错误答案出来。这是模型的天生短板,不是额外调参能解决的。
RAG的思路说白了很朴素:模型不懂没关系,我不强迫它背下所有东西,我给它一个“开卷考试”的机会。用户提问后,系统先去外部知识源里检索出相关的资料片段,再把这些片段拼进Prompt里扔给大模型生成回答。相当于大模型从“闭卷背诵”变成“带着参考书答题”,答案来源有据可查,胡编概率自然下降。
1.2 RAG和微调怎么选,别一上来就动权重
很多刚入门的朋友一遇到“模型不懂业务”就想着微调,这其实是成本最高、风险也最大的路径。微调是在改模型的权重,它适合解决“行为模式”层面的问题,比如让模型按特定语气回复、学会某种输出格式、或者掌握某种推理偏好。而RAG解决的是“事实记忆缺失”问题,比如让模型知道内部文档里写了什么、最新流程是什么样。
我的习惯做法是,先问自己三个问题:
- 知识更新频率高不高?高频更新直接用RAG,微调一次成本太高。
- 答案是否要求可追溯?需要引用来源就上RAG,微调做不到精确溯源。
- 涉及的数据量是否巨大?几万篇文档不适合微调,RAG的方案更现实。
反过来,如果要求模型输出风格彻底转变、需要它学会特定领域的“行话”和推理套路,那微调是配菜,可以和RAG配合使用。主流的做法始终是“RAG为主、微调锦上添花”,很少有人只靠一种走天下。
2. 完整RAG流程解析:四个环节,每个都藏着细节
2.1 索引阶段:从原始文档到可检索片段
我见过很多入门方案直接把PDF丢进向量库就完事了,结果检索质量惨不忍睹。索引阶段的本质,是把非结构化数据转成结构化可检索的形态,核心操作是“切分+向量化”,但哪些粒度切、怎么切、切完怎么保留语义,都是有讲究的。
切分策略是关键。OpenAI的官方建议是灵活切分而非固定长度切分,因为固定字符数会把一个完整语义段拦腰截断。我在中文文档上吃过亏——按256个字符硬切,经常把一段论述切两半,检索命中率直接掉十几个点。更合理的做法是:
- 按标题、段落、表格等“自然边界”切分,优先保语义完整。
- 切分块大小(chunk size)控制在512~1024个token之间,兼顾检索粒度和上下文窗口利用。
- 相邻块之间加少量重叠(overlap),避免边界处的关键信息丢失。
向量化就是把文本块通过Embedding模型转成语义向量。这里需要做一次选择:用通用Embedding模型还是领域微调过的模型。我实测过,在金融、医疗这类垂直领域,通用模型(比如开源的bge系列或者OpenAI的text-embedding-3-small)效果可能有偏差,如果数据量足够,花些时间用领域语料微调Embedding模型的收益非常大,检索recall往往能提升二三十个点。
2.2 检索阶段:纯向量不够,得混着用
检索阶段有个经常被低估的事实:大量查询是“关键字精确匹配”型,语义检索反而不擅长。比如用户搜“API接口返回401错误”,如果你的知识片段里写的是“未授权访问(401)”,纯向量检索很容易跑偏。
我推荐混合检索(Hybrid Search):把BM25传统关键词检索和向量语义检索的结果融合起来,再用权重把排序做一遍。这种方案在实践中非常稳,尤其是处理专业术语、产品名、编号这类文本时,能补掉向量模型看不懂“车轱辘话”的缺陷。融合权重可以先用50:50起步,再根据评估结果调。
2.3 重排阶段:让最相关的几块内容排在前面
检索阶段返回Top K个候选片段,但Top K并不等于Top K最相关——第一次粗排给出的顺序往往没那么准。这时候需要引入重排模型(Reranker),它会把查询和每个候选片段的关联度做精细打分。典型做法是用交叉编码器(Cross-Encoder),相比Embedding模型的双塔结构,它对相关性的判断更精准,因为查询和文档一起过模型,能充分交互。
重排的选择上,开源界好用的是bge-reranker系列,商业方案有Cohere Rerank。我在真实项目里习惯把粗排的Top 50个片段过一遍Reranker,再取Top 5~10喂给大模型。这一步带来的质量提升,往往比换更好的大模型还明显。
2.4 生成阶段:Prompt写好,答案质量就稳了一半
到了生成阶段,LLM本身成了核心,Prompt的组织方式直接影响最终回答能否“有据可依”。我总结了一套经典Prompt模板思路,大致结构是:
- 系统指令,明确要求模型“只基于提供的资料内容回答,不要编造”。
- 声明资料不足时的行为——必须诚实说不知道,不强行回答。
- 把检索片段按相关性降序排好,贴上来源标签。
- 用户原问题放在最后,保持指令清晰。
还有一个容易被忽视的细节:要限制模型回答中出现与检索片段无关的术语或数据。实测下来,把这四条写清楚之后,幻觉比例能降一半以上。
3. 核心选型:向量数据库和Embedding模型怎么挑
3.1 向量数据库推荐,从轻量到重量
现在市面上向量数据库多到让人眼花,Faiss、Chroma、Milvus、Weaviate、Elasticsearch内置的向量索引、pgvector、Qdrant,每个都有人吹。我的选型原则很简单:数据量小、偏原型验证,用Chroma或FAISS,零运维成本,本地跑通再说。数据上了百万级、需要集群和权限管理,直接上Milvus或Qdrant。如果团队已经有Elasticsearch体系,那也别单独引一套向量库,直接用ES的KNN能力就行,省掉一份运维账单。
另外得提醒一句:别神话向量数据库,它本质上就是个带索引结构的存储引擎。选型时重点看三样:索引算法(HNSW还是IVF)、规模化后的性能衰减曲线、周边配套的监控和权限管理。这三样定下来,兜底能力就够了。
3.2 Embedding模型选择:通用、领域与多模态
Embedding模型的选型比向量库更影响检索效果。通用场景直接上OpenAI的text-embedding-3-small或者开源的BGE-large-zh-v1.5,效果都不错。领域场景,尤其是中文专业术语密集的场景,我建议优先试试各家中文榜单的头部模型,像BGE、M3E、文心Embedding这类,但也别只看榜单分数——我遇到过榜单排名靠前但实际检索效果拉胯的模型,因为评测集和你业务数据分布差太多。
多模态场景就得用专门的Multi-Modal Embedding模型,比如CLIP或Chinese CLIP,它能把图片、文本映射到统一向量空间。如果你要做“文档里的图/表也能被检索到”的需求,这块就别偷懒用纯文本 Embedding,要么上多模态Embedding,要么先把图转述成文本。
3.3 文档解析与预处理:向量化之前的隐藏工程
这块是新手最容易忽略的坑。我接手过一个合同审核项目,PDF里全是扫描件,没做OCR就直接切块向量化,结果检索出来的一堆乱码,回答质量当然全面崩盘。正确的预处理链路至少要包括:
- PDF、Word、扫描件统一转成纯文本,扫描件必须加一步OCR。
- 表格结构尽量转成Markdown表格,方便模型理解行列关系。
- 去掉页眉页脚、页码、水印等无关噪音。
- 如果有多栏排版,先做版面分析,再按阅读顺序抽取文本。
预处理做得好,后端的检索效果能提升一大截。很多团队在这里省时间,结果后面调试模型调试到怀疑人生,其实问题根本不在于模型。
4. 完整实操:从文档上传到问答上线
4.1 环境准备与基础依赖安装
这里给出的是开箱即用的技术栈组合:Python + LangChain或LlamaIndex做编排框架 + Chroma做向量存储 + bge-m3做Embedding + bge-reranker做重排 + 任意大模型API做生成。这套组合的好处是:能跑通全流程,且每个组件都能被替换,适合先跑通再做性能优化。
安装依赖时有一点要留意:chromadb 和 langchain 的版本经常互相较劲,最好用一个干净的虚拟环境分别安装,装完先跑个最小用例验证 import 正常再继续。
4.2 数据准备与切分示例
假设你有一批Markdown格式的内部运维文档,我建议直接读取Markdown并按二级标题进行切分,这样既能保留标题层级,又能控制每个chunk的大小适中。如果文档没有清晰结构,那就老老实实用LangChain的RecursiveCharacterTextSplitter,优先按“\n\n”作为分隔符,其次按“\n”和空格,设好chunk_size=600,chunk_overlap=100。这个参数不是玄学,是基于“平均中文一句话约50字、一个语义块约500字”的经验值,你可以在评估时灵活调整。
4.3 索引构建与本地持久化
索引构建的核心代码逻辑是:逐个切分文本块,调用Embedding模型生成向量,写入向量库并做持久化。Chroma默认的持久化目录是本地磁盘上的一个文件夹,重跑服务时不会丢失。这里有一个值得强调的点:务必把原始文本和元数据(如来源文档名、段落标题)一起存进向量库,因为后面生成阶段要给模型提供来源引用,没有元数据的话溯源无从谈起。
4.4 查询与生成环节串联
到了查询阶段,整个链路是:问题进来 → 向量检索粗排 → 混合检索合并 → 重排模型精排 → 组装Prompt → 调大模型生成 → 输出带引用的回答。我自己习惯在这条链路上埋几个日志点:检索命中了哪些片段、重排后分数最高的是谁、最终喂给模型的内容是什么。没有埋点,出了问题根本没法排查。
组装Prompt时把“资料引用”和“用户问题”之间用分隔符区分开,清晰告诉模型哪些是要参考的、哪些是要回答的。生成模型调用时温度可以设低一点,0.2~0.3左右,减少随机性。如果想要能输出的引用来源列表,可以让模型在答案末尾用固定格式输出引用的文档ID,再后端映射成文件名和页码。
5. 评估体系:没有指标,你连优化方向都找不到
5.1 检索质量评估:Recall, Precision, MRR
RAG效果出问题,先别急着骂模型,先评估检索坏了还是生成坏了。检索质量主要看三个指标:
- Recall@K:正确答案在Top K结果中出现的比例,衡量“找没找全”。
- Precision@K:Top K结果中正确结果的比例,衡量“找得准不准”。
- MRR:第一个正确答案在结果列表中的排名倒数,衡量“最相关的排多前”。
我自己的做法是,先人工造一个包含50~100条QA对的评估集,每条QA精确标注应该命中哪些知识片段。然后跑一遍检索,算上面三个指标。Recal如果低于70%,基本可以断定切分、Embedding或检索策略有问题,应该先调整,而不是去改生成Prompt。
5.2 生成质量评估:忠实度与答案相关性
生成质量评估不能只看“答没答出来”,核心是看两件事:
- 忠实度(Faithfulness):答案中的事实是否能在检索片段中找到依据。我觉得这是RAG生命线,幻觉重灾区都在这里。
- 答案相关性(Answer Relevance):回答是否直接解决了用户问题,有没有答非所问。
用大模型做裁判是现在的主流评估方法,可以让GPT-4逐个维度打分,但不能裸测,得给它一套详细打分标准和示例,否则不同批次的分数波动很大。有条件的话,定期抽一批结果请业务方人工复核,毕竟最终打分的是用户体验,不是模型自己。
6. 工程化难点与避坑指南
6.1 上下文窗口有限,怎么塞下所有相关资料
RAG落地最常遇到的硬约束是模型窗口有限,而且检索出的片段常常超过容量。我的策略是分两层过滤:先在粗排阶段把候选从几百缩到50个,再在重排阶段把50个缩到5~10个。这两层过滤都过完之后,组装Prompt时还要再量一下总token,超出模型极限的片段宁可丢弃,也不能让Prompt被截断。
如果手头的文档特别长,比如几十页的行业报告,一个片段根本说不清,可以用摘要树或多跳检索的方案,先定位到相关章节,再对这个章节做过细粒度的检索。这类技术市面上已经有成熟框架,真遇到再做深入研究,别自己从零造轮子。
6.2 文档更新与淘汰机制
RAG系统上线后,最容易被忽视的是数据更新。文档一变,向量库里的老向量就是“过期知识”,如果还在被检索到,模型就会一本正经回答旧流程。至少要做三件事:
- 记录每个 chunk 的来源文档名和更新时间,更新时按来源删除旧向量后重建。
- 有新增文档时,增量执行索引构建,别每次都全量重算,浪费算力。
- 定期给所有向量做一次批量失效检查,清除源文档已删除或已归档的 chunk。
6.3 多轮对话中的检索Query改写
多轮对话场景下,用户常常说“那它怎么处理?”——这里“它”指什么,依赖前文。如果直接把这句话拿到向量库里检索,基本检索不到东西。标准的解法是:先用大模型把多轮历史压缩成一个独立query,比如“它怎么处理”改写成“Redis集群节点宕机后如何自动故障转移”,再拿改写后的query去做检索。别小看这一步,很多RAG系统在对话场景里效果崩掉,一半原因是query改写没做。
6.4 常见问题速查与排查思路
我这里整理了一张问题排查速查表,都是实际项目中高频踩过的坑:
| 现象 | 可能原因 | 排查方向 |
|---|---|---|
| 检索结果明显不相关 | 切分粒度太粗/太细、Embedding模型不匹配 | 先看检索日志,人工核对命中chunk是否符合语义 |
| 答案有幻觉,编造信息 | 检索片段没被正确引用、Prompt没限定必须基于资料 | 检查最终喂给大模型的Prompt,是否包含无用或冲突片段 |
| 答非所问 | 多轮query未改写 | 检查多轮时的query改写逻辑 |
| 长文档总是答不全 | 切片后跨章节语义丢失 | 考虑按章节切分,或引入摘要树、多跳检索 |
| 系统延迟太高 | 粗排候选量太大,重排开销高 | 硬限制粗排候选数,缩短重排列表长度 |
7. 我的实践心得与后续扩展方向
7.1 从单点工具走向Agent能力
RAG玩透了之后,它会从一个知识问答工具变成Agent的记忆和工具调用底座。我在最新一个项目里,已经不再只做“查了答”,而是让Agent根据初步检索结果判断是否还需调用数据库、是否需要联网搜索,再把走查和检索结果一起交给模型做决策。这种组合拳上手之后,才体会到RAG真正的护城河不是单一流程,而是能充当整个Agent系统里可靠的短期记忆模块。
扩展方向可以参考的是:再加上意图识别、任务规划、工具调用这些模块,RAG就从“知识百科”升级成“智能工作者”。但前提是基础检索质量已经打磨到位,不然Agent每一步拿到的都是错误资料,上层再智能也没用。
7.2 别忘了成本与性能之间的平衡优化
最后想专门提一嘴成本优化。很多团队一上来就往最贵的模型、最大的向量库上配置,几周后预算燃烧得厉害才想起控制。实测下来有两招非常有效:第一,检索质量稳定后,可以把生成模型换成同系列成本更低的型号,质量差距远小于价格差距。第二,对常见问题加一层轻量缓存——同一问题命中缓存后直接返回既定答案,不要重复走RAG全链路,这一步能把API账单打下来好几成。
我个人的感受是,RAG方案规划不要想一步到位,先跑通再完善,每一次优化都建立在上一步的评估数据上。把基础检索质量和Prompt工程打磨好,后面升级可以做得非常平滑;反过来基础烂,上层加什么高级模块都是白搭。希望这篇全景梳理能让你对RAG的整个工程脉络更清楚,下次搭系统时少交一点学费。