这道题,我觉得面试官真正想问的是:在工业级系统里,你怎么在效果和效率之间做取舍。相关性计算不是选一个模型跑分就完事,它是一套级联流水线,不同阶段用不同方法,各有适用边界。
先说关键词匹配。别看现在大模型火,[[BM25]] 依然是工业界召回阶段的标配,没有之一。它的核心思想很简单:词频不是越高越好,增长有饱和,用参数 k1 控制;文档越长不一定越相关,用 b 做长度归一化;罕见词比常见词更有区分度,用 IDF 加权。公式我就不背了,但它的好处是确定性强、可解释、延迟极低。在客服退款场景里,用户问“退款多久到账”,BM25 能准确命中“退款到账时间”这个文档,因为它对“退款”和“到账”这种关键词非常敏感。但局限也很明显:词汇鸿沟,用户说“苹果”是水果还是手机,BM25 分不清;而且它完全基于字面匹配,语义上“退货”和“退款”相近,它就不行。
所以有了语义匹配,也就是 稠密向量检索。[[双塔]]架构,查询和文档分别编码成向量,用 [[ANN]] 近似最近邻检索。这个方法的优势是能跨越词汇鸿沟,把“我想投诉”和“对服务不满”映射到相近的向量空间。在商家满减政策检索里,用户问“凑单怎么优惠”,语义上能和“满300减50”这种文档匹配上,BM25 可能就漏了。但双塔有个大坑:离线建索引快,在线检索也快,但训练和调优成本高,而且对长尾 query 效果不稳定。如果训练数据覆盖不全,比如新出的促销活动,向量召回可能直接跑偏。所以工业界通常不会只用向量,而是 [[混合检索]],BM25 和向量两条路都走,结果合并或加权,保证召回率高。
再精排阶段,用深度学习模型做交互式匹配。最典型的就是 [[Cross-Encoder]],把查询和文档拼成 [CLS] query [SEP] doc [SEP] 输入 BERT,取 [CLS] 输出过 MLP 得到相关性分数。效果最好,但计算代价极大,没法对全量文档做,只能对召回的 top-K [[重排]]。在订单异常检索场景,比如用户问“我付了款但订单显示未支付”,精排模型能理解“付了款”和“未支付”的矛盾关系,把最相关的客服话术排到前面。但要注意,如果召回的 top-K 里没有正确答案,精排再强也没用。所以上线我会特别关注召回阶段的 Recall@K,如果 K 不够大,精排就是空转。
最后说落地风险和前提。混合检索是常态,但混合不是简单拼凑,要处理分数归一化、延迟叠加、一致性等问题。比如 BM25 和向量分数怎么合并?我倾向用加权求和或级联,先向量粗筛再用 BM25 精调。另一个风险是 索引更新延迟:知识库文档有新增或修改,向量索引不能实时更新,如果用户刚上传了新政策,但索引还是旧的,召回就会漏。我会用双索引机制,base 索引定期重建,delta 索引增量插入,查询时合并,再用版本号做一致性校验。
还有一个延伸点值得注意:现在有些方案尝试用 [[ColBERT]] 这种延迟交互模型,在召回阶段做 token 级相似度,效果接近 Cross-Encoder 但速度快很多。不过它的索引存储量很大,对资源有要求。
所以整体上,我会把相关性计算看成一套流水线,关键词召回兜底,语义召回扩量,精排提精,每一步都有明确的适用边界和风险点。没有银弹,只有 trade-off。