从 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 有线程池,我觉得就够了。 响应结构……就包装个 codemsgdata

面试官(点头):

嗯,基本方向没问题,虽然比较粗略。后面我会追问一些细节。


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 分钟

调优思路:

  1. 最大连接数不要拍脑袋:
    • 参考数据库允许的最大连接数
    • 估算每个实例所需连接数
  2. 保证 池内连接 < DB 最大连接数,否则可能把数据库打挂。
  3. 结合业务 QPS 和单请求 SQL 数量评估。

3. 接口限流与防刷(Q3)

常见策略:

  1. 网关限流(推荐):
    • Nginx + Lua
    • Spring Cloud Gateway + Redis
  2. 应用级限流
    • 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]

订单服务负责:

  1. 创建订单草稿
  2. 调用库存服务预扣库存
  3. 调用支付服务生成支付链接

7. Kafka/RabbitMQ 事件通知(Q7)

Kafka vs RabbitMQ:

  • Kafka:
    • 高吞吐、日志型消息
    • 适合行为埋点、订单事件流
  • RabbitMQ:
    • 特性丰富(路由、延时等)
    • 适合复杂路由、任务队列

订单事件 Topic 设计:

  • Topic:order-events
  • Key:orderId
  • Value:JSON / Avro / Protobuf

考虑问题:

  1. 有序性:同一订单的事件落到同一分区(按 orderId 做 key)。
  2. 幂等:消费者写入 DB 前先检查是否处理过(幂等表 / 状态表)。
  3. 消息丢失
    • Producer:acks=all + 重试
    • Consumer:处理完再 commit offset

8. Redis 缓存设计与三大问题(Q8)

缓存模式:

  • Cache Aside(旁路缓存):
    • 读:先读缓存,缓存 miss 则查 DB 并写入缓存
    • 写:先写 DB,再删缓存

三大问题:

  1. 缓存穿透:大量请求不存在的 Key
    • 方案:缓存空值、布隆过滤器
  2. 缓存击穿:某个热点 key 过期瞬间被大量请求
    • 方案:加互斥锁、逻辑过期
  3. 缓存雪崩:大量 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)

典型流程:

  1. 开发提交代码到 Git
  2. Jenkins/GitLab CI 触发流水线:
    • mvn clean test 执行测试
    • mvn package 构建 jar
    • docker build 构建镜像
  3. 推送镜像到私有仓库(Harbor 等)
  4. 使用 kubectl / Helm 部署到 Kubernetes

这样可以做到:

  • 每次提交自动测试
  • 自动部署到测试 / 预发布环境

11. RAG 基础与电商客服应用(Q11)

RAG(Retrieval Augmented Generation)核心思想:

  1. 将企业文档(商品说明、退换货政策等)向量化
  2. 用户提问时向量检索相关片段
  3. 将检索结果作为上下文,交给大模型生成回答

在电商客服中的用法:

  • 解决“规则多且经常变”的问题:
    • 活动规则、优惠券说明
    • 退换货政策
  • 可以做到:
    • 回答有“出处”,可解释
    • 更新文档就更新答案,无需重新训模型

12. RAG 落地流程(Spring AI + 向量数据库)(Q12)

简化流程:

  1. 文档加载(Document Loading)
    • 读取数据库、ES、Markdown、PDF 等
  2. 文本切分(Chunking)
    • 每段 300–1000 字左右,保证语义完整
  3. 向量化(Embedding)
    • 使用 OpenAI / 本地 Embedding 模型
    • 得到向量,存入向量数据库(Milvus、Chroma、Redis)
  4. 检索(Semantic Search)
    • 用户问题 → 向量
    • 召回 Top-k 相关片段
  5. 生成(Generation)
    • 把检索到的片段 + 用户问题作为 Prompt,喂给 LLM
    • 得到回答

Spring AI 的作用:

  • 统一调用不同 LLM 和 Embedding 模型
  • 提供向量存储接口(VectorStore)
  • 提供 RAG/ChatTemplate 等能力

13. Agent 与工具调用(Q13)

Agent 的本质:

  • 一个拥有“思考 + 计划 + 工具调用”能力的智能体
  • 可以根据用户意图自动调用:
    • 订单查询 API
    • 支付 API
    • 风控服务

工具调用标准化:

  1. 为每个 API 声明:
    • 名称、描述
    • 请求参数 schema
    • 返回值结构
  2. Agent 通过这些元数据决定何时调用哪个工具
  3. MCP(模型上下文协议)等规范正在试图标准化这件事

在电商客服中的场景:

  • 用户:“帮我查下订单有没有发货”
  • Agent:
    1. 理解意图:查询订单状态
    2. 调用订单服务 GET /orders/{id}
    3. 组织自然语言回答

14. 减少 AI 幻觉的方法(Q14)

幻觉(Hallucination):

  • 模型一本正经地胡说八道
  • 例如瞎编“本店支持 365 天无理由退货”

主要手段:

  1. 高质量检索
    • 提升召回的准确度与相关性
    • 对召回结果做过滤(时间、店铺、商品)
  2. 严格 Prompt 约束
    • 明确要求:“如果文档中没有相关信息,请回答‘我不知道’”
  3. 输出后处理
    • 对关键字段(金额、时间、活动名称)做规则校验
    • 必要时再查一次系统
  4. 可追溯
    • 要求模型在回答中附带引用片段
    • 方便审计与回溯

15. 会话记忆与复杂工作流(Q15)

会话记忆(Chat Memory):

  • 短期记忆:同一对话中的几个轮次
  • 长期记忆:重要信息(常用收货地址、偏好)

实现方式:

  • 存在 Redis / 数据库:
    • key:session:{userId}
    • value:最近对话摘要、重要槽位(订单号、地址)

复杂工作流:

  • 一个“改收货地址”的流程:
    1. 确认订单是否可修改
    2. 进行风控校验
    3. 调用订单服务更新地址
    4. 通知物流

实现思路:

  1. 使用工作流引擎(Camunda、Flowable)编排
  2. 或使用 “Agentic RAG” + 工具调用框架:
    • Agent 负责规划步骤
    • 每一步调用不同工具
    • 由框架协调状态与异常重试

七、总结

通过这场“面试官 vs 水货程序员小Y”的对话,我们串联了:

  1. Java + Spring Boot 基础:接口、ORM、测试、连接池
  2. 微服务与中间件:Spring Cloud、Kafka/RabbitMQ、Redis 缓存
  3. 可观测性与 CI/CD:Prometheus、Grafana、ELK、Jenkins、Docker、K8s
  4. AI 智能客服实践:RAG、Agent、向量数据库、会话记忆、复杂工作流

如果你是刚入门的 Java 求职者,可以按这个顺序一步步学习:

Java 基础 → Spring Boot 实战 → 微服务与中间件 → 监控与部署 → RAG + Agent 实战

下次面对大厂面试官的时候,争取不要再像小Y一样“含糊其辞”了。

更多推荐