从Spring Boot到Agentic RAG互联网大厂Java面试三轮实战对话与详解场景一家头部内容社区 AIGC 智能问答平台招聘中高级 Java 开发。严肃的面试官 vs 搞笑的“水货程序员”小 Y通过 3 轮、逐步加深的问答覆盖 Java 基础、Spring 全家桶、微服务、缓存、消息队列、搜索、AI RAG 等核心技术。文末附完整答案解析小白也能看懂。一、业务背景设定公司产品是一个“内容社区 AIGC 问答 智能客服”的综合平台类似用户在社区发帖、点赞、评论内容社区与UGC后台有推荐系统、搜索系统、风控系统新增 AI 问答与企业智能客服支持 RAG 和 Agent 工作流大数据与AI服务、企业协同与SaaS技术栈核心后端Java 11/17Spring Boot、Spring Cloud、Spring WebFlux存储MySQL Redis Elasticsearch Kafka容器运维Docker、Kubernetes、Prometheus、Grafana、ELKAISpring AI RAG 向量数据库Milvus/Chroma/Redis Agentic Workflow面试分 3 轮每轮 3~5 个问题场景逐渐复杂。二、第一轮基础服务与业务接口相对简单小 Y 尚能发挥业务场景实现“帖子发布与详情查看”服务用户可以发帖、查看帖子详情与评论列表。第一轮对话面试官小 Y先从简单的来。我们帖子服务是一个 Spring Boot 应用提供 REST API。请你说说你会如何设计发帖和查帖这两个接口用什么 HTTP 方法、URL、以及大致的请求/响应结构在 Spring MVC 里这两个接口你会怎么写说下核心注解和参数绑定方式。小 Y这个简单我发帖就用POST比如/posts请求体放 JSON标题、内容、作者 ID。查帖子就GET /posts/{id}返回帖子详情和评论。Spring MVC 就RestController上面RequestMapping方法上PostMapping和GetMapping参数用RequestBody、PathVariable绑定返回一个对象就会自动转 JSON用 Jackson。这个稳的。面试官回答得还不错基本 RESTful 思路是对的。再问下 3. 假设发帖接口要做简单校验比如标题不能为空、长度不能超过 100你会怎么实现用什么注解小 Y啊这个用那个……好像是NotNull之类的吧我记得可以在字段上加几个注解然后控制层就自动校验了反正我以前项目里别人配好的我就照抄。笑面试官好的那最后一个 4. 对于这些接口你会怎么写单元测试用到哪些测试框架小 Y单元测试嘛肯定是 JUnit 5然后还可以用 Mockito 模拟服务层。我一般就是写几个测试方法调一下 Controller看能不能跑通。细节嘛……呃……这个回头我可以再查一下文档。挠头三、第二轮高并发、缓存与消息队列开始暴露“水货”气质业务场景升级帖子发布成功后需要异步刷写到推荐系统增加作者的发帖计数更新 Redis 缓存发送消息给下游“搜索索引服务”Elasticsearch第二轮对话面试官现在我们的发帖接口 QPS 比较高帖子详情访问量也很大。考虑高并发性能你会怎么设计缓存比如热门帖详情你打算怎么用 Redis说说你的缓存 Key 设计、过期策略、以及避免缓存击穿、雪崩、穿透的方案。小 YRedis 我熟缓存 Key 我就用post:{id}value 放帖子 JSON。过期时间嘛随缘……呃不是根据业务设置比如 10 分钟。击穿和那几个我记得是缓存雪崩就多设置点随机过期时间。穿透就用布隆过滤器。击穿就加锁或者用什么互斥锁策略吧。反正思路就是这些。面试官思路还行那我们继续。 2. 发帖成功后要通知“搜索索引服务”更新 Elasticsearch 索引你会选择用什么消息队列Kafka、RabbitMQ、还是其他说说你的考虑。小 Y这个看公司爱好吧。要是追求高吞吐一般就是 Kafka。我感觉大家都用 Kafka就……用 Kafka。理由嘛主要是大厂都这么配的。严肃脸面试官如果你用 Kafka 3. 大致的 Topic 设计、消息内容结构会怎么做生产者、消费者在 Spring Boot 里怎么写小 YTopic 就叫post_created之类的消息体就是 JSON里面放帖子 ID、标题、内容。Spring Boot 里我记得加spring-kafka依赖然后用配置写一下 broker 地址生产者就用KafkaTemplate发送消费者就KafkaListener。我以前看同事写过很像的。面试官好那再往下。 4. 索引服务使用 Elasticsearch 时怎么保证写入 ES 和写 MySQL 时的一致性比如MySQL 成功ES 失败你会怎么补偿或者保证最终一致性小 Y这个……呃……我觉得一般不会失败吧小声真失败了就重试一下可以写个定时任务扫一遍没成功的再写一次。具体细节我觉得可以后面慢慢优化嘛……面试官嗯思路有一点但比较模糊。最后一个 5. 这些高并发场景下你会用到哪些监控指标比如 Prometheus Grafana你会重点监控哪些指标来判断系统是否健康小 Y监控……我知道要看 QPS还有 RT 响应时间。还有错误率5xx 比例。Kafka 那边可以看看消费堆积。Prometheus、Grafana 这些我基本没配过就是会看图。尴尬笑四、第三轮微服务、容器化与 AI RAG/Agent彻底开始模糊应对业务场景再次升级我们要把“帖子服务”、“搜索服务”、“推荐服务”、“AI 问答服务”、“企业智能客服服务”拆成多个微服务引入 RAG检索增强生成、向量数据库实现“基于社区知识库的智能问答”和企业文档问答要在 Kubernetes 上部署配合 CI/CD 自动上线第三轮对话面试官我们先从微服务说起。现在帖子服务、搜索服务、AI 问答服务都是独立微服务你会用什么框架做服务治理和调用Spring Cloud、Dubbo、还是 gRPC请说明你的选择和典型使用场景。小 Y嗯……这个要看历史包袱和公司喜好。我之前听说 Spring Cloud 比较全家桶有注册中心Eureka/Consul、网关Spring Cloud Gateway/Zuul再加个 OpenFeign 做调用。我个人觉得……同事们都用 Spring Cloud 的话我也可以跟上。中规中矩的“别人都这么做”式回答面试官好那如果我们用 Spring Cloud OpenFeign你会怎么设计从“AI 问答服务”调用“知识检索服务”的接口包括Feign 客户端如何声明如何做超时和熔断比如用 Resilience4j小 YFeign 的话就写个接口然后加FeignClient(name knowledge-service)方法上GetMapping或者PostMapping参数正常写。超时和熔断的话好像在配置文件里可以设超时时间熔断我知道 Resilience4j 能弄一些注解比如CircuitBreaker但是我没亲自配过。小声面试官那我们具体到 AI 场景。现在我们要做一个 RAG检索增强生成系统 2. 用户在社区问问题“AI 问答服务”需要先在向量数据库比如 Milvus/Chroma/Redis 向量索引检索相关帖子内容然后把检索结果和用户问题一起喂给大模型Spring AI OpenAI 模型生成答案 你能简单描述一下整个调用链和关键组件吗小 Y这个我最近在看但还没做过。大概就是先把帖子内容用 Embedding 模型向量化存到向量数据库用户提问时也向量化一下然后做相似度检索拿到几个相关文档然后把这些内容拼到 Prompt 里让模型生成答案。这叫 RAG。我知道有 Spring AI可以帮我们调用模型和做提示填充。细节上嘛向量数据库怎么配我还需要再研究一下。认真但略显虚面试官那我们再进阶一点Agentic RAG 3. 我们希望“智能客服系统”可以根据问题自动选择工具比如查订单调用订单微服务查物流调用物流微服务查社区知识调用 RAG 检索查询风控结果调用风控微服务 你理解的 Agent、工具执行框架、工具调用标准化大概是个什么概念如何和现有 Java 微服务体系结合小 YAgent……我理解就是一个“更聪明的机器人”它可以根据用户问题决定下一步用哪个工具。工具执行框架就是预先定义好工具的接口比如“查订单”是一个函数Agent 可以决定要不要调用。工具调用标准化嘛就是统一输入、输出格式方便编排。怎么和 Java 微服务结合……呃大致可以通过 HTTP 调用或者 gRPC 这些方式统一一下具体实现我还没真正做过只是看过几篇文章。继续模糊面试官好最后一个问题 4. 对于这种多服务、多组件MySQL、Redis、Kafka、向量数据库、模型服务的复杂系统你会如何在 Kubernetes 上部署并利用 CI/CDJenkins/GitLab CI/GitHub Actions实现一键发布说说核心步骤和注意点即可。小 YK8s 的话我知道要写 Deployment、Service、ConfigMap、Secret 这些 YAML。CI/CD 就在 GitLab CI 或 GitHub Actions 里面写 pipeline先打包 Maven、再用 Docker 打镜像推到镜像仓库然后 Kubectl 或者 Helm 更新。注意点……就注意配置要分环境、健康检查要配好资源限制也要设一下。具体的 YAML 我平时是让 DevOps 大哥搞的我主要关注业务代码。尴尬又真诚面试官行今天就先到这儿你回去等通知吧我们后面会统一反馈。五、面试问题详细解析小白也能看懂下面对上文三轮问题逐个做详细解析按照“业务场景 技术要点”的方式整理。第一轮解析Spring Boot REST 校验 测试1. 发帖 / 查帖接口设计业务场景内容社区最基础的功能发帖、看帖。典型 REST 设计发帖POST /api/postsRequest BodyJSON{ title: 如何学习 Spring Boot, content: ……, authorId: 123 }Response返回新建帖子的详细信息包含自增 ID{ id: 1001, title: 如何学习 Spring Boot, content: ……, authorId: 123, createdAt: 2024-06-01T10:00:00Z }查帖详情GET /api/posts/{id}Path VariableidResponse帖子详情 评论列表可拆成两个接口也可聚合返回{ id: 1001, title: 如何学习 Spring Boot, content: ……, authorId: 123, comments: [ {id: 1, content: 写得不错, userId: 456}, {id: 2, content: 收藏了, userId: 789} ] }REST 设计要点使用资源名复数/posts表示“帖子集合”使用 HTTP 方法区分“动作”POST创建GET查询PUT/PATCH更新DELETE删除2. Spring MVC 实现接口的核心注解控制层示例RestController RequestMapping(/api/posts) public class PostController { private final PostService postService; public PostController(PostService postService) { this.postService postService; } PostMapping public PostDTO createPost(Valid RequestBody CreatePostRequest req) { return postService.createPost(req); } GetMapping(/{id}) public PostDTO getPost(PathVariable Long id) { return postService.getPost(id); } }核心注解说明RestController相当于Controller ResponseBody返回对象会自动序列化为 JSON默认 JacksonRequestMapping类级别路径前缀PostMapping/GetMapping方法级别的 HTTP 路由RequestBody从请求体中读取 JSON 并绑定到 Java 对象PathVariable从 URL 路径中读取变量3. 参数校验Bean Validation使用 JSR 规范Jakarta Bean Validation在 DTO 上加约束注解并在 Controller 使用Valid触发校验。public class CreatePostRequest { NotBlank Size(max 100) private String title; NotBlank private String content; NotNull private Long authorId; // getter / setter }要点常用注解NotBlank、NotNull、Size、Min、Max等在 Controller 方法参数前加Valid才会触发校验配合ControllerAdviceExceptionHandler(MethodArgumentNotValidException)可以统一处理错误并返回友好 JSON4. 单元测试与集成测试在 Spring Boot 中常用JUnit 5基础测试框架Spring Boot TestSpringBootTest、WebMvcTestMockitoMock service 或 repositoryAssertJ链式断言示例只测试 Controller Web 层不启动完整容器WebMvcTest(PostController.class) class PostControllerTest { Autowired private MockMvc mockMvc; MockBean private PostService postService; Test void testGetPost() throws Exception { PostDTO dto new PostDTO(); dto.setId(1L); dto.setTitle(test); Mockito.when(postService.getPost(1L)).thenReturn(dto); mockMvc.perform(get(/api/posts/1)) .andExpect(status().isOk()) .andExpect(jsonPath($.id).value(1L)); } }第二轮解析Redis 缓存 Kafka 消息 ES 最终一致性 监控1. 详情缓存设计与缓存三大问题业务场景热点帖子详情访问量很高直接打 MySQL 会有性能瓶颈于是使用 Redis 做缓存。Key 设计post:{id}如post:1001值帖子详情 JSON 字符串过期策略一般为几十分钟到几个小时加随机偏移如在 30 分钟基础上加0~5分钟随机数避免大量 Key 同时过期导致缓存雪崩三大问题与常见解法缓存穿透大量请求访问根本不存在的数据DB 也没有导致每次都打 DB方案布隆过滤器比如在 Redis 或 Guava 里过滤掉明显不存在的 ID或者对查询结果为空的 ID 也写入缓存短期空值缓存缓存雪崩某一时刻大量 Key 同时过期请求全部打到 DB方案为每个 Key 的 TTL 加随机偏移做多级缓存本地 Caffeine Redis缓存击穿某个热点 Key 过期了短时间大量请求打到 DB方案使用互斥锁重建缓存只有一个线程去查 DB其余等待使用逻辑过期后台线程异步刷新2. Kafka 选型与 Topic 设计业务场景发帖成功后需要通知“搜索索引服务”更新 Elasticsearch要求高吞吐、高可用、可回溯。选 Kafka 的理由高吞吐量适合日志、行为上报、搜索索引等场景多副本和分区机制弹性扩展和故障恢复消费组机制支持水平扩展消费者Topic 设计名称post-created、post-updated等按事件类型命名分区根据 QPS 分配按postIdhash 到分区可以保证同一帖子事件有序消息内容JSON 或 Protobuf{ eventType: POST_CREATED, postId: 1001, authorId: 123, title: 如何学习 Spring Boot, createdAt: 2024-06-01T10:00:00Z }Spring Boot 集成示例生产者Service public class PostEventPublisher { private final KafkaTemplateString, String kafkaTemplate; public void publishPostCreated(PostCreatedEvent event) { String key String.valueOf(event.getPostId()); String value objectMapper.writeValueAsString(event); kafkaTemplate.send(post-created, key, value); } }消费者Service public class PostEventConsumer { KafkaListener(topics post-created, groupId search-indexer) public void onMessage(String message) { // 反序列化写入 Elasticsearch } }3. MySQL 与 Elasticsearch 的最终一致性问题如果写 MySQL 成功但写 ES 失败如何保证最终一致常见方案事务内只写 MySQL然后通过消息队列Kafka异步写 ES发帖服务在 DB 事务提交后发送事件到 Kafka索引服务消费事件并写入 ES如果写 ES 失败自动重试带最大重试次数死信队列DLQ记录失败消息定时任务扫描失败记录进行补偿Outbox 模式在业务 DB 中增加outbox事件表在同一个事务中写业务表和 outbox 表后台有一个可靠的“Outbox 消费者”轮询表发送消息给 Kafka/ES保证“写 DB”与“发送消息”具备事务性总体原则放弃强一致追求可观测的最终一致性。4. 监控指标Prometheus Grafana Micrometer关键指标应用层QPS接口调用次数/秒延迟P95、P99 响应时间错误率HTTP 5xx 占比线程池使用情况活跃线程、队列长度Redis命中率、连接数、慢查询、内存使用KafkaTopic 的 lag积压量生产/消费 TPS消费者异常DB(MySQL)QPS、慢查询数连接池指标HikariCP容器CPU/内存使用率、重启次数使用 Micrometer Spring Boot actuator 暴露/actuator/prometheusPrometheus 拉取Grafana 展示图表和告警。第三轮解析微服务治理 RAG/Agent K8s/CI/CD1. 微服务调用与治理Spring Cloud / Dubbo / gRPC场景帖子服务、搜索服务、AI 问答服务、知识检索服务、订单/物流服务等都是独立微服务。Spring Cloud服务注册/发现Eureka/Consul配置中心Spring Cloud Config / Nacos网关Spring Cloud Gateway / Zuul声明式调用OpenFeign容错Resilience4jDubbo适合高性能 RPC常用于内部服务调用gRPC跨语言、高性能二进制协议Protobuf示例AI 问答服务通过 Feign 调用知识检索服务FeignClient(name knowledge-service, path /api/knowledge) public interface KnowledgeClient { GetMapping(/search) ListDocDTO search(RequestParam(query) String query); }配合 Resilience4jService public class QaService { CircuitBreaker(name knowledgeService, fallbackMethod fallbackSearch) public ListDocDTO searchDocs(String query) { return knowledgeClient.search(query); } public ListDocDTO fallbackSearch(String query, Throwable t) { // 降级策略返回空列表或兜底答案 return Collections.emptyList(); } }2. RAG检索增强生成架构业务场景基于社区帖子和企业文档提供“智能问答”和“企业文档问答”。RAG 典型流程离线构建知识库文档加载从数据库、Elasticsearch、OSS、企业网盘等读取文档切分 Chunk长文档拆成小片段比如 500~1000 字向量化调用 Embedding 模型OpenAI / 本地模型 / Ollama生成向量存储向量 原文片段保存到向量数据库Milvus/Chroma/Redis Vector在线查询用户问题向量化在向量数据库中做相似度检索找到 Top-K 相关片段采用提示填充Prompt Filling模板你是一个知识助手根据下面给出的参考文档回答用户问题。 如果文档中没有相关信息请明确说不知道不要编造。 【用户问题】 {question} 【参考文档】 {context}调用大模型生成答案避免 AI 幻觉Hallucination在 Prompt 中明确要求“没有证据不要乱编”在答案中引用相关文档的片段或链接对敏感场景加规则/风控Spring AI 可以帮助统一“向量化 检索 模型调用”的开发体验Java 开发只需要配置好EmbeddingClientVectorStoreMilvus/Chroma/RedisChatModelOpenAI/Ollama 等3. Agent 与工具执行框架Agentic RAG业务场景智能客服不仅要“查知识”还要“查订单、查物流、查风控记录”等需要调用多个后端系统。Agentic RAG 的核心思想在 RAG 的基础上让“Agent”拥有调用工具Tool的能力工具的本质是“函数/接口”例如getOrderStatus(orderId)→ 调订单服务getDeliveryInfo(orderId)→ 调物流服务ragSearch(question)→ RAG 检索工具调用标准化每个工具有统一的名称参数描述类型、含义返回格式模型可以根据用户意图决定是否调用工具以及调用顺序工作流与 Java 微服务结合方式在 Java 后端定义一层 Tool Adapter对内部微服务HTTP/gRPC/Dubbo封装为函数式接口对外暴露统一的 JSON-RPC / HTTP API供 Agent 调用可以使用“工具执行框架”来统一调度记录日志、重试、超时等复杂工作流案例用户问“我昨天买的那本《Java 并发编程实战》现在物流到哪了”Agent 解析需要先查订单→再查物流→再 RAG 检索售后规则工作流工具 AgetOrderByUserAndProduct(userId, productName)工具 BgetDeliveryStatus(orderId)工具 CragSearchAfterSalePolicy(productCategory)Agentic RAG 的优势同时利用结构化数据订单、物流和非结构化知识售后文档能完成更加复杂的“多步任务”4. Kubernetes 部署与 CI/CDK8s 部署要素Deployment描述应用副本数、镜像、启动命令Service对外暴露端口ClusterIP / NodePort / LoadBalancerConfigMap配置文件如application.ymlSecret敏感信息DB 密码、API KeyIngress域名路由示例简化版apiVersion: apps/v1 kind: Deployment metadata: name: post-service spec: replicas: 3 selector: matchLabels: app: post-service template: metadata: labels: app: post-service spec: containers: - name: post-service image: registry.example.com/post-service:1.0.0 ports: - containerPort: 8080 envFrom: - configMapRef: name: post-service-config - secretRef: name: post-service-secretCI/CD 流程以 GitLab CI 为例代码提交到 Git 分支GitLab CI Pipelinemvn test运行单元测试JUnit/Mockitomvn package打包 Jardocker build构建 Docker 镜像docker push推送到镜像仓库kubectl apply或helm upgrade更新到 K8s生产环境需蓝绿部署或滚动升级健康检查liveness/readiness probe灰度发布、回滚策略六、总结从“会用 API”到“能设计系统”这篇文章通过严肃面试官和搞笑“水货程序员”小 Y 的三轮对话从一个内容社区 AIGC 平台的场景出发逐步覆盖第一轮Spring Boot/Spring MVC、REST、Bean Validation、JUnit 测试第二轮Redis 缓存设计、Kafka 事件驱动、Elasticsearch 最终一致性、Prometheus Grafana 监控第三轮Spring Cloud 微服务治理、OpenFeign Resilience4j、RAG/向量数据库、Agentic RAG、K8s 部署 CI/CD如果你正在准备互联网大厂的 Java 面试建议按照本文的业务场景自行画出整体架构图把每一块技术点用自己的语言讲给别人听至少用 Spring Boot 实现一套简化版 Demo发帖、缓存、Kafka 事件、简单搜索再尝试加上一个简单的 RAG 服务哪怕是用本地小模型当你能把“技术关键字列表”串成一个完整的业务故事并讲清楚设计取舍时你离真正的大厂中高级 Java 工程师就不远了。