Skip to content

AI+Java中级开发面试题库 ​

生成时间:2026-05-20 22:52


【面试题】1. 说说RAG检索增强生成的核心原理,为什么比纯大模型调用更适合企业知识问答场景? ​

【标准答案】RAG的核心思路是"检索+生成"两步走:先把用户问题通过向量检索从知识库召回相关文档片段,再把这些上下文拼接到Prompt里送给大模型生成答案。

相比纯大模型,RAG有三个关键优势:

  • 知识可更新:企业业务文档天天变,RAG改索引就行,不用重新训练模型
  • 答案可追溯:能给出来源文档链接,用户能验证真假,这是企业合规刚需
  • 幻觉可控:模型基于检索到的真实文档回答,不会凭空编造

技术栈上,一般用向量数据库(如Milvus、Pinecone)做语义检索,Embedding模型(如BGE、M3E)把文本转成向量,大模型只负责理解和生成。成本也低,不需要微调,一个中等规模的RAG系统,部署成本可能只是微调模型的十分之一。


【面试题】2. Spring Boot中@Transactional注解在什么情况下会失效?生产环境怎么规避? ​

【标准答案】失效场景主要有四类:

  1. 方法不是public:Spring AOP代理要求public方法,private/protected直接穿透
  2. 同类内部调用:this.method()绕过了代理对象,事务增强没机会介入
  3. 异常被catch吞掉:默认只在RuntimeException回滚,手动catch又不抛出,事务提交了
  4. 传播行为配置错误:比如嵌套调用时用了REQUIRES_NEW,内层事务独立提交,外层回滚影响不到

生产规避措施:

  • 统一加AOP切面校验方法访问权限,非public直接告警
  • 同类调用改用ApplicationContext.getBean()或AopContext.currentProxy()获取代理对象
  • 异常处理统一用全局异常处理器,不要在业务代码里随意catch
  • Code Review环节强制检查事务传播行为配置

【面试题】3. 设计一个电商大促场景下的库存扣减方案,怎么保证不超卖? ​

【标准答案】这是个经典的高并发一致性问题,核心方案是"Redis预扣+异步落库+兜底校验":

第一层:Redis原子扣减

// Lua脚本保证原子性
if redis.call('GET', stock_key) >= order_count then
    return redis.call('DECRBY', stock_key, order_count)
else
    return -1
end

Redis扛流量,Lua脚本保证不超卖。

第二层:异步消息落库 Redis扣减成功后发MQ消息,异步扣MySQL库存。消费者做幂等处理,避免消息重复导致库存错误。

第三层:兜底校验 下单前再查一次MySQL真实库存,如果Redis和MySQL不一致,说明有数据漂移,触发补偿流程。

为什么不用分布式锁?锁粒度太粗,并发上不去。Redis原子操作+异步落库这套组合拳,能扛住万级QPS,而且数据最终一致。


【面试题】4. 解释一下向量数据库的HNSW索引原理,为什么查询速度比传统倒排索引快? ​

【标准答案】HNSW(Hierarchical Navigable Small World)是个分层的图索引结构,核心思想是"跳表+小世界网络":

结构设计:

  • 分多层,顶层节点少、连接稀疏,底层节点多、连接密集
  • 查询时从顶层入口节点开始,贪心搜索到最接近目标向量的节点,再跳到下一层继续找
  • 类似地图的"先看城市,再看街道,再看门牌号",逐层缩小范围

为什么快:

  • 传统倒排索引是精确匹配,向量检索是相似度计算,倒排索引帮不上忙
  • HNSW把高维空间搜索复杂度从O(N)降到O(log N),百万级数据几毫秒返回
  • 图结构支持增量更新,不用全量重建索引

工程取舍:

  • 内存占用大,适合百万级数据,十亿级要分片
  • 构建索引慢,适合读多写少场景
  • 参数调优(M、efConstruction)直接影响召回率和查询速度,生产环境需要压测验证

【面试题】5. ConcurrentHashMap在Java 8中的实现有什么变化?put操作流程是什么? ​

【标准答案】Java 7 vs Java 8的重大区别:

Java 7:分段锁(Segment数组),每个Segment继承ReentrantLock,并发度受Segment数量限制

Java 8:CAS+synchronized,锁粒度更细,直接锁桶节点

put流程六步:

  1. 计算key的hash,定位桶位置
  2. 桶为空,CAS尝试插入新节点
  3. 桶不为空,synchronized锁住头节点
  4. 遍历链表,key相同则覆盖value,不同则尾插
  5. 链表长度>=8且数组长度>=64,转红黑树
  6. 插入完成后检查是否需要扩容(多线程协助扩容)

关键优化:

  • 锁粒度从Segment级别降到桶级别,并发度上限从Segment数量(默认16)变成数组长度
  • 扩容时多线程协同处理,每个线程负责一部分桶的迁移
  • 读操作完全无锁,用volatile保证可见性

【面试题】6. 提示词工程的Chain-of-Thought(思维链)技术是什么?在实际项目中怎么用? ​

【标准答案】CoT的核心是让模型"分步思考",把复杂问题拆成推理链,而不是直接输出答案。

原理: 大模型本质是概率预测下一个token,单步推理容易跳步出错。加一句"让我们一步步思考",模型会显式展开推理过程,中间步骤的推理误差能在后续步骤自我修正。

实际应用三步走:

  1. Few-shot CoT:Prompt里给2-3个带推理过程的示例,模型学会模仿
  2. Zero-shot CoT:直接加"请一步步分析并给出推理过程",适合通用场景
  3. Self-Consistency:让模型生成多个推理路径,投票选最一致的答案

