面灵AI→

水滴公司 AI 全栈工程师一面:从进程线程到 Agent 记忆设计

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

《面试题目》

  1. 自我介绍。
  2. 你两个实习经历分别在什么地方?哪个城市?
  3. 进程和线程的区别?
  4. 进程之间会共享一些资源,对吧?还有其他的吗?
  5. 假如一个程序由多个进程组成,进程间通信的方式都有哪些?
  6. 还有其他的吗?
  7. 管道通信有哪些特点?
  8. 网络那块了解吗?你是什么专业的?
  9. 说一下 TCP,它的特性是什么?
  10. 你刚才讲 TCP 的「安全性」是什么意思?
  11. TCP 三次握手是走哪三次?
  12. 实际过程中也用过 Java,对吗?
  13. Java 创建线程池用 ThreadPoolExecutor,它有几个核心参数?
  14. 这几个参数的作用分别是什么?
  15. 拒绝策略里「放弃第一个」是啥意思?是放弃当前这个吗?
  16. 「放弃最后一个」是啥?
  17. 悲观锁和乐观锁是什么概念?都什么时候用?
  18. CAS 如果不满足条件会怎么样?
  19. CAS 有什么问题?还有其他弊端吗?
  20. CAS 跟悲观锁比有什么优势?
  21. 你刚说 CAS 等待时间会长,又说它并发快很多,这跟它矛盾吗?
  22. Java 里 volatile 关键字是什么意思?
  23. 平时会用到消息队列,比如 Kafka、RabbitMQ,它们的作用是什么?
  24. 后端接口或服务卡顿、响应慢,想排查的话有哪些维度或方面?
  25. 刚讲到一个慢查询,是吧?
  26. 负载就是 CPU,是吧?
  27. 内存,还有其他想到的吗?
  28. 假如你项目里依赖了 Redis,有什么需要观察的?
  29. 假如是因为 Redis 导致系统慢,Redis 你都看哪些指标?
  30. 假如现在要基于大模型做一个 Agent,让你来设计,你认为都需要设计哪些方面?
  31. 记忆和知识库,如果让你来设计,该怎么设计?都应该考虑哪些方面?
  32. 语义切分你怎么来做?
  33. 检索的时候只做了相似度检索吗?
  34. 写入的时候,图用的是什么数据库?
  35. 图检索的目的是什么?
  36. 工具层你怎么设计?有过经验吗?
  37. 都用过哪些 Agent 相关的框架?
  38. LangGraph 和 DeepAgents 有什么区别?
  39. 还有用过其他的框架吗?
  40. 平时编程过程中都用哪些模型?
  41. 我这边就问这么多,你有什么疑问吗?

《参考解析》

1. 进程、线程与 IPC。 进程是资源分配的最小单位,线程是 CPU 调度的最小单位;同一进程内的线程共享地址空间、文件描述符、信号处理和全局变量,各自拥有栈、寄存器和线程本地存储(TLS)。所以「进程共享什么」的准确答法是:共享的是进程的内存空间与内核资源,而不是进程之间;跨进程默认不共享用户态内存,必须通过 IPC。IPC 主要有:管道(匿名管道只能亲缘进程、半双工;命名管道 FIFO 可有名访问)、消息队列(内核维护、按消息边界、可设优先级)、共享内存(最快,但要自己做同步,通常配合信号量)、信号量(计数同步,不传数据)、信号(异步通知,信息量极小)、Socket(可跨主机,TCP/UDP/Unix Domain Socket)。共享内存的选择要讲清楚:省掉两次拷贝所以快,但多个进程同时写同一块内存必须加锁,否则数据竞争。

2. TCP 特性与三次握手。 TCP 提供面向连接、可靠、有序、字节流式、全双工的传输:序号 + 确认 + 超时重传保证可靠,滑动窗口做流量控制,拥塞控制(慢启动、拥塞避免、快重传、快恢复)适配网络,校验和检测比特错误。面试官问「安全性」时其实是在问这几个机制是不是加密——TCP 本身不加密、不认证,只保证「到达且有序」,安全要靠 TLS/HTTPS 叠加。三次握手:客户端发 SYN(seq=x)→ 服务端回 SYN+ACK(seq=y, ack=x+1)→ 客户端回 ACK(ack=y+1);两次不够是因为服务端无法确认「客户端还能收到自己的包」,且历史重复 SYN 会让服务端建立无效连接。

3. 线程池参数与拒绝策略。 七个参数:corePoolSize、maximumPoolSize、keepAliveTime、unit、workQueue、threadFactory、handler。执行顺序是「核心线程 → 队列 → 非核心线程 → 拒绝策略」,注意不是核心满了就立刻扩到最大,而是先塞队列,队列满了才扩容,这一点常被追问。四种内置拒绝策略:AbortPolicy 抛 RejectedExecutionException(默认);CallerRunsPolicy 让提交任务的线程自己跑,形成反压;DiscardPolicy 静默丢弃新任务;DiscardOldestPolicy 丢掉队列里最老的任务(队首)再重试提交。所以「放弃第一个」是 DiscardOldestPolicy,丢的是排队最久的那一个、不是当前任务;「放弃最后一个」对应 DiscardPolicy,丢的是刚提交的新任务。生产上更推荐自定义策略:落库/写 MQ 做补偿,或返回明确的失败码,避免静默丢任务。

