Skip to content

AI+Java中级开发面试题库(带答案) ​

生成时间: 2026-05-20 22:28
题目数量: 10道
覆盖范围: AI(5题) + Java中级(5题)


【面试题】1. 请详细说说RAG检索增强生成的核心原理,以及如何优化RAG系统的检索准确率? ​

【标准答案】RAG的核心原理其实很简单:把检索和生成结合起来。传统大模型有个硬伤——知识截止,训练完就固定了。RAG的思路是:用户提问时,先从知识库里检索相关内容,把检索结果塞进Prompt,再让大模型基于这些内容回答。

架构分三步:

  1. 离线索引:文档切片 → 向量化(Embedding)→ 存入向量数据库
  2. 在线检索:用户Query向量化 → 向量相似度搜索 → 返回Top-K相关片段
  3. 增强生成:检索内容 + Query拼成Prompt → 大模型生成答案

优化检索准确率的几个关键点:

  • 切片策略优化:别傻傻按固定字符数切,要按语义边界(段落、章节)。重叠窗口(Overlap)也很重要,防止关键信息被切断。

  • Embedding模型选型:通用模型(如text-embedding-ada-002)不一定适合垂直领域。企业内部文档建议微调或选择领域专用模型。

  • 混合检索:纯向量检索有局限,加上关键词检索(BM25)做Hybrid Search,效果更稳。Elasticsearch 8.x已经支持向量+关键词混合查询。

  • 重排序(Rerank):检索Top-50,用Cross-Encoder重排取Top-10,精度能提升15%-30%。代价是多一次模型调用,但值得。

  • Query改写与扩展:用户Query可能表达模糊,用LLM改写或生成多个查询变体,扩大召回面。

实际项目中,我们就是这么优化的:切片用语义切分+10%重叠,检索用Hybrid,Rerank后Top-10进Prompt,准确率从72%提到91%。


【面试题】2. JVM内存模型是怎样的?线上Full GC频繁,你如何排查和优化? ​

【标准答案】JVM内存模型分五大区域:

  • 堆(Heap):对象实例存储,GC主要区域。年轻代(Eden + Survivor0 + Survivor1)和老年代。
  • 方法区(Metaspace):类元数据、常量池。JDK8后从永久代改成Metaspace,用本地内存。
  • 虚拟机栈:每个线程一个,存储栈帧(局部变量表、操作数栈)。
  • 本地方法栈:Native方法服务。
  • 程序计数器:当前执行的字节码行号。

Full GC频繁排查步骤:

  1. 先看GC日志:-XX:+PrintGCDetails 开启。看Full GC频率、耗时、原因(System.gc()? 老年代满?Metaspace满?)。

  2. dump内存分析:jmap -histo:live pid 快速看对象统计,jmap -dump:format=b,file=heap.hprof pid 导出完整堆,用MAT或JProfiler分析。重点关注:

    • 哪些对象占用最多内存
    • 谁在引用它们(Dominator Tree)
    • 是否有内存泄漏(对象该回收但没回收)
  3. 常见原因及优化:

    • 大对象直接进老年代:调整 -XX:PretenureSizeThreshold,让大对象进年轻代或直接分配在堆外。
    • 对象晋升过快:Survivor区太小,调大 -XX:SurvivorRatio(默认8:1:1,改成6:1:1)。
    • 内存泄漏:静态集合、ThreadLocal未remove、连接池未关闭。修复代码。
    • Metaspace满:类加载过多(反射、动态代理),调大 -XX:MaxMetaspaceSize 或优化代码。
  4. GC算法调优:

    • 低延迟场景用G1:-XX:+UseG1GC,设置期望停顿时间 -XX:MaxGCPauseMillis=200。
    • 大堆场景用ZGC:JDK15+生产可用,停顿时间<10ms。

实战案例:我们有个服务每小时Full GC一次,查出来是定时任务批量加载数据到静态Map没清理。改成局部变量+弱引用后,Full GC消失。


【面试题】3. 请设计一个AI Agent的架构,能够完成"分析用户需求→调用工具→生成报告"的完整流程。 ​

【标准答案】AI Agent架构核心是规划(Planning)→ 执行(Action)→ 反思(Reflection)的循环。我设计一个实用的架构:

