面试面经 · 大疆
【大疆】【Agent 开发】【暑期实习二面】面经(八股+大模型项目+手撕)
大疆 Agent 开发 暑期实习二面面经
背景:海外一年制硕士,主攻 NLP 与分布式系统,此前有一段大模型应用层实习。
题目摘要
- Go 语言基础:goroutine 调度模型(GMP)、channel 底层结构、内存逃逸分析。
- MySQL/Redis 八股:MVCC 实现原理、聚簇索引与非聚簇索引区别、Redis 持久化机制(RDB vs AOF)及混合持久化。
- Agent 项目深挖:RAG 检索质量优化、Function Calling 的容错设计、多轮对话上下文管理策略、推理成本优化方案。
- 手撕算法:「设计一个支持在 O(1) 时间内完成 insert、delete 和 getRandom 的数据结构」(LeetCode 380 变体,要求元素可重复,getRandom 需按权重返回)。
项目深挖
面试官全程围绕简历上的 Agent 项目展开,连环追问非常细,不放过任何实现细节。以下是最有代表性的三个问题及参考回答方向。
追问 1:你的 RAG 管线检索质量不稳定,体现在哪些场景?如何定位与解决?
参考方向:不要只说"效果不好",要具体到失败模式。我提到两类典型问题——① 涉及多实体关系的复杂问题(如"这个无人机和那个遥控器兼容吗")被拆成多个子查询后,单向量检索召回片段分散,拼接后信息不完整;② 专业术语(如"IMU 标定")在通用 embedding 模型下语义表征不准。
解决路径:针对问题①引入查询重写(Query Rewriting),先用 LLM 将原问题改写为多个子查询,分别检索后按段落来源做重排融合;针对问题②建立领域同义词库,在检索前做术语扩展。同时引入混合检索(BM25 + 稠密向量),用 RRF(Reciprocal Rank Fusion)合并结果。面试官进一步追问"重排模型怎么选的",我回答先用 bge-reranker-base 做粗排,再用 LLM 做精排(只对 top 20 做 LLM 打分),并强调 LLM 精排的 token 成本可控。
追问 2:Function Calling 如果模型返回了不存在的函数名或参数格式错误,你的系统如何兜底?
参考方向:考察工程容错意识。我的方案分三层:① Schema 约束层——在 system prompt 中注入严格的 JSON Schema,并设置 tool_choice 为 auto 时要求模型先输出思考过程(reasoning)再输出调用;② 解析容错层——写了一个健壮的解析器,支持截取 JSON 片段、修复未闭合括号、将单引号转双引号等常见格式错误;③ 运行时校验层——函数名做白名单匹配,参数用 zod 做运行时校验,校验失败时把错误信息回传给模型,让其重新生成调用。面试官追问"如果模型连续三次调用失败怎么办",我回答设置最大重试次数,超过后降级为纯文本回复并记录日志用于后续 fine-tune 数据收集。
追问 3:多轮对话中上下文无限膨胀,你怎么控制成本?
参考方向:核心是分层上下文管理。我采用三块设计:① 固定系统提示 + 工具定义(这部分缓存不随对话增长);② 滑动窗口保留最近 N 轮完整对话;③ 早期对话做摘要压缩(用 LLM 生成结构化摘要,包含用户意图、已调用工具、关键结论)。同时设置 token 预算监控,当接近阈值时触发异步压缩任务。面试官追问"摘要压缩的 LLM 调用本身也是成本",我回答压缩任务用更小的模型(如 7B 量级),且只在每 5 轮或 token 超阈值时触发,压缩频率远低于主对话调用。另外还提到对工具返回的长文本做 truncation + 关键信息抽取,而非全量塞入上下文。
手撕算法
题意:设计一个数据结构,支持三种操作,均摊时间复杂度 O(1):
insert(val):插入一个元素(允许重复)delete(val):删除一个元素(若有多个只删一个)getRandom():返回一个随机元素,概率与该元素的出现次数成正比
关键思路:面试官给的变体是"元素可重复 + 加权随机"。基础版(无重复)用 HashMap + ArrayList 即可,但加权随机需要额外设计。
我的解法:维护一个 HashMap<Integer, Integer> 记录每个值的剩余个数,同时维护一个动态数组存储所有"存活元素"(每个值只存一份)。insert 时若该值首次出现则加入数组;delete 时减少计数,若计数归零则与数组末尾元素交换后 pop(保证 O(1) 删除)。getRandom 的加权随机部分,我提出两种方案:① 若数据量小,直接按计数展开成重复元素的数组再随机索引(空间换时间);② 更优做法是维护一个 Fenwick Tree(树状数组)存储前缀权重,随机生成 [1, totalWeight] 的整数后二分查找定位元素,单次 O(log n)。面试官提示"如果允许空间 O(n) 且插入删除不频繁,方案①够用;但若要严格 O(1) getRandom,需要引入额外的索引结构"。最终我实现了方案②,并解释树状数组的 update 和 query 复杂度。
准备建议
- 把项目里的"坏味道"提前想清楚。面试官问的每个问题都在挑战你项目的边界条件和失败场景。建议把自己项目按"输入异常、并发冲突、资源超限、结果错误"四个维度各列出 3 个可能失败的场景,并准备对应的降级方案。不要只准备"我做了什么",要准备"如果坏了怎么办"。
- Go 语言不要只背八股,要能画图。GMP 调度、channel 的 sendq/recvq 结构、sync.Pool 的 victim cache 机制,面试官很可能让你在白板上画出内存布局或状态流转。建议自己动手画一遍 goroutine 从创建到阻塞到恢复的完整生命周期,以及 channel 在无缓冲和有缓冲情况下的阻塞唤醒流程。MySQL 的 MVCC 同理,要能画出 ReadView 的活跃事务列表如何决定可见性。
- 手撕算法要准备"变体应对策略"。大疆的算法题往往不是原题,而是在原题上加一个约束(如本题的重复元素 + 加权随机)。平时刷题时养成习惯:每做完一道题,自己设计 2 个变体(改数据结构、改复杂度要求、改输入约束),并思考原解法哪里会失效。另外务必练习在 15 分钟内完成"思路阐述 + 写码 + 自测用例"的完整流程,面试时时间非常紧。
一面通过后约 5 天收到二面通知,整体节奏紧凑,面试官对工程细节的追问深度明显高于一面,建议重点打磨项目中的异常处理和成本控制细节。
想系统备战大厂大模型/Agent 开发?NiceOffer 提供 SDE+LLM 双轨 1v1 陪跑,合同保底 40w 年薪,文末扫码咨询。