1. 为什么RAG成了面试里的“必答题”
如果你最近一年在找算法岗或者大模型应用岗,大概率会发现一个现象:面试官不再只问Transformer八股了,而是会突然抛出一句——“你做过RAG吗?聊聊你的理解。”这不是跟风,而是因为RAG已经从“论文里的概念”变成了“工程里必须落地的模块”。我面过也面过别人,发现很多候选人对RAG的理解停留在“检索+拼接+生成”这三步,但面试官真正想听的,是你有没有踩过坑、有没有优化过、有没有想过为什么这么设计。
RAG全称Retrieval-Augmented Generation,检索增强生成。它的核心逻辑很朴素:大模型本身的知识有截止日期,也有幻觉,那就在回答问题之前,先去外部知识库里把相关材料找出来,塞进上下文,让模型基于材料回答。听起来简单,但真正做起来,从文档切分到向量检索再到重排序,每一步都有大量细节决定最终效果。面试里的“6连问”通常不是六个独立问题,而是一条链:原理是什么、怎么切分、怎么检索、怎么重排、怎么生成、怎么评估。这条链上任何一个环节答得含糊,面试官就能判断你只是“跑过demo”还是“真正调过系统”。
这篇文章我打算把这条链拆开,结合我自己在多个项目里实际调优的经验,把每个环节的“为什么”和“怎么做”讲透。不管你是准备面试,还是正在搭建自己的RAG系统,这些内容都能直接拿去用。我不会只给你一个流程图,而是会告诉你:为什么朴素RAG经常效果不好、为什么切分策略比模型选择还重要、为什么重排序能救回一半的召回损失。这些才是面试官真正想听的“干货”。
2. 第一问:RAG到底解决了大模型的哪些硬伤
2.1 知识截止与幻觉:两个必须分开看的问题
很多人把RAG的价值笼统概括为“让模型知道更多”,这个说法太糙了。大模型有两个独立的硬伤,RAG对它们的解决程度完全不同。
第一个是知识截止。模型训练数据有截止日期,之后发生的事情它不知道。这个问题RAG解决得很直接:把新信息放进外部知识库,检索出来塞进上下文就行。但这里有个隐藏坑——如果检索出来的材料和模型内部知识冲突,模型倾向于相信谁?实测下来,如果材料在上下文中位置靠前且表述明确,模型会优先采信材料;但如果材料模糊或者位置靠后,模型很可能回到自己的旧知识。所以RAG不是“加了检索就万事大吉”,上下文的位置和表述方式同样关键。
第二个是幻觉。模型会编造不存在的事实,这个问题RAG只能缓解,不能根治。因为幻觉的来源不只是知识缺失,还有模型对自身不确定性的错误估计。你给它材料,它可能仍然编造,尤其是当材料里没有直接答案时。我见过一个案例:问一个关于某内部流程的问题,知识库里只有部分相关文档,模型没有说“材料不足”,而是把几个文档的片段拼接成了一个看似合理但完全错误的答案。所以RAG系统里必须加一道“拒答”机制,当检索置信度低于阈值时,让模型明确说“根据现有资料无法回答”,而不是硬编。
2.2 朴素RAG的流水线为什么经常跑不通
朴素RAG的流程是:文档切分→向量化→存入向量库→查询向量化→相似度检索→拼接上下文→生成。这条流水线在demo里跑得通,一到真实场景就崩,原因通常出在三个地方。
第一,切分粒度与语义完整性冲突。按固定长度切,比如512个token一刀切,很容易把一个完整段落切成两半,检索出来的片段缺少上下文,模型看不懂。按段落切,又可能一段太长,向量化后语义被稀释,检索精度下降。
第二,向量相似度不等于语义相关性。用户问“如何申请报销”,文档里写的是“费用审批流程”,字面不相似但语义相关,纯向量检索可能漏掉。反过来,有些文档字面相似但答非所问,也会被召回来。
第三,上下文窗口的浪费。检索回来一堆片段,全塞进去,其中可能只有一两段真正有用,其余都是噪声。模型在噪声里找答案,准确率会明显下降。所以RAG的优化,本质上是在“召回率”和“精度”之间找平衡,而朴素RAG两头都不占。
面试里如果被问到“RAG有什么缺点”,不要只说“检索不准”,要具体到切分、向量语义、上下文噪声这三个层面,面试官会立刻知道你真正调过。
3. 第二问:文档切分策略怎么选才不踩坑
3.1 固定长度、语义切分与递归切分的适用场景
切分是RAG的第一道关,也是最能体现经验的地方。常见的策略有三种,我分别说一下适用场景和坑。
固定长度切分最简单,按token数或字符数一刀切,通常加一个重叠窗口(overlap)来缓解语义断裂。比如每512个token切一段,相邻段重叠128个token。这个策略适合结构松散、段落边界不明显的文档,比如聊天记录、日志。但它的坑在于:重叠窗口会增加存储和检索成本,而且如果文档本身有清晰的章节结构,固定切分反而破坏了结构信息。
语义切分是先用模型判断句子之间的语义相似度,在相似度骤降的地方切一刀。这个策略适合长篇文章、技术文档,能保证每段语义完整。但它的坑是计算成本高,而且对短文档不划算。另外,语义切分的阈值很难调,阈值太高切得太碎,太低又切不开。
递归切分是我最常用的折中方案。它按层级来:先按大标题切,如果某段还是太长,再按小标题切,再长就按段落切,最后才按固定长度切。这样既保留了文档的层级结构,又控制了每段的长度。LangChain里的RecursiveCharacterTextSplitter就是干这个的,你可以指定分隔符优先级,比如先按“\n\n”切,再按“\n”切,最后按“。”切。
3.2 切分长度与重叠窗口的参数计算
切分长度设多少,不是拍脑袋决定的。它取决于两个因素:嵌入模型的最大输入长度和生成模型的上下文窗口。
假设你用的嵌入模型最大输入是512个token,那切分长度就不能超过512,否则会被截断。但实际建议设在256到384之间,因为太长的文本向量化后,语义会被平均掉,检索精度反而下降。重叠窗口一般设切分长度的10%到20%,比如切分384,重叠64。
生成模型的上下文窗口决定了你能塞多少段。假设窗口是8K token,系统提示词占500,用户问题占100,留给检索材料的空间大约是7400。如果每段384 token,理论上能塞19段。但实际不要塞满,因为模型在长上下文里对中间位置的信息注意力会下降,这就是著名的“lost in the middle”现象。我的经验是塞5到8段,把最相关的放在最前面和最后面,中间放次相关的。
| 切分策略 | 适用场景 | 优点 | 坑点 |
|---|---|---|---|
| 固定长度 | 日志、聊天记录 | 实现简单、速度快 | 破坏语义完整性 |
| 语义切分 | 长篇文章、技术文档 | 语义完整 | 计算成本高、阈值难调 |
| 递归切分 | 结构化文档 | 保留层级、长度可控 | 需要设计分隔符优先级 |
切分不是一次性的,要跟着检索效果反复调。我一般会先跑一轮评估,看召回的材料里有多少是“断头断尾”的,再决定要不要调整切分参数。
4. 第三问:向量检索的精度瓶颈在哪里
4.1 嵌入模型选型:不是越大越好
嵌入模型负责把文本转成向量,它的质量直接决定检索的上限。很多人一上来就选最大的模型,觉得维度越高越好,其实不一定。
选嵌入模型要看三个指标:检索精度、推理速度、维度成本。精度可以用MTEB榜单参考,但榜单分数高不代表你的场景就好。比如你处理的是法律文书,通用模型可能不如在法律语料上微调过的小模型。速度方面,如果知识库有百万级文档,嵌入模型的推理速度直接影响索引构建时间。维度成本则关系到向量库的存储和检索延迟,768维和1536维的存储差一倍,检索速度也差不少。
我的建议是:先用一个中等规模的通用模型跑基线,比如BGE-base或者GTE-base,看召回效果。如果精度不够,再考虑换大模型或者微调。微调嵌入模型需要构造正负样本对,成本不低,但效果提升往往很明显,尤其是垂直领域。
4.2 相似度度量与索引类型的选择逻辑
向量检索的核心是相似度计算,常见的有余弦相似度、点积、欧氏距离。余弦相似度最常用,因为它对向量长度不敏感,只看向量方向。点积和余弦的区别在于是否归一化,如果向量已经归一化,两者等价。
索引类型决定了检索速度和召回率的平衡。Flat索引是暴力检索,召回率100%但速度慢,适合小知识库(几万条以内)。IVF索引把向量聚类,检索时只查最近的几个簇,速度快但可能漏掉边界上的向量。HNSW是基于图的索引,检索速度快且召回率高,是目前最常用的,但内存占用大。
选择逻辑很简单:知识库小于10万条,用Flat或HNSW;大于10万条,用IVF或HNSW加量化。如果内存紧张,可以考虑PQ量化,但会损失精度。
4.3 混合检索:为什么纯向量不够
纯向量检索有个致命问题:它对关键词精确匹配不敏感。比如用户问“错误码E502怎么解决”,向量检索可能召回一堆关于“错误处理”的文档,但就是漏掉那个专门讲E502的。这时候需要混合检索,把向量检索和关键词检索(比如BM25)的结果融合。
融合策略有两种:加权求和和倒数排名融合(RRF)。加权求和需要调权重,RRF更简单,它只看排名不看分数,把两个检索结果的排名做倒数相加。实测下来,RRF在多数场景下更稳,因为它不需要归一化分数,避免了不同检索器分数尺度不一致的问题。
混合检索的坑在于:如果两个检索器召回的结果高度重叠,融合后提升不明显;如果完全不重叠,融合后噪声会变多。所以通常还要加一个重排序模型来精排。
5. 第四问:重排序为什么能救回一半的召回损失
5.1 交叉编码器与双编码器的本质区别
重排序的核心是换一种更精细的相关性计算方式。检索阶段用的双编码器(bi-encoder)是把查询和文档分别编码成向量,然后算相似度。这种方式快,但查询和文档之间没有交互,细粒度的语义匹配会丢失。
重排序用的交叉编码器(cross-encoder)是把查询和文档拼在一起输入模型,让模型直接输出相关性分数。因为有了交互,它能捕捉到更细的语义关系,比如否定、条件、指代。代价是慢,因为每个查询-文档对都要过一次模型,没法预计算。
所以标准流程是:检索阶段用双编码器召回Top 50到100,重排序阶段用交叉编码器精排,取Top 5到10送给生成模型。这样既保证了速度,又提升了精度。
5.2 重排序模型的选型与延迟权衡
重排序模型的选择要看延迟预算。如果系统要求端到端响应在2秒内,重排序的耗时必须控制在200毫秒以内。这时候可以用小一点的交叉编码器,比如MiniLM级别的,或者用蒸馏过的模型。
如果延迟不敏感,可以用大模型做重排序,甚至用生成模型来打分。我试过用7B的模型做重排序,精度确实高,但单次推理要几百毫秒,Top 50排下来要十几秒,完全不实用。所以重排序模型的选择,本质上是在精度和延迟之间找平衡点。
另一个坑是:重排序模型也需要和你的领域匹配。通用重排序模型在垂直领域可能不如微调过的小模型。如果领域数据多,可以考虑用领域数据微调一个交叉编码器,效果提升很明显。
5.3 重排序的输入构造与截断策略
重排序模型的输入是“查询+文档”,但文档可能很长,超过模型的最大输入长度。这时候需要截断。截断策略有两种:头截断和尾截断。头截断保留文档开头,尾截断保留结尾。哪个更好取决于你的文档结构。如果关键信息通常在开头,用头截断;如果在结尾,用尾截断。
更精细的做法是:先用检索阶段的高分片段作为重排序的输入,而不是整个文档。因为检索阶段已经定位到了相关片段,重排序只需要在这个片段上做精细判断。这样既避免了截断信息丢失,又减少了输入长度。
重排序不是万能的。如果检索阶段Top 50里根本没有相关文档,重排序也救不回来。所以召回率和精度要分开优化,先保证召回,再提精度。
6. 第五问:生成阶段怎么让模型“说人话”
6.1 上下文拼接的顺序与格式设计
检索和重排序之后,你手里有一堆相关片段,怎么把它们拼成上下文送给模型,直接决定生成质量。
顺序上,我试过三种:按相关性降序、按文档原始顺序、两头强中间弱。实测下来,两头强中间弱效果最好,因为模型对开头和结尾的注意力最强。具体做法是把最相关的两段放开头和结尾,次相关的放中间。
格式上,每段前面加一个来源标记,比如“【文档1】”,段与段之间用分隔符隔开。这样模型能区分不同来源,也方便你在生成结果里做引用。另外,在系统提示词里要明确告诉模型:“只根据以下材料回答,如果材料中没有答案,就说不知道。”这句话能显著降低幻觉率。
6.2 提示词模板里的防幻觉设计
防幻觉的提示词设计有几个关键点。第一,明确边界:告诉模型只能使用提供的材料,不能使用内部知识。第二,要求引用:让模型在回答里标注信息来源,比如“根据文档1”。第三,允许拒答:明确说“如果材料不足以回答,请直接说无法回答”。第四,禁止推测:告诉模型不要根据材料做推断,只做直接陈述。
我见过一个反例:提示词里写“请根据材料回答”,模型就以为可以自由发挥,结果把材料里的片段重新组合成了一个错误答案。后来改成“只允许逐字引用材料中的原句来回答”,幻觉率立刻降下来了。当然这样回答会不够流畅,所以需要在流畅性和准确性之间找平衡。
6.3 生成参数的温度与长度控制
生成阶段的参数也会影响RAG效果。温度建议设低,0.1到0.3之间,因为RAG需要的是准确复述,不是创意写作。温度高了模型容易自由发挥,增加幻觉。最大长度要限制,避免模型长篇大论。通常答案长度不会超过材料总长度,设一个合理上限就行。
另外,重复惩罚可以适当调高,防止模型反复说同一句话。但不要调太高,否则会导致语句不通顺。这些参数没有固定值,需要在你的场景里跑评估来调。
7. 第六问:RAG系统怎么评估和持续优化
7.1 检索评估:召回率、MRR与NDCG
评估RAG要分两段:检索质量和生成质量。检索质量的核心指标是召回率,即相关文档有多少被召回了。如果召回率低,后面再怎么优化都没用。计算召回率需要标注数据,即每个查询对应哪些文档是相关的。标注成本高,但可以用大模型辅助标注,再人工抽检。
除了召回率,还有MRR(平均倒数排名)和NDCG(归一化折损累计增益)。MRR看第一个相关文档的排名,NDCG看整个排序的质量。这两个指标比重排序更关注排序质量,适合评估重排序模型的效果。
7.2 生成评估:忠实度、答案相关性与幻觉率
生成质量的核心是忠实度,即答案是否完全基于提供的材料,没有编造。评估忠实度可以用大模型做裁判,让一个模型判断答案里的每个陈述是否能在材料里找到依据。这个方法成本低,但裁判模型本身也可能出错,所以需要人工抽检校准。
答案相关性是另一个指标,看答案是否直接回答了问题。有时候答案忠实于材料,但答非所问,比如问“怎么申请”,答“申请条件是什么”。这个指标可以用人工评估,也可以用模型评估。
幻觉率是最关键的指标,计算方式是:在答案里找出所有无法在材料中验证的陈述,除以总陈述数。这个指标直接反映RAG系统的可靠性。
7.3 用A/B测试驱动迭代的实操方法
评估不是为了打分,是为了驱动迭代。我的做法是:每次改动一个变量,跑一轮评估,看指标变化。比如这周只改切分长度,下周只改重排序模型,这样能清楚知道每个改动的影响。
A/B测试在RAG里比较难做,因为用户查询分布不均匀。我的经验是:构造一个固定的评估集,包含各种类型的查询,每次改动都在这个评估集上跑。评估集要覆盖简单事实查询、多跳推理、否定查询、模糊查询等场景。这样指标才有可比性。
另外,线上反馈也很重要。可以在答案旁边加一个“有用/没用”的按钮,收集用户反馈。但要注意,用户点“没用”不一定是因为答案错,可能是答案不完整或者格式不好。所以线上反馈要结合人工分析,不能只看数字。
| 评估维度 | 核心指标 | 评估方法 | 迭代优先级 |
|---|---|---|---|
| 检索质量 | 召回率、MRR | 标注数据+模型辅助 | 最高 |
| 重排序质量 | NDCG | 标注数据 | 高 |
| 生成质量 | 忠实度、幻觉率 | 模型裁判+人工抽检 | 最高 |
| 用户体验 | 有用率、点击率 | 线上反馈 | 中 |
8. 面试里怎么把6连问答出“经验感”
面试官问RAG,不是想听你背定义,而是想判断你有没有真正调过系统。所以回答的时候,不要只给结论,要给“我试过什么、发现什么、怎么改的”。
比如问“切分怎么选”,不要只说“用递归切分”,要说“我试过固定切分,发现召回的材料经常断头断尾,后来换成递归切分,按标题层级切,召回质量明显提升,但切分长度从512降到384之后,检索精度又涨了一截”。这样面试官就知道你真正跑过评估。
再比如问“重排序有用吗”,不要只说“有用”,要说“我试过不加重排序,Top 5里经常只有2到3个相关,加了交叉编码器重排序之后,Top 5里相关文档能到4个以上,但延迟从200毫秒涨到了500毫秒,后来换了个蒸馏过的小模型,延迟回到300毫秒,精度只掉了不到一个点”。这种带数据的回答,比任何理论都有说服力。
还有一个技巧:主动提坑。面试官如果问“RAG有什么坑”,你可以说“最大的坑是检索和生成之间的信息损失。检索阶段召回的相关文档,在拼接上下文时可能因为截断或者顺序问题,被模型忽略了。我遇到过检索Top 1的文档,在生成时完全没被用上,后来发现是因为它被放在了上下文中间,模型注意力不够。把最相关的放两头之后,这个问题就解决了”。这种细节,只有真正调过系统的人才知道。
最后,如果面试官问“你怎么评估RAG”,不要只说“用召回率和准确率”,要说“我分两段评估,检索段看召回率和MRR,生成段看忠实度和幻觉率。评估集是我自己构造的,覆盖了简单查询、多跳查询和否定查询。每次改动只动一个变量,跑一轮评估看指标变化。线上还会收集用户反馈,但反馈要结合人工分析,不能只看数字”。这样回答,面试官基本就能判断你是有实战经验的。
RAG这个方向,理论不难,难的是工程细节。面试里的6连问,本质上是在考你有没有把这些细节串起来。希望这篇内容能帮你把这条链理清楚,不管是面试还是实际项目,都能直接用上。