面灵AI→

拼多多 AI Agent开发三面:上下文、断点恢复与多 Agent 协作

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

《面试题目》

  1. 自我介绍。
  2. 介绍你的 Agent 代码生成链路全流程,从用户输入需求到最终代码交付,完整流程是什么?中间有几个环节?每个环节的输入输出是什么?
  3. 长流程任务中,上下文超限问题你怎么解决?如果 1M 的上下文窗口也不够怎么办?别说分块,我要听具体的工程方案。
  4. 断点恢复是怎么做的?服务重启后,如何加载未完成的任务状态?你存了哪些状态信息?存在哪里?恢复后怎么保证状态一致性?如果恢复失败了怎么办?
  5. 多 Agent 同时修改同一个文件时,怎么防止冲突?有没有用分布式锁?锁的粒度是什么?
  6. Codebase Memory 怎么初始化和更新维护?
  7. 知识库检索在什么时机使用?具体怎么实现的?知识库检索调优做了吗?怎么调的?
  8. 代码生成有什么多 Agent 保障机制?测试用例是怎么生成的?
  9. 大规模代码场景下,Agent 上下文怎么维护?
  10. 代码审查 Agent 怎么做的?是全量逐行扫描吗?怎么优化?
  11. 怎么防止用户重复创建相同任务?幂等性怎么设计?
  12. 你平时常用哪些数据库?MySQL 索引底层是什么结构?为什么选用 B+ 树而不是 B 树?
  13. B+ 树叶子节点存储空间大小是多少?索引存在硬盘还是内存?
  14. Spring Bean 注入的逻辑是怎样的?
  15. 大模型的缓存机制了解吗?
  16. 代码生成系统中长耗时 Agent 占用资源、影响并发,怎么优化?
  17. Java 类加载机制,JVM 如何根据类名查找 class 文件?如何从网络加载字节码?
  18. Python 多线程和 Java 多线程核心区别?GIL 全局解释器锁产生的原因?
  19. FastAPI URL 路由底层实现原理?请求如何匹配对应处理函数?
  20. Qdrant 向量数据库特点以及选型理由?
  21. HNSW 底层实现?优点?朴素向量检索如何实现?
  22. 详细讲一下项目流程和架构,难点是什么?是否端到端打通了,卡点是什么?
  23. Agent 输出效果如何量化评估?
  24. RAG 如果存在图片类非文本内容如何处理?
  25. 职业发展规划,公司选择倾向?
  26. 如何看待工作强度大、节奏快的问题?
  27. 你的多 Agent 架构,每个 Agent 之间怎么传递消息?是否有人工介入?怎么控制 Agent 的?是否有观测的方式?
  28. 数据存在云端会有安全问题吗?
  29. 为什么采用 ForkJoinPool 线程池?
  30. 讲讲实习中的难点?
  31. 你的 Agent 怎么实现不同任务的隔离?
  32. Agent 如何保证分析、输出结果准确性?
  33. Agent 评测体系,测试用例覆盖范围?
  34. LangChain 与 LangGraph 核心区别?
  35. 使用什么 Agent 开发框架?自研框架和开源框架差异?
  36. 手撕题:实现一个 LRU Cache,要求 get 和 put 都是 O(1)。追问:如果要求这个 LRU 支持泛型和过期时间,你怎么改代码?过期时间存哪里?多线程环境下怎么保证线程安全?synchronized 和 ReentrantLock 怎么选?

《参考解析》

代码生成链路的讲法:把环节和产物列清楚:从需求到交付要能报出编号的环节,例如「需求解析与澄清 → 仓库检索与上下文装配 → 任务拆解(文件级计划)→ 多 Agent 并行生成补丁 → 静态检查与编译 → 测试生成与执行 → 代码审查 → 生成 PR 与说明」。每个环节都要说清输入输出(比如「上下文装配」的输入是任务描述加检索到的文件片段,输出是带 token 预算的 prompt 包),因为面试官问的就是输入输出格式。链路里要标出「哪一步是确定性的、哪一步依赖模型」——确定性的部分(编译、测试、diff 应用)必须做成硬门禁,模型输出只能作为候选,这样链路的可靠性才有底座。