整体架构:

用户输入
    ↓
意图识别器(Intent Classifier)
    ↓
任务规划器(Planner)←──┐
    ↓                  │
工具选择器(Tool Router)│
    ↓                  │
工具执行器(Executor)───┘
    ↓                  │
结果聚合器(Aggregator)←
    ↓
反思修正器(Reflector)
    ↓
报告生成器(Generator)
    ↓
结构化报告输出

核心模块设计:

  1. 意图识别器:轻量级模型(如GPT-4o-mini)快速分类,确定任务类型(数据分析、文档查询、代码生成等)。

  2. 任务规划器:主模型拆解任务为子步骤。用ReAct(Reasoning + Acting)模式,先"思考"再"行动"。

  3. 工具路由层:

    • 工具注册表:维护可用工具清单(数据库查询、API调用、文件读写、代码执行等)
    • 语义匹配:用Embedding匹配用户意图与工具描述
    • 输出:调用工具名 + 参数(LLM生成)
  4. 执行器:

    • 沙箱隔离执行(如Python REPL、Docker容器)
    • 超时控制、异常捕获
    • 执行结果标准化返回
  5. 反思修正器:

    • 检查执行结果是否满足任务目标
    • 不满足则重新规划(Re-planning)
    • 最多3轮迭代
  6. 报告生成器:

    • 模板化输出(Markdown/JSON/PDF)
    • 包含:任务摘要、执行步骤、关键发现、可视化图表

技术选型:

  • 框架:LangChain(灵活)或 Spring AI(Java生态)
  • 工具定义:JSON Schema描述输入输出
  • 状态管理:Redis存储对话历史和中间结果

核心Prompt示例(ReAct):

Thought: 用户想要分析销售数据,我需要先查询数据库。
Action: sql_query
Action Input: {"query": "SELECT * FROM sales WHERE date > '2024-01-01'"}
Observation: [返回10000条记录]
Thought: 数据太多,我需要聚合统计...
Action: python_code
Action Input: {"code": "df.groupby('region').sum()"}

这套架构在我参与的项目中落地,能完成数据分析、报告生成的端到端自动化。


【面试题】4. Spring Boot的自动装配原理是什么?如何自定义Starter? ​

【标准答案】Spring Boot自动装配核心就一句话:约定优于配置 + 条件化装配。

原理拆解:

  1. @SpringBootApplication注解是个组合注解:

    • @SpringBootConfiguration:本质是@Configuration
    • @ComponentScan:扫描当前包及子包
    • @EnableAutoConfiguration:自动装配核心
  2. @EnableAutoConfiguration通过@Import(AutoConfigurationImportSelector.class)导入选择器。

  3. AutoConfigurationImportSelector的核心逻辑:

    • 读取META-INF/spring.factories(旧版)或META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports(新版)
    • 加载所有候选配置类(如RedisAutoConfiguration、DataSourceAutoConfiguration)
    • 根据条件注解筛选生效的配置:
      • @ConditionalOnClass:类路径存在某类
      • @ConditionalOnMissingBean:容器中不存在某Bean
      • @ConditionalOnProperty:配置文件有某属性
  4. 执行时机:Spring容器启动时,通过ImportSelector回调selectImports()方法,批量注册配置类。

自定义Starter步骤:

假设我们要做一个logging-spring-boot-starter:

  1. 创建Maven项目:

    logging-spring-boot-starter(空项目,只做依赖聚合)
    logging-spring-boot-autoconfigure(核心逻辑)
  2. autoconfigure模块编写配置类:

    java
    @Configuration
    @ConditionalOnClass(LoggingService.class)
    @EnableConfigurationProperties(LoggingProperties.class)
    public class LoggingAutoConfiguration {
        
        @Bean
        @ConditionalOnMissingBean
        public LoggingService loggingService(LoggingProperties props) {
            return new LoggingService(props.getLevel(), props.getFormat());
        }
    }
  3. 属性类:

    java
    @ConfigurationProperties(prefix = "logging.custom")
    public class LoggingProperties {
        private String level = "INFO";
        private String format = "JSON";
        // getter/setter
    }
  4. 注册自动配置:

    • 在resources/META-INF/spring/创建文件org.springframework.boot.autoconfigure.AutoConfiguration.imports
    • 内容:com.example.LoggingAutoConfiguration
  5. 使用方引入依赖:

    xml
    <dependency>
        <groupId>com.example</groupId>
        <artifactId>logging-spring-boot-starter</artifactId>
    </dependency>

    配置application.yml:

    yaml
    logging:
      custom:
        level: DEBUG
        format: TEXT

