面灵AI→

CVTE 应用开发一面:LangGraph 编排深挖与 Java 线程池源码

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

《面试题目》

实习项目(LangGraph Agent)

  1. 请做一下自我介绍。
  2. 介绍一下科大讯飞的数据处理 Agent,为什么用 LangGraph 搭建?有没有考虑过其他框架或实现形式,优缺点如何?LangGraph 是不是最合适的方案,有没有更好的?
  3. 这套 LangGraph 编排里各节点的输入、输出、传递是怎么设计的,具体怎么做的?
  4. 主图和 LLM Agent 子图之间的信息传递是如何进行的?
  5. 如何提高 Agent 数据处理的准确率?通过哪些方式?
  6. 当前 Agent 链路如何实现持久化?为什么用 Redis?除了 Redis 还有哪些存储形式?
  7. 如何保证 Agent 某个节点出现异常后能及时恢复?光靠 Redis 可以实现吗?
  8. 你在这套 Agent 的构建中扮演什么角色,哪些是你完成的,效果怎么样?
  9. 这个数据处理 Agent 是如何评估好坏的?

工程八股

  1. 实习中如何用适配器模式统一管理数据格式与规范?
  2. 接口模式和策略模式的区别是什么?
  3. 工作里用过哪些设计模式?举例说明体现工程思维的地方。
  4. Redis 的持久化机制是怎样的,各有什么优缺点,最佳实践是什么?
  5. 进程、线程、协程分别是什么,有什么区别?
  6. 线程池了解过吗,知道哪些?
  7. 核心线程和非核心线程的区别?
  8. 从源码角度介绍 Java 线程池的运行过程,并说说你从中学到了什么。

手撕

  1. 口述一道二分题(本地 IDE 写)。

《参考解析》

「为什么用 LangGraph」要答到取舍层

这题如果只答「因为它支持多 Agent、有状态」,面试官一定追问「那为什么不用 AutoGen 或自己写个循环」。可用的答法是把需求拆成三条,再逐条对上框架能力:一是流程里有明确的状态机(分类、抽取、校验、回写几个阶段要能中断和续跑),LangGraph 的图 + checkpointer 天然表达这个;二是需要人审或失败重试时能从中间节点恢复,靠的是 checkpoint 而不是重跑整条链;三是主子图要能独立演进,子图当节点挂进主图,边界清晰。再补一条不足:它的抽象对简单线性流程偏重,如果只是一次 LLM 调用加两次工具调用,自己写反而更轻。这样答完,结论是「在当前流程复杂度下它最合适,流程变简单就不合适」——面试官要的就是这种有条件的判断。

节点间传什么、怎么传

稳妥的设计是全局共享一份 State(比如消息列表、原始输入、抽取结果、校验标记、错误信息),节点只声明「我读哪些字段、写哪些字段」,写回时按 reducer 合并而不是整份覆盖。主子图之间有两种传法:子图作为节点时共享父图 State 的某个子集,或者在子图入边做字段映射、出边把结果合并回父 State。要主动说清一个坑:多个节点并发写同一个字段时会互相覆盖,所以要么给该字段定义合并策略(如追加列表),要么让写它的节点串行。

准确率、持久化、异常恢复、评估

准确率的抓手按性价比排:输入侧做清洗与结构化(把自由文本变成带 schema 的字段)、输出侧强制结构化并做 schema 校验、校验不过就带错误信息重试一次、仍然不过走规则兜底或转人工;再加一份小规模标注集做回归,防止改 prompt 时把已经对的样本改坏。持久化用 Redis 的动机通常是低延迟 + TTL 自动过期 + 部署简单,存的是每一步的 checkpoint;但要说清它的边界——Redis 是缓存型存储,掉电或淘汰策略都可能丢数据,AOF everysec 最多丢一秒,要求强一致就得落 Postgres 或对象存储。异常恢复只靠 Redis 不够:还需要幂等键(同一任务重放不会重复写库)、节点级的重试与超时、以及失败时的补偿和告警,否则恢复出来的是「状态在半路」的任务。评估这块别只说「人工看」,给出可量化的三层:字段级准确率、任务级成功率、人工修正率,再配一个固定样本集每次改动都跑。

八股部分的要点

适配器模式解决的是「接口不兼容」,把不同来源的数据格式转成内部统一结构,重点在转换层单一职责;策略模式解决的是「同一行为多种算法可替换」,重点在运行时选择。两者常一起用:适配器负责进来的数据,策略负责选处理算法。Redis 持久化是 RDB(快照、恢复快、可能丢较多数据)与 AOF(追加日志、丢得少、文件大恢复慢)以及 4.0 之后的混合持久化,最佳实践通常是开 AOF everysec 加定期 RDB 做冷备。进程有独立地址空间,线程共享地址空间、切换开销小,协程是用户态调度、由程序自己让出,适合 IO 密集高并发。线程池源码那条主线是 ctl 一个原子变量同时存运行状态和线程数、execute 的三步判断(核心线程未满就新建、否则入队、队列满再看是否达到最大线程数、最后走拒绝策略),以及 Worker 用 AQS 实现中断空闲线程。被问「学到了什么」时,答「池化要给出有界队列和明确的拒绝策略,否则会把上游拖垮」比背源码细节更加分。

手撕二分

口述时把三个边界讲清楚就够了:循环不变量(区间是左闭右闭还是左闭右开)、mid 用 left + (right - left) / 2 防溢出、返回时区分「找到」与「插入位置」。写完主动说一句测试用例(空数组、单元素、目标在两端、目标不存在),比等面试官挑错更好。