先说个结论:这两年大模型面试里,但凡带“RAG”字样的岗位,召回策略几乎是被问得最密集的环节。原因很简单——生成端现在各家差距在缩小,反而是召回端决定了整个系统的效果上限。我面试过不少候选人,简历上写着“熟悉RAG”,但一问到召回细节就露馅了,比如“为什么用混合检索而不是纯向量”“重排到底解决什么问题”“召回路怎么设计才能保证指标和体验都过关”,能答到点子上的人非常少。
这篇文章不搞理论堆砌,我用实际做项目踩坑的视角,把召回策略从原理到落地一条线捋清楚。内容覆盖面试高频考察点,也覆盖真正干活时用得上的参数、流程和话术,收藏这一篇,够用了。
1. 召回在RAG里的真实位置:不只是“搜一下”
很多人理解RAG就是“向量检索+拼Prompt”,但这个理解在大厂实际系统里会死得很惨。面试官真正想确认的是:你有没有把召回当成一个策略系统来思考,而不是一个孤立的检索调用。
1.1 为什么召回决定了RAG的天花板
生成端再强,能用的信息上限就是召回回来的那几段文本。如果召回的片段本身就错了、缺了、或者上下文被切得七零八落,后面的Prompt拼接、答案生成全是在错误地基上盖楼。
我常用一个类比:召回相当于给大模型“配眼镜”。眼镜度数不对,后面看什么都模糊。你在面试里如果能主动说出“召回决定了系统的上限,生成只是尽可能逼近这个上限”,这句话本身就能让面试官对你高看一眼。
1.2 召回策略的四个层次
在实际项目中,我把召回策略拆成四个层次来设计:
- 检索源层:数据存在哪里,怎么划分、怎么建索引。这层解决的是“能搜到什么”的问题。
- 召回触发层:用什么方式把候选内容捞出来——向量、关键词、知识图谱、SQL,还是组合。这层解决的是“怎么搜出来”的问题。
- 排序融合层:多路召回结果怎么做合并、去重、重排。这层解决的是“哪个结果该排前面”的问题。
- 阈值与截断层:到底留多少结果给生成端,怎么避免噪音。这层解决的是“喂什么给模型”的问题。
大多数候选人能讲到第二层就已经不错了,但能把第三、第四层讲清楚的人,才是真正做过系统的人。面试官一般会在你提到重排、阈值、相关性截断这些词的时候眼睛发亮。
1.3 面试中召回问题的考察本质
面试官不会直接问“召回策略是什么”,而是会从场景切入。比如“如果你的知识库里有1000万文档,用户问了一个很口语化的问题,你会怎么召回”——这背后藏着的考察点其实是:你有没有处理过查询多样性、数据规模、延迟约束这些真实工程约束。
我建议面试时别急着给方案,先反问两个问题:一是候选文档的粒度和格式是什么,二是对延迟的容忍度是多少。就这两个问题,能区分出你是背题还是真正做过系统。
2. 召回策略的核心链路拆解
一套能落地的召回系统,核心链路绕不开三块:索引构建、召回触发、结果融合。下面我按实际落地顺序拆开讲。
2.1 索引构建:被绝大多数人忽略的起点
面试里很多人一上来就讲Embedding模型选型,但真正的老手会先讲索引。因为索引的粒度直接决定了召回的上限。
文档切分策略是我第一个踩坑的地方。早期做项目时直接用固定长度切分,比如512个字符一刀切,结果大量语义完整的段落被拦腰截断,召回回来的片段经常“前言不搭后语”。后来改成结构感知切分——按Markdown标题、段落、列表等结构边界来切,效果立竿见影。
切分长度也没有统一答案,需要根据Embedding模型的编码上限来定。常见的做法是:Embedding模型如果支持512个token,那切分块大小就控制在300~400个token之间,保留一定重叠(比如50~100个token),这样能尽量避免关键信息刚好被切在边界上。
2.2 混合检索:为什么纯向量不够用
纯向量检索的问题在于:向量表达的是“语义近似”,而不是“精确匹配”。用户问了一个包含精确产品编号、型号、人名的问题时,向量检索往往给出看似相关、实则不精确的结果。
举个实际例子:用户问“A100显卡在FP16精度下的显存占用和性能表现”,如果把这个问题直接embedding去检索,可能会召回一堆讨论A100架构的泛泛内容,而文档里那句精确写了“FP16下显存占用40GB”的关键信息反而排在很后面。
这时候就需要稀疏检索兜底——用BM25或者干脆直接做词法匹配,把包含“A100”“FP16”“40GB”这些精确词条的文档强制提上来。这就是混合检索的价值:语义找泛、词法找精。
我目前用下来比较稳的混合方式是:
- 向量检索(比如用BGE或OpenAI的Embedding模型)负责召回语义相关的Top 100。
- BM25关键词检索负责召回精确匹配的Top 100。
- 两条路的结果合并,再做去重和重排。
2.3 重排序:最终效果的分水岭
很多RAG Demo系统只做到混合检索合并就停了,直接取Top 5喂给大模型。真实项目里这一步会非常不稳定,因为向量检索和BM25各自返回的Top结果里都混着不少噪音。
重排环节解决的就是这个问题:用更强的模型对融合后的候选集做一次精细打分。我常用的方案是Cross-Encoder——把查询和每个候选文档拼成一个句子对,一起送入模型,输出相关性得分。这个方案比Embedding模型的双塔结构更准,因为模型能充分交互地理解查询和文档之间的关系。
重排模型的选择上,直接找一个开源的相关性重排模型,比如BGE-reranker系列,或者在Annotation数据集上微调一个更贴合自身业务场景的模型。如果对实时性要求高,也可以用更轻量的模型,但效果会打折扣。一般重排的候选量控制在50~200条以内,太少会丢召回,太多延迟扛不住。
2.4 查询改写:让“烂问题”也能被召回
真实用户的问题往往非常口语化,还带着指代和省略。举个Case:用户第一轮问“你们支持哪些数据库”,系统回答后用户紧接着说“那他们支持分布式吗”——这里的“他们”指代的是上一轮提到的数据库。如果不做指代消解,直接拿“他们支持分布式吗”去召回,效果可想而知。
查询改写是召回链路里容易被忽略、但性价比很高的一环。常用手段包括:
- 指代消解:把“他们”“这个功能”“那款产品”替换成具体实体。
- 查询扩展:把简短的查询扩展成更完整的表述,比如“RAG优化”可以扩展成“RAG检索优化的方法与策略”。
- 多轮改写:结合对话历史,把当前问题补全成一个独立可检索的问题。
我用过两种实现方式:一是用大模型做改写,效果最好但延迟成本高;二是用规则+小模型做消解,速度快但覆盖有限。通常的做法是把两者结合:先规则快速处理,遇到置信度低的再调用大模型。
3. 实操落地:从零搭一套可用的召回系统
理论讲再多,不如把一套真实可跑的流程走一遍。这里我分享一个可以直接参考的项目级落地路径,从数据准备到性能调优全流程覆盖。
3.1 数据准备与切分实操
第一步是收集文档并做清洗。需要去掉页眉页脚、重复内容、乱码字符,最好统一转成Markdown或纯文本格式,避免后续处理时被格式问题干扰。
第二步是切分。我通常用递归字符切分和结构感知切分结合的方式:
- 先用结构信息定位大块边界,比如标题、列表、表格。
- 再对每个大块内做字符切分,超过上限的继续递归切。
- 最终切分完的块需要满足两个条件:语义完整、长度可控。
切分完可以做一个快速抽查——找出包含关键实体但被切到边界附近的块,看有没有出现语义断档。如果频繁出现“A100显卡支持的精度包括FP16”被切成“A100显卡支持的精度包”和“括FP16”这种情况,说明切分还需要优化。
3.2 索引构建与检索服务
索引构建阶段,我推荐用向量数据库来管理。目前主流的方案都有很成熟的API,直接把切分好的文档块写入集合,指定Embedding模型,系统会自动完成向量化。
关键的几个参数:
- Embedding维度:取决于所用模型,常见的有768、1024、1536等,在创建集合时就固定下来,后面不好改。
- 相似度度量方式:绝大多数场景用余弦相似度,少数场景用内积或欧氏距离。
- 索引类型:数据量小用暴力检索(FLAT)精度最高;数据量大用HNSW,但需要调
M和ef_construction参数来平衡精度与内存。
检索服务的实现上,核心是把混合检索封装成一个统一接口。接收查询后,并行发起向量检索和BM25检索,拿到结果后进融合模块。这个服务要设计好超时控制和降级策略——比如向量检索超时了,先用BM25结果顶上,保证核心链路不断。
3.3 融合与重排细节
融合模块的核心任务是合并多路召回结果。我的做法分三步:
- 归一化分数:向量检索和BM25的分数分布差异很大,不能直接相加,需要各自做归一化(比如Min-Max或Rank-based归一化)。
- 去重:两路结果会召回同一个文档,需要按文档ID去重,保留分数较高的一路。
- 重排打分:将去重后的候选文档逐条和查询拼成句子对,送入重排序模型算出相关性得分,再按新得分排序。
重排后的Top K数量一般取3~10条。取太少,信息可能不足;取太多,会引入噪音且浪费生成端的上下文空间。我常用的是Top 5,上下文比较充裕时会放宽到Top 8。
3.4 一个完整的召回链路参数参考
以下是我在某个知识库问答项目中实际用过的配置,可以直接当初始模板参考:
| 模块 | 参数 | 参考配置 |
|---|---|---|
| 切分 | 切分块大小 | 400 token |
| 切分 | 重叠长度 | 80 token |
| 嵌入 | Embedding模型 | 支持512 token编码的通用Embedding模型 |
| 向量检索 | 召回数量 | 100条 |
| 稀疏检索 | BM25召回数量 | 100条 |
| 融合 | 归一化方式 | 排名位置加权融合 |
| 重排 | 重排候选数量 | 200条以内 |
| 重排 | 最终保留 | 5~8条 |
| 生成 | 上下文窗口 | 3000~4000 token |
这个配置适合中等规模(50万~100万文档)的知识库,延迟控制在300~500毫秒以内。规模更大或对延迟更敏感,需要考虑引入粗排+精排两级架构,以及更激进的截断策略。
4. 召回效果的评估与调优
“效果好不好”是面试和实际项目里逃不掉的问题。但很多人的评估方式非常粗糙——肉眼看了几个case就说“还行”。在真正做系统时,评估需要分层、量化。
4.1 离线指标怎么设计
离线阶段建议构建一个带标注的小规模测试集,至少包含100~200条“问题-相关文档ID”的对应关系。指标上重点看:
- Recall@K:前K条召回结果中,相关文档被召回的覆盖率。
- Precision@K:前K条结果中,真正相关文档的占比。
- MRR(倒数排名):第一个相关文档出现在第几位的倒数,衡量“排在最前面的结果质量”。
混合检索、切分策略、重排模型——每一个环节的改动,都在这些指标上做A/B对比。没有指标支撑的调优都是情绪化调优,记住这句。
4.2 在线指标怎么设计
离线指标不能完全代表线上体验,因为用户实际问题分布和测试集有偏差。在线层面我会额外关注:
- 用户反馈率:用户对回答点了“有帮助”或“无帮助”的比例。
- 二次检索率:用户对回答不满意,重新提问或主动修改问题的比例。
- 任务完成率:在工具调用类RAG场景里,用户能否在一次交互中完成目标任务。
在线效果和离线指标之间经常存在不一致,比如离线Recall很高但线上用户就是不买账——这时要去看是不是召回了相关内容但排序不对,把关键信息压到了后面,或者相关文档确实召回了但文档本身质量太差。
4.3 召回失败的归因与优化
遇到召回效果差时,别急着换模型。我总结出一套归因排查顺序:
- 先看索引粒度:是不是切分把关键段落截断了?
- 再看召回通道:纯向量漏召回,还是BM25漏召回?分别看两路单独的Top 10结果就能定位。
- 然后看融合逻辑:是不是某一路分数被异常拉高,导致另一路的结果被挤掉?
- 最后看重排模型:是不是Cross-Encoder对业务术语不够敏感?
排查顺序非常重要。很多同事一上来就换Embedding模型,折腾一个礼拜,最后发现是切分粒度的问题,前三天就能定位到。
5. 大厂面试高频问题与应对框架
这一节直接上干货。我梳理了几个大厂面试中反复出现的召回相关问题,并给出回答思路,而不是标准答案——因为面试官厌烦背答案的候选人,但欣赏有框架的思考者。
5.1 “你的RAG系统召回效果差,怎么排查?”
这个问题的考察核心是归因能力。我建议按上面第四节说的顺序回答:索引→通道→融合→重排。每一步都给出具体的验证方法,比如“我会先随机抽20个bad case,看相关文档是否在切分时被破坏;如果没有,再单独看两路检索的召回结果……”
面试官会追问:“那你怎么判断是切分问题,而不是Embedding模型问题?”这时候要答出区分方法——把同一个查询用不同切分方式各跑一遍,如果结果差异大,说明问题在切分;如果结果都差且相似,说明问题在模型。
5.2 “混合检索的两路分数怎么合并?”
这是个非常工程化的细节问题。上面提到了归一化,但面试官还会追问“归一化之后直接加吗?”这时可以回答:直接加权求和是最简单的baseline,但实际更推荐用排名位置加权或学习排序的方式。比如把“向量检索的第1名”和“BM25的第1名”按排名位置赋予权重,再用动态调权的方式合并。
能说出来“直接用分数相加有分数分布偏差的问题,所以我会先做归一化再考虑权重”这句话,面试官就知道你真做过混合检索。
5.3 “重排模型的候选集选多少?为什么不是全部的召回结果?”
这个问题考察对成本和效果的权衡理解。重排模型是Cross-Encoder,虽然效果更好,但计算成本远高于双塔检索。如果候选集太大,比如几千条,延迟会爆炸。
所以实际设计是:向量检索和BM25先把候选从全量文档冲刷到200条以内,重排模型只在这200条里做精细排序。这是一种漏斗式的由粗到精设计——先用廉价方式圈定候选范围,再用昂贵方式精准排序。
5.4 “长文档、多模态文档的召回怎么做?”
长文档的处理核心是切分和层次检索。我的做法是两层结构:第一层对文档做摘要或者元数据检索,定位到文档级别;第二层在命中的文档内部做段落级检索。这样既避免了把整篇长文档一次性embedding导致超限的问题,也提升了定位精度。
多模态文档的常规思路是:对文档里的图片做OCR、对音频做转写,把非文本内容转录成文本后再走标准召回链路。如果面试官追问“OCR精度不高怎么办”,可以回答引入视觉语言模型做图文联合理解——这个问题能答到这一层,基本就是加分项了。
6. 从“能用”到“好用”:召回优化的进阶路线
基础链路搭建完成后,召回策略还有很长一段优化空间。这里的每一步都能作为面试时展示深度的话题。
6.1 精排前加粗排:应对超大候选集
当文档规模到了千万级别,召回出来的候选可能就有几百上千条,直接全量重排会非常吃力。我的做法是在向量检索和重排之间加一道粗排:用更轻量的模型(比如双塔模型余弦相似度加一些手工特征)把候选从1000条压到100条,再做精排。这样精度损失很小,但延迟和算力节省非常明显。
6.2 查询侧的Embedding优化
对查询做改写之后再进行向量化,效果通常比直接用原始查询好。这是“查询理解”层面的优化。大厂里这个模块可以独立成一个服务,专门负责query的纠错、改写、扩展、指代消解,再转发给检索引擎。
对这个方向有兴趣的话,可以重点研究一下如何利用大模型做意图识别与query结构化,这一块面试里讲出来会非常加分。
6.3 用小样本反馈数据迭代重排模型
无监督的Embedding检索只能做到“差不多”,要做到“懂业务”,必须让重排模型学习业务反馈数据。比如用户标记过“这个回答有用”,那对应的文档和问题就是正样本;标记过“没用”,就是负样本。
我试过的做法是:定期从线上日志里捞反馈数据,构造“问题-文档-相关性”训练集,在通用重排模型上做增量微调。只需要几千条高质量标注,效果就能有明显提升。这个操作在面试里作为“落地细节”讲出来,比背十个模型名都管用。
6.4 多路召回扩展
除了向量和BM25,实际系统里还可以增加其他召回通道:
- 知识图谱召回:实体关联查询,适合“谁和谁什么关系”这类问题。
- SQL/Tag召回:结构化筛选,适合“近30天创建的文档”这类带条件的问题。
- 向量聚类召回:对历史高频问题做聚类,相似query直接匹配历史最优结果。
多路召回会让融合层变复杂,但效果提升往往值得。面试里提到“我在某个细分场景加了知识图谱召回”,会立刻和那些只做过Demo的候选人拉开差距。
7. 我对召回策略设计的一些经验体会
文章的最后,分享几个我在实际项目中反复验证过的体会,希望能帮你在面试或落地时少走弯路。
第一个体会是:召回策略没有银弹,全是取舍。别追求模型最强、参数最优,要在效果、成本、延迟之间找平衡点。面试里如果能主动说出“我选择了XX方案,因为在这个场景下延迟比精度更敏感”,这比大谈SOTA模型更让面试官信服。
第二个体会是:召回效果差,先去质疑数据,再质疑模型。我调过太多所谓的“模型效果问题”,最后发现都是切分不合理、文档本身有错误、或者Embedding模型遇到了没见过的专有名词。数据质量永远是第一位的。
第三个体会是:可观测性必须前置设计。从第一天就要把每条查询召回结果单独记录,带上耗时和分数明细。出了bad case才能快速归因,否则调优全靠猜。
第四个体会是:做RAG召回,永远要把“生成端需要什么”放在心上。召回不是把相关的东西堆给大模型就结束了。大模型需要的不是尽可能多的相关文本,而是把完整、不重复、有逻辑关联的信息,按合理的顺序排列好。多想想生成的上下文窗口有限,你需要的是最优的信息组合,而不是最多的信息堆砌。
我自己每次调召回策略时,心里都在重复一句话:让对的信息,在对的时间,以对的形式,出现在生成模型面前。这句话也送给你。