关键点:条件注解确保"有配置就用,没配置就用默认",不干扰用户自定义Bean。


【面试题】5. 向量数据库选型时需要考虑哪些因素?Milvus、Pinecone、Chroma各自适合什么场景? ​

【标准答案】向量数据库选型要看五个维度:性能、规模、部署方式、生态、成本。

选型考量因素:

  1. 性能指标:

    • 查询延迟(QPS、P99延迟)
    • 索引构建速度
    • 吞吐量(并发能力)
  2. 规模支撑:

    • 向量维度支持(通常512-1536维)
    • 数据量级(百万、十亿级)
    • 横向扩展能力
  3. 索引算法:

    • HNSW(层次导航小世界):高召回率,内存占用大
    • IVF(倒排文件索引):适合大规模,可调精度
    • PQ(乘积量化):压缩向量,牺牲精度换空间
  4. 部署方式:云托管 vs 自托管

  5. 生态集成:SDK语言、框架集成(LangChain/LlamaIndex支持)

主流方案对比:

特性MilvusPineconeChroma
部署自托管(K8s/Docker)仅云托管嵌入式/自托管
规模十亿级向量百亿级(云原生)百万级
性能高性能,支持GPU加速全托管,性能稳定轻量级,适合开发
索引HNSW/IVF/PQ多种自研索引,黑盒HNSW
生态Python/Go/Java SDK,LangChain支持Python SDK,深度集成Python优先,LangChain原生
成本自建硬件成本,开源免费按向量数+查询量计费免费
适合场景大规模生产环境快速上线、无运维需求原型开发、小规模应用

推荐场景:

  • Milvus:数据量大(>1亿向量)、有K8s运维能力、对成本敏感、需要定制化索引调优。国内企业首选,社区活跃。

  • Pinecone:快速验证产品、团队小、不想折腾运维、预算充足。海外创业公司常用。

  • Chroma:本地开发测试、百万级以下数据、嵌入式部署(直接跑在应用进程里)、Python技术栈。

实战建议:

  • 项目初期用Chroma快速验证,确定需求后再迁移到Milvus生产环境。
  • Milvus集群建议至少3节点,数据量<500万可以用单机版测试。
  • 索引选择:召回率要求高用HNSW,数据量大用IVF+PQ组合。

我们项目用Milvus自托管,2000万向量,QPS 500+,P99延迟15ms,跑得很稳。


【面试题】6. Redis分布式锁如何实现?Redlock算法解决了什么问题?生产环境如何保证可靠性? ​

【标准答案】Redis分布式锁基础实现用SET key value NX PX expire,但单节点有单点故障风险。生产环境要用Redlock算法或Redisson框架。

基础实现(单节点):

java
// 加锁
String lockValue = UUID.randomUUID().toString();
Boolean locked = redis.set("lock:order_123", lockValue, "NX", "PX", 30000);

// 业务逻辑...

// 解锁(Lua脚本保证原子性)
String script = "if redis.call('get', KEYS[1]) == ARGV[1] then " +
                "return redis.call('del', KEYS[1]) else return 0 end";
redis.eval(script, Arrays.asList("lock:order_123"), lockValue);

问题:单节点Master宕机,锁丢失,多个客户端同时获得锁。

Redlock算法原理:

  1. 获取当前时间戳
  2. 依次向N个Redis节点请求加锁(通常5个)
  3. 计算加锁成功节点数,超过半数(3个)且总耗时<锁过期时间,则加锁成功
  4. 有效时间 = 锁过期时间 - 加锁耗时
  5. 失败则向所有节点发起解锁

Redisson实现(推荐):

