本文是我给自己的简历做的答辩手册,已做脱敏处理(公司与业务关键词统一替换为 XXX)。写它的原则只有一条:简历上的每一句话,都能扩展成一个 2 分钟的故事;故事里的每个名词,都能再被追问三层。
结构分三部分:主打项目(大模型数据挖掘平台)、第二个项目(数据闭环平台)、通用问题(转型、并发方法论、反问环节)。每题给「一句话定位 → 故事版 → 陷阱题」三层。
配合简历最新版本使用。原则:简历上的每一句话,都能扩展成一个 2 分钟的故事;故事里的每个名词,都能再被追问三层。
用法:先背「一句话定位」,再练「故事版」(背景→冲突→方案→结果),最后过一遍「陷阱题」。
第一部分:AI 大模型数据挖掘平台(项目二,主打项目)
一句话定位
一个让业务人员用大模型挖掘XXX数据的平台:提需求 → 做实验调提示词 → 人工审核 → 变成生产规则去批量挖掘。我独立负责后端,Python/FastAPI,推理本身不在我这边跑,提交给公司的XXX平台执行,我负责任务的提交、跟踪和结果回收。
Q1. 讲讲这个平台的整体流程?(开场必问)
答(按主线走,30 秒讲完):
- 需求收集:用户在页面上填挖掘需求——要挖什么标签、数据量多大、优先级;提交后结构化落库。
- 实验调优:基于需求创建实验,绑定模型和参数,上传一批样本数据,创建推理任务——任务提交给XXX平台跑大模型推理,结果文件写到对象存储,平台轮询状态、回收结果。
- 人工审核:推理成功的任务进入审核列表,审核人看提示词、看推理结果,通过或拒绝;同一任务只能审一次。
- 规则入库:审核通过时,在同一个事务里写审核记录和挖掘规则——规则就是「验证过的提示词 + 模型版本 + 结果格式」的打包。
- 生产使用:后续大批量挖掘直接读规则库,保证上生产的提示词都经过实验验证和人工把关。
为什么这么设计(升华一句):核心价值是「规则来源于真实需求与实验验证」,避免未经验证的提示词直接用于生产挖掘——这是整个流程存在的理由。
Q2. 为什么推理不自己做,要交给XXX平台?(架构边界题)
答:
- GPU 资源调度、模型部署、批量推理优化是专门的基础设施问题,公司已有平台承接,重复建设没有意义。
- 挖掘平台的核心价值在流程闭环——需求、实验、审核、规则库;把推理自建等于把精力花在养 GPU 上,偏离了平台的定位。
- 所以边界划得很清楚:我们管编排和状态,XXX平台管算力。 平台调用XXX平台的接口提交任务,XXX平台执行完通过回调/轮询把状态和结果文件地址给我们。
追问「跨平台调用,对方挂了怎么办?」 → 提交失败任务保持初始状态并记录原因,后台轮询进程负责重试;已在跑的任务靠轮询对账状态。我们这边的原则是:任何跨系统的交互都假设对方会失败,失败后要能自动恢复。
Q3. 为什么用 Redis 分布式锁?数据库锁不行吗?(简历上最显眼的技术决策,必问)
答(讲成故事):
- 背景:生产环境服务部署两个副本,每个副本都跑后台轮询进程,扫描同一批运行中的任务。
- 冲突:两个副本同时更新同一行,出现两类问题——一是 MySQL 死锁(任务表的二级索引上有间隙锁,两个事务加锁顺序交叉就死锁),二是「丢失更新」(两个副本同时读状态、各自计算、先后写回,后写的把先写的覆盖了)。
- 最初的方案:数据库行锁(SELECT FOR UPDATE)+ 应用层捕获死锁重试。问题在于锁的粒度和事务绑死——持锁时间等于事务时间,事务里有文件下载、调外部接口这种慢操作时,锁竞争被急剧放大,重试兜底代码越写越复杂。
- 重构后:Redis 分布式锁把「协调谁来写」从 MySQL 里拆出来——Redis 管「谁能写」,MySQL 只管「写什么」。耗时 I/O 都在锁的协调下、事务之外执行,数据库事务缩到毫秒级。
追问「为什么不用乐观锁(版本号)?」
考虑过。乐观锁适合「冲突偶发」的场景——大家基本不撞,撞了重试成本低。我们的场景是两个副本每一轮扫描必然撞上(扫的是同一批任务),乐观锁会大量重试空转,浪费的是两边的数据库连接和 CPU。冲突是常态时,悲观协调比乐观重试合理。
追问「锁的粒度怎么定的?」
按实体划分:主任务一把锁、批任务一把锁、数据集一把锁、实验一把锁,外加阶段级的「单飞锁」(同一阶段同一时刻只允许一个副本执行,另一个直接跳过、下一轮自然补上)。不做全局大锁——全局锁等于把双副本退化成单副本,白白浪费一半算力。原则是「扁平、单锁、不嵌套」:一条调用链最多持一把实体锁,需要两把锁的操作拆成两段(先持 A 锁做完释放,再持 B 锁做第二段),从设计上杜绝死锁。
追问「任务没执行完,锁过期了怎么办?」
锁设了 TTL(30 秒),持锁期间有后台线程定期续期(看门狗机制,和 Redisson 的思路一样)。正常结束主动释放;进程崩了续期停止,TTL 到期锁自动消失——不会出现进程死了锁永远不释放的死局。
追问「Redis 主从切换的瞬间,锁在两个客户端手里怎么办?」(Redlock 争议,高级陷阱)
这个理论风险存在:主节点写了锁还没同步到从节点就挂了,从节点升主,另一个客户端能拿到同一把锁。业界对此有争议(Redlock 之争),我们的选择是不上 Redlock,用业务幂等兜底——最坏情况是两个副本重复解析同一份结果,而解析写库是按子任务维度覆盖写的,执行两次结果一样。
锁是性能优化(避免无谓的重复劳动),幂等才是正确性保障。 把正确性押在锁协议上是本末倒置。
Q4. Redis 挂了为什么直接报错,不降级成无锁继续跑?(可靠性哲学题)
答:
- 无锁跑等于回到死锁和数据覆盖的老问题,而且这种错乱是静默的——数据错了没有报错,等发现时已经污染了一片,排查成本极高。
- 我们的系统是批处理型,不是在线服务:停一轮扫描没有任何损失,下一轮 Redis 恢复了自动补上,任务本来就允许延迟。
- 这是批处理系统和在线系统的本质区别:在线服务优先可用性(降级也要响应),批处理系统优先正确性(宁可慢,不可错)。
加分收尾:我们把这条做成了硬约束——代码评审有强制检查项,Redis 不可达必须抛异常,禁止 catch 掉退化成无锁逻辑。规范不靠自觉,靠机制。
Q5. 「结果不丢不重」具体怎么做的?(可靠性设计题,按三层讲)
第一层:不丢——三条触发路径
- 回调:XXX平台跑完主动通知我们,负责「快」;
- 定时兜底扫描:每轮扫描「该出结果但没出」的任务,主动去查,负责「全」——回调依赖对方可靠送达,对方的重试策略不受我们控制,丢一个回调任务就永远卡住;
- 卡住检测:长时间停留在中间状态的任务强制检查、解卡。
任何一条路径漏了,另外两条会补上。只要结果文件存在,最终一定会被处理。
第二层:不重——一次性执行锁
三条路径可能同时到达(回调刚到、扫描也扫到了),解析入口有一把单飞锁:同一子任务同一时刻只有一个执行者,另一个直接跳过。
第三层:最后防线——幂等写
就算极端情况下解析执行了两次(比如锁失效),写库是按子任务维度覆盖写的,执行两次和执行一次结果相同。
收尾一句:机制上三路互补、竞态上加锁去重、最后靠幂等兜底——不指望任何单一机制是完美的。
Q6. 为什么创建任务时在接口里同步提交XXX平台,不扔队列异步提交?(异步边界题)
答:
- 同步提交的价值是即时反馈:参数错了、XXX平台不可用,用户当场看到失败并修正。如果异步化,用户看到「创建成功」,任务却永远停在初始状态,失败要等轮询才暴露——反馈延迟而且诡异。
- 提交本身是一次很快的接口调用,不是耗时操作,没有异步的必要。
- 我的判断标准:异步的边界是「耗时」和「可失败可重试」,不是「所有外部调用都异步」。
追问「提交XXX平台成功了,但本地事务回滚了怎么办?」(分布式一致性陷阱)
顺序设计成「先落库、再提交XXX平台」:本地任务记录先写好(初始状态),再调XXX平台;提交失败就把任务标记为初始+错误信息,轮询重试。反过来的悬挂场景(XXX平台收到了、本地没记录)用任务 ID 做幂等键——XXX平台侧同 ID 重复提交只执行一次。两个方向的失败都有兜底,这就是先落库再外调的原因。
Q7. 轮询的间隔怎么定?轮询会不会给数据库造成压力?(工程细节题)
答:
- 间隔按业务容忍度定:推理任务本身是分钟级到小时级的,状态同步晚几十秒没有业务影响,所以轮询间隔在秒级到分钟级,远粗于任务耗时。
- 压力控制:轮询查询走索引、只扫非终态任务(终态任务不再变化,不需要扫);双副本下阶段单飞锁保证同一阶段同一时刻只有一个副本在扫,轮询压力不随副本数增长。
- 为什么不用消息队列做状态同步?XXX平台侧已有回调,MQ 只解决「通知快」,不解决「通知丢」——对账型的轮询是最终一致的最后保障,它和回调是互补而不是二选一。
Q8. 审核通过为什么要在一个事务里写两张表?(事务边界题)
答:
- 审核记录(谁审的、结论、备注)和挖掘规则(提示词+模型+结果格式的打包)必须同生共死:只写了审核记录没写规则,规则库缺失,生产挖掘用不了;只写了规则没写审核记录,这条规则就变成「来历不明」——审计时说不清谁批准的。
- 所以同一个事务内写入,规则内容由任务、实验、需求三处信息聚合。
- 「同一任务只允许审核一次」也是在这个事务里保证的(唯一约束),防止重复审核产生两条规则。
追问「为什么规则内容要聚合三个表,不冗余存在任务里?」
提示词在实验上、需求信息在需求表上、结果文件在任务上——规则是「这次验证通过的完整快照」,入库时聚合一次、固化下来。之后实验改了提示词、需求改了描述,都不影响已入库的规则。规则库里的每条规则都是不可变的历史快照,这保证了生产挖掘的可复现性。
Q9. 环境隔离具体怎么做的?(工程素养题)
答:
- 配置分层:基础配置 + 按 APP_ENV 加载 dev/prod 配置,后者覆盖前者;生产配置不进代码仓库。
- 一个踩过坑的点:Redis 库号由环境变量强制派生,锁的 key 带环境命名空间。之前测试环境和生产环境如果误用同一个 Redis,测试进程可能锁住生产的任务——这类事故一旦发生极难排查,所以从机制上杜绝:代码里不允许手写库号,只能由环境派生。
Q10. 这个项目最难的部分 / 最有成就感的部分?(必问,选锁重构)
故事线(2 分钟版):
- 事故:生产告警,任务状态错乱——有的任务结果丢了,有的状态被改回去。
- 排查:日志显示两个副本在同一时间窗处理同一批任务;数据库有死锁记录。根因是双副本并发写 + 间隙锁,以及「读了再写」之间的覆盖。
- 方案:设计 Redis 锁体系(上面 Q3 的内容),核心原则「Redis 管谁能写、MySQL 管写什么」「扁平单锁不嵌套」。
- 守门:把设计原则写进代码评审强制检查项,还写了 CI 脚本自动拦截违规用法(比如直接调锁的底层 API 而不走封装的上下文管理器)——防止半年后新同事不知道背景,写出会死锁的代码。
- 结果:上线后死锁和数据覆盖归零;后来排查问题只看一个写入方,定位速度快了很多。
重点讲第 4 步——修 bug 是本职工作,把规范固化成机制、让错误用法无法再被写出来,这是这段经历里最值钱的部分。
第二部分:XXX数据闭环平台(项目一)
一句话定位
XXX数据的采集-回传-质检-入库平台。我负责采集数据和采集需求两个后端模块(Java/Spring),参与XXX端任务下发;前端可视化部分借助 AI 编程工具完成,我负责需求拆解和验收。
⚠️ 诚实原则:这个项目你是「用 AI 搞全栈」,Java 不是你的主语言。面试官深挖 Java 语言特性(JVM 调优、并发包源码)时,坦然承认:「我的主语言是 Python,Java 是到岗后借助 AI 工具快速上手的,语言层面的深水区不如做了五年 Java 的同事,但工程问题——状态设计、数据一致性、故障排查——是相通的,我可以讲我实际解决过的。」这比硬撑可信十倍。
Q11. 连接池故障是怎么回事?(项目一主打故事)
故事线:
- 现象:服务跑一段时间后,请求批量报错,重启就好,过一阵又坏。
- 排查:报错是「拿到的数据库连接不可用」。链路上有四层负载均衡和数据库的空闲超时——数据库端会把空闲太久的连接杀掉,但连接池不知道,池子里存着一堆「看起来正常、实际已断」的僵尸连接,业务借到就报错。
- 根因:旧版本连接池组件不支持主动探活(keepalive),没法定期验证池内连接的存活。
- 方案:升级连接池组件开启主动探活 + 调整池大小配置。关键决策是控制改动范围:只升级连接池这一个组件,不连带升级 Spring Boot 大版本——大版本升级意味着全量回归测试,风险和排期都不可控;连接池单独升级,影响面小、可验证、可回滚。
- 结果:上线后零复发。
这题的考点不是连接池知识,是「最小改动原则」——生产事故修复时,改动范围就是风险范围。把这个决策逻辑讲出来,比讲连接池参数重要。
追问「怎么验证升级是安全的?」 → 测试环境复现故障场景(手动杀数据库连接模拟空闲超时),验证探活能剔除僵尸连接;生产灰度一个副本先升,观察连接池指标正常后全量。
Q12. 状态机是怎么设计的?(设计能力题)
答:
- 采集需求的生命周期有多个环节:创建 → 下发XXX端 → 采集 → 回传 → 质检 → 入库,每个环节有各自的状态。
- 设计了两类约束:
- 流转约束:定义合法的状态转移路径,非法转移直接拒绝(比如没采集完不能进质检)。
- 数量恒等约束:回传数 ≤ 采集数、质检数 ≤ 回传数——数据在管道里只能变少不能变多,多了说明有 bug 或脏数据,系统层面直接拦住。
- 看门狗:XXX通信不可靠(XXX端进隧道、信号差),下发后长时间无响应不能直接判失败——判成「停滞(可恢复)」状态,定时检查,网络恢复后自动续跑;超过阈值才升级处理。把「暂时联系不上」和「确定失败」区分开,是XXX场景的特殊性。
追问「为什么数量约束放系统层,不放业务检查?」
业务检查是人肉的、事后的;系统层约束是机制的、实时的。恒等约束落地后,「采集成功但质检数对不上」这类非法状态在数据库层面就不可能出现——一致性靠机制保障,不靠人的自觉。
Q13. 查询性能优化做了什么?(N+1 问题,用大白话讲)
答:
- 问题:列表页接口慢。排查发现 ORM 的懒加载机制——列表查出 20 条主记录后,页面还要展示每条的关联信息,ORM 就为每一行单独发一条查询,20 行就是 20 次额外查询(这就是常说的 N+1 问题:1 次主查询 + N 次关联查询)。
- 方案:统一改成三步——先把 20 行的关联 ID 收集起来,一条 IN 查询批量取回,再在内存里按 ID 建索引组装。21 次查询变 2 次。
- 另外修了一个隐蔽的同类问题:有代码对空集合没有短路,ID 列表为空时仍然发了查询。
- 架构层面:同团队、同扩缩容节奏的两个模块之间,原来走跨服务接口调用取数,改成直接读同一个库——少一次网络往返、少一个故障点。跨服务调用不是免费的,能用简单方案就不上分布式。
Q14. XXX端下发的护栏是什么?(业务理解题)
答(挑 2-3 个讲):
- 换行符坑:平台生成的下发脚本在XXX端 Linux 上执行报「命令找不到」,排查发现脚本带了 Windows 换行符(CRLF),Linux 的 shell 把
\r当成命令的一部分。护栏:所有下发脚本强制 LF 行尾。 - 磁盘按XXX型号解析:不同XXX型号的存储挂载路径不同,下发时按XXX型号解析目标磁盘,避免写错位置。
- 停止红线:「停止采集」指令下发后,无论XXX端执行成功还是失败(比如XXX端断联收不到),平台侧状态一律置为已停止。业务上的考虑:宁可平台认为停了、实际XXX端多录了一段(数据多不是事故),也不能平台认为在跑、XXX端实际停了或反过来——状态不一致会导致「幽灵录制」(没人知道XXX端还在录)。红线的本质是:失败时选择业务上安全的那一边。
Q15. 前端部分你做了什么?(诚实 + AI 协作能力题)
答(不装懂,讲协作方法):
前端不是我的专业方向,这部分是借助 AI 编程工具完成的,我的角色是需求拆解、方案把关和验收。举个例子:点云文件很大,浏览器直接加载会卡死,方案是分片按需加载——先加载视野内的部分,滚动/缩放时再补;超过 50MB 的极端文件自动降级为简化渲染。另外国内地图有坐标系偏移问题(GPS 原始坐标和地图显示坐标不是一套体系),做了转换。
我能讲清楚每个方案「为什么」,具体的前端 API 细节我不如专业前端熟——但我验证过效果,出了问题能定位到方案层面。
追问:你们前端整体是什么架构?(微前端,这个要能讲)
我们平台是「宿主 + 多个子应用」的微前端架构(qiankun 方案)。宿主是老的单体大前端,负责登录、菜单、全局状态;新业务(比如我做的数据平台)拆成独立子应用,独立仓库、独立部署。
联动方式分四层,我都能讲:
- 路由挂载:宿主配一条通配路由(如
/data/*),命中后不渲染自己的页面,而是把一块 DOM 容器交给子应用挂载;- 运行时注册:子应用的访问地址不写死在构建里,而是容器启动时从环境变量生成一份运行时配置注入页面——一份镜像跑多环境,换环境不用重新构建宿主;
- 同源代理:浏览器只访问宿主域名下的相对路径(如
/micro-apps/xxx/),由 nginx(开发时是 dev-server proxy)转发到子应用真实地址——顺带解决了跨域和子应用域名不对外暴露的问题;- 通信:宿主通过挂载参数下发权限点和全局状态(用户信息等),子应用消费;子应用同时支持独立启动(自己拉全局状态),所以能脱离宿主单独开发调试。
这套架构的收益:新业务不碰老代码(发布互不阻塞)、子应用可以单独扩容;代价是首屏多一次子应用资源加载(我们用预取缓解)、全局样式必须约束在子应用自己的根节点里(否则 7 个子应用互相污染)。
这个回答的价值:2026 年的面试,「会用 AI 跨栈交付 + 能把关方案」本身就是能力,掩饰才是减分项。微前端这段是加分项——它证明你不只是「让 AI 写页面」,而是理解整个前端工程体系怎么组织的。
第三部分:通用/横向问题
Q16. 你是 Python 背景,为什么现在写 Java?怎么快速上手的?
公司业务栈是 Java 为主,到岗后项目需要就上。上手路径:先读现有代码理解分层和约定(比看教程快),借助 AI 工具做语言细节的翻译(Python 思维 → Java 惯用法),Code Review 时重点看同事对我代码的修改意见。我的定位是工程能力可迁移——状态设计、一致性、故障排查这些和语言无关;语言特定的深水区(JVM 调优)我坦承需要时间积累。
Q17. 两个项目里都有「双副本/多副本并发」问题,你的通用方法论是什么?
三步:
- 先问正确性靠什么——靠幂等(重复执行无害),这是底线;
- 再问性能靠什么——靠协调(锁/单飞),避免重复劳动;
- 最后问可观测性——写入路径收敛到单一协调方之后,出问题只需要查一条路径。
顺序不能反:先上锁不设计幂等,锁一失效数据就错;先设计好幂等,锁只是优化,怎么坏都不出正确性事故。
Q18. 如果让你重新设计这个平台,你会改什么?(反思题)
准备 1-2 个真诚的点,例如:
状态同步现在靠轮询+回调,如果重来会在任务和平台之间加一条事件流(如 Kafka),状态变更事件化,轮询退化为对账——实时性更好,排查时有完整的事件时间线。当时没做是因为回调+轮询已经满足业务容忍度,不为「更优雅」支付超出需求的复杂度——但如果任务规模再上一个量级,事件化是明确的演进方向。
Q19. 你有什么想问我们的?(反问环节,别浪费)
- 「咱们团队的任务系统里,跨副本的协调是用什么方案?」(展示你带着思考来)
- 「这个岗位进来后前半年最重要的交付是什么?」
- 避免问薪资福利(留给 HR 面)。
附:已删除内容的「防身」说明
简历里删掉了 HikariCP、Feign、potree、proj4、GCJ02、爆炸半径、Argo、Qwen3/CLIP 等名词。如果面试官从别的渠道(比如追问技术栈)提到这些词,用「概念级」回答即可:
| 名词 | 一句话概念(够了,别展开) |
|---|---|
| HikariCP | Java 生态最常用的数据库连接池,我们那次故障就是升级了它 |
| Feign | Java 里声明式的 HTTP 客户端,用于服务间调用;我们把部分跨服务调用改成了共库直读 |
| potree | 浏览器端渲染大规模点云的开源库,支持分片按需加载 |
| proj4 / GCJ02 | 坐标系转换库 / 国内地图的加密坐标系(GPS 坐标要偏移转换才能和地图对齐) |
| 爆炸半径 | 就是「改动的影响范围」,我说的是最小改动原则 |
| Argo Workflow | K8s 上的工作流引擎,XXX平台那边用它调度 GPU 批量推理 |
原则:能说一句话概念的,被问到就大方说;说不清的(比如 GPU 调度细节),直接说「这部分是XXX平台团队负责,我只对接接口」——边界清晰本身就是专业。
最后:面试前一晚的自检清单
- 每个项目的「一句话定位」能脱口而出
- Q3(为什么 Redis 锁)、Q5(不丢不重)、Q10(最难的事)、Q11(连接池)四个核心故事各练一遍出声讲,控制在 2 分钟
- Q3 的 Redlock 追问、Q6 的事务回滚追问——两个陷阱题的答案背熟
- 「幂等是正确性、锁是优化」这句话至少自然地说出一次
- 前端/Java 弱项的诚实答法(Q15/Q16)练到不心虚