工程落地注意:

  • CoT增加输出长度,成本和延迟都上升,生产环境要控制思考步数
  • 简单分类任务不需要CoT,反而增加幻觉风险
  • 推理过程可能暴露敏感逻辑,对外输出的产品要考虑脱敏

【面试题】7. MySQL联合索引(a,b,c)在哪些查询场景能用上?最左前缀原则的底层原理是什么? ​

【标准答案】索引能用的场景:

  • WHERE a = 1 ✅ 前缀匹配
  • WHERE a = 1 AND b = 2 ✅ 等值前缀
  • WHERE a = 1 AND b = 2 AND c = 3 ✅ 全覆盖
  • WHERE a = 1 AND c = 3 ⚠️ 只用到a,c用不上(中间断了)
  • WHERE b = 2 AND c = 3 ❌ 不满足最左前缀
  • WHERE a = 1 AND b LIKE 'xx%' ✅ 范围查询后还能用
  • WHERE a = 1 AND b > 2 AND c = 3 ⚠️ a和b能用,c用不上(范围查询后失效)

底层原理: B+树索引是按字段顺序排列的,联合索引先按a排序,a相同再按b排序,b相同再按c排序。就像电话簿"省-市-区"排序,知道省能定位,知道省市能更精确,但只知道区是没法快速查找的。

优化建议:

  • 等值查询字段放前面,范围查询字段放后面
  • 排序字段如果能复用索引顺序,能避免filesort
  • 不要盲目建联合索引,索引维护有成本,高频查询才值得

【面试题】8. 设计一个AI Agent的任务规划模块,怎么让模型能拆解多步骤任务并执行? ​

【标准答案】AI Agent的核心是"感知-规划-执行"循环:

架构设计三模块:

  1. 规划器(Planner)

    • 用户意图转结构化任务图(DAG)
    • 每个节点标注:动作类型(搜索/计算/API调用)、输入参数、依赖关系
    • 用ReAct(Reasoning + Acting)范式:Thought → Action → Observation循环
  2. 执行器(Executor)

    • 工具调用层:封装搜索引擎、数据库查询、API调用等
    • 沙箱隔离:外部调用超时控制、异常捕获、重试机制
    • 输出标准化:统一返回JSON格式结果
  3. 记忆层(Memory)

    • 短期记忆:当前对话上下文,存储在内存
    • 长期记忆:历史任务结果存向量库,相似任务复用
    • 工作记忆:任务中间状态,支持断点续执行

关键流程:

用户输入 → 意图识别 → 任务分解(LLM生成DAG) → 拓扑排序执行 → 结果聚合 → 输出

工程难点:

  • 任务依赖错误处理:某步失败是否回滚?部分失败如何通知用户?
  • 工具调用权限控制:不能让Agent随意调用敏感API
  • 成本控制:多步骤任务可能触发数十次LLM调用,需要设置步数上限

【面试题】9. Kafka消息丢失的场景有哪些?生产环境怎么保证消息不丢? ​

【标准答案】消息可能在三个阶段丢失:

生产端丢失:

  • 发送方式用异步不关心结果,网络抖动消息发了但没成功
  • 阻塞队列满,消息被丢弃

Broker端丢失:

  • 多副本没同步完成,Leader挂了,新Leader数据不全
  • unclean.leader.election.enable=true,ISR外副本当选Leader

消费端丢失:

  • 自动提交offset,消息还在处理,应用挂了,重启后消息丢了

生产不丢方案:

  1. 生产端:

    • acks=all,等待所有ISR副本确认
    • retries配置重试次数
    • 用带回调的send方法,失败时记录本地日志重试
  2. Broker端:

    • replication.factor >= 3,至少3副本
    • min.insync.replicas > 1,至少2个副本同步完成
    • unclean.leader.election.enable=false,禁止ISR外副本当选
  3. 消费端:

    • 关闭自动提交,业务逻辑执行完手动提交offset
    • 消费失败时发送到死信队列(DLQ)人工处理

【面试题】10. JVM新生代为什么要分Eden区和Survivor区?对象晋升老年代的流程是什么? ​

【标准答案】为什么分Eden和Survivor:

  • Eden区:新对象都在这里分配,大部分对象"朝生夕死",一次Minor GC能回收90%+
  • Survivor区:存活的"中年对象",经历多次GC还没死,有资格进老年代
  • 为什么两个Survivor:解决内存碎片。如果只有一个Survivor,GC时存活对象要压缩,开销大。两个Survivor用复制算法,from区存活对象复制到to区,from区直接清空,没有碎片

晋升老年代条件:

  1. 年龄达标:默认15次GC(-XX:MaxTenuringThreshold),每次GC在Survivor区年龄+1
  2. 空间担保失败:Survivor区存不下,直接晋升(动态年龄判定)
  3. 大对象直接进老年代:超过-XX:PretenureSizeThreshold的对象,避免在新生代来回复制
  4. 空间分配担保:老年代剩余空间 > 新生代所有对象总和,Minor GC才安全,否则触发Full GC

调优实践:

  • Eden:S0:S1默认8:1:1, SurvivorRatio可调
  • 新生代太小导致对象过早晋升老年代,频繁Full GC
  • 新生代太大导致Minor GC停顿时间长,找平衡点
  • 用jstat -gcutil监控各区域使用率,别等OOM再排查

本轮题库覆盖考点:

  • AI:RAG架构、向量数据库HNSW、提示词工程CoT、AI Agent规划、生产级消息不丢方案
  • Java:Spring事务、ConcurrentHashMap源码、MySQL索引优化、Kafka消息可靠性、JVM内存模型