Spring AI 面试题库
生成时间: 2026-05-22 22:56 题目数量: 10道
本轮 Spring AI 面试题库(带答案)
【面试题】1. ChatClient 和 ChatModel 有什么区别?实际项目怎么选?
【标准答案】 这两个是不同层级的抽象。ChatModel 是底层接口,直接跟模型厂商对接,你给它 Prompt,它返回 ChatResponse,是最原始的调用方式。ChatClient 是高层门面,在 ChatModel 之上封装了 Fluent API、Advisor 机制、对话记忆这些高级能力。
实际项目我首选 ChatClient,因为它的链式调用特别舒服,比如:
chatClient.prompt()
.user("分析这段代码")
.advisors(new QuestionAnswerAdvisor(vectorStore))
.call()
.content();一行搞定 RAG 增强。除非你要做深度定制,比如自己实现调度逻辑,才考虑直接用 ChatModel。Spring AI 1.0 之后,官方也明确推荐用 ChatClient 作为统一入口。
【面试题】2. Advisor 机制是什么?能解决什么问题?
【标准答案】 Advisor 是 Spring AI 的拦截器架构,类似 Spring MVC 的 HandlerInterceptor。它在请求前后的切面中注入逻辑,比如:
- 请求前:把历史对话塞进 Prompt、从向量库检索相关文档
- 响应后:记录日志、转换输出格式
典型场景:
- ChatMemoryAdvisor:自动管理对话历史,不用每次手动拼接 Message 列表
- QuestionAnswerAdvisor:RAG 场景下,根据用户问题自动检索向量库,把相关文档作为上下文注入
核心接口是 CallAroundAdvisor 和 StreamAroundAdvisor,前者处理同步调用,后者处理流式响应。实现 aroundCall 方法,拿到 AdvisedRequest 做增强,再调用 nextAroundCall 传递给下一个 Advisor。
【面试题】3. VectorStore 这么多实现(PGVector、Redis、Pinecone、Chroma、Milvus),生产环境怎么选?
【标准答案】 选型看三个维度:数据规模、部署模式、团队能力。
PGVector:
- 优势:团队熟悉 PostgreSQL,运维成本低,事务支持好
- 劣势:大规模向量检索性能一般,适合中小规模(百万级以内)
- 场景:已有 PG 基础设施,向量只是辅助功能
Milvus:
- 优势:专为向量设计,十亿级检索性能强,支持多种索引(IVF、HNSW)
- 劣势:独立集群,运维复杂
- 场景:大规模向量检索,专门的向量数据库场景
Redis Stack:
- 优势:团队熟悉,支持向量+缓存一体化,延迟低
- 劣势:内存成本高,适合热数据
- 场景:对延迟敏感,数据量不大
Pinecone:
- 优势:全托管,零运维,快速上手
- 劣势:成本高,数据出海外有合规风险
- 场景:海外项目,快速验证
我的经验:中小项目直接 PGVector,省运维;大规模项目 Milvus;海外快速上 Pinecone。
【面试题】4. Function Calling 的 tool_call 调度流程是怎样的?底层原理是什么?
【标准答案】 整个流程分三步:
第一步:模型决策 用户问题 + 可用工具列表发送给模型,模型判断是否需要调工具。如果需要,返回 tool_call 类型的响应,包含函数名和参数。
第二步:函数执行 Spring AI 自动解析 tool_call,从 Spring 容器找到对应 Bean,传入参数执行。这里关键是 JSON Schema 自动生成——框架扫描 @Bean 注册的函数,根据方法签名生成 Schema,模型根据 Schema 填参数。
第三步:结果回填 执行结果封装成 tool 类型的 Message,连同原始对话一起再发给模型,模型给出最终回答。
底层原理:Spring AI 通过 FunctionCallback 接口封装函数,FunctionCallbackWrapper 负责参数解析和结果转换。配置时用 @Bean 注册,框架自动扫描并注入到 ChatClient。
【面试题】5. BeanOutputConverter 怎么用?有什么坑?
【标准答案】 BeanOutputConverter 用于把模型输出转换成 Java 对象,核心方法:
BeanOutputConverter<Order> converter = new BeanOutputConverter<>(Order.class);
Order order = converter.convert(response.getContent());使用要点:
- POJO 必须有无参构造和 setter/getter
- 字段名要和 JSON key 一致,或用
@JsonProperty映射 - 嵌套对象也能自动映射,但类型要匹配
常见坑:
- Schema 不准确:框架生成的 JSON Schema 有时不够精确,复杂对象可能映射失败。建议手动指定 Schema:java
BeanOutputConverter<Order> converter = new BeanOutputConverter<>(Order.class, customSchema); - 模型幻觉字段:模型可能返回多余字段,
ObjectMapper默认不报错,但业务逻辑可能异常。建议配置DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES - 空值处理:模型可能返回
null,业务代码要防御
【面试题】6. ChatMemory 对话记忆怎么持久化?InMemoryChatMemory 有什么局限?
【标准答案】 Spring AI 的 ChatMemory 接口定义了对话历史管理规范:
public interface ChatMemory {
void add(String conversationId, List<Message> messages);
List<Message> get(String conversationId, int lastN);
void clear(String conversationId);
}InMemoryChatMemory 局限:
- 数据只存内存,应用重启就丢失
- 单机,无法横向扩展
- 适合单轮会话或临时缓存
持久化方案: 实现自定义 ChatMemory,底层用数据库存储:
public class JdbcChatMemory implements ChatMemory {
private JdbcTemplate jdbc;
@Override
public void add(String conversationId, List<Message> messages) {
messages.forEach(msg -> {
jdbc.update(
"INSERT INTO chat_memory (conv_id, role, content, created_at) VALUES (?,?,?,?)",
conversationId, msg.getMessageType().name(), msg.getContent(), Instant.now()
);
});
}
@Override
public List<Message> get(String conversationId, int lastN) {
return jdbc.query(
"SELECT role, content FROM chat_memory WHERE conv_id = ? ORDER BY created_at DESC LIMIT ?",
(rs, i) -> new ChatMessage(rs.getString("role"), rs.getString("content")),
conversationId, lastN
);
}
}生产环境建议:Redis(热数据)+ MySQL(冷数据),配合 TTL 自动清理。
【面试题】7. 多模型对接怎么实现切换?spring.ai.* 配置怎么配?
【标准答案】 Spring AI 通过 spring.ai.* 配置前缀实现多模型切换。
配置示例(OpenAI):
spring:
ai:
openai:
api-key: ${OPENAI_API_KEY}
base-url: https://api.openai.com
chat:
options:
model: gpt-4
temperature: 0.7切换到 Ollama:
spring:
ai:
ollama:
base-url: http://localhost:11434
chat:
options:
model: llama3多模型并存: 如果项目里要同时支持多个模型,可以定义多个 ChatModel Bean:
@Bean
public ChatModel openAiChat(OpenAiChatProperties props) {
return new OpenAiChatModel(props);
}
@Bean
public ChatModel ollamaChat(OllamaChatProperties props) {
return new OllamaChatModel(props);
}业务代码里按需注入:
@Autowired @Qualifier("openAiChat")
private ChatModel openAi;
@Autowired @Qualifier("ollamaChat")
private ChatModel ollama;动态切换:用路由策略,根据请求参数或用户配置选择模型:
public ChatModel resolveModel(String modelType) {
return switch (modelType) {
case "openai" -> openAi;
case "ollama" -> ollama;
default -> openAi;
};
}【面试题】8. 流式响应(Streaming)怎么实现?有什么注意事项?
【标准答案】 Spring AI 的流式响应用 Flux<String> 返回:
@GetMapping(value = "/chat/stream", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
public Flux<String> streamChat(@RequestParam String question) {
return chatClient.prompt()
.user(question)
.stream()
.content();
}核心注意点:
背压处理: WebFlux 的 Flux 自带背压机制,客户端消费慢时自动降低生产速度。但要注意:如果上游模型响应很快,下游消费慢,可能导致内存积压。建议用
limitRate()控制速率:java.stream().content().limitRate(10)超时控制: 流式响应超时比较特殊,不能简单用
timeout(),建议用takeUntilOther():javaFlux<String> timeoutSignal = Flux.interval(Duration.ofSeconds(30)); stream.content().takeUntilOther(timeoutSignal);错误恢复: 流式中断要优雅降级:
java.onErrorResume(e -> { log.error("Stream error", e); return Flux.just("抱歉,生成中断"); })前端对接: SSE 格式,前端用
EventSource接收:javascriptconst source = new EventSource('/chat/stream?question=xxx'); source.onmessage = e => console.log(e.data);
【面试题】9. Spring AI 1.0 相比之前的版本有哪些重大变化?
【标准答案】 Spring AI 1.0 是正式版,相比 M 系列(Milestones)有几个核心变化:
1. ChatClient 统一入口: 之前版本 ChatModel 和 StreamingChatModel 分离,1.0 之后统一用 ChatClient 的 call() 和 stream() 方法,API 更一致。
2. Advisor 架构稳定: 之前 Advisor 是实验特性,1.0 正式稳定。CallAroundAdvisor 和 StreamAroundAdvisor 接口固化,官方提供 ChatMemoryAdvisor、QuestionAnswerAdvisor 等实现。
3. VectorStore 接口统一: 之前不同向量库接口有差异,1.0 统一为:
public interface VectorStore {
void add(List<Document> documents);
List<Document> similaritySearch(String query);
List<Document> similaritySearch(SearchRequest request);
}新增 SearchRequest 支持分页、过滤、阈值等参数。
4. 配置前缀标准化: spring.ai.* 正式成为配置规范,所有模型配置统一前缀:
spring.ai.openai.*spring.ai.ollama.*spring.ai.anthropic.*
5. 结构化输出增强: BeanOutputConverter 支持更复杂的 POJO,新增 entity() 方法直接映射:
Order order = chatClient.prompt()
.user("解析订单:" + text)
.call()
.entity(Order.class);【面试题】10. 设计一个智能客服系统,要支持多轮对话、知识库检索、订单查询,用 Spring AI 怎么架构?
【标准答案】 我会分四层设计:
第一层:接入层
- WebFlux 暴露两个端点:
/chat(同步)、/chat/stream(流式) - 前端用 SSE 接收流式响应
- 请求参数:
userId、sessionId、question
第二层:对话编排层(核心)
@Service
public class CustomerServiceOrchestrator {
private final ChatClient chatClient;
private final VectorStore vectorStore;
public String chat(String userId, String sessionId, String question) {
return chatClient.prompt()
.user(question)
// 对话记忆
.advisors(new MessageChatMemoryAdvisor(chatMemory, sessionId, 10))
// RAG 增强
.advisors(new QuestionAnswerAdvisor(vectorStore))
// 工具调用
.functions("queryOrder", "queryLogistics")
.call()
.content();
}
}第三层:工具层
queryOrder:查询订单状态(Bean 注册,参数:订单号)queryLogistics:查询物流信息(Bean 注册,参数:运单号)knowledgeSearch:知识库检索(Advisor 自动处理)
第四层:数据层
- ChatMemory:Redis 存储,按 sessionId 分 key,TTL 24h
- VectorStore:Milvus 存知识库文档,PGVector 存临时数据
- 业务库:MySQL 存订单、物流数据
核心流程:
- 用户问题进来
- ChatMemoryAdvisor 自动注入历史对话
- QuestionAnswerAdvisor 检索知识库,把相关文档注入 Prompt
- 模型判断是否需要调工具(查订单/物流)
- Function Calling 执行查询,结果回填
- 模型生成最终回复
- 历史记录存入 Redis
性能优化:
- 流式响应,减少首字延迟
- 向量库索引优化(HNSW)
- 对话历史压缩(只保留关键信息)
- 工具调用结果缓存(热点订单)
题目统计: 共10道面试题,覆盖技术基础(2题)、架构设计(3题)、场景实操(3题)、版本更新(1题)、综合应用(1题)