虾皮 AI 应用开发一面面经
- 轮次
- 一面
- 结果
- 挂
- 时间
- 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 进来先做改写与扩展(同义扩展、指代消解、必要的分词处理)→ 多路召回并行 → 融合排序 → 去重与业务加权 → Rerank 精排 → 上下文构建 → LLM 生成 → 事实核查后输出。多路召回的必要性来自每种检索的失效模式互补:向量召回语义泛化好但专有名词、型号、数字弱;BM25 精确匹配强但换个说法就召不回;标题召回对「某产品的官方说明」这类指向性查询有效;实体召回补人名地名机构名;时间召回处理「最近」「最新」这类时效诉求。工程上要注意三件事:几路召回要并行发,总延迟取决于最慢的一路而不是累加;各路口径要统一(Top-K 相同、用排名融合保证可比);成本要算清——向量检索和 BM25 是主要开销,标题/实体/时间这类走轻量索引,成本很低。
RRF、去重与排序稳定性。RRF 的公式是 score = Σ w_i /(k + rank_i),其中 rank_i 是该文档在第 i 路召回中的名次,k 通常取 60:k 越小头部名次权重越大、长尾好结果容易被淹没,k 越大排名影响越平滑。权重 w_i 要靠实验调,比如向量 0.4、BM25 0.3、标题 0.1、实体 0.1、时间 0.1,每次只调一路看 NDCG 变化,最后再回落做平衡。去重必须用稳定的文档标识(chunk_id)而不是内容 hash——同一段内容不同切块方式 hash 不同,会出现重复。实现上是「chunk_id → 融合分数」的映射,同一 chunk 被多路命中就把分数累加;标题命中可额外加分,再叠一层文档配额限制单一文档占位过多。排序稳定性容易被忽略:融合分数相同时必须加次级排序键(chunk_id 字典序或时间戳降序),否则每次返回顺序不同,测试不稳定、AB 实验也不可比——用 HashMap 做中间容器还会引入遍历顺序的不确定性,应该用 TreeMap 或显式排序。
Reranker 超时降级与延迟分布。Rerank 是链路里精度提升最多、也最容易成为延迟瓶颈的一环,因为它对每个候选都要跑一次交叉编码。降级策略是:设一个超时阈值(例如 200ms,远高于 Reranker 的 P99),超时后不抛异常,而是返回融合阶段的 Top-K 结果,同时标记 degraded=true 并记录 trace_id、超时时间、返回条数;监控里对降级率设阈值告警(超过 5% 说明 Reranker 服务有问题)。降级的代价要能说清:用户无感知,但答案精度会略降。压缩整体延迟还有一个方向是用小模型做 Rerank,把精排耗时从 80ms 级降到 50ms 级。
评测集、测试覆盖与重构等价性。评测问题要分层,通常按简单(单跳事实)、中等(多跳推理)、困难(对抗性查询、长尾实体)三档,各档占比要能反映真实流量,困难集不足会让模型在简单问题上刷出虚高指标。测试要覆盖正常路径与异常路径:召回、融合、去重、加分、配额、超时降级、边界都要有,且每项都有明确输入与预期输出。重构(比如 1800 行缩到 500 行)的验收方式是黄金测试集:准备一批覆盖各场景的查询,重构前后各跑一遍、逐条 diff 输出,出现差异必须人工分析——行为变了就改回去或明确记录为有意变更,不能「跑通了就发布」。自动化 diff 要进 CI,否则下一次重构又得靠人肉。困难与对抗样例要专门构造:多跳问题、长尾实体、同义词替换、拼写错误、prompt 注入,以及知识库里确实没有答案的问题(用来检验模型会不会如实说不知道而不是编造)。
消息队列压测与故障注入。压测要给出可复现的口径:单机吞吐、P99 延迟、并发连接数、队列(分区)数、消费者数与平均消息大小,方法是逐步加压找到「吞吐不再增长而延迟急剧上升」的拐点,而不是只报一个峰值数字。消费者数一般与分区数对齐;消息体积的长尾对吞吐影响很大,大消息要压缩或走对象存储加引用。故障注入用来验证可靠性指标:注入 broker 宕机、网络分区、消费者宕机,消费端按消息 ID 统计重复与丢失;重复主要发生在消费者提交 offset 前宕机,靠幂等消费加去重表(Redis + TTL)解决;不丢靠生产者 acks=all 加副本。Broker 重启的恢复时间要拆开看:leader 选举与消费者 rebalance 各占多久,rebalance 慢就调 session.timeout.ms 与 heartbeat.interval.ms,但调太小会误判 broker 宕机导致频繁 rebalance。如果数据还没测,先建基线(空载资源占用、吞吐、延迟、错误率),再定验收标准(P99、错误率、重复率、丢失率的阈值),优化后才有对照。
AB 实验口径与护栏指标。实验结论要能站住,必须先说清口径:统计窗口(7 天滚动)、去重方式(按 user_id,同一天多次只算一次)、样本口径(排除机器人与测试账号)、分流逻辑(按 user_id 哈希取模保证同一用户始终进同一组)、以及指标定义(回关率是关注后对方也回关的比例,排除取关后重新关注)。护栏指标和转化指标要一起看:负反馈率、举报率、取关率反映内容质量与合规,页面加载时间、接口错误率、消息队列积压、缓存命中率反映稳定性,转化率涨了但举报率也涨,说明是在透支体验。阈值要提前定好并写进实验设计(比如负反馈超过基线 20% 告警、举报超过 15% 回滚),否则事后解释空间太大。
用 AI 写代码的正确姿势。给 AI 的输入要包含四样东西:明确目标、可参考的既有代码(让它复用而不是另造一套)、数据结构与接口签名、以及之前踩过的坑写成的约束(比如「同 chunk 多路命中必须去重」「权重必须配置化不能硬编码」)。任务拆成可验收的小步,每步都有判定标准,而不是「实现混合检索」这种一句话需求——需求太泛的典型后果是它生成的去重逻辑用内容 hash、权重写死在代码里。AI 的产出要重点验证异常路径:正常路径它写得不错,超时传播、并发共享状态、数据结构的有序性这三处最容易出问题(例如用 HashMap 存中间结果导致顺序不确定、超时信号没往下传)。手写二叉树中序遍历用栈:一路把左孩子压栈,弹出访问后再转向右孩子,时间 O(n)、空间 O(树高),并补一句 Morris 遍历可以做到 O(1) 空间但要临时改树结构。