面灵AI→

虾皮 AI 应用开发一面复盘:从 RAG 链路到工程稳定性

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

《面试题目》

  1. 请做一下自我介绍。
  2. 做 RAG 功能时,你给 AI 提供了什么目标、代码和上下文?
  3. 你如何把 RAG 开发拆成多个任务,并判断每一步已经完成?
  4. AI 第一次产出了哪些错误或不合理设计?你是怎么发现并修正的?
  5. 最终用了哪些测试、评测和数据证明 RAG 项目有效?
  6. 「日均 2.7 万入团用户」的统计时间窗口、去重方式和用户口径是什么?
  7. 「每位新人 0.5 个关注」「75% 回关」这些数字来自实验观测还是估算?
  8. 实验上线后除了曝光、点击和关注转化率,还应观察哪些体验和稳定性护栏?
  9. 消息队列实际测过的单机吞吐、延迟、并发连接数、队列数、消费者数和消息大小分别是多少?
  10. Broker 重启后的恢复耗时是多少?
  11. 你如何通过故障注入验证消息重复投递率和丢失率?
  12. 如果数据还没测量,你会优先建立哪些基线、压测方法和验收标准?
  13. 请完整说明 RAG 从用户输入到答案输出的在线查询链路。
  14. 为什么需要多路召回,不只做向量或向量加全文检索?
  15. 同一个 chunk 被多路召回命中时如何合并和去重?
  16. RRF 的公式是什么?各通道权重如何设置?
  17. 融合分数相同时,如何保证排序稳定和结果确定?
  18. Reranker 超时时返回哪个阶段的结果?怎样标记降级?
  19. RAG 中哪段核心代码是你独立实现的?举一个删除、修复或调整权重的真实例子。
  20. 40 条评测问题怎样分层?31 项测试分别覆盖什么?
  21. 你如何验证检索服务从约 1800 行重构到约 500 行后行为等价?
  22. 你如何构造困难样例、对抗样例和失败样例?
  23. 在两个 AI Agent 实操方向中选择一个,并先写清问题定义、技术设计、接口、约束和测试范围。
  24. 你如何让 AI 实现多路混合检索融合模块,并验证 RRF、去重、标题加分、文档配额和 reranker 超时降级?
  25. 你如何解释 AI 生成的方案和代码,找出确定性、性能、超时传播或数据结构方面的问题并修正?
  26. 不使用递归,手写二叉树的中序遍历。
  27. 反问:团队业务方向、技术栈构成、校招生培养机制是什么?

《参考解析》

RAG 在线链路与多路召回。 完整链路是:query 进来先做改写与扩展(补全指代、纠错、同义扩展),然后并行执行多路召回——向量召回负责语义、BM25 负责专有名词与精确匹配、标题召回提升标题命中、实体召回提升人名地名匹配、时间召回保证时效性;每路各取 Top-20,用 RRF 融合后去重,再做标题加分与文档配额控制(每个文档最多取 3 个 chunk,避免单一文档霸榜),接着 Rerank 精排取 Top-5,最后按「最相关的放开头和结尾」的顺序拼 Context 交给模型生成,生成后做事实核查再输出。为什么不能只做向量:向量对专有名词与型号不敏感,BM25 对同义改写无能为力,两路的失效模式互补;面经里给出的消融数字很直观——只向量是 0.72,加 BM25 到 0.81,加标题 0.85,加实体 0.87,加时间 0.89。多路并行的延迟取决于最慢一路而不是累加,这也是它成本可接受的原因;标题、实体、时间这三路用轻量索引,成本很低。

RRF、去重与排序确定性。 RRF 的公式是 score = Σ w_i / (k + rank_i),k 取 60(k 太小会让头部权重过大、长尾好结果被淹没),权重按通道重要性配置化(示例是向量 0.4、BM25 0.3、标题 0.1、实体 0.1、时间 0.1),并且权重必须来自实验而不是拍脑袋——时间通道从 0.05 调到 0.1 让 NDCG@10 提升 3%,但会让部分长期有效文档排名下滑,最后定在 0.08,这个来回过程恰恰是面试官想听的。去重必须用 chunk_id 而不是内容 hash:同一个 chunk 在不同切块方式下 hash 不同,用 hash 去不掉重复。实现上维护 chunk_id → 融合分数 的映射,逐路累加,最后排序取 Top-K。排序确定性是容易被忽略的工程细节:分数相同时要有次级排序键(chunk_id 字典序或时间戳降序),并让分数保留固定小数位,否则每次返回顺序不同、AB 实验的对照组与实验组不可比;测试方法是固定输入跑 100 次,输出必须完全一致。Reranker 超时的处理原则是「降级但不报错」:超时阈值设 200ms(Reranker 的 P99 是 80ms),超时后返回 RRF 融合的 Top-5、标记 degraded=true 并记录 trace_id、超时时间与返回条数,降级率超过 5% 触发告警;早期版本直接抛异常让用户看到报错,是典型的「异常路径没设计」的失误。

