1. 为什么RAG成了面试里的"必考题"
这两年但凡跟大模型沾边的岗位,面试里不聊几句RAG,面试官自己都觉得这轮没问到位。我前阵子帮几个朋友做模拟面试,发现一个很普遍的现象:简历上写着"熟悉RAG",一问细节就开始背概念——"检索增强生成就是把外部知识库接进大模型"。这句话没错,但它等于什么都没说。面试官真正想听的,是你有没有亲手搭过、调过、被坑过。
RAG(Retrieval-Augmented Generation,检索增强生成)本质上解决的是一个很朴素的问题:大模型的参数里存的是训练时见过的知识,训练截止之后的事它不知道,你公司内部的文档它更不知道。硬要它回答,它就会一本正经地编。RAG的思路是,在模型开口之前,先去一个外部知识库里把相关资料捞出来,塞进上下文,让模型"看着材料答题"。听起来简单,但真正落地时,从文档切分到检索排序再到生成,每一步都有大量可以深挖的细节,而这些细节恰恰是面试官区分"用过"和"懂"的分水岭。
这篇内容我打算把RAG面试里最高频的六个问题拆开讲透,不是给你标准答案让你背,而是把每个问题背后的原理、常见的坑、以及我实际调优时的思路都摊开。适合正在准备大模型相关岗位面试的人,也适合已经上手做RAG项目但总觉得效果差一口气的开发者。读完你应该能明白:面试官问这个问题时,他到底在考察什么,以及你该怎么答才能显出真功夫。
2. 第一问:RAG到底解决了大模型的哪些硬伤
2.1 知识时效性与私有知识的双重困境
大模型有三个绕不开的硬伤,RAG分别对应解决。第一个是知识时效性。模型的训练数据有截止日期,截止日期之后发生的事情它一概不知。你问它某个上个月刚发布的产品参数,它要么说不知道,要么编一个。第二个是私有知识缺失。公司内部的规章制度、项目文档、客户资料,这些从来没进过训练集,模型不可能知道。第三个是幻觉问题。模型在不确定的时候倾向于"编一个看起来合理的答案",而不是承认自己不知道。
RAG对这三个问题的处理逻辑是不一样的。对时效性和私有知识,RAG是"补料"——把最新、最相关的资料检索出来喂给模型。对幻觉,RAG是"约束"——让模型的回答有据可依,理论上它应该基于检索到的内容作答,而不是凭空发挥。但这里有个关键认知:RAG并不能完全消除幻觉。如果检索回来的内容本身就是错的,或者模型没有严格遵循检索内容,幻觉照样会出现。面试时如果你能主动点出这一点,面试官会觉得你是有实战经验的。
我见过不少候选人把RAG说成"万能药",这其实是个减分项。成熟的从业者应该清楚每个方案的边界。RAG擅长的是开放域问答、知识库问答、文档摘要这类场景,但它不擅长需要复杂推理、多步计算的任务——那些任务检索回来的资料再多,模型也未必能正确推理。
2.2 和微调相比,RAG的取舍在哪里
面试里经常跟着问一句:"那你为什么不直接微调模型?"这个问题考的是你对两种方案的理解深度。微调是把新知识"写进"模型参数里,RAG是把新知识"放在"模型外面。两者的核心差异可以用一张表说清楚。
| 对比维度 | 微调(Fine-tuning) | RAG |
|---|---|---|
| 知识更新成本 | 高,每次更新都要重新训练 | 低,改知识库即可 |
| 知识可溯源 | 难,模型说不清知识来源 | 易,能给出引用出处 |
| 训练数据需求 | 需要大量高质量标注数据 | 只需文档本身 |
| 推理成本 | 低,一次前向传播 | 较高,多了检索环节 |
| 适合场景 | 固定领域的风格、格式对齐 | 知识频繁更新、需要溯源 |
实际项目里,这两者往往不是二选一,而是配合使用。比如用微调让模型学会某个领域的回答风格和格式,用RAG给它补充实时知识。面试时能说出"看场景组合使用",比单纯说"RAG更好"要加分得多。我个人的经验是,如果知识更新频率高于每月一次,优先考虑RAG;如果是要模型学会一种特定的输出格式或语气,微调更合适。
2.3 一个容易被忽略的边界:RAG不解决推理能力
有个坑我踩过:曾经有个需求是让系统根据多份合同条款做逻辑推理,判断某个行为是否违约。我一开始想用RAG把相关条款检索出来让模型判断,结果发现模型经常把条款张冠李戴。后来才想明白,RAG解决的是"知识获取",不解决"逻辑推理"。检索回来的条款再多,如果模型本身的推理能力不够,或者条款之间的逻辑关系太复杂,它照样会出错。
所以面试时如果被问到"RAG的局限性",你可以从这几个角度答:检索质量依赖文档质量、对复杂推理帮助有限、上下文长度限制了能塞进去的资料量、检索和生成之间存在语义鸿沟。能说出这些,说明你不是只看了几篇入门文章。
3. 第二问:文档切分这件事,为什么比想象中难
3.1 切分粒度直接决定检索质量
很多人以为文档切分就是"按固定字数切",这是最粗糙的做法,也是效果最差的做法之一。切分粒度是个需要反复权衡的参数:切得太碎,每个片段信息不完整,检索出来答非所问;切得太粗,一个片段里混了好几个主题,检索时噪声大,还会浪费宝贵的上下文窗口。
我一般会先看文档类型再定策略。技术文档、法律合同这类结构清晰的,优先按标题层级切,一个二级标题下的内容作为一个块;聊天记录、访谈稿这类口语化的,按对话轮次或语义段落切;纯叙述性的长文,才考虑按固定长度加重叠窗口切。所谓重叠窗口,就是相邻两个块之间保留一部分重复内容,防止一个完整的语义被硬生生切断。常见的重叠比例是块大小的10%到20%。
这里有个经验值可以参考:块大小在256到512个token之间,对大多数问答场景比较友好。但这绝不是铁律,我做过一个客服问答的项目,块大小调到128效果反而更好,因为用户的问题通常很短,小块检索更精准。所以块大小必须结合你的查询特点来调,不能照搬别人的参数。
3.2 语义切分与结构切分的取舍
固定长度切分最大的问题是"断章取义"。比如一句话被从中间切开,前半句在块A,后半句在块B,检索时两个块单独看都不完整。为了解决这个问题,出现了语义切分——用模型判断句子之间的语义相似度,在语义转折的地方切。还有一种更实用的做法是结构切分,利用文档本身的Markdown标题、段落、列表等结构来切。
我的实际选择是:能用结构切分就用结构切分,因为快、稳、可解释。语义切分虽然理论上更优,但计算成本高,而且模型判断语义边界本身也可能出错。一个折中方案是"结构优先,语义兜底"——先按标题切,如果某个标题下的内容过长,再对这个长块做语义切分。
提示:切分时一定要保留每个块的元数据,比如它来自哪个文档、哪个章节、原文位置。这些元数据在后续做引用溯源和结果过滤时非常有用,很多人一开始不存,后面想加就得重新处理整个知识库。
3.3 特殊内容的处理:表格、代码、图片
真实文档里不只有纯文本。表格、代码块、图片这些特殊内容,如果处理不好,检索质量会大打折扣。表格我一般会转成Markdown格式保留结构,或者用一句话概括表格内容作为该块的摘要。代码块要保留语言标识和缩进,否则检索出来模型看不懂。图片目前主流做法是用多模态模型生成图片描述,把描述文本作为检索对象。
这里有个细节:表格如果太大,切成多个块会破坏行列对应关系。我的做法是给表格的每个块都加上表头信息,这样即使被切开,模型也能知道每一列代表什么。这个技巧在财务报表、参数对比表这类场景里特别管用。
4. 第三问:向量检索和关键词检索,到底该用哪个
4.1 两种检索方式的本质差异
向量检索(也叫语义检索)是把文本转成高维向量,通过计算向量之间的余弦相似度来找相关内容。它的优势是能理解语义——你搜"怎么退款",它能找到写着"如何申请退货"的文档,即使字面不一样。关键词检索(比如BM25)是靠词频和逆文档频率打分,优势是精确匹配——你搜一个产品型号"X200",它能精准找到包含这个型号的文档,而向量检索可能会把"X200"和"X300"混在一起。
这两种方式各有盲区。向量检索对专有名词、数字、代码这类精确信息不敏感,因为embedding模型在训练时可能没见过这些词,或者把它们映射到了相近的语义空间。关键词检索则对同义词、换一种说法无能为力。所以面试时如果被问"用哪种",标准答案不是二选一,而是混合检索。
4.2 混合检索的融合策略
混合检索的核心是把两种检索的结果融合起来。最简单的做法是加权求和,给向量检索和关键词检索各分配一个权重,比如0.7和0.3。但权重怎么定是个问题,不同查询类型最优权重不一样。更优雅的做法是倒数排名融合(RRF),它不依赖具体分数,只看排名,把两个结果列表里每个文档的排名取倒数再相加,排名越靠前得分越高。
RRF的好处是不用归一化分数,因为向量相似度和BM25分数量纲完全不同,直接加权很容易出问题。我实测下来,RRF在大多数场景下比简单加权更稳,尤其是当两种检索的分数分布差异很大时。下面是一个RRF的简化实现思路:
def rrf_fusion(vector_results, keyword_results, k=60): scores = {} for rank, doc_id in enumerate(vector_results): scores[doc_id] = scores.get(doc_id, 0) + 1 / (k + rank + 1) for rank, doc_id in enumerate(keyword_results): scores[doc_id] = scores.get(doc_id, 0) + 1 / (k + rank + 1) return sorted(scores.items(), key=lambda x: x[1], reverse=True)这里的k是个平滑参数,通常取60,作用是降低高排名文档的绝对优势,让融合更平滑。这个参数不用太纠结,60是论文里的经验值,实际调优空间不大。
4.3 什么时候该放弃向量检索
虽然向量检索是RAG的主流,但有些场景它真的不合适。比如法律条文检索,用户搜"劳动合同法第三十九条",向量检索很可能找不准,因为条文编号这种精确信息embedding表达不好。再比如代码检索,用户搜一个函数名,关键词检索几乎完胜。所以我的建议是:先分析你的查询类型分布,如果精确查询占比高,关键词检索的权重就要调高,甚至可以考虑只用关键词检索加规则过滤。
面试时如果能结合具体场景说"我会先看查询日志,统计精确查询和语义查询的比例,再决定检索策略",这比背概念强太多。
5. 第四问:检索回来的内容,怎么排序和筛选
6.1 粗排之后为什么还要精排
检索阶段(无论是向量还是关键词)通常叫"粗排",它追求的是快,从海量文档里快速筛出几十上百个候选。但粗排的精度有限,直接把这几十个塞给模型,噪声太大。所以需要一个"精排"环节,用更复杂的模型对这几十个候选重新打分排序。
精排模型(也叫Reranker)通常是交叉编码器(Cross-Encoder),它把查询和文档拼在一起输入模型,输出一个相关性分数。和向量检索用的双编码器(Bi-Encoder)相比,交叉编码器能捕捉查询和文档之间的细粒度交互,精度更高,但速度慢,所以只能用在候选集较小的精排阶段。这个"粗排召回、精排排序"的两阶段架构,是RAG里非常经典的设计,面试时能讲清楚这个架构的来龙去脉,基本就过关了。
6.2 上下文压缩:把噪声挤出去
精排之后还有一个常被忽略的环节:上下文压缩。检索回来的文档块里,可能只有一两句话和问题相关,其余都是噪声。如果整块塞给模型,既浪费上下文窗口,又可能干扰模型判断。上下文压缩的思路是用模型判断块里哪些句子真正相关,只保留相关部分。
实现方式有两种:一种是抽取式,直接删掉不相关的句子;一种是生成式,用模型把相关内容改写成更精炼的表述。抽取式更安全,不会引入新信息;生成式更简洁,但有改写失真的风险。我一般优先用抽取式,只有在块特别长、噪声特别多的时候才考虑生成式。
6.3 一个实战中的排序陷阱
这里分享一个我踩过的坑。有段时间我发现检索结果里,一些明显不相关的文档总是排在前列。排查后发现,是因为这些文档特别长,包含的关键词多,在BM25里得分虚高。解决办法是给BM25加长度归一化,或者干脆在精排阶段用交叉编码器把长文档的虚高分数压下去。
另一个坑是"位置偏差"。有些embedding模型对文档开头的内容更敏感,导致块开头的句子权重过高。如果你的文档块是固定长度切的,块开头可能正好是上一段的结尾,语义不完整,就会误导检索。解决办法是切分时保证块开头是完整句子,或者在块前面加上所属章节的标题作为上下文。
6. 第五问:生成阶段怎么让模型"照着材料说话"
6.1 提示词设计的核心是约束
检索做得再好,如果生成阶段模型不听话,照样白搭。生成阶段的核心是提示词设计,而提示词设计的核心是约束。你要在提示词里明确告诉模型:只根据提供的资料回答,资料里没有的就说不知道,不要自己发挥。这句话听起来简单,但很多人的提示词写得太宽松,模型就会自由发挥。
一个我常用的提示词结构是这样的:先给角色设定(你是一个严谨的问答助手),再给资料(用分隔符包起来),再给约束(只依据资料回答,无法回答时明确说明),最后给问题。分隔符很重要,它能让模型清楚知道哪部分是资料、哪部分是问题,避免混淆。
注意:约束性提示词不是万能的。如果检索回来的资料本身自相矛盾,或者模型判断资料不足以回答,它可能还是会编。所以提示词要和检索质量配合,不能指望提示词解决所有问题。
6.2 引用溯源:让答案可验证
RAG相比纯生成的一大优势是可溯源。你可以在提示词里要求模型在回答时标注引用来源,比如"根据文档A的第三章"。这样用户能验证答案,也能增加信任感。实现上,需要在检索时给每个块带上来源标识,生成时要求模型输出这些标识。
但这里有个现实问题:模型标注的引用不一定准确,它可能张冠李戴。所以更稳妥的做法是,在生成之后用一个单独的步骤做引用校验,检查模型引用的内容是否真的在对应文档里。这个校验可以用简单的字符串匹配,也可以用模型判断。我一般会做一层轻量校验,至少保证引用的文档ID是真实存在的。
6.3 温度参数与回答风格
生成阶段的温度参数(temperature)也值得聊。温度越高,模型输出越随机、越有创造性;温度越低,输出越确定、越保守。RAG场景下,我一般把温度调低,比如0.1到0.3,因为我们要的是准确、忠实的回答,不是创意写作。如果温度太高,模型容易在资料基础上"添油加醋"。
另外,回答的长度也要控制。太短可能信息不全,太长可能夹带私货。我通常会在提示词里限定回答长度,或者要求模型先给结论再给依据,这样即使回答长,用户也能快速抓到重点。
7. 第六问:RAG效果不好,怎么系统性排查
7.1 先定位是检索问题还是生成问题
RAG效果差,第一步不是急着改代码,而是定位问题出在哪个环节。方法很简单:把检索回来的内容单独拿出来看,如果检索结果里根本没有正确答案,那是检索问题;如果检索结果里有正确答案,但模型没答对,那是生成问题。这个二分法能帮你快速缩小排查范围。
我见过很多人一上来就调提示词,结果发现根本是检索没召回正确文档,提示词调出花来也没用。所以排查顺序一定是先检索后生成。
7.2 检索问题的排查清单
如果确定是检索问题,按这个清单逐项排查:
- 文档是否真的在知识库里:有时候文档压根没入库,或者入库时解析失败,内容为空。
- 切分是否合理:正确答案是否被切成了碎片,导致检索不到完整信息。
- embedding模型是否适合你的领域:通用embedding模型在专业领域(如医疗、法律)可能表现不佳,需要考虑领域微调或换模型。
- 查询改写是否必要:用户的问题可能太口语化,和文档表述差异大,需要先做查询改写,把口语化问题转成更接近文档表述的形式。
- 检索数量是否足够:召回数量太少可能漏掉正确答案,太多则引入噪声,需要调优。
7.3 生成问题的排查清单
如果是生成问题,排查方向不同:
- 提示词约束是否够强:模型是否被明确要求只依据资料回答。
- 上下文是否太长:太长的上下文可能导致模型"迷失在中间",忽略关键信息。可以考虑把最相关的资料放在上下文开头或结尾。
- 模型本身能力是否够:有些小模型遵循指令的能力弱,换个更大的模型可能直接解决。
- 是否存在资料冲突:检索回来的多份资料互相矛盾,模型无所适从。
7.4 建立评估体系,别靠感觉调优
最后也是最重要的一点:RAG调优必须建立评估体系,不能靠感觉。你需要一批标注好的问答对,每次改动后跑一遍,看准确率、召回率、忠实度这些指标的变化。没有评估体系,你改了一个参数,感觉变好了,但可能只是这一两个case变好,整体反而变差。
评估指标我一般关注三个:检索的召回率(正确答案有没有被检索到)、答案的准确率(回答对不对)、答案的忠实度(回答是否基于检索内容,没有编造)。这三个指标能覆盖RAG的主要环节。建立评估集一开始费时间,但它是后续所有优化的基础,值得投入。
8. 面试里那些加分与减分的细节
聊完六个核心问题,再补充几个面试现场的观察。加分项通常有这些:能主动说出RAG的局限性、能结合具体项目讲踩坑经历、能说清楚某个参数为什么这么设、能提到评估体系。减分项也很明显:只会背概念、把RAG说成万能、说不出任何实操细节、被追问就卡壳。
我个人的体会是,面试官问RAG,不是要考你背了多少论文,而是想确认你有没有真正动手做过、有没有独立思考。所以准备面试时,与其背标准答案,不如把自己做过的项目从头到尾捋一遍,把每个决策背后的理由想清楚。哪怕项目不大,只要你能讲透其中的取舍和踩坑,就比空谈架构强得多。
还有一个实用建议:面试前可以自己动手搭一个最小可用的RAG系统,哪怕只有几十个文档。亲手跑一遍切分、检索、生成的全流程,你对每个环节的理解会完全不一样。很多面试里能答出彩的细节,都是动手过程中才会遇到的。