做一个生产级RAG系统,远不是“装个向量库、跑个embedding、拼一段prompt”那么简单。我做过从0到1的完整RAG开发,也踩过不少坑,这篇就把整条链路拆开讲透:它到底解决什么问题、架构怎么搭、每个环节有哪些实操细节和暗坑,以及怎么量化评估效果。文章面向正在做LLM应用开发、或者已经搭了一版但检索质量一言难尽的朋友,尽量把话说直白,能落地。
1. RAG到底在解决什么问题
1.1 大模型的三个死穴:时效、幻觉、私有知识
先搞清楚为什么需要RAG,不然后面的方案全是拍脑袋。
大模型给我们带来的惊艳体验背后,藏着三个绕不开的缺陷。
缺陷一是知识有时效性。模型参数在训练阶段固化后,训练数据截止日之后的新知识它一概不知道。你问它最新政策、刚发布的行业报告,除非重新训练,否则它永远答不出来。实际业务场景里,知识每天都在变,根本不可能靠重训来追。
缺陷二是幻觉。大模型本质是“下一个词的概率预测器”,当它不确定答案时,不会老实说“我不知道”,而是非常自信地编造一个看起来像模像样的回答。开放域闲聊没人较真,但企业内部知识问答、客服系统、专业咨询场景,幻觉就是红线,轻则答非所问,重则误导业务决策。
缺陷三是不具备私有知识。通用大模型对互联网公开内容掌握得再充分,对你公司的内部制度、项目文档、产品手册、客户对话记录一无所知,这部分知识从不出现在公开语料库中,模型根本训练不到。
这三个缺陷叠加在一起,决定了光靠裸模型无法支撑真正专业、严谨、实时更新的业务场景。知识必须外置,“外挂知识库”成为必然选择。
1.2 为什么选RAG而不是微调
说到给模型补知识,很多人的第一反应是微调。我早期也试过这条路,后来发现方向不对。
微调的本质是调整模型的权重分布,让它学习某种“行为模式”或“表达风格”,它不是给模型装记忆。你让微调模型记住企业几千份内部文档里的具体数据,它要么记住得稀疏,要么干脆学串了。微调需要高质量指令样本、大量算力,而且每次文档更新都要重新微调,代价高得离谱。
RAG的解决思路完全不同。它把知识保存在外部,模型只在回答时“查资料”。文档更新了,只更新索引,模型本身完全不动。这种方式的好处是明显的:
- 知识源可控,文档改了立刻生效,不存在“训练完之后知识固化”的问题。
- 来源可追溯,模型引用了哪一段文档,系统可以明确展示给用户,方便核验。
- 开发成本相对可控,不需要昂贵的训练集群,普通的服务部署就能转起来。
- 幻觉得到有效抑制,模型是基于检索到的真实上下文做生成,而非凭空编码。
我并不是说微调没有用。事实上,微调和RAG经常可以组合使用,比如先微调让模型学会特定格式输出,再挂RAG提供内容素材。但如果你要解决的核心问题是“让模型知道那些它不知道的知识”,RAG是更低成本、更灵活的路径。
2. RAG系统设计:先把架构画明白
2.1 核心链路:数据侧与查询侧的协同
整套RAG系统可以拆成两条独立运行的链路:一条是数据侧,负责把文档处理成可检索的索引;另一条是查询侧,负责把用户问题变成检索指令并组装答案。
数据侧链路大概是这样的:
- 文档解析:把PDF、Word、Markdown、网页等各类格式拆成纯文本,保留必要结构信息。
- 数据清洗:去掉页眉页脚、重复信息、垃圾字符、超链接等噪声。
- 文本切片:把长文档切成多个适合检索和喂给模型的片段。
- 向量化:用嵌入模型把每个切片转换成高维向量。
- 索引存储:把向量以及原文内容、元数据一起写入向量数据库,建立可查的索引。
查询侧链路则是一条实时问答管线:
- 查询理解:对用户问题做预处理和改写,补全上下文。
- 向量检索:把问题转成向量,在向量库中找出相似度最高的候选文档片段。
- 每路召回与融合:根据需要,可能同时走关键词检索和向量检索,再把结果按加权或算法融合。
- 重排序:对召回的候选片段做精细化打分,选出最相关的一批。
- 生成回答:把问题和选中的片段组装成提示词,交给生成模型输出答案,并附上引用来源。
这套架构的核心设计思想是:把“知识的存储与查找”和“语言的生成与表达”彻底解耦。存储查找交给检索系统,生成表达交给大模型,各干各的擅长的事。
2.2 影响效果的四个关键因素
架构图画起来很简单,但不同的人做出来的系统效果天差地别。差别来自四个环节的决策质量。
第一是切片策略。切片大小、切片方式、是否重叠,直接决定检索的粒度。切片太大,每块内容主题混杂,检索精度低;切片太小,上下文不完整,模型生成时缺乏足够背景。这个后面专门讲。
第二是嵌入模型。不同嵌入模型对语义的理解能力差异很大。通用模型可能在你的垂直领域表现不佳,需要选型甚至微调嵌入模型。
第三是检索策略。简单的向量相似度检索往往不够,混合检索(向量加关键词)在很多场景下更稳,重排环节更是决定答案质量的胜负手。
第四是提示词模板。同样的检索结果,不同的提示词拼装方式,输出质量能差出三倍五倍。上下文如何组织、如何提示模型不要瞎编、如何要求标注引用,都会影响最终效果。
这四点我后面会逐个拆开讲实操。先把设计层面的策略选型讲清楚,因为方向错了,后面的努力全是白费。
3. 切片、向量化与检索:决定RAG质量的三板斧
3.1 切片策略:先说为什么切片,再说怎么切
很多人做RAG时拿到文档就直接往库里塞,结果检索质量惨不忍睹。根本原因在于检索和生成对“文本粒度”的要求是矛盾的。
大模型一次能接受的输入长度有限,你不可能把整本操作手册都塞进去。而向量检索的本质是找“语义相近”的文本,如果一块文本里包含多个主题,它的语义向量会互相拉扯,导致检索时跟谁都不像。
切片的核心目标,是在“粒度够细、语义纯粹”和“上下文够全、信息完整”之间找平衡。我采用的默认策略有三套,按文档类型来选。
固定长度切片最简单,按字符数切,比如每片512个字符或1024个字符,配合少量重叠。适用于结构统一、段落长度接近的文档,比如日志、标准化报告。优点是实现简单、稳定可控,缺点是容易从句子中间或段落中间切开,破坏语义完整性。
递归字符切片是我个人的首选。设定一组分隔符层级,优先按段落切,段落太长再按句子切,句子还长就按字符切。这种切法能最大程度保住自然语义边界,对绝大多数业务文档都适用。
语义切片在工程上更复杂。利用嵌入模型计算相邻句子相似度,把相似度断崖式下跌的位置当作边界。这种切法对主题变化明显的文档效果好,但计算成本高,适合处理长文章、研究报告这类内容。
切片大小怎么定?我给出的经验参考是:通用问答场景下每片256到512字符较为稳妥,知识文档场景可以放到512到1024字符。切片太小,单个片段包含的信息量不足,模型生成时还得同时捞四五块才能拼出完整答案;切片太大,又引入大量无关噪声。我用过的项目里,有把切片从2048调低到512后,检索准确率直接提升十几个百分点的案例。
还有一个细节你们可能没注意:切片重叠。相邻切片之间保留一段重叠文本,通常占切片长度的10%到20%,可以避免关键信息恰好落在切片边界被硬生生拆散。打个比方,一句话被从中间截断,前半段在后一个片段里没有主语,后半段在前一个片段里没有谓语,检索时谁都匹配不好。重叠就是给边界信息上的一道保险。
3.2 嵌入模型:选型与避坑
嵌入模型负责把文本映射成向量,是整个检索系统的“理解层”。它的质量上限决定检索的天花板。
选型时我主要看四个维度。
一是语言适配性。英文语料选通用英文模型没问题,但中文场景必须挑中文语料训练过的模型,不然语义理解非常飘。
二是向量维度。高维度向量表达能力强,但存储和计算成本也高。从768维降到384维,内存占用直接砍半,而效果损失在部分场景中可以忽略。
三是领域匹配度。做法律问答就用法律语料优化过的嵌入模型,做代码检索就用代码数据训练的模型。没有完全匹配的,优先选通用能力强的,再考虑在自建语料上做无监督对比学习微调。
四是输入长度上限。嵌入模型一般有最大输入长度限制,比如512个token。切片长度必须控制在模型可接受的范围内,否则超长部分会被截断,语义信息直接丢光。
嵌入模型跟切片的配合有一些容易踩的坑。比如我遇到过文档里有大量表格和代码,直接按纯文本切分后,嵌入模型对表格结构和缩进敏感的语义完全无感,检索效果非常差。后续把表格转成键值对文本、代码块标注语言再切分,效果才正常起来。
另外一个真实教训是,整个系统里嵌入模型、重排模型、生成模型必须各司其职。有人试图用同一个模型既做嵌入又做重排,实际效果两头不讨好。嵌入模型追求的是把“语义相近”的文本映射到相近位置,重排模型追求的是对“问题-文档”对做精细相关度打分,这是两种不同的任务目标。
3.3 向量数据库选型
向量数据库负责存储高维向量并提供检索能力,是RAG系统的“记忆仓库”。市面上的可选方案不少,我大致把它们分成三类。
轻量级方案适合原型验证和小规模数据。内存索引类的向量检索库足够用了,数据量在百万级以内、机器内存充裕时,检索速度快得感人。缺点是数据量大或并发高时不友好,持久化能力也一般。
中型方案是带持久化的开源向量检索系统,多部署在后端流程里。支持分布式、支持混合索引、有成熟的过滤条件,适合中小规模的业务数据。这套方案的好处是完全可控、没有额外费用,缺点是运维成本自己扛,索引参数需要手动调优。
全托管方案适合上生产、不想管基础设施的场景。云厂商提供的向量数据库服务或者直接借传统数据库的向量检索能力,都有不错的延展性。优点是省心,缺点是成本更高,而且可能有供应商绑定风险。
我个人的建议是,千万不用一上来就追求最贵的方案。先用轻量级方案把RAG链路跑通,确认检索质量和业务指标OK之后,再根据数据规模平滑迁移到更重型的方案。换了库,代码层面改动主要是索引创建和查询接口,核心链路可以保持不变。
向量数据库中索引类型的选择也影响查询性能。常见的索引如平面扫描、IVF、HNSW各有取舍。我通常用HNSW,它在查询延迟和召回质量之间平衡得最好。建索引时还有一个参数需要注意,就是查询时的候选集大小,这个值调大能提升召回率,代价是延迟变高,需要针对线上并发实测调优。
3.4 检索到重排:别只依赖向量相似度
检索环节最常见的错误,就是只拿用户问题嵌入后的向量去向量库做相似度搜索。向量相似度确实能捕获语义相关性,但存在几个先天不足。
一是一些场景下用户问题里包含精确的关键词、编号、品牌名,向量检索对这类精确匹配天然不敏感。比如用户搜索“AP-3075型控制器”,向量检索可能返回一堆“控制器”相关内容,却找不到确切的型号。二是因为问题往往很短,信息量不足,嵌入后的向量可能偏离真实意图。三是向量相似度和“相关度”不完全是同一回事,语义相近不等于信息契合。
我的做法是混合检索。向量检索负责召回“语义相关”,BM25这类稀疏检索负责召回“词汇匹配”,两条路的结果融合后,再交给重排模型精排。
融合方式我用过简单的加权求和,也用过RRF算法。RRF的思想是给每个文档在每路结果中的排位倒数算分,最后汇总排序。它的好处是不需要手动调权重,对两路结果的分数分布差异不敏感,实测下来比拍脑袋定的加权融合稳定得多。
重排环节是质量的胜负手。初始召回一般取二十到五十个候选,重排模型逐一对“问题-候选文档”对做交叉编码打分,最后只保留三到五个最相关的片段送给大模型生成。交叉编码模型能同时看到问题和文档的全文交互,打分精度远高于双塔结构的嵌入模型。
我见过太多RAG项目,检索召回了正确的文档片段,但因为没用重排,相关片段排名靠后,被截断在输入长度之外,最终生成的答案完全跑偏。重排在算力上确有额外成本,但它对最终效果带来的提升往往非常明显。
3.5 提示词组装与生成
检索再准,生成环节出了问题,前面全白搭。提示词是将检索结果与生成模型连接在一起的粘合剂。
我设计生成提示词的基本原则是:把系统指令、检索到的上下文片段、用户问题三件事彻底分开。系统指令规定模型的身份和回答行为,例如只允许依据给定文档回答、不能臆造未提及的信息、如果文档没有答案就直接说不知道。上下文片段按顺序编号排列,并给出对应来源标识。用户问题放在最后,需要模型回答的内容清晰独立。
上下文片段数量也是个需要权衡的参数。我常用的是返回三到五个片段。片段太少可能缺关键信息,片段太多会稀释模型注意力,还可能超出上下文窗口。如果业务场景复杂,宁可追求片段质量而非数量。
还有一个被忽略的细节:片段顺序。把得分最高的片段放在上下文最前面或紧挨用户问题的位置,对生成质量有正向影响。我测试过一个案子,同样五个片段,都按重要度从高到低排列输出,比打乱顺序输出的答案命中率高了将近一成。原因是模型的注意力分布不均匀,关键信息放在容易被注意到的位置,更容易被正确利用。
4. 效果评估:不量化就没有优化空间
4.1 检索与生成,两个维度分开评估
RAG系统上线之前,很多团队凭“感觉回答还行”就推上线,这是大忌。RAG的效果评估必须拆成两个独立维度,分别量化。
第一个维度是检索质量。对应指标主要是召回率和精确率。召回率的含义是“所有相关文档里我捞出了几个”。精确率的含义是“我捞出的文档里有几个是真正相关的”。实操中,我会把一批测试问题整理出来,人为标注每个问题对应的相关文档,然后跑系统的检索链路,计算top-k召回率和精确率。
第二个维度是生成质量。更关键的是生成内容的忠实度和相关性。忠实度指生成的答案是否严格基于检索到的上下文,有没有夹带模型编造的私货。相关性指答案是否正面回答了用户的问题,没有答非所问。对这两者的评估可以靠人工打分,也可以借鉴RAG评测工具的思路,用大模型当裁判对答案进行打分,但裁判模型的稳定性和偏差需要额外注意。
搭建评估集是一件值得花时间的事。我会为每个垂直领域准备五十到一百条真实用户问题,覆盖常用问题、模糊问题、多跳问题、无答案问题等类型。其中“无答案问题”非常关键,它测试的是系统在知识库确实没有相关信息时,是否老老实实说不知道,而不是胡编一个答案。
4.2 评估集驱动的迭代节奏
有了评估集,迭代就有了方向。我习惯用一套简单的方式对比版本间差异。
首先跑检索评估,对比新旧版本在召回率和精确率上的变化。如果检索指标平滑下降,问题出在切片或嵌入环节;如果检索指标稳定但生成效果变差,问题更多在提示词或生成参数。
其次跑生成评估,对每条测试问题的输出做忠实度和相关性评分,逐条记录问题案例。每改一次切片策略、换一次嵌入模型、调一次重排阈值,都重新跑一遍完整评估,把数字记录下来对比。
做得多了你会发现,很多“效果不好”的问题,本质上都是检索质量差导致下游生成质量差。先花大力气把检索指标做上去,生成效果通常会同步改善。这个顺序不搞明白,很容易对着一段提示词改来改去,收效甚微。
我在某个知识库项目中经历过一件印象深刻的事:检索召回率从45%一路优化到85%,生成答案的主观满意度从不到六成提升到九成以上。后续基本没怎么动提示词,效果就靠检索侧撑起来了。这充分说明检索质量是RAG系统的地基,地基稳了,上面的楼才能盖高。
5. 常见问题与排坑实录
5.1 检索结果一团糟:先查切片和嵌入模型
症状是检索回来的片段跟用户问题不相关,甚至驴唇不对马嘴。排查顺序从成本最低的项目开始。
第一查切片是否合理。如果切片跨主题严重,句子被截断,向量表达必然是混乱的。把几条失败的检索样例打印出来,人工看一下切片边界,问题通常一目了然。
第二查嵌入模型是否匹配。中文语料用英文模型、通用模型处理专业领域,都是常见翻车现场。换个领域适配的嵌入模型再跑检索评估,指标对比立竿见影。
第三查是否缺少混合检索。纯向量检索在精确关键词匹配场景下天然吃亏,如果你们的检索问题里经常出现型号、编号、人名,混合检索是必须补上的能力。
5.2 检索到了正确答案却不放进去
这个坑很隐蔽。有时候检索结果里明明有正确答案的片段,但重排环节把它排得太靠后,超过了截断阈值。用户看到的是被切掉的部分。
解决方案有两个方向。一是提高保留片段数量,从三个加到五个,让正确答案有更多机会进入上下文。二是优化重排模型的排序质量,检查重排模型是否是领域适配的,必要时用人工标注数据微调重排模型。
另外还要检查一个工程细节:输入给生成模型时,有没有把片段内容和引用来源一并传入。如果只传了片段文本丢了来源,模型无法确信答案出处,风格会偏向泛泛而谈。
5.3 答案还带着幻觉
做完RAG之后幻觉只能被显著抑制,很难彻底消除。如果幻觉仍然高发,从三个角度排查。
首先检查提示词是否明确约束模型“只能依据给定文档回答”。如果没有显式指令,模型很容易回归到兴之所至的自由生成模式。
其次检查检索片段是否断章取义。有些文档内容本身是碎片化的,比如表格拆出的单列信息、列表拆出的孤立条目,模型缺乏上下文时只能自我脑补。这类问题要从切片策略上优化,保证每个片段内部有完整的语境。
最后检查无答案问题的处理策略。严格模式下,如果检索最高相似度分低于某个阈值,直接拒绝回答而不是强行生成。给用户返回“知识库中没有找到相关信息”,比编造一个答案体面得多。
5.4 评估成绩不错,线上体验却差
这种情况我遇到过好几次,根本原因通常是测试评估集和真实场景分布不一致。线上用户的提问方式是口语化的、碎片化的,而你评估集里的问题可能写得太书面、太完整。
对策是持续从线上日志采集真实用户问题,定期扩充评估集。尤其是线上一些低质量、多轮对话、带错别字的问题,必须送进评估集,让系统在这些问题上反复迭代。还有一类多跳问题非常考验RAG能力,比如“上个月A项目的负责人是谁,他之前在哪个团队”,这需要两步甚至多步检索与推理,大多数前期版本都处理不好,只能靠数据积累和查询改写逐步改善。
6. 进阶与扩展:从能用走向好用
6.1 查询改写
用户问题在真实场景中往往信息不足。比如“它的价格是多少”,这里的“它”指代前文中的某产品。如果直接把这句话拿去做检索,指的是什么完全无从谈起。
查询改写的常见做法是:先用大模型结合对话历史把这种模糊问题改写成一个自包含的清晰问题,再拿改写后的文本去做向量检索。这个环节实现成本不高,但对检索质量提升很明显,尤其在多轮问答场景里效果显著。
6.2 多路召回与路由
不同问题适合不同的检索方式。事实性精确问题适合关键词检索,语义模糊问题适合向量检索,统计数据问题可能需要查结构化表格。激进一点的方案是做问题路由:先判断问题类型,再决定走哪条检索路线上游服务。
更简单有效的通用方案是混合检索把多条召回结果统一送进重排环节,让重排模型来做最终裁决。我在落地时更倾向于后者,因为路由规则本身就很难写完备,一旦规则错了,整条路都错了。混合检索加重排的架构,规则更少,容错性更强。
6.3 结构化知识与图增强
传统RAG处理的是非结构化文本,但业务里面大量知识是结构化的:实体关系、组织架构、产品关联、事件时间线。用向量方式存这些结构化关系的效果并不好。
图增强型检索是当前值得关注的方向。简单理解是:在普通向量检索之上,额外建立一个知识图谱,把文档中的实体和关系抽取出来,当用户问题涉及实体关联分析时,从图谱上做相关路径探索,把得到的子图信息配合向量检索结果一起送给生成模型。
这种方案在回答“A和B之间有哪些项目合作关系,合作持续时间分别是多久”这类多跳关系问题时,效果好于纯向量检索。代价是实现复杂度明显上升,需要引入实体抽取与关系抽取流程,对工程能力有要求。如果你们现阶段不需要这类能力,就先不要碰,复杂度是实打实的成本。
写在最后的实操心得
做RAG这么久,我最大的体会是:这个系统的性能上限,取决于最弱的那一个环节。切片切得粗暴,嵌入再强也救不回来;嵌入选型不对,检索再多路也白搭;检索结果一堆噪声,提示词写得再精致,生成质量照样受限。很多团队一开始追着最新的模型、最炫的框架走,却忽略了最基础的数据质量,最终效果自然平平。
我的建议是先做好三件事:把文档清洗到位,把切片策略调成最适合你数据形态的形态,把评估集搭起来并让数据说话。这三件事做完,系统的地基就稳了,之后再加混合检索、重排、查询改写这些进阶能力,每加一层都能看到实实在在的效果变化。
还有一个小技巧送给大家:别迷信一次开发到位,RAG迭代应该以星期为单位来看变化。每次只动一个变量,跑评估、看数据、记录结论,再动下一个变量。这个节奏虽然慢,但每一步都踏实,反而比频繁改动、多变量一起调、最后出了问题都不知道是哪个环节导致的开发方式高效得多。这套方法论,支撑了我好几个RAG项目的成功落地。希望你们也能用同样的节奏,把自己的RAG系统一点一点打磨到真正能上生产的水平。