java
RLock lock = redissonClient.getLock("order:123");
try {
    // 尝试加锁,等待10秒,锁30秒后自动释放
    if (lock.tryLock(10, 30, TimeUnit.SECONDS)) {
        // 业务逻辑
    }
} finally {
    if (lock.isHeldByCurrentThread()) {
        lock.unlock();
    }
}

Redisson内置Watch Dog机制,自动续期,防止业务没执行完锁就过期。

生产环境可靠性保证:

  1. 锁续期(Watch Dog):业务执行时间超过锁过期时间,后台线程自动续期(默认每10秒续期到30秒)。

  2. 锁可重入:Redisson用Hash结构存储,field是线程ID,value是重入次数。

  3. 等待队列:加锁失败的线程进入等待队列,锁释放后通过Pub/Sub通知,避免自旋空转。

  4. 多节点部署:Redis Cluster或5个独立节点,防止单点故障。

  5. ** fencing token机制**:每次加锁生成递增token,业务操作时校验token,防止锁过期后误操作(适合对一致性要求极高的场景)。

注意点:

  • 锁过期时间设置合理(业务执行时间的2-3倍)
  • 不要在事务内加锁,可能导致锁提前释放
  • 异常情况必须解锁,用try-finally包裹

替代方案对比:

方案优点缺点
Redis分布式锁性能高,实现简单极端情况可能丢锁
Zookeeper锁强一致性强性能差,运维复杂
etcd分布式锁强一致性,K8s原生学习成本高

业务允许少量冲突用Redis,金融级强一致用Zookeeper或etcd。


【面试题】7. 提示词工程(Prompt Engineering)有哪些核心技巧?如何设计一个结构化的系统Prompt? ​

【标准答案】提示词工程核心目标:让大模型稳定输出预期结果。关键技巧有8个:

核心技巧:

  1. 角色设定(Role Prompting)

    • 明确身份:"你是一位资深Java架构师..."
    • 设定能力边界:"你只回答Java相关问题,其他领域请说不知道"
  2. 任务拆解(Chain-of-Thought)

    • 分步思考:"请一步步分析:1.先理解问题 2.列出方案 3.对比优劣 4.给出结论"
    • Zero-shot CoT:"让我们一步步思考"
  3. Few-Shot示例

    • 给2-5个示例,定义输出格式
    输入:Java 8新特性
    输出:Lambda表达式、Stream API、Optional类
    
    输入:Spring Boot核心注解
    输出:@SpringBootApplication、@Configuration、@EnableAutoConfiguration
  4. 输出格式约束

    • JSON Schema、Markdown、表格
    • "请以JSON格式返回,包含字段:name, age, skills"
  5. 约束与否定

    • "不要使用专业术语"
    • "回答不超过100字"
    • "不要编造信息,不确定就说不知道"
  6. 上下文注入

    • 提供背景信息、用户画像、业务场景
    • "用户是Java中级开发,请用他能理解的语言"
  7. 迭代优化

    • 先写初版Prompt → 测试 → 分析错误 → 优化
    • A/B测试不同Prompt效果
  8. 结构化Prompt模板

系统Prompt结构化设计:

markdown
# 角色定义
你是一位AI+Java技术面试官,专门考察Java中级开发和AI应用能力。

## 能力设定
- 深谙Java并发编程、JVM调优、Spring生态
- 熟悉大模型原理、RAG架构、Prompt工程
- 面试风格:追问细节、考察实战经验

## 任务目标
根据候选人回答,评估技术深度、逻辑清晰度、表达能力。

## 回答规范
1. 先给出评分(1-10分)及理由
2. 指出回答亮点(用✓标注)
3. 指出不足或遗漏(用✗标注)
4. 追问1-2个延伸问题

## 输出格式
### 评分:X/10
### 亮点
- ✓ ...
### 不足
- ✗ ...
### 追问
1. ...

## 约束
- 不要过度鼓励,客观评价
- 不懂的领域直接说"超出考察范围"
- 评分标准统一,避免前后矛盾

实战建议:

  • 系统Prompt和用户Prompt分离,系统Prompt定义人设和规则,用户Prompt提供具体任务
  • 复杂任务用多轮Prompt(规划→执行→校验)
  • 高频场景沉淀Prompt模板库

我们团队的Prompt模板已经标准化,新项目5分钟就能配好一个可用的Agent。


