面灵AI→

去哪儿 AI 面

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

《面试题目》

  1. 请做一下自我介绍。
  2. 深拷贝用递归实现会出现什么问题?
  3. 循环引用问题怎么解决?
  4. 用 WeakMap 之后仍然出现栈溢出,该怎么解决?
  5. Redis 的过期删除机制是怎样的?
  6. 大模型应用的提示词里,系统提示词和用户提示词有什么区别?为什么系统提示词优先于用户提示词?
  7. ReAct 和 Plan-and-Execute 框架有什么区别?复杂情况、高容错要求的场景该用哪个,为什么?
  8. 讲一个你开发过的全栈项目:目标是什么,怎么衡量效果?

《参考解析》

  1. 深拷贝的递归实现与循环引用:递归版深拷贝最直接的两个坑是深度过大把调用栈打爆(栈溢出),以及对象互相引用导致无限递归。前者本质是递归深度等于对象层级,浏览器与 Node 的调用栈都只有几千到上万层量级,链表、树、嵌套配置一深就炸;后者是 A 引用 B、B 又引用 A,拷贝时没有「已访问」的概念就会一直绕圈。

  2. 循环引用的解法与 WeakMap 的边界:标准解法是维护一张「原对象 → 拷贝结果」的映射表,进入一个对象前先查表:命中就直接返回已创建的副本,没有就先建空壳登记、再填属性。用 Map 或 WeakMap 都行,WeakMap 的好处是键为弱引用、拷贝结束后不阻止原对象被回收,缺点是键必须是对象、不能遍历。WeakMap 本身不会造成栈溢出——栈溢出仍然来自递归深度,正确写法是把递归改成显式栈或队列做广度/深度遍历,或者干脆用 structuredClone 这类原生实现;面试里如果对方说「用 WeakMap 会栈溢出」,要能把两个问题拆开:引用环靠查表解决,深度靠迭代解决。

  3. Redis 的过期删除机制:Redis 采取「惰性删除 + 定期删除」组合,再加内存淘汰兜底。惰性删除是访问 key 时才判断是否过期,过期就删并返回空——它保证不会返回过期数据,但冷 key 会一直占内存。定期删除是每 100ms 触发一次,从设置了过期时间的 key 里随机抽样(默认每次 20 个),删除其中已过期的,如果抽样中过期比例超过 25% 就继续抽下一轮,并限制单次执行时间,避免阻塞主线程。两者都不能保证过期 key 立刻被清掉,所以内存达到 maxmemory 时还要靠淘汰策略(noeviction、allkeys-lru、volatile-lru、allkeys-random 等)保证写入。追问方向一般是主从与持久化:从库不主动删过期 key,只等主库同步 DEL;RDB/AOF 落盘时,过期的 key 在主库侧已经删除就不会进文件,恢复时再靠惰性删除兜底。

  4. 系统提示词与用户提示词的区别:两者在模型侧没有本质区别,都是同一段上下文里的 token,区别来自框架约定与安全设计。系统提示词由应用方写入,定义角色、能力边界、输出格式和不可违反的约束;用户提示词来自使用者,表达具体诉求。约定系统提示词优先,是因为它是应用可信任的输入,而用户输入天然不可信——如果二者同级,用户只要说「忽略上面的要求」就能改写应用规则。工程上的做法是把系统提示词固定在消息序列开头,用角色标记或模板明确分隔,并把模型无法校验的约束放到系统提示词之外的强制层(输出校验、工具白名单)去做,而不是只靠一句「请遵守系统提示」。

  5. ReAct 与 Plan-and-Execute 的取舍:ReAct 是「想一步、做一步、看结果再想下一步」,把推理和工具调用交错进行,适合环境反馈不确定、路径短的探索式任务,灵活但容易绕圈,且每步都要一次模型调用,长任务成本高、容易中途跑偏。Plan-and-Execute 先让模型产出完整计划,再逐步执行,必要时重规划,好处是全局目标明确、可并行、可人工审核计划,代价是计划质量决定上限,环境突变时要付重规划成本。高容错、复杂场景一般选 Plan-and-Execute 打底、在单步执行里嵌 ReAct 做局部调整:外层保证不迷路,内层保证能应对变量;同时给每一步加校验和回滚点,失败重试有上限,超限就交回人工,而不是无限重试。

  6. 全栈项目的衡量口径:讲项目时面试官想听的是「你定义了什么问题、用什么指标判断做成了」。指标要分层:业务侧看转化率、留存、人均使用次数这类结果指标;技术侧看 P95 延迟、错误率、单次调用成本、并发承载;项目侧看交付周期与迭代次数。目标要给出基线,比如「把首次响应从 3 秒压到 800ms 以内」,而不是「做了性能优化」。技术选型也要能说出被否掉的方案和原因,这比堆功能列表更能体现判断力。