从 Java 微服务到 RAG 智能客服:大厂电商场景下的一场灵魂面试
从 Java 微服务到 AI RAG:大厂电商面试官与水货程序员小Y的灵魂拷问
一、面试背景:电商+AI 智能客服系统
场景设定在某互联网大厂的 电商 + 智能客服(AIGC / RAG) 团队,主要技术栈:
- 核心语言与平台:Java 8/11、JVM、Spring Boot、Spring Cloud
- 持久化与缓存:MyBatis、Redis、Spring Cache、HikariCP
- 消息与异步:Kafka、RabbitMQ
- AI 与 RAG:Spring AI、向量数据库(Milvus/Redis)、Embedding 模型、Agentic RAG
- 监控与运维:Prometheus、Grafana、ELK、Zipkin
- CI/CD:Git、Maven、Jenkins、Docker、Kubernetes
业务是这样:
做一个电商客服中台:
- 负责订单、商品、用户咨询;
- 接入大模型,实现 RAG 检索增强生成 的智能客服;
- 要保证高并发、可观测性和可扩展性。
下面进入面试现场:面试官严肃理性,小Y略显轻浮,经常打哈哈。
二、第一轮:Java 基础 + Spring Boot 电商接口
Q1:高并发下订单查询接口怎么设计?(Java + Spring Boot 基础)
面试官:
我们有一个电商订单查询接口:
GET /api/orders/{orderId}, 10 万 QPS 高并发,你打算用什么技术栈和大致结构来实现?
小Y:
嗯,这种不就用 Spring Boot 写个 Controller,底下调个 Service,再调个 Mapper 查数据库嘛? 高并发的话……我就加个线程池,
@RestController一写就完事了。
面试官(微微皱眉):
具体一点,数据库连接池、线程模型、JSON 序列化、以及接口的返回结构,你能再说说吗?
小Y:
数据库嘛就用 MySQL ……连接池,常用的是 HikariCP 吧,性能好。 序列化用 Jackson,Spring Boot 默认的那种就行。 线程模型的话 Tomcat 有线程池,我觉得就够了。 响应结构……就包装个
code、msg、data。
面试官(点头):
嗯,基本方向没问题,虽然比较粗略。后面我会追问一些细节。
Q2:为什么建议选择 HikariCP?如何调优?(数据库连接池)
面试官:
你刚才提到 HikariCP,
- 为什么大厂普遍选 HikariCP 而不是 C3P0?
- 高并发情况下你会怎么配置连接池参数?
小Y(开始飘):
这个……HikariCP 吧,就是快,性能比 C3P0 高很多。 调优的话,我一般就默认配置,嗯,默认就挺快的。 具体参数,我感觉要看情况,生产环境再说。
面试官(面无表情):
任何东西都“看情况”,你至少说说核心参数……最大连接数、空闲连接数、超时时间?
小Y:
最大连接数就……弄个 10 ?空闲连接就 5?超时时间就默认……
面试官(叹气):
好,先记下来了,我们后面在答案里给你“补作业”。
Q3:接口如何防止被频繁刷流量?(安全 + 限流)
面试官:
对订单查询这种接口,容易被刷。你打算在接口层做什么保护?
比如:
- 用户单 IP 的 QPS 控制?
- 如何在 Spring Boot 里落地?
小Y:
限流嘛,我就用 Redis 搞个计数,过期时间 1 秒,超过就拦截。 Spring Boot 里就写个拦截器,或者 AOP 注解啥的,判断下 Redis。
面试官(露出一点欣慰):
嗯,这个思路不错,
- Redis 做计数
- 拦截器/过滤器做统一限流
细节有缺失,但方向是对的。
Q4:如何用 Swagger/OpenAPI 管理电商订单接口?(API 文档)
面试官:
你们订单接口多了以后,前端、测试、运营都找你要接口文档。 你会用什么工具?如何在 Spring Boot 里集成?
小Y:
这个简单,用 Swagger 呗,现在不是都用 OpenAPI 3 吗。 我加个依赖,然后用注解
@Operation、@Schema描述参数和返回值。 然后生成一个 UI 页面,让测试自己看。
面试官:
可以,说明你有用过。 生产上可能还会结合网关、权限控制这块,后面有机会再聊。
Q5:单元测试怎么写?(JUnit + Mockito)
面试官:
对这个订单查询接口,你会怎么写单元测试? 用到哪些框架?
小Y:
用 JUnit 5 写测试类,简单的就
@SpringBootTest跑一下。需要 mock 的地方用 Mockito,比如 mock 掉 Repository,保证不访问真实数据库。
面试官:
嗯,这个也还可以,不过你更应该多写 纯单元测试, 不要什么都
@SpringBootTest,那是集成测试,成本偏高。
三、第二轮:微服务 + 消息队列 + 缓存
现在,需求升级:
电商订单系统拆成多个微服务:订单、库存、支付、客服。 用户下单后,需要:
- 扣减库存
- 创建订单
- 发消息给客服系统做“智能催付、推荐”
使用 Spring Cloud + Kafka / RabbitMQ。
Q6:如何做订单创建的微服务拆分?(Spring Cloud + REST)
面试官:
请你设计一下微服务拆分:
- 订单服务
- 库存服务
- 支付服务
用 Spring Cloud / OpenFeign 来调用的话,大致结构怎么画?
小Y:
嗯……
- 订单服务:接收下单请求,写订单表;
- 库存服务:提供扣减库存接口;
- 支付服务:调支付渠道。
它们之间就用 Feign 互相调,
@FeignClient声明一下,像调用本地方法一样。
面试官:
注册发现、熔断限流、配置中心呢?
小Y(开始模糊):
注册就用 Eureka ……或者 Nacos 吧,都可以。 熔断就用 Resilience4j 做下 fallback。 配置中心……Spring Cloud Config 吧。
面试官:
方向对,但比较散,你对整个 Spring Cloud 体系还是理解不够整体。答案区会给你画个简图。
Q7:订单状态变更如何通知智能客服?(Kafka/RabbitMQ)
面试官:
用户下单成功后,需要通知客服系统:
- 可能做推荐
- 做催付
你会用 Kafka 还是 RabbitMQ?怎么设计 Topic / Exchange?
小Y:
我看大家都说 Kafka 牛,那我用 Kafka 吧。 设计一个 topic:
order-events,然后把下单事件发过去。 客服系统就消费者订阅这个 topic。
面试官:
有什么需要注意的?比如:
- 消息有序性
- 重复消费
- 消息丢失?
小Y(心虚):
嗯……有序的话可以按订单 ID 做 key…… 重复消费就幂等处理一下…… 消息丢失……我记得设置下 ack 模式啥的?
面试官:
好的,你知道有这些问题,答案区我会帮你把细节补充完整。
Q8:如何设计 Redis 缓存订单详情?(Redis + Spring Cache)
面试官:
热门订单经常被查询,你会如何用 Redis 做缓存,避免数据库被打挂?
小Y:
这个我比较熟:
- 把订单详情放 Redis,key 就是
order:detail:{orderId};- 查的时候先查 Redis,没有再查 DB。
- 用 Spring Cache 的
@Cacheable注解就行。
面试官:
缓存穿透、击穿、雪崩呢?
小Y:
穿透就缓存空值…… 击穿就加个锁…… 雪崩就设置随机过期时间……
面试官:
这个不错,答得相对完整。
Q9:如何监控这些微服务?(Prometheus + Grafana + Zipkin)
面试官:
微服务拆多了,你怎么观测系统状态? 监控指标、调用链、日志大致怎么做?
小Y:
指标就用 Micrometer 采集,然后 Prometheus 拉; Grafana 展示。
调用链用 Zipkin 或者 Jaeger。 日志就 ELK 呗,Logstash 收集,ES 存储,Kibana 看图。
面试官:
好,这块说明你有接触过,整体观念还可以。
Q10:CI/CD 如何落地?(Git + Maven + Jenkins + Docker + K8s)
面试官:
微服务这么多,你如何做持续集成与持续部署?
小Y:
提交代码到 Git,Jenkins 监听,
- 用 Maven 打包
- Docker 构建镜像
- 推到镜像仓库
- 然后部署到 Kubernetes。
面试官:
回答简略但方向 OK,后面可以聊 Helm、GitOps 等更细内容。
四、第三轮:AI 智能客服、RAG 与 Agent
现在进入这个团队的核心卖点——AI 智能客服。
需求:
- 用户在 App 里输入自然语言问题:
- “帮我查一下这个订单有没有发货?”
- “推荐几个适合跑步的耳机。”
- 系统需要理解意图,调用相应微服务或知识库。
- 要使用 RAG(检索增强生成) + Agent(智能代理) 架构。
Q11:什么是 RAG?在电商客服里怎么用?
面试官:
先解释一下:
- 你理解的 RAG(检索增强生成)是什么?
- 在我们的电商客服里,RAG 能做什么?
小Y:
RAG 就是检索增强生成,
- 大概就是先把资料向量化,存在向量数据库里;
- 用户问问题先去检索相关文档,再让大模型生成答案。
在电商客服里……
- 可以检索商家、商品说明、退换货规则之类的,然后回答用户。
面试官:
嗯,这个回答还不错,有点感觉。
Q12:如何落地 RAG?(Spring AI + 向量数据库 + Embedding)
面试官:
假设我们用 Spring AI、Redis 向量索引 或 Milvus 等向量数据库, 请你说说落地流程:
- 文档怎么加载?
- 向量化用什么?
- 检索和生成的流程如何串起来?
小Y(开始虚):
文档的话……可以从数据库、ES 里读出来,然后……切成段落, 用 Embedding 模型生成向量,比如 OpenAI 的 embedding, 存到向量数据库。
查询时……根据用户问题,向量化,再去检索相似文档, 然后把这些文档给大模型,让它生成答案…… 具体代码细节我……还没怎么看。
面试官:
好,流程上对的,但确实比较概念化。答案区会补一个简化的流程图。
Q13:什么是 Agent?怎么帮客服调用微服务?
面试官:
我们希望智能客服不仅会“聊天”,还会:
- 自动查询订单状态
- 自动创建售后单
- 调用风控服务
这就需要 Agent(智能代理)能力。你怎么理解 Agent?
小Y:
Agent 就是让大模型能自动调用工具、API,那种会“自己想下一步该干嘛”的东西。 它可以根据用户意图决定:
- 是直接用知识库回答
- 还是要调用订单服务的 API。
面试官:
工具怎么描述?调用标准化怎么做?
小Y:
嗯……这个,我印象里可以用一些 schema、metadata 描述 API, 然后让 Agent 按那个格式调用。 但我没实际做过,只是看过资料。
面试官:
好的,至少你知道方向。实践经验有待补齐。
Q14:如何减少 AI 幻觉(Hallucination)?
面试官:
智能客服如果“胡说八道”,比如瞎编活动规则,是很危险的。 你会怎么减少 AI 幻觉?
小Y:
我觉得就是多用 RAG, 让模型基于真实文档回答,尽量不要自由发挥。
还有就是……让它输出时带引用文档?或者做一些校验?
面试官:
还可以,要补充的点不少,答案区会讲:
- 检索质量
- 模型约束
- 后处理与规则校验。
Q15:会话记忆、复杂工作流怎么设计?
面试官:
用户可能连续问:
- “帮我查一下昨天下的耳机订单。”
- “帮我改一下收货地址。”
你需要:
- 记住 TA 的上下文
- 调用多个微服务完成复杂流程
你会怎么设计会话内存和工作流?
小Y(彻底含糊):
会话内存嘛,就……存 Redis? 把上下文放里面…… 工作流的话……可以用一个流程引擎,或者在代码里写 if-else 流程…… 这个我确实没怎么做过,感觉挺复杂的。
面试官(笑而不语):
行,知道不太懂就好。答案区我们会给一份“新手版”思路。
五、面试结束:
面试官:
好,今天就到这里吧。
你 Java 和微服务的基础还能用,但对底层原理和 AI 相关落地实践还比较薄弱。 回去可以重点补一补:
- HikariCP 调优
- Kafka 消息语义
- Spring Cloud 体系结构
- RAG 与 Agentic RAG 实战
面试结果我们会通过邮件通知你,回去等通知吧。
小Y走出会议室,心里默念:
“回去得好好补补了,不然下次又要被人当场上课了……”
六、详细答案与新手学习指南
下面是对上面问题的系统化梳理,适合新手学习。
1. 电商订单查询接口设计(Q1)
典型技术栈:
- Java 8/11 + Spring Boot
- Web:Spring MVC(同步阻塞模型)
- ORM:MyBatis / Spring Data JPA
- 连接池:HikariCP
- JSON:Jackson
基本结构:
@RestController
@RequestMapping("/api/orders")
public class OrderController {
private final OrderService orderService;
public OrderController(OrderService orderService) {
this.orderService = orderService;
}
@GetMapping("/{orderId}")
public ApiResponse<OrderDTO> getOrder(@PathVariable Long orderId) {
OrderDTO order = orderService.getOrderById(orderId);
return ApiResponse.success(order);
}
}
@Service
public class OrderService {
private final OrderMapper orderMapper; // MyBatis Mapper
public OrderService(OrderMapper orderMapper) {
this.orderMapper = orderMapper;
}
public OrderDTO getOrderById(Long orderId) {
OrderEntity entity = orderMapper.selectById(orderId);
if (entity == null) {
throw new OrderNotFoundException(orderId);
}
return OrderConverter.toDTO(entity);
}
}
ApiResponse 统一返回结构:
public class ApiResponse<T> {
private int code;
private String message;
private T data;
// static helpers ...
}
Spring Boot 默认:
- 使用 Tomcat/Undertow 线程池处理请求
- 使用 Jackson 做 JSON 序列化
在高并发下需要结合后面的缓存、连接池调优等。
2. HikariCP 调优(Q2)
为什么选 HikariCP?
- 性能好:连接获取开销小、延迟低
- 配置简单、默认值合理
- 在 Spring Boot 2+ 中已成为默认连接池
核心参数:
spring:
datasource:
hikari:
maximum-pool-size: 50 # 最大连接数
minimum-idle: 10 # 最小空闲连接
idle-timeout: 600000 # 空闲超时 10 分钟
connection-timeout: 30000 # 获取连接超时 30 秒
max-lifetime: 1800000 # 连接存活最大时间 30 分钟
调优思路:
- 最大连接数不要拍脑袋:
- 参考数据库允许的最大连接数
- 估算每个实例所需连接数
- 保证 池内连接 < DB 最大连接数,否则可能把数据库打挂。
- 结合业务 QPS 和单请求 SQL 数量评估。
3. 接口限流与防刷(Q3)
常见策略:
- 网关限流(推荐):
- Nginx + Lua
- Spring Cloud Gateway + Redis
- 应用级限流:
- Redis + 拦截器/过滤器
- Guava RateLimiter(单机)
Redis 计数 + AOP 示例:
- Key:
rate_limit:{ip}:{api} - 过期时间:1 秒
- 超过阈值直接返回错误码
伪代码:
String key = "rate_limit:" + ip + ":" + api;
Long count = redisTemplate.opsForValue().increment(key);
if (count == 1) {
redisTemplate.expire(key, 1, TimeUnit.SECONDS);
}
if (count > limit) {
throw new TooManyRequestsException();
}
4. Swagger/OpenAPI 文档管理(Q4)
使用 springdoc-openapi:
依赖:
<dependency>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
<version>2.5.0</version>
</dependency>
注解示例:
@Operation(summary = "获取订单详情", description = "根据订单 ID 获取订单详情")
@GetMapping("/{orderId}")
public ApiResponse<OrderDTO> getOrder(@PathVariable Long orderId) { ... }
访问 http://localhost:8080/swagger-ui.html 查看文档。
5. 单元测试(Q5)
- 单元测试:用 JUnit 5 + Mockito
- 集成测试:
@SpringBootTest
示例:
@ExtendWith(MockitoExtension.class)
class OrderServiceTest {
@Mock
private OrderMapper orderMapper;
@InjectMocks
private OrderService orderService;
@Test
void getOrderById_shouldReturnOrder() {
OrderEntity entity = new OrderEntity();
entity.setId(1L);
when(orderMapper.selectById(1L)).thenReturn(entity);
OrderDTO dto = orderService.getOrderById(1L);
assertEquals(1L, dto.getId());
verify(orderMapper).selectById(1L);
}
}
6. 微服务拆分与 Spring Cloud(Q6)
基本组件:
- 注册中心:Eureka / Consul / Nacos
- 配置中心:Spring Cloud Config / Nacos Config
- 服务调用:OpenFeign / RestTemplate / WebClient
- 网关:Spring Cloud Gateway
- 熔断限流:Resilience4j
简单架构:
[API Gateway]
|
v
[Order Service] --Feign--> [Inventory Service]
\
Feign--> [Payment Service]
订单服务负责:
- 创建订单草稿
- 调用库存服务预扣库存
- 调用支付服务生成支付链接
7. Kafka/RabbitMQ 事件通知(Q7)
Kafka vs RabbitMQ:
- Kafka:
- 高吞吐、日志型消息
- 适合行为埋点、订单事件流
- RabbitMQ:
- 特性丰富(路由、延时等)
- 适合复杂路由、任务队列
订单事件 Topic 设计:
- Topic:
order-events - Key:
orderId - Value:JSON / Avro / Protobuf
考虑问题:
- 有序性:同一订单的事件落到同一分区(按 orderId 做 key)。
- 幂等:消费者写入 DB 前先检查是否处理过(幂等表 / 状态表)。
- 消息丢失:
- Producer:
acks=all+ 重试 - Consumer:处理完再 commit offset
- Producer:
8. Redis 缓存设计与三大问题(Q8)
缓存模式:
- Cache Aside(旁路缓存):
- 读:先读缓存,缓存 miss 则查 DB 并写入缓存
- 写:先写 DB,再删缓存
三大问题:
- 缓存穿透:大量请求不存在的 Key
- 方案:缓存空值、布隆过滤器
- 缓存击穿:某个热点 key 过期瞬间被大量请求
- 方案:加互斥锁、逻辑过期
- 缓存雪崩:大量 key 在同一时间过期
- 方案:过期时间加随机因子、分散失效时间
Spring Cache 示例:
@Cacheable(cacheNames = "order-detail", key = "#orderId")
public OrderDTO getOrderById(Long orderId) { ... }
9. 监控与可观测性(Q9)
指标(Metrics):
- Micrometer + Prometheus + Grafana
- 常见指标:
- QPS、响应时间、错误率
- JVM 指标(GC、内存、线程数)
调用链(Tracing):
- Spring Cloud Sleuth + Zipkin / Jaeger
- 用 TraceId 串起跨服务调用
日志(Logging):
- Logback / Log4j2 + ELK
- 日志 JSON 化便于检索
10. CI/CD 流水线(Q10)
典型流程:
- 开发提交代码到 Git
- Jenkins/GitLab CI 触发流水线:
mvn clean test执行测试mvn package构建 jardocker build构建镜像
- 推送镜像到私有仓库(Harbor 等)
- 使用
kubectl/ Helm 部署到 Kubernetes
这样可以做到:
- 每次提交自动测试
- 自动部署到测试 / 预发布环境
11. RAG 基础与电商客服应用(Q11)
RAG(Retrieval Augmented Generation)核心思想:
- 将企业文档(商品说明、退换货政策等)向量化
- 用户提问时向量检索相关片段
- 将检索结果作为上下文,交给大模型生成回答
在电商客服中的用法:
- 解决“规则多且经常变”的问题:
- 活动规则、优惠券说明
- 退换货政策
- 可以做到:
- 回答有“出处”,可解释
- 更新文档就更新答案,无需重新训模型
12. RAG 落地流程(Spring AI + 向量数据库)(Q12)
简化流程:
- 文档加载(Document Loading)
- 读取数据库、ES、Markdown、PDF 等
- 文本切分(Chunking)
- 每段 300–1000 字左右,保证语义完整
- 向量化(Embedding)
- 使用 OpenAI / 本地 Embedding 模型
- 得到向量,存入向量数据库(Milvus、Chroma、Redis)
- 检索(Semantic Search)
- 用户问题 → 向量
- 召回 Top-k 相关片段
- 生成(Generation)
- 把检索到的片段 + 用户问题作为 Prompt,喂给 LLM
- 得到回答
Spring AI 的作用:
- 统一调用不同 LLM 和 Embedding 模型
- 提供向量存储接口(VectorStore)
- 提供 RAG/ChatTemplate 等能力
13. Agent 与工具调用(Q13)
Agent 的本质:
- 一个拥有“思考 + 计划 + 工具调用”能力的智能体
- 可以根据用户意图自动调用:
- 订单查询 API
- 支付 API
- 风控服务
工具调用标准化:
- 为每个 API 声明:
- 名称、描述
- 请求参数 schema
- 返回值结构
- Agent 通过这些元数据决定何时调用哪个工具
- MCP(模型上下文协议)等规范正在试图标准化这件事
在电商客服中的场景:
- 用户:“帮我查下订单有没有发货”
- Agent:
- 理解意图:查询订单状态
- 调用订单服务
GET /orders/{id} - 组织自然语言回答
14. 减少 AI 幻觉的方法(Q14)
幻觉(Hallucination):
- 模型一本正经地胡说八道
- 例如瞎编“本店支持 365 天无理由退货”
主要手段:
- 高质量检索
- 提升召回的准确度与相关性
- 对召回结果做过滤(时间、店铺、商品)
- 严格 Prompt 约束
- 明确要求:“如果文档中没有相关信息,请回答‘我不知道’”
- 输出后处理
- 对关键字段(金额、时间、活动名称)做规则校验
- 必要时再查一次系统
- 可追溯
- 要求模型在回答中附带引用片段
- 方便审计与回溯
15. 会话记忆与复杂工作流(Q15)
会话记忆(Chat Memory):
- 短期记忆:同一对话中的几个轮次
- 长期记忆:重要信息(常用收货地址、偏好)
实现方式:
- 存在 Redis / 数据库:
- key:
session:{userId} - value:最近对话摘要、重要槽位(订单号、地址)
- key:
复杂工作流:
- 一个“改收货地址”的流程:
- 确认订单是否可修改
- 进行风控校验
- 调用订单服务更新地址
- 通知物流
实现思路:
- 使用工作流引擎(Camunda、Flowable)编排
- 或使用 “Agentic RAG” + 工具调用框架:
- Agent 负责规划步骤
- 每一步调用不同工具
- 由框架协调状态与异常重试
七、总结
通过这场“面试官 vs 水货程序员小Y”的对话,我们串联了:
- Java + Spring Boot 基础:接口、ORM、测试、连接池
- 微服务与中间件:Spring Cloud、Kafka/RabbitMQ、Redis 缓存
- 可观测性与 CI/CD:Prometheus、Grafana、ELK、Jenkins、Docker、K8s
- AI 智能客服实践:RAG、Agent、向量数据库、会话记忆、复杂工作流
如果你是刚入门的 Java 求职者,可以按这个顺序一步步学习:
Java 基础 → Spring Boot 实战 → 微服务与中间件 → 监控与部署 → RAG + Agent 实战
下次面对大厂面试官的时候,争取不要再像小Y一样“含糊其辞”了。
更多推荐


所有评论(0)