滴滴日常后端一面:慢查询与 RAG 检索链路
- 轮次
- 一面
- 结果
- 已挂
- 时间
- 2026-09
- 来源
- 牛客网
《面试题目》
- 介绍百度实习期间的项目:项目结构怎么设计的?这个平台主要面向哪些用户?资产流转和落地怎么实现?项目技术栈怎么选?模型怎么调用的?模型兜底怎么实现?Token 消耗成本怎么管控?
- MySQL 慢查询一般怎么排查?主要看哪些关键字?
- Key 怎么看是否命中索引和数据量?Rows 怎么看单次查询扫描数据量?
- Using Index 和 Using Where 的区别是什么?什么情况会回表?怎么优化?
- 乐观锁怎么实现?version 版本号字段怎么设计?修改前怎么比对版本号?版本号不一致时轮询还是报错?怎么选?
- RAG 检索系统整体流程怎么设计?为什么做三个并行检索模块?规则判断和重排序机制怎么整合结果?
- 用户 Query 怎么做意图改写和分析?内置 Prompt 怎么设计?大模型怎么拆分 Query、明确意图?
- BM25 关键字检索怎么实现?向量检索为什么用 Milvus?意图检索怎么做?
- 多路检索结果怎么汇总去重?大模型怎么给不同算法结果评分?Top5 或 Top10 怎么截取?怎么作为上下文补充给大模型?
- RAG 准确率怎么控制?上线前质量保障方案怎么做?增加检查线程怎么做?怎么对比 System Prompt 上下文和大模型最终回答的偏差?
- 反问:业务、面试流程、是否有转正、对 AI 的看法。
《参考解析》
MySQL 慢查询排查:第一步是确认有慢查询,slow_query_log=ON + long_query_time 配合 pt-query-digest 或 mysqldumpslow 聚合出 Top SQL,也可以直接 SHOW FULL PROCESSLIST 看正在跑的语句。第二步用 EXPLAIN(MySQL 8.0 还可以 EXPLAIN ANALYZE 看真实耗时)读执行计划,重点字段是 type(要避免 ALL 全表扫描,目标是 ref/range/const)、key(实际用的索引,NULL 表示没用索引)、key_len(用到的联合索引前几列)、rows(预估扫描行数,越大越可疑)、filtered(过滤后剩余比例)、Extra(出现 Using filesort、Using temporary 基本就是要优化了)。常见改法:补联合索引并遵守最左前缀、把函数和隐式类型转换从索引列上挪走、用覆盖索引消掉回表、深分页改成游标(WHERE id > ?)或延迟关联、大事务拆小减少锁等待。
Using Index 与 Using Where、回表:Using index 表示查询需要的数据列全在索引里,直接从索引返回,不需要回表,也就是覆盖索引;Using where 表示在存储引擎取到行之后 Server 层还要再做一次过滤,索引没能把条件全部消化掉。InnoDB 的二级索引叶子节点只存索引列和主键值,所以只要查询的列超出了索引覆盖范围,就得拿主键回聚簇索引取整行,这就是回表。优化手段:把 select 的列收窄、建立包含查询列的联合索引做成覆盖索引、用 ORDER BY ... LIMIT 走索引避免排序、必要时用索引条件下推(ICP,Using index condition)在引擎层提前过滤。要注意别盲目加索引——每个索引都会拖慢写入并占空间,联合索引的列顺序按区分度高的在前、等值条件在前、范围条件在后。
乐观锁的 version 设计:典型做法是表上加一列 version INT NOT NULL DEFAULT 0,读出时一并取出,更新时带上旧值做条件并自增:UPDATE t SET ..., version = version + 1 WHERE id = ? AND version = ?,靠受影响行数判断是否成功——返回 0 就说明期间被人改过。列名和类型上,用 BIGINT 更稳(避免长期高频更新导致回绕),也可以直接用 updated_at 时间戳,但并发写在同一毫秒时会失效,所以业务表更推荐独立 version 列。冲突后的处理要看业务语义:抢资源类(抢单、扣库存)直接失败返回、让用户重试更快;协作编辑类(配置、文档)则适合重读-重算-重试的循环重试(限制最大次数加退避),因为用户的修改意图本来就应该叠加而不是丢弃。强一致要求高、冲突概率大的场景应该换成悲观锁(SELECT ... FOR UPDATE)或分布式锁,别硬扛乐观锁的重试成本。
RAG 检索链路设计:完整链路是「Query 理解 → 多路召回 → 融合排序 → 重排 → 上下文组装 → 生成 → 引用与校验」。做三个并行检索模块的常见理由是覆盖不同查询类型:BM25 管关键词精确匹配(型号、专有名词、报错码),向量检索管语义近似(换个说法也能召回),意图/结构化检索管枚举与筛选(时间、部门、指标名)。多路结果汇总不能简单拼起来:先按文档 id 或内容指纹去重(同文档多段命中时保留最高分片段并合并上下文),再做分数归一化(各路的打分尺度不同,需要 min-max 或 RRF 倒数排名融合,RRF 的好处是不依赖分数绝对值),然后交给重排模型(cross-encoder 或大模型打分)精排,最后按 token 预算截断 Top5/Top10 拼进 prompt,并标注来源编号以便生成时引用。准确率控制靠三件事:离线建评测集(问题-标准答案-相关文档)算召回率/命中率/答案正确率;上线前跑回归对比新旧链路;线上加校验环节,比如让模型先给引用再答、用规则检查答案里的数字是否出现在检索上下文里、比对 System Prompt 提供的上下文与最终回答的偏差(无依据的断言就拦下来重答或拒答)。
意图改写与成本兜底:Query 改写的目标是补全上下文(多轮里「它」「这个」指代谁)、拆解复合问题(「A 和 B 对比」拆成两个子查询)、纠正口语与错别字。内置 Prompt 的写法是给模型明确的结构化输出约束(JSON:重写后的 query 列表 + 意图标签 + 需要的过滤条件),并提供 3~5 个 few-shot 覆盖多轮指代、条件筛选、指标口径这几类难例。Token 成本管控则可以分层:简单意图走规则或小模型、命中缓存直接返回、限制上下文长度与最大输出、对同一请求做结果缓存、按用户/租户做配额与限流,以及模型路由——先试便宜模型,失败或质量不达标再升级到强模型作为兜底。