面灵AI→

去哪儿测试开发一面:测试 Agent、RAG 与索引

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

《面试题目》

项目经验与技术深度

  1. 你对哪段实习印象最深?为什么?
  2. 你的测试 Agent 项目有什么亮点或难点?
  3. AI 生成脚本时结果不稳定(如 UI 元素定位),你如何解决?
  4. 在脚本匹配 / 检索中,你用了 RAG,具体是怎么做的?
  5. RAG 分层检索(标签 + 语义匹配)的效果如何评估?
  6. 持续上传新文档后,如何衡量 RAG 召回效果的稳定性?(是否设置了固定的回归样本集?)
  7. 断言的粒度是怎么设计的?(细粒度如元素位置,还是粗粒度如仅判断存在?)

数据库与索引

  1. 项目测试中有用到 DB register(数据库表)吗?你怎么测试的?
  2. 多表联查时如何使用索引?索引的原理是什么?怎么测试索引是否生效?
  3. 你对 MySQL 的索引了解有多少(如 B+Tree)?

Java 基础

  1. HashMap 和 ConcurrentHashMap 的原理与区别?

Redis

  1. 你对 Redis 有了解吗?(追问:有没有实际使用或测试过)

测试用例设计(发红包场景)

  1. 设计发红包功能的测试用例,你从哪些维度考虑?(功能、异常、安全、性能、兼容性)

测试 Agent 的改进方向

  1. 除了你已经采用的限制 prompt 和固定元素定位,还有什么可能的提升点?
  2. 你的 RAG 在初始几个文档时效果达标,但增加到几十个文档后,如何自动追踪其检索效果的变化?

团队与角色期望

  1. (反问环节)测试团队的自动化程度和 AI 建设程度如何?新人如何切入?
  2. 入职半年的核心产出期待是什么?

《参考解析》

RAG 分层检索与召回稳定性评估

分层检索的典型做法是「先用结构化标签粗筛,再在候选集里做向量语义匹配」:把文档按业务线、页面、版本、文档类型打标签,查询时先按标签收窄检索空间,再算语义相似度。好处是精度和速度都能提升,新上传的文档按标签立即生效而不污染其他域,缺点是标签体系本身要维护、标签打错会造成系统性漏召。评估要两条线同时做:离线建一个有标注的回归集(问题 → 正确文档/片段 id),固定下来每次改动都跑,看 Recall@k、MRR、命中率以及「文档数从 10 涨到 50 时指标怎么变」的曲线;无标注时可以用 LLM-as-judge 打相关性分,但必须先和人工标注对齐过一致性。在线则看端到端业务指标(脚本生成成功率、用例通过率),而不是只看召回分。稳定性追踪靠「每次上传文档后自动跑一遍固定回归集并落库,画指标随文档量变化的曲线并设阈值报警」(比如 Recall@5 跌破 0.8 就告警),同时监控空召回率、「召回结果全部来自单篇文档」这类分布异常,以及切片或去重规则变更导致的召回抖动。

AI 生成脚本为什么不稳定,怎么治

根因是模型只看到截图或 DOM 文本,选择器是「创作」出来的而不是「发现」的——同一页面两次生成可能给出不同定位方式,页面一改版全挂。可落地的改法:① 把定位收敛到稳定的语义锚点(data-testid、role + accessible name、label 文本),推动业务代码加测试标识;② 定位结果落库复用,只在失效时才重新生成(失败重试 + 自适应修复),不要每次从零生成;③ 一次生成 N 个候选定位,用真实运行结果筛选出通过的那个;④ 受约束生成,只允许模型从给定的定位策略集合里选,减少自由度;⑤ 输入从纯截图换成 DOM 快照加可访问性树,模型判断更准;⑥ 给脚本加显式等待和重试,并把「偶发失败」和「真失败」分开统计,引入 flaky 率指标来度量稳定性而不是只看通过率。

断言粒度设计