评测体系与重构等价性。 评测集要分层才有区分度:40 条里简单 15 条(单跳事实查询)、中等 15 条(多跳推理)、困难 10 条(对抗性查询与长尾实体),困难样例的通过率从 40% 提到 75% 才是真正的优化重点。自动化测试按模块切分覆盖(召回 12 项、融合 8 项、去重 4 项、标题加分 2 项、配额 2 项、超时降级 2 项、边界 1 项),每项都有明确输入与预期输出。指标上离线看 Recall@5、MRR、NDCG@10 与端到端答案准确率,在线看追问率、转人工率与负反馈率。重构等价性验证是这场面试里很见功力的一问:检索服务从约 1800 行重写为约 500 行,靠的是 200 条查询的黄金测试集,重构前后各跑一遍逐条 diff,把差异人工归因;实际抓到的边界 case 是空 query——旧实现返回空列表、新实现抛异常,统一为旧行为后才算等价;这套 diff 集成进 CI,每次重构都跑。

AB 实验、口径与体验护栏。 分流按 user_id 哈希取模,保证同一用户始终在同一组;实验组与对照组各 5% 流量、各约 50 万用户、观测 7 天覆盖工作日与周末;显著性是 p<0.05。口径必须能追到埋点:日均入团用户是 7 天滚动窗口的日均值,按 user_id 去重(同一用户当天多次只算一次),定义为「主动点击加入群聊并完成验证」,排除机器人与测试账号——早期没排除机器人导致数据虚高,加了设备指纹与行为特征过滤才拿到真实数据。只盯转化率是危险的:上线后转化率涨了、举报率也涨了,所以护栏指标必须和主指标一起看,包括负反馈率、举报率、取关率、页面加载时间、接口错误率、消息队列积压、缓存命中率;阈值可以定成负反馈率超基线 20% 告警、举报率超基线 15% 回滚。

消息队列压测与故障注入。 压测要报的是可复现的参数组合:单机吞吐 10 万条/秒、P99 延迟 5ms、并发连接 5000、队列 50、消费者 20、平均消息 1KB(最大约 100KB,大消息会拖慢吞吐,超过 10KB 压缩后提升约 15%);方法是 JMeter 加 Kafka 自带工具逐步加压到拐点(吞吐不再增长、延迟急剧上升那一点)。消费者数应与分区数对齐,一个分区一个消费者,否则会积压。Broker 重启的恢复耗时拆成 leader 选举约 2 秒、消费者 rebalance 约 5 秒、总计约 10 秒,靠调小 session.timeout.ms(10 秒到 6 秒)与 heartbeat.interval.ms(3 秒到 2 秒)把 rebalance 从 15 秒降下来,但还不能调太小,否则会误判 broker 宕机而频繁 rebalance;恢复期间不丢消息靠副本与 ISR 选主。故障注入用 Chaos Mesh 模拟网络分区、broker 宕机、消费者宕机,跑 72 小时,测得重复率低于 0.01%、丢失率为 0;重复主要发生在提交 offset 前宕机,解法是消费端幂等加去重表(Redis 存消息 ID,TTL 24 小时)。如果没有历史数据,先建基线(空载资源占用、从 10 并发逐级加压、找拐点),再定验收标准(P99、错误率、重复率、丢失率),最后才谈优化。

用 AI 开发的正确姿势。 面试官连问四题(给了什么上下文、怎么拆任务、AI 出了什么错、怎么验证)是在确认你是不是「AI 的审稿人」而不是「AI 的搬运工」。可复用的答案是:上下文要给已有实现、数据结构定义、公式与接口签名,还要把踩过的坑写进 spec(同一个 chunk 多路命中必须去重、权重必须配置化);任务拆成有验收标准的六步(数据预处理、索引构建、多路召回、融合去重、Rerank、生成),每步达标才进下一步;AI 的典型缺陷集中在异常路径与确定性(去重漏了、权重硬编码、超时不传播、HashMap 遍历顺序不稳定、多请求共享可变状态),所以验证要靠边界测试与单元测试而不只是肉眼 review。手撕题是栈实现的中序遍历(先一路压左子树,弹栈访问后转向右子树,O(n) 时间、O(h) 空间),被追问空间优化时可以提 Morris 遍历能做到 O(1) 但要临时改树结构;反问环节问团队业务、技术栈与培养机制,对方的回答(电商 AI 应用、Python 为主加 Go 做高并发、K8s 部署、AI 生成代码必须人工 review)也帮你判断这个团队是不是真的在做落地。