上下文超限与断点恢复:预算管上下文,状态机管恢复:把上下文当预算来管,而不是当容器来塞。四件事:一是分层——系统指令与工具定义固定占一部分(走前缀缓存),当前任务与最近几轮对话占一部分,代码与文档按需检索注入,历史用摘要压缩;二是按需检索替代全量装载,代码场景用符号索引(函数、类、调用关系)先定位再取片段,而不是把整个仓库塞进去;三是摘要要有结构(已完成、当前状态、待办、关键实体),并且关键事实单独落结构化存储,不依赖摘要保真;四是预算分配要显式,比如 40% 给系统与工具、30% 给检索片段、20% 给历史、10% 留给输出。1M 窗口也不够时,本质问题不是窗口小,而是任务粒度太粗——正确方向是任务拆解加子 Agent 隔离,让每个子任务只装自己需要的上下文,再把结果汇总。要能被中断恢复,先要有落库的状态机。状态信息至少包含:任务 ID、当前步骤、每步的输入输出摘要、对外副作用单号、重试计数、版本号与时间戳。持久化选型上,流程状态放关系库(要事务与查询)或带事务的 KV,大对象(代码片段、日志)放对象存储只存引用;用 LangGraph 这类框架的话 checkpoint 机制本身就是这个思路。恢复时按状态机找未完成任务,从最后一个成功的检查点继续,并且做两件事保证一致性:一是写操作全程幂等(幂等键由任务与步骤推导,重复执行返回首次结果);二是恢复前对外部状态做一次对账(查 PR 是否已创建、文件是否已改),以外部真实状态为准修正本地状态。恢复失败要落死信表、告警并给出人工接管入口,别让它无声无息地卡在中间。

多 Agent 并发写同一文件:先隔离,再串行,最后才谈锁:文件级并发冲突的最优解不是加分布式锁,而是让不同 Agent 不写同一处:任务拆解阶段就按文件或模块分配所有权,避免重叠;对必须共享的文件,用「生成补丁(diff)而不是直接写文件」的模式,Agent 只产出针对固定基线版本的 patch,由中心调度串行应用,冲突时重新取最新基线再生成。锁确实是备选,但粒度要选对:按仓库加锁太粗(吞吐掉到不能忍),按文件加锁更合理,实现上用带租约和超时的锁(Redis 或数据库行锁),并处理持锁者崩溃后的过期释放。更完整的做法是乐观并发:应用 patch 时比对基线版本号,不一致就拒绝并让 Agent 基于新版本重做,这样大部分情况下根本不需要锁。

Codebase Memory 与检索调优:Codebase Memory 的目标是让 Agent 不必每次重读仓库。初始化可以分三层:符号层(解析 AST 建函数、类、导入关系与调用图)、语义层(对文件与函数做 embedding 存向量库,用于自然语言检索)、经验层(历史任务的改动记录、常见坑、评审意见)。更新维护靠事件驱动:增量索引在提交或合并时更新受影响文件,定期全量重建兜底,索引与 commit 版本对齐以便回溯。检索调优的顺序是「先看召回再看排序」:切块粒度按语法结构切(函数级、类级),别按固定字符数切;查询侧做查询改写(把口语需求扩成代码术语与同义词);召回用向量加关键词(BM25)混合再重排;最后用一组真实任务做离线评测,看「命中正确文件的比例」和「最终任务成功率」两个指标一起动,别只盯召回率。

框架与八股:把常用原理答出关键点:LangChain 偏组件与链式编排,提供模型、检索、工具的积木;LangGraph 在其之上做有状态图编排,核心是节点、边、条件跳转和 checkpoint,适合需要循环、人工介入和可恢复的长流程——这个区别要能一句话说清。B+ 树考的是「为什么」:非叶节点只存键、不存数据,扇出更大,树高更低(通常 3~4 层就能撑千万级行),叶子节点用双向链表串起来,天然支持范围扫描与排序,因此比 B 树更适合磁盘上的索引;InnoDB 页默认 16KB,非叶节点能存几百到上千个键,索引本身是存在磁盘上的、查询时按页加载进缓冲池。GIL 是 CPython 解释器级互斥锁,为了保护引用计数等内部状态,所以多线程无法并行执行字节码,CPU 密集要靠多进程或 C 扩展,IO 密集则因释放 GIL 仍能受益。FastAPI 路由本质是启动时把路径注册成路由表(按路径与方法匹配,路径参数走正则或转换器),请求进来遍历匹配到 endpoint 再走依赖注入;HNSW 则是分层可导航小世界图,上层稀疏做长跳、下层稠密做精查,查询复杂度接近对数级,代价是索引内存占用高。

手撕 LRU 及其扩展:标准答案是哈希表加双向链表——哈希表存 key 到节点的映射保证 O(1) 定位,双向链表维护访问顺序(头部最新、尾部最旧),get 命中后把节点移到头部,put 超容量时淘汰尾部节点并同步删除哈希表项。扩展问题分别答:支持泛型就把 key 与 value 参数化(Java 里 LinkedHashMap 开 accessOrder 并重写 removeEldestEntry 就是现成实现,但要能自己手写);支持过期时间就给节点存过期时间戳并在 get 时惰性删除,再配一个按过期时间排序的结构(堆或时间轮)做定期清理;线程安全最省事是整体加锁,要更高并发就用分段锁,或 ConcurrentHashMap 加链表操作加锁。synchronized 与 ReentrantLock 的取舍:前者语法简单、由 JVM 管理、有锁升级优化,适合竞争不激烈的短临界区;后者支持可中断、超时、公平锁与条件变量,需要这些能力时选它。