面灵AI→

长鑫存储 Agent 开发实习一面:BM25、双路召回与 Rerank

轮次
一面
时间
2026-10
来源
牛客网

《面试题目》

  1. 说下简历里的 Agent 项目?项目有开源吗?(当场查看了项目的 GitHub 地址和提交记录)
  2. 为什么要写后端 Java 项目?这个后端项目具体做什么的?
  3. 我看你提到 BM25,BM25 的底层原理?
  4. 为什么要做稀疏稠密双路召回?
  5. 为什么要用 Rerank?详细的算法原理了解吗?
  6. Agent 的业务框架了解吗?
  7. 你说的这个比较像平台吧,为什么要多租户?

《参考解析》

BM25 的底层原理:词频饱和 + 文档长度归一化 + IDF。 公式是 score = Σ IDF(qi) · f(qi,D)·(k1+1) / [f(qi,D) + k1·(1 − b + b·|D|/avgdl)],其中 f 是查询词在文档里的出现次数、|D| 是文档长度、avgdl 是平均文档长度。三个要点要讲出来:一是词频不是线性加分——出现 1 次到 2 次收益很大,出现 20 次到 21 次几乎没有收益,所以分子用饱和形式,k1(常用 1.2~2.0)越小饱和越快,它相当于 TF-IDF 里 TF 的「封顶」;二是长文档天然更容易命中查询词,所以用 |D|/avgdl 做惩罚,b(常用 0.75)控制归一化强度,b=0 就是关闭归一化;三是 IDF 用 log((N − n + 0.5)/(n + 0.5)) 这类带平滑的形式给稀有词更高权重,避免出现极端值。还要主动交代它的边界:BM25 是词袋模型,只看词有没有出现、出现几次,不理解语义,同义词、缩写、中英文混写一律匹配不上——这正是后面要配一路向量召回的原因;工程上它落在倒排索引上算,可增量更新、延迟低、可解释,冷启动没有训练成本。

稀疏稠密双路召回是补齐彼此的盲区。 稀疏路(BM25、SPLADE 这类)强在精确匹配:型号、错误码、专有名词、人名,字面命中就是强信号,而且不需要训练、可解释、对低频词友好;稠密路(embedding 向量 + ANN 检索)强在语义改写:用户说「车机连不上网」也能召回「T-Box 网络异常排查」。单用一路都漏:只用向量时,问一个特定编号或错误码常常召回一堆语义相近但没用的片段;只用 BM25 时,口语化提问和文档术语对不上就直接空召回。融合有两种常见做法:分数归一化(min-max 或 z-score)后加权求和,或者 RRF(Σ 1/(k + rank)),后者不依赖两路分数量纲,工程上更稳。几个容易踩的坑:两路各取 Top-K 会让候选集膨胀、把后段精排的成本推高,要控制总候选数;稀疏路必须和索引侧用同一套分词/分析器,否则线上查不到;融合权重可以按查询类型动态调,出现型号、错误码时偏向稀疏路。

Rerank 的算法原理与「为什么要两阶段」。 召回阶段是双塔结构:query 和 doc 各自编码成向量,doc 向量可以离线预计算,线上只做一次向量点积或倒排求交,快但粗——两塔之间没有任何交互,细粒度的词级匹配信息被丢掉了。Rerank 用的是交叉编码器(cross-encoder):把 query 和 doc 拼成一条序列送进同一个模型,token 之间做全交叉注意力,直接输出一个相关性分数,精度比双塔高一个档次,代价是每一对都要跑一次前向、无法预计算,所以只能对召回后的 Top 50~200 做。常见模型是 BGE-reranker 系列、Cohere Rerank、monoT5;训练用「query + 正例 + 难负例」的 pairwise/listwise 目标,难负例的质量决定效果上限。工程取舍要说清楚:Top-K 取多大(K 大召回全但延迟线性上涨)、延迟预算怎么保(ONNX/TensorRT 加速、量化、批处理、截断输入长度)、服务超时要能降级回召回顺序。面试官想听的是这段成本账——用便宜模型把候选从百万级压到百级,再用贵模型精排,是算力与精度的折中,不是模型堆叠。

多租户:为什么 Agent 平台一定要做。 多租户是把同一套系统逻辑隔离给多个组织使用,Agent/RAG 平台逃不掉,原因有三条:数据边界——每个租户的知识库、对话历史、向量集合绝不能串,串一次就是事故;成本与配额——模型调用、存储、QPS 要按租户计量和限流;配置隔离——模型 key、可用工具、提示词模板都要按租户下发。隔离粒度从弱到强是:共享库共享表加 tenant_id、共享库独立 schema、独立库或独立实例,成本与隔离强度同步上升,多数 SaaS 取中间那档。技术落点是「租户身份全程透传」:入口从域名/子域/token 解析出 tenant,往后每一层都带上——向量库用独立 collection 或 metadata 过滤,MySQL 每张业务表都带 tenant_id 并做联合索引(靠 ORM 全局过滤器或行级安全策略强制),缓存 key 加租户前缀,异步任务与日志也要带。常见坑包括某个查询忘了加租户条件导致越权(要靠审计和测试兜)、单租户的大查询把共享资源打满(要按租户限流和配额)、以及把「租户」和「用户」两个层级混用——租户是隔离边界,用户是租户内的身份,权限模型要分层设计。