AI+Java中级开发面试题库(带答案)
生成时间: 2026-05-20 22:28
题目数量: 10道
覆盖范围: AI(5题) + Java中级(5题)
【面试题】1. 请详细说说RAG检索增强生成的核心原理,以及如何优化RAG系统的检索准确率?
【标准答案】RAG的核心原理其实很简单:把检索和生成结合起来。传统大模型有个硬伤——知识截止,训练完就固定了。RAG的思路是:用户提问时,先从知识库里检索相关内容,把检索结果塞进Prompt,再让大模型基于这些内容回答。
架构分三步:
- 离线索引:文档切片 → 向量化(Embedding)→ 存入向量数据库
- 在线检索:用户Query向量化 → 向量相似度搜索 → 返回Top-K相关片段
- 增强生成:检索内容 + 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频繁排查步骤:
先看GC日志:
-XX:+PrintGCDetails开启。看Full GC频率、耗时、原因(System.gc()? 老年代满?Metaspace满?)。dump内存分析:
jmap -histo:live pid快速看对象统计,jmap -dump:format=b,file=heap.hprof pid导出完整堆,用MAT或JProfiler分析。重点关注:- 哪些对象占用最多内存
- 谁在引用它们(Dominator Tree)
- 是否有内存泄漏(对象该回收但没回收)
常见原因及优化:
- 大对象直接进老年代:调整
-XX:PretenureSizeThreshold,让大对象进年轻代或直接分配在堆外。 - 对象晋升过快:Survivor区太小,调大
-XX:SurvivorRatio(默认8:1:1,改成6:1:1)。 - 内存泄漏:静态集合、ThreadLocal未remove、连接池未关闭。修复代码。
- Metaspace满:类加载过多(反射、动态代理),调大
-XX:MaxMetaspaceSize或优化代码。
- 大对象直接进老年代:调整
GC算法调优:
- 低延迟场景用G1:
-XX:+UseG1GC,设置期望停顿时间-XX:MaxGCPauseMillis=200。 - 大堆场景用ZGC:JDK15+生产可用,停顿时间<10ms。
- 低延迟场景用G1:
实战案例:我们有个服务每小时Full GC一次,查出来是定时任务批量加载数据到静态Map没清理。改成局部变量+弱引用后,Full GC消失。
【面试题】3. 请设计一个AI Agent的架构,能够完成"分析用户需求→调用工具→生成报告"的完整流程。
【标准答案】AI Agent架构核心是规划(Planning)→ 执行(Action)→ 反思(Reflection)的循环。我设计一个实用的架构:
整体架构:
用户输入
↓
意图识别器(Intent Classifier)
↓
任务规划器(Planner)←──┐
↓ │
工具选择器(Tool Router)│
↓ │
工具执行器(Executor)───┘
↓ │
结果聚合器(Aggregator)←
↓
反思修正器(Reflector)
↓
报告生成器(Generator)
↓
结构化报告输出核心模块设计:
意图识别器:轻量级模型(如GPT-4o-mini)快速分类,确定任务类型(数据分析、文档查询、代码生成等)。
任务规划器:主模型拆解任务为子步骤。用ReAct(Reasoning + Acting)模式,先"思考"再"行动"。
工具路由层:
- 工具注册表:维护可用工具清单(数据库查询、API调用、文件读写、代码执行等)
- 语义匹配:用Embedding匹配用户意图与工具描述
- 输出:调用工具名 + 参数(LLM生成)
执行器:
- 沙箱隔离执行(如Python REPL、Docker容器)
- 超时控制、异常捕获
- 执行结果标准化返回
反思修正器:
- 检查执行结果是否满足任务目标
- 不满足则重新规划(Re-planning)
- 最多3轮迭代
报告生成器:
- 模板化输出(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自动装配核心就一句话:约定优于配置 + 条件化装配。
原理拆解:
@SpringBootApplication注解是个组合注解:
@SpringBootConfiguration:本质是@Configuration@ComponentScan:扫描当前包及子包@EnableAutoConfiguration:自动装配核心
@EnableAutoConfiguration通过
@Import(AutoConfigurationImportSelector.class)导入选择器。AutoConfigurationImportSelector的核心逻辑:
- 读取
META-INF/spring.factories(旧版)或META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports(新版) - 加载所有候选配置类(如RedisAutoConfiguration、DataSourceAutoConfiguration)
- 根据条件注解筛选生效的配置:
@ConditionalOnClass:类路径存在某类@ConditionalOnMissingBean:容器中不存在某Bean@ConditionalOnProperty:配置文件有某属性
- 读取
执行时机:Spring容器启动时,通过
ImportSelector回调selectImports()方法,批量注册配置类。
自定义Starter步骤:
假设我们要做一个logging-spring-boot-starter:
创建Maven项目:
logging-spring-boot-starter(空项目,只做依赖聚合) logging-spring-boot-autoconfigure(核心逻辑)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()); } }属性类:
java@ConfigurationProperties(prefix = "logging.custom") public class LoggingProperties { private String level = "INFO"; private String format = "JSON"; // getter/setter }注册自动配置:
- 在
resources/META-INF/spring/创建文件org.springframework.boot.autoconfigure.AutoConfiguration.imports - 内容:
com.example.LoggingAutoConfiguration
- 在
使用方引入依赖:
xml<dependency> <groupId>com.example</groupId> <artifactId>logging-spring-boot-starter</artifactId> </dependency>配置
application.yml:yamllogging: custom: level: DEBUG format: TEXT
关键点:条件注解确保"有配置就用,没配置就用默认",不干扰用户自定义Bean。
【面试题】5. 向量数据库选型时需要考虑哪些因素?Milvus、Pinecone、Chroma各自适合什么场景?
【标准答案】向量数据库选型要看五个维度:性能、规模、部署方式、生态、成本。
选型考量因素:
性能指标:
- 查询延迟(QPS、P99延迟)
- 索引构建速度
- 吞吐量(并发能力)
规模支撑:
- 向量维度支持(通常512-1536维)
- 数据量级(百万、十亿级)
- 横向扩展能力
索引算法:
- HNSW(层次导航小世界):高召回率,内存占用大
- IVF(倒排文件索引):适合大规模,可调精度
- PQ(乘积量化):压缩向量,牺牲精度换空间
部署方式:云托管 vs 自托管
生态集成:SDK语言、框架集成(LangChain/LlamaIndex支持)
主流方案对比:
| 特性 | Milvus | Pinecone | Chroma |
|---|---|---|---|
| 部署 | 自托管(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框架。
基础实现(单节点):
// 加锁
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算法原理:
- 获取当前时间戳
- 依次向N个Redis节点请求加锁(通常5个)
- 计算加锁成功节点数,超过半数(3个)且总耗时<锁过期时间,则加锁成功
- 有效时间 = 锁过期时间 - 加锁耗时
- 失败则向所有节点发起解锁
Redisson实现(推荐):
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机制,自动续期,防止业务没执行完锁就过期。
生产环境可靠性保证:
锁续期(Watch Dog):业务执行时间超过锁过期时间,后台线程自动续期(默认每10秒续期到30秒)。
锁可重入:Redisson用Hash结构存储,field是线程ID,value是重入次数。
等待队列:加锁失败的线程进入等待队列,锁释放后通过Pub/Sub通知,避免自旋空转。
多节点部署:Redis Cluster或5个独立节点,防止单点故障。
** fencing token机制**:每次加锁生成递增token,业务操作时校验token,防止锁过期后误操作(适合对一致性要求极高的场景)。
注意点:
- 锁过期时间设置合理(业务执行时间的2-3倍)
- 不要在事务内加锁,可能导致锁提前释放
- 异常情况必须解锁,用try-finally包裹
替代方案对比:
| 方案 | 优点 | 缺点 |
|---|---|---|
| Redis分布式锁 | 性能高,实现简单 | 极端情况可能丢锁 |
| Zookeeper锁 | 强一致性强 | 性能差,运维复杂 |
| etcd分布式锁 | 强一致性,K8s原生 | 学习成本高 |
业务允许少量冲突用Redis,金融级强一致用Zookeeper或etcd。
【面试题】7. 提示词工程(Prompt Engineering)有哪些核心技巧?如何设计一个结构化的系统Prompt?
【标准答案】提示词工程核心目标:让大模型稳定输出预期结果。关键技巧有8个:
核心技巧:
角色设定(Role Prompting)
- 明确身份:"你是一位资深Java架构师..."
- 设定能力边界:"你只回答Java相关问题,其他领域请说不知道"
任务拆解(Chain-of-Thought)
- 分步思考:"请一步步分析:1.先理解问题 2.列出方案 3.对比优劣 4.给出结论"
- Zero-shot CoT:"让我们一步步思考"
Few-Shot示例
- 给2-5个示例,定义输出格式
输入:Java 8新特性 输出:Lambda表达式、Stream API、Optional类 输入:Spring Boot核心注解 输出:@SpringBootApplication、@Configuration、@EnableAutoConfiguration输出格式约束
- JSON Schema、Markdown、表格
- "请以JSON格式返回,包含字段:name, age, skills"
约束与否定
- "不要使用专业术语"
- "回答不超过100字"
- "不要编造信息,不确定就说不知道"
上下文注入
- 提供背景信息、用户画像、业务场景
- "用户是Java中级开发,请用他能理解的语言"
迭代优化
- 先写初版Prompt → 测试 → 分析错误 → 优化
- A/B测试不同Prompt效果
结构化Prompt模板
系统Prompt结构化设计:
# 角色定义
你是一位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排序
就像电话簿:先按姓排序,同姓按名排序。你只知道名,没法直接查找。
查询案例分析:
WHERE a=1→ ✅ 完全走索引WHERE a=1 AND b=2→ ✅ 完全走索引(a、b都能用)WHERE a=1 AND b=2 AND c=3→ ✅ 完全走索引WHERE a=1 AND c=3→ ⚠️ 只有a走索引,c需要回表过滤WHERE b=2→ ❌ 完全不走索引WHERE a=1 AND b>2 AND c=3→ ⚠️ a、b走索引,c不走(范围查询后的列失效)
执行计划验证:
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):
ALTER TABLE t ADD INDEX idx_acb(a, c, b);方案2:覆盖索引
查询只返回索引列,避免回表:
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:强制索引(不推荐)
SELECT * FROM t FORCE INDEX(idx_abc) WHERE a=1 AND c=3;索引设计原则:
- 选择性高的列放左边:区分度大的列优先,比如user_id > status
- 覆盖高频查询:分析慢查询日志,针对性建联合索引
- 避免冗余索引:有
(a, b, c)就不需要(a, b)和(a) - 控制索引数量:单表建议≤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优势:
生态丰富:
- 模型集成:OpenAI、Anthropic、Azure、本地模型(Ollama)开箱即用
- 向量库:Milvus、Pinecone、Chroma等20+支持
- 工具链:Google Search、Wikipedia、Python REPL等
- 社区活跃:GitHub 90k+ stars,第三方集成多
抽象完整:
- Chain:任务编排链
- Agent:自主决策+工具调用
- Memory:对话历史管理
- RAG:检索增强生成组件
- LCEL(LangChain Expression Language):声明式编排
开发效率高:
- Python脚本快速原型验证
- Jupyter Notebook交互调试
- LangSmith可视化追踪调试
适合场景:
- AI Native应用(AI是核心功能)
- 快速原型验证
- 数据科学团队(Python技术栈)
Spring AI优势:
Java企业级开发:
- 与Spring Boot无缝集成
- 依赖注入、配置管理、Actuator监控开箱即用
- 企业级安全、事务、日志体系
生产级特性:
- 与Spring AI集成的Observability(Micrometer)
- 多模型统一API(OpenAI、Azure、Ollama、通义千问)
- VectorStore抽象(Redis、Milvus、PGVector)
团队适配:
- Java团队学习成本低
- 现有Spring项目快速集成AI能力
- 企业级部署、运维体系成熟
适合场景:
- 传统企业应用增加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步:确认是哪个进程
top -c # 查看CPU占用最高的进程
# 或
htop # 更友好的界面找到占用CPU最高的Java进程PID,比如12345。
第2步:确认是用户态还是内核态
top -p 12345 -H%us高:用户态,Java应用代码问题%sy高:内核态,系统调用频繁(如大量IO、上下文切换)
第3步:找到占用CPU的线程
top -H -p 12345 # 显示进程内所有线程找到CPU占用最高的线程TID,比如9876,转成16进制:0x2694。
第4步:Dump线程栈
jstack 12345 > thread_dump.txt
# 或
kill -3 12345 # 输出到应用日志在thread_dump.txt中搜索0x2694(16进制TID),定位到具体代码。
常见原因及解决:
死循环/无限循环
- Thread Dump显示同一段代码一直在执行
- 定位到代码修复
频繁GC
jstat -gcutil 12345 1000查看GC频率- 如果Full GC频繁,按前面讲的方法分析堆内存
- 可能是内存泄漏或堆设置太小
锁竞争激烈
- Thread Dump显示大量线程BLOCKED状态
- 找到锁对象,优化锁粒度或改用无锁数据结构
正则表达式回溯
- 复杂正则匹配大文本,导致CPU飙升
- 优化正则,加超时限制
序列化/反序列化
- JSON/XML序列化大对象,CPU密集
- 异步处理或优化数据结构
加密/解密运算
- 大量加密操作占用CPU
- 使用硬件加速或异步处理
紧急处理:
# 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排查、索引优化)
- 工程实践:穿插在各题中
每道题答案都是面试场景的满分口语版,直击要点,不堆砌术语。