分三层考虑:① 元素级存在性断言,最稳、跨版本不易碎;② 属性与文本断言(文案、数值、状态),要处理动态数据,用正则或忽略变化参数;③ 视觉与位置断言(截图 diff、坐标、像素),最脆,分辨率、字体、主题一变就红。落地默认用 ①②,只有 UI 回归兜底才用截图 diff,且必须设相似度阈值和忽略区域。原则是把断言绑到业务语义上(断言「下单成功」而不是「这个按钮的 class 变了」),把固定 sleep 换成显式条件等待(等元素可见、等接口返回),失败时保留现场(DOM 快照、截图、网络日志),便于区分真 bug 和脚本脆。

索引原理与「怎么测索引生效」

InnoDB 的索引是 B+Tree:非叶子节点只存键,叶子节点存数据并用双向链表相连,因此范围查询只需沿叶子链走,三层左右即可支撑千万级数据。主键索引是聚簇索引,叶子存整行;二级索引的叶子存主键值,查非索引列要回表,查询列全在索引里则是覆盖索引。联合索引遵循最左前缀,WHERE a = ? AND b > ? 中 b 之后的列用不上索引;对索引列做函数运算、隐式类型转换、LIKE '%x' 前导通配、OR 连接非索引列都会失效。测试索引是否生效有几种手段:① EXPLAIN 看 type(const/eq_ref/ref/range 优于 index/ALL)、key、rows、Extra(Using index 是覆盖索引,出现 Using filesort、Using temporary 要警惕);② 对比加索引前后的执行时间与扫描行数;③ 用 SHOW INDEX 和 SHOW STATUS LIKE 'Handler_read%' 观察实际读取行数;④ 在测试库造大数据量(几百万行)再验证,小表下优化器可能直接全表扫描,测不出差异;⑤ 用慢查询日志(slow_query_log + long_query_time)回归验证。多表联查时,被驱动表(EXPLAIN 里靠后的那行)的关联字段一定要有索引,否则每扫一行驱动表就要全表扫一次被驱动表。

HashMap 与 ConcurrentHashMap

HashMap 是数组 + 链表 + 红黑树(链表长度达到 8 且数组长度达到 64 才树化,否则先扩容),默认容量 16、负载因子 0.75,扩容翻倍;JDK 8 的 rehash 用高低位链表拆分成两条,避免了 JDK 7 头插法在并发扩容时形成环形链表。它非线程安全,并发 put 会丢数据甚至死循环(JDK 7)。ConcurrentHashMap 在 JDK 7 用分段锁(Segment 继承 ReentrantLock,默认 16 段,段内并发),JDK 8 改成 CAS + synchronized 锁单个桶的头节点,读操作基本无锁(Node 的 val 和 next 用 volatile 保证可见性),size 用 baseCount 加 CounterCell 分散计数。两个常被追问的点:ConcurrentHashMap 不允许 null 键和 null 值(无法区分「不存在」和「值为 null」);它的单次操作原子但复合操作不原子,「先 get 再 put」仍需用 computeIfAbsent、merge 这类原子方法。从测试角度还可以补一句:并发扩容时多线程会协助迁移,已迁移的桶会放 ForwardingNode 标记,因此扩容期间读操作仍能正确路由。

发红包功能的测试用例设计

按维度铺开。功能:正常发与抢、单聊红包与群红包、等额与随机(随机金额之和必须等于总额、每份不低于最小值如 0.01、分布无负数)、指定人数、24 小时未领完退回、重复领取拦截、发红包者自己抢、余额扣减与退回、领取记录与明细一致性。异常:余额不足、金额为 0 / 负数 / 超过单笔上限、人数为 0 或超过上限、网络中断与重复提交、红包已抢完、过期后再抢、并发抢同一个红包导致超发。安全:越权抢定向红包、金额参数被篡改、请求重放、注入。性能:高并发下(秒杀式)的超发、响应时间、数据库行锁竞争与连接池耗尽。兼容性:不同客户端版本、不同支付渠道、不同系统。数据一致性:红包总额与领取明细对账、扣款与发放的原子性、失败回滚。测试手段上,并发用 JMeter 或 Locust 模拟 N 个用户同时抢,断言「已领取份数 ≤ 总份数」且「已领金额之和 ≤ 总额」;幂等用同一请求 id 重放验证;超发这类问题要构造临界值(比如只剩 0.01 元时两人同时抢)。