CVTE 应用开发一面:LangGraph 编排深挖与 Java 线程池源码
- 轮次
- 一面
- 时间
- 2026-10
- 来源
- 牛客网
《面试题目》
实习项目(LangGraph Agent)
- 请做一下自我介绍。
- 介绍一下科大讯飞的数据处理 Agent,为什么用 LangGraph 搭建?有没有考虑过其他框架或实现形式,优缺点如何?LangGraph 是不是最合适的方案,有没有更好的?
- 这套 LangGraph 编排里各节点的输入、输出、传递是怎么设计的,具体怎么做的?
- 主图和 LLM Agent 子图之间的信息传递是如何进行的?
- 如何提高 Agent 数据处理的准确率?通过哪些方式?
- 当前 Agent 链路如何实现持久化?为什么用 Redis?除了 Redis 还有哪些存储形式?
- 如何保证 Agent 某个节点出现异常后能及时恢复?光靠 Redis 可以实现吗?
- 你在这套 Agent 的构建中扮演什么角色,哪些是你完成的,效果怎么样?
- 这个数据处理 Agent 是如何评估好坏的?
工程八股
- 实习中如何用适配器模式统一管理数据格式与规范?
- 接口模式和策略模式的区别是什么?
- 工作里用过哪些设计模式?举例说明体现工程思维的地方。
- Redis 的持久化机制是怎样的,各有什么优缺点,最佳实践是什么?
- 进程、线程、协程分别是什么,有什么区别?
- 线程池了解过吗,知道哪些?
- 核心线程和非核心线程的区别?
- 从源码角度介绍 Java 线程池的运行过程,并说说你从中学到了什么。
手撕
- 口述一道二分题(本地 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 防溢出、返回时区分「找到」与「插入位置」。写完主动说一句测试用例(空数组、单元素、目标在两端、目标不存在),比等面试官挑错更好。