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