跳到主要内容

SpringAI开发面试速查

对应模块

本文对应 Spring AI详细解析 模块全部文档的面试考点提炼。这是本项目独有的Java/Spring生态AI开发内容。

架构与设计

Q1:Spring AI的核心设计理念是什么?跟直接调模型API比优势在哪?

设计理念跟Spring Data一脉相承——面向接口编程,屏蔽底层差异。不管你底层用OpenAI、Claude还是Qwen,业务代码用的都是同一套ChatClient API。换模型改配置就行,代码零改动。

直接调API的痛点:每个厂商的SDK类名、方法名、参数结构都不同,换个提供商要大改代码;流式/非流式实现方式各异;错误处理逻辑要针对每家写一套。

Spring AI解决了这些,核心抽象:ChatClient(高层API)→ ChatModel(模型抽象)→ 各Provider实现(OpenAI/Ollama/阿里等)。

📖 Spring AI核心架构解析


Q2:ChatClient和ChatModel分别是什么角色?

ChatModel:低层抽象,对应一个具体的模型实现。每个Provider实现一个(OpenAiChatModel、OllamaChatModel等)。直接调用时需要手动组装Prompt、解析返回。

ChatClient:高层流式API,包装了ChatModel。提供链式调用、自动类型转换、Advisor注入等便利能力。日常开发主要跟ChatClient打交道。

类比:ChatModel像JDBC的Connection,ChatClient像JPA的Repository——后者在前者基础上做了很多易用性封装。

📖 Spring AI核心架构解析 | Java调用大模型全景图


Q3:流式输出在Spring AI中怎么实现?工程上要注意什么?

通过WebFlux的Flux响应式流实现:

@GetMapping(value = "/chat/stream", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
public Flux<String> stream(@RequestParam String q) {
return chatClient.prompt().user(q).stream().content();
}

前端通过EventSource或fetch的ReadableStream接收SSE事件。

工程注意点:

  • Nginx/网关层要禁用response buffering(否则会攒一堆再一次性推)
  • 设置合理的超时时间(大模型生成可能要几十秒)
  • Token粒度太碎时可以做mini-batch(每积攒5-10个Token推一次)
  • 要处理连接中断后的优雅降级

📖 响应式流式输出详解


结构化输出与类型安全

Q4:怎么让大模型可靠地输出结构化JSON?Spring AI如何简化这件事?

三种手段按优先级:

  1. 原生JSON Mode:模型API层面强制只输出合法JSON(response_format参数)
  2. Function Calling:让模型"调用函数",参数本身就是结构化数据
  3. Prompt约束+解析+重试:不支持前两种时的兜底方案

Spring AI的做法非常优雅——直接定义一个Java类,调用时指定.entity(),框架自动处理Schema生成、Prompt注入、响应解析:

record FilmReview(String title, int score, String comment) {}

FilmReview review = chatClient.prompt()
.user("评价一下电影《盗梦空间》")
.call()
.entity(FilmReview.class);

底层:Spring AI自动把Java类转成JSON Schema注入到Prompt中,解析模型输出并反序列化。如果解析失败会自动重试。

📖 结构化输出深度剖析


Advisor拦截器

Q5:Advisor机制的设计思路?怎么用它实现RAG?

Advisor借鉴了Spring MVC的Interceptor/AOP思想——在LLM请求的生命周期中提供"前置处理"和"后置处理"的插入点。

执行流程:请求进来 → Advisor链逐个前置处理 → 发给模型 → Advisor链逆序后置处理 → 返回。

用Advisor实现RAG:

ChatClient client = ChatClient.builder(chatModel)
.defaultAdvisors(
new MessageChatMemoryAdvisor(memory), // 加载对话历史
new RetrievalAugmentationAdvisor(retriever) // 检索并注入文档
)
.build();

RetrievalAugmentationAdvisor在前置阶段:拿用户问题去向量库检索 → 把检索结果拼进System Prompt → 模型就能基于真实文档回答了。

好处:RAG逻辑、记忆逻辑、日志逻辑彼此独立,可插拔组合。

📖 Advisor拦截器机制揭秘


对话记忆

Q6:Spring AI的对话记忆系统怎么设计?多用户多会话怎么隔离?

核心组件是ChatMemory接口 + MessageChatMemoryAdvisor:

  • 存储:把每轮对话持久化(内存/Redis/数据库,按需选)
  • 加载:每次请求时按conversationId加载历史消息
  • 裁剪:控制加载条数或Token上限,防止超出上下文窗口

多用户隔离通过conversationId实现——每个用户的每个对话窗口分配唯一ID,查询和存储都以此为主键。

var advisor = new MessageChatMemoryAdvisor(chatMemory, conversationId, 10);
// 10 = 最多加载最近10条消息

高级玩法:隔了很久回来的对话,可以在加载前做相关性判断——如果当前问题跟历史对话语义无关,就不加载旧历史(相当于自动"新话题检测")。

📖 对话记忆系统设计


Q7:Prompt模板在Spring AI中怎么用?跟硬编码字符串比好在哪?

Spring AI的PromptTemplate用花括号占位符做参数化构建,用法跟MessageFormat类似:定义模板字符串,调用时传入Map填充变量。

比如定义一个模板包含role、style、question三个占位符,调用template.create(Map.of(...))时把具体值传进去,框架自动替换生成最终Prompt。

比硬编码字符串的优势:

  • 模板可以从外部文件加载(Resource接口读取classpath下的.st文件),修改不用改代码重新部署
  • 支持版本管理和A/B测试(同一个入口切不同模板文件)
  • 参数校验——忘传某个变量会报错而不是生成一个带占位符的Prompt
  • 跟Advisor配合可以实现动态Prompt组装

📖 提示词工程实践指南

🎁优惠