【面试题】8. MySQL索引优化实战:联合索引(a,b,c),查询WHERE a=1 AND c=3能走索引吗?如何优化? ​

【标准答案】这道题考的是最左前缀原则。答案是:能走索引,但只能用到a列,c列用不上索引,需要回表过滤。

最左前缀原则详解:

联合索引(a,b,c)的B+树结构是按a、b、c的顺序排列的。可以理解为:

  • 先按a排序
  • a相同时按b排序
  • a、b都相同时按c排序

就像电话簿:先按姓排序,同姓按名排序。你只知道名,没法直接查找。

查询案例分析:

  1. WHERE a=1 → ✅ 完全走索引
  2. WHERE a=1 AND b=2 → ✅ 完全走索引(a、b都能用)
  3. WHERE a=1 AND b=2 AND c=3 → ✅ 完全走索引
  4. WHERE a=1 AND c=3 → ⚠️ 只有a走索引,c需要回表过滤
  5. WHERE b=2 → ❌ 完全不走索引
  6. WHERE a=1 AND b>2 AND c=3 → ⚠️ a、b走索引,c不走(范围查询后的列失效)

执行计划验证:

sql
EXPLAIN SELECT * FROM t WHERE a=1 AND c=3;
-- key: idx_abc(用了索引)
-- key_len: 4(只用到了a,4字节)
-- Extra: Using index condition; Using where(ICP下推,但仍需回表)

优化方案:

方案1:调整索引顺序

如果查询模式多为(a, c)查询,创建联合索引(a, c, b):

sql
ALTER TABLE t ADD INDEX idx_acb(a, c, b);

方案2:覆盖索引

查询只返回索引列,避免回表:

sql
SELECT a, b, c FROM t WHERE a=1 AND c=3;
-- Extra: Using index(索引覆盖,不需要回表)

方案3:ICP(Index Condition Pushdown)

MySQL 5.6+默认开启,把c列过滤下推到存储引擎层,减少回表次数。

方案4:强制索引(不推荐)

sql
SELECT * FROM t FORCE INDEX(idx_abc) WHERE a=1 AND c=3;

索引设计原则:

  1. 选择性高的列放左边:区分度大的列优先,比如user_id > status
  2. 覆盖高频查询:分析慢查询日志,针对性建联合索引
  3. 避免冗余索引:有(a, b, c)就不需要(a, b)和(a)
  4. 控制索引数量:单表建议≤5个索引,索引过多影响写入性能

实战案例:

订单表查询慢,索引是(user_id, order_time, status),查询WHERE user_id=123 AND status='PAID'。调整索引为(user_id, status, order_time)后,查询从500ms降到10ms。


【面试题】9. LangChain和Spring AI在AI应用开发上各有什么优势?如何选择? ​

【标准答案】这是个好问题,直接决定技术栈选型。核心区别:LangChain是Python生态的AI应用框架,Spring AI是Java/Spring生态的对应方案。

LangChain优势:

  1. 生态丰富:

    • 模型集成:OpenAI、Anthropic、Azure、本地模型(Ollama)开箱即用
    • 向量库:Milvus、Pinecone、Chroma等20+支持
    • 工具链:Google Search、Wikipedia、Python REPL等
    • 社区活跃:GitHub 90k+ stars,第三方集成多
  2. 抽象完整:

    • Chain:任务编排链
    • Agent:自主决策+工具调用
    • Memory:对话历史管理
    • RAG:检索增强生成组件
    • LCEL(LangChain Expression Language):声明式编排
  3. 开发效率高:

    • Python脚本快速原型验证
    • Jupyter Notebook交互调试
    • LangSmith可视化追踪调试
  4. 适合场景:

    • AI Native应用(AI是核心功能)
    • 快速原型验证
    • 数据科学团队(Python技术栈)

Spring AI优势:

  1. Java企业级开发:

    • 与Spring Boot无缝集成
    • 依赖注入、配置管理、Actuator监控开箱即用
    • 企业级安全、事务、日志体系
  2. 生产级特性:

    • 与Spring AI集成的Observability(Micrometer)
    • 多模型统一API(OpenAI、Azure、Ollama、通义千问)
    • VectorStore抽象(Redis、Milvus、PGVector)
  3. 团队适配:

    • Java团队学习成本低
    • 现有Spring项目快速集成AI能力
    • 企业级部署、运维体系成熟
  4. 适合场景:

    • 传统企业应用增加AI能力
    • Java技术栈团队
    • 需要与现有Spring生态集成