4. CAS、乐观锁与悲观锁。 悲观锁假设冲突一定发生,先加锁再操作(synchronized、ReentrantLock、select ... for update),适合写多、冲突高的场景;乐观锁假设冲突少,先改再校验版本号/CAS。CAS 比较并交换,失败不会阻塞,而是返回 false 或自旋重试。三个经典问题:① ABA——值从 A 改回 A,CAS 察觉不到,解决用版本号或 AtomicStampedReference;② 自旋开销——高冲突下大量 CPU 空转,需要退避或改锁;③ 只能保证单个变量原子性,多变量要 AtomicReference 或加锁。优势是无锁、无上下文切换、读多写少时吞吐高;「等待时间长」和「并发快」不矛盾——单次失败要重试所以延迟可能更高,但没有阻塞和唤醒开销,吞吐量在高并发低冲突下更好,冲突一高优势就消失。

5. volatile 与消息队列。 volatile 保证可见性和有序性(禁止指令重排),不保证原子性;实现上靠内存屏障:写前 StoreStore、写后 StoreLoad,读后 LoadLoad/LoadStore,强制刷回主存并使其他核的缓存行失效(MESI)。典型用途是状态标志位、双重检查锁定的单例引用。消息队列解决三件事:解耦(生产方不关心谁消费)、削峰(把瞬时流量缓冲成可控速率)、异步(非关键链路不同步等待),附带重试、顺序、广播能力。代价是一致性变弱(最终一致)、系统复杂度上升(重复消费、消息丢失、积压),所以消费端必须幂等,生产端要做本地消息表或事务消息。

6. 接口慢的排查维度。 从外到内分层看:① 入口层——Nginx/网关的 QPS、连接数、5xx、超时,DNS 与 TLS 握手;② 应用层——线程池是否打满、GC 停顿(GC 日志、jstat)、CPU 使用率与 load、锁竞争(jstack 看 BLOCKED)、慢方法(Arthas trace、APM 链路);③ 存储层——慢查询(slow_query_log + EXPLAIN)、连接池等待、主从延迟、锁等待;④ 依赖层——Redis 的慢命令与大 key、MQ 积压、第三方接口超时;⑤ 容量层——带宽、磁盘 IO、文件句柄。排查原则是「先定位是哪个环节的耗时」而不是逐个猜:用分布式追踪拿到 P99 的 span 分布,再看该环节的资源指标。Redis 要看的指标包括 QPS、命中率、内存使用与碎片率、evicted keys、blocked clients、slowlog、主从复制延迟、连接数;常见慢因是大 key(hgetall 千万字段)、keys *、集中过期、以及单线程被长命令阻塞。

7. Agent 的整体设计。 分五层:① 输入与路由——意图识别、参数抽取、缺参澄清;② 规划——单步 ReAct 还是先 Plan 再执行,复杂任务要拆子任务并维护状态机;③ 工具层——工具描述(名称、参数 schema、何时用)、权限与副作用分级、超时与重试、结果裁剪;④ 记忆——短期是会话窗口与摘要,长期是用户偏好与事实,写入要有抽取、去重、过期与冲突消解;⑤ 评测与可观测——离线评测集、在线埋点(成功率、轮次、token、人工采纳率)、全链路 trace。约束上必须有步数预算、token 预算、wall-clock 超时和人工兜底,防止空转和死循环。

8. 记忆与知识库。 记忆按「事实 / 偏好 / 事件」三类存,键是用户 id + 类型,写入前做抽取与去重(相似度阈值 + LLM 裁决),带来源与时间戳,支持用户查看和删除;冲突时以「新且明确」覆盖「旧且推测」,不确定的标为待确认。知识库是共享的领域知识,走文档解析 → 切分 → 向量化 → 索引(向量 + 关键词 + 元数据)→ 检索 → 重排 → 生成。两者不能混在一张表:记忆是私有、可写、量小;知识库是公共、只读、量大。检索要混合:向量召回语义相近,BM25 召回专有名词和数字,元数据过滤缩小范围,最后 rerank 精排;只用相似度会在「精确编号」「同义词」两类查询上翻车。

9. 语义切分与图检索。 切分先按文档结构(标题、段落、表格)切,再对超长段落做语义切分:相邻句子做 embedding,计算相似度,在相似度低谷处断开,控制块大小与重叠;固定长度切分会把一句话劈开,导致召回片段缺主语。图数据库常用 Neo4j(或 NebulaGraph),写入的是实体与关系(人—公司—岗位、文档—概念—引用),目的是多跳推理和关联召回——比如「和这个人同组的同事面过哪些题」,向量检索只能找到相似文本,找不到关系路径。图检索一般作为混合检索的一路:先用实体链接定位节点,再按 1~2 跳扩展候选,最后和向量召回一起重排;跳数要限制,否则候选爆炸。

10. LangGraph 与 DeepAgents。 LangGraph 是「图编排」框架:节点是函数或模型调用,边是显式转移,支持条件分支、循环、检查点(checkpoint)和人工介入,本质是把 Agent 流程写成可恢复的状态机,适合流程确定、需要可控与可观测的场景。DeepAgents 更偏「开箱的深度 Agent」:内置规划(todo list)、子 Agent 派生、文件系统与上下文管理,让模型自己拆任务并长时间执行,适合开放式研究型任务,代价是可控性弱、成本高、调试难。选型判断:业务流程固定、要审计和回滚就用图编排;探索型、步骤无法预先枚举才用自治 Agent。工具层设计的关键是把「工具做什么、什么时候用、参数约束、失败怎么办」写清楚,副作用工具要二次确认,返回值要裁剪成模型能读的摘要,并在服务端做参数校验和权限检查。