选型建议:

维度选LangChain选Spring AI
团队技术栈Python为主Java/Spring为主
应用定位AI Native产品传统应用+AI增强
开发阶段快速原型、探索阶段生产级稳定版本
运维要求容器化部署、云原生传统企业运维体系
集成需求深度集成AI工具链与现有Spring体系集成

混合方案:

有些团队这样搞:Python+LangChain做AI核心服务(RAG、Agent),Java+Spring Boot做业务服务,通过HTTP/gRPC通信。适合AI团队和业务团队分离的场景。

我们项目是Java团队,选的Spring AI,2周就接上了通义千问+Milvus,RAG问答服务上线。


【面试题】10. 线上服务CPU飙到100%,如何快速定位和解决? ​

【标准答案】CPU 100%是线上最常见的问题之一,排查思路要快、准、狠。

快速定位步骤:

第1步:确认是哪个进程

bash
top -c  # 查看CPU占用最高的进程
# 或
htop    # 更友好的界面

找到占用CPU最高的Java进程PID,比如12345。

第2步:确认是用户态还是内核态

bash
top -p 12345 -H
  • %us高:用户态,Java应用代码问题
  • %sy高:内核态,系统调用频繁(如大量IO、上下文切换)

第3步:找到占用CPU的线程

bash
top -H -p 12345  # 显示进程内所有线程

找到CPU占用最高的线程TID,比如9876,转成16进制:0x2694。

第4步:Dump线程栈

bash
jstack 12345 > thread_dump.txt
# 或
kill -3 12345  # 输出到应用日志

在thread_dump.txt中搜索0x2694(16进制TID),定位到具体代码。

常见原因及解决:

  1. 死循环/无限循环

    • Thread Dump显示同一段代码一直在执行
    • 定位到代码修复
  2. 频繁GC

    • jstat -gcutil 12345 1000 查看GC频率
    • 如果Full GC频繁,按前面讲的方法分析堆内存
    • 可能是内存泄漏或堆设置太小
  3. 锁竞争激烈

    • Thread Dump显示大量线程BLOCKED状态
    • 找到锁对象,优化锁粒度或改用无锁数据结构
  4. 正则表达式回溯

    • 复杂正则匹配大文本,导致CPU飙升
    • 优化正则,加超时限制
  5. 序列化/反序列化

    • JSON/XML序列化大对象,CPU密集
    • 异步处理或优化数据结构
  6. 加密/解密运算

    • 大量加密操作占用CPU
    • 使用硬件加速或异步处理

紧急处理:

bash
# 1. 快速扩容(如果有备用节点)
# 2. 限流,降低流量入口
# 3. 重启问题节点(保留现场,先dump)
jstack 12345 > /tmp/dump_$(date +%s).txt
kill -9 12345
# 4. 服务降级,关闭非核心功能

预防措施:

  • 监控告警:CPU > 80%告警
  • 定期做性能测试和压测
  • 代码审查关注死循环、正则复杂度
  • GC日志持久化,定期分析

实战案例:

我们有次CPU 100%,Thread Dump定位到一个正则校验邮箱地址的代码,正则写得复杂,遇到特殊构造的输入就疯狂回溯。修复正则后,CPU降到10%以内。


总结 ​

本轮覆盖:

  • AI方向(5题):RAG原理与优化、AI Agent架构设计、向量数据库选型、Prompt工程、框架对比
  • Java方向(5题):JVM内存与GC、Spring Boot自动装配、Redis分布式锁、MySQL索引优化、CPU问题排查

题目类型分布:

  • 技术基础:3题(JVM、索引、Redis)
  • 架构设计:3题(RAG、Agent、框架选型)
  • 场景实操:2题(向量数据库、分布式锁)
  • 性能优化:2题(CPU排查、索引优化)
  • 工程实践:穿插在各题中

每道题答案都是面试场景的满分口语版,直击要点,不堆砌术语。