Spring AI 面试题库
生成时间:2026-05-21 20:34 (Asia/Shanghai) 题目数量:10道 覆盖范围:Spring AI 核心架构、RAG、Function Calling、多模型对接、结构化输出、Chat Memory、微服务部署、版本更新、生态集成、前沿趋势
【面试题】1. Spring AI 中 ChatClient 和 ChatModel 的区别是什么?实际开发中应该用哪个?
【标准答案】ChatModel 是底层模型调用接口,直接面向 AI 模型,只负责发送 Prompt 拿到 Response,是最原始的 API。ChatClient 是 Spring AI 1.0 引入的统一高级入口,类似 WebClient 之于 RestTemplate,它在 ChatModel 之上封装了 Fluent API、Advisor 链、Memory、结构化输出等能力。
实际开发中必须用 ChatClient,原因三点:
- Fluent API 链式调用,代码可读性强:
chatClient.prompt().user("你好").call().content() - Advisor 机制只在 ChatClient 层生效,RAG、Memory、日志切面全部挂在这条链上
- 结构化输出
.entity(Order.class)一行搞定,ChatModel 得自己写 OutputConverter
只有在需要极致控制底层参数(如自定义 HTTP 客户端、特殊 request header)时才直接用 ChatModel,99% 的业务场景 ChatClient 够用。
【面试题】2. Spring AI 的 Advisor 机制是什么?如何用 Advisor 实现 RAG 和对话记忆?
【标准答案】Advisor 是 Spring AI 1.0 的核心架构设计,本质是请求/响应拦截器链,类似 Servlet Filter 或 Spring Interceptor。每个 Advisor 可以在请求发给模型前修改 Prompt,也可以在模型响应后修改结果。
接口核心:CallAroundAdvisor(同步)和 StreamAroundAdvisor(流式),关键方法是 aroundCall() 和 aroundStream(),传入 AdvisedRequest 返回 AdvisedResponse。
RAG 实现方式:用 QuestionAnswerAdvisor,它会在请求前自动调用 VectorStore 的 similaritySearch 检索相关文档,把检索结果拼接到 Prompt 上下文中,整个过程对业务代码透明。
对话记忆实现方式:用 MessageChatMemoryAdvisor,它在请求前从 ChatMemory 中读取历史消息追加到 Prompt,响应后把新的用户消息和 AI 回复存入 ChatMemory。
关键细节:Advisor 有顺序,order 值小的先执行。Memory 的 order 要比 RAG 小,因为要先恢复上下文,再做检索增强,顺序反了会导致 RAG 拿不到当前轮次的完整上下文。
【面试题】3. Spring AI 的 RAG 流程中,TokenTextSplitter 和 EmbeddingModel 分别扮演什么角色?切分策略怎么选?
【标准答案】TokenTextSplitter 负责把长文档切成小段,EmbeddingModel 负责把文本段转成向量。两者是 RAG 数据预处理流水线的两个串联环节。
TokenTextSplitter 的核心参数:
defaultChunkSize:每段 token 数,一般 500-1000minChunkSizeChars:最小字符数,过滤太短的碎片maxNumChunks:最大分段数,防止超大文档打爆内存
切分策略选择:
- 通用文档:默认按 token 切,简单粗暴,够用
- 代码/结构化文档:建议自己写 Splitter,按函数/类/段落切,保持语义完整
- 表格数据:按行切,每行带表头,否则检索结果缺上下文
EmbeddingModel 的选型:
- OpenAI
text-embedding-3-small:性价比之王,1536 维,适合大多数场景 - 本地部署用
bge-large-zh:中文效果好,Ollama 一键启动 - 注意:写入和查询必须用同一个模型,向量空间不同会导致相似度计算全废
一个容易踩的坑:切分时 overlap 设太小,跨段的语义被切断;设太大,存储和检索重复太多。推荐 overlap 设 chunkSize 的 10%-15%。
【面试题】4. Spring AI Function Calling 的完整调用流程是什么?@Bean 注册函数的原理是什么?
【标准答案】完整流程四步走:
- 注册:用
@Bean定义一个返回Function<I, O>的 Bean,Spring AI 自动扫描注册 - Schema 生成:Spring AI 根据函数的入参类型
I,自动生成 JSON Schema(包括字段名、类型、描述),作为tool定义发给模型 - 模型决策:模型判断需要调工具时,返回
tool_call响应,包含函数名和参数 - 框架调度:Spring AI 框架自动拦截
tool_call,从注册表找到对应 Bean,用模型给的参数执行,把结果回传给模型,模型再生成最终回答
@Bean 注册原理:Spring AI 的 FunctionCallbackContext 在启动时扫描所有 Function 类型的 Bean,提取函数名(默认取 Bean 名)、入参类型、输出类型,构建注册表。也可以用 FunctionCallback.builder() 手动注册,更灵活,可以自定义 name、description、inputType。
关键配置:在 ChatClient 调用时通过 .functions("getWeather", "searchDB") 声明本次对话可用哪些工具,模型只会在声明的工具中选择调用。
踩坑点:入参类必须有无参构造器,字段要加 @JsonProperty(required=true) 和 @JsonPropertyDescription,否则生成的 Schema 不准,模型传参会出错。
【面试题】5. Spring AI 支持 Structured Output 的三种方式分别是什么?各有什么坑?
【标准答案】三种方式,从简单到复杂:
方式一:BeanOutputConverter
var converter = new BeanOutputConverter<>(Order.class);
String format = converter.getFormat(); // 拿到 JSON Schema 指令
// 拼到 prompt 里让模型按格式输出
// 然后 converter.fromModelOutput(result) 反序列化坑:format 指令是追加到 Prompt 末尾的,模型可能不遵守格式,尤其是小模型。需要显式在 prompt 中强调"严格按 JSON 格式输出"。
方式二:ChatClient 的 .entity() 方法
Order order = chatClient.prompt().user("生成订单").call().entity(Order.class);一行搞定,底层自动用 BeanOutputConverter + JSON 解析。坑:只支持同步调用,流式场景不能用;解析失败直接抛异常,没有降级。
方式三:OpenAI 原生 structured output(json_schema 模式)
ChatResponse response = chatModel.call(new Prompt("生成订单",
ChatOptionsBuilder.builder().withResponseFormat(new ResponseFormat(ResponseFormat.Type.JSON_SCHEMA, schema)).build()));这个最强,模型层面保证输出格式,几乎不会出错。坑:只有 OpenAI 和少数模型支持,Ollama 本地模型不支持;Schema 写错了调试困难。
通用避坑:POJO 字段用基本类型别用包装类(int 别用 Integer),日期字段加 @JsonFormat,枚举字段加 @JsonProperty 映射,否则反序列化大概率翻车。
【面试题】6. Spring AI 的 ChatMemory 接口设计是什么?生产环境怎么持久化?
【标准答案】ChatMemory 接口非常简洁:
public interface ChatMemory {
void add(String conversationId, List<Message> messages);
List<Message> get(String conversationId, int lastN);
void clear(String conversationId);
}核心就是三个操作:存、取、清。默认提供 InMemoryChatMemory,用 ConcurrentHashMap 存,重启全丢,只能开发测试用。
生产持久化方案:
Redis 方案:自己实现
ChatMemory,用 Redis List 存消息,LPUSH追加、LRANGE取最近 N 条。优点是天然支持 TTL 过期清理,适合高并发场景。数据库方案:建
chat_memory表,字段conversation_id, message_type, content, timestamp,查询用ORDER BY timestamp DESC LIMIT N。适合需要审计日志和复杂查询的场景。混合方案:热数据放 Redis(最近 20 条),冷数据落库(完整历史),兼顾性能和合规。
关键设计点:
- lastN 参数:不能无限拉历史,token 超了模型直接报错。一般取最近 10-20 条,配合模型的 context window 计算
- 消息裁剪:系统消息永远保留,只裁剪中间的历史对话
- 并发安全:同一个 conversationId 可能并发写,Redis 天然原子性,数据库要加乐观锁或用 INSERT 不 UPDATE
【面试题】7. Spring AI 多模型切换怎么实现?spring.ai.* 配置前缀的规则是什么?
【标准答案】Spring AI 用 spring.ai.<provider>.* 的配置前缀区分不同模型提供商,每个 provider 有独立的自动配置类。
配置示例:
spring:
ai:
openai:
api-key: sk-xxx
chat:
options:
model: gpt-4o
temperature: 0.7
ollama:
base-url: http://localhost:11434
chat:
options:
model: qwen2.5
zhipu:
api-key: xxx
chat:
options:
model: glm-4切换方式三种:
依赖切换:只引入一个 starter(如
spring-ai-openai-spring-boot-starter),Spring Boot 自动配置只生效一个 ChatModel Bean。最简单,但换模型要改依赖重启。多 Bean + @Primary:引入多个 starter,用
@Primary指定默认 Bean,其他用@Qualifier按需注入。运行时动态路由:自己封装一个
RoutingChatModel,内部维护 Map<String, ChatModel>,根据请求参数动态选择。适合 A/B 测试或降级场景。
踩坑:多 starter 同时引入时,自动配置可能冲突。用 spring.autoconfigure.exclude 排除不需要的,或者用 @ConditionalOnProperty 精确控制。
【面试题】8. Spring AI 在微服务架构中部署,API Key 管理和限流熔断怎么做?
【标准答案】
API Key 管理:
- 绝对不能硬编码,用 Spring Cloud Config 或 Vault 统一管理,
spring.ai.openai.api-key用${VAULT_API_KEY}引入 - 多租户场景:不要每个租户一个配置文件,用 Key Pool(Key 池),运行时轮询/随机选取,一个 Key 限流了自动切下一个
- Key 轮转:配置中心热更新,不需要重启服务。Spring Cloud Config 配合
@RefreshScope或 Nacos 动态推送
限流熔断:
- 外层限流:用 Sentinel 或 Resilience4j 在 ChatClient 调用外面包一层,QPS 阈值按模型 API 的 RPM 限制设(如 OpenAI gpt-4o 是 500 RPM)
- 熔断降级:连续 N 次调用失败或超时,熔断器打开,直接返回预设的兜底回答,避免雪崩
- 超时设置:模型调用默认超时可能很长,必须手动设。Spring AI 支持通过
spring.ai.openai.chat.options.max-tokens控制输出长度,超时用 HTTP Client 层控制 - 排队机制:突发流量先入队,用 Redis + 令牌桶控制出队速率,避免瞬间打爆模型 API 的并发限制
实际部署建议:模型调用服务单独拆一个微服务,不要和业务逻辑耦合。这样限流熔断配置集中管理,升级模型 SDK 也不影响业务服务。
【面试题】9. Spring AI 1.0 正式版相比之前的里程碑版本有哪些关键变化?
【标准答案】三个核心变化:
1. ChatClient 成为统一入口 之前版本大家直接用 ChatModel,不同模型的调用方式有细微差异。1.0 之后 ChatClient 统一了所有模型的调用方式,Fluent API 一致:prompt().user().call()/stream()。官方明确表态:ChatClient 是推荐的唯一入口,ChatModel 降级为底层 SPI。
2. Advisor 架构正式确立 之前版本的拦截/增强能力散落在各处,没有统一抽象。1.0 把 Advisor 定义为标准接口,所有横切关注点(RAG、Memory、日志、审计)都通过 Advisor 链实现。开发者自定义 Advisor 只需实现 CallAroundAdvisor 接口,通过 order 控制执行顺序。
3. VectorStore 接口统一 之前不同向量库的 API 差异较大,1.0 统一了 VectorStore 接口:add()/delete()/search()/query()。切换向量库只换依赖和配置,业务代码零改动。新增了对 PGVector 和 Chroma 的官方支持。
4. spring.ai. 配置前缀标准化* 之前版本配置属性比较混乱,1.0 统一为 spring.ai.<provider>.<feature>.* 的命名规范,配合 Boot 的 metadata 自动补全,开发体验大幅提升。
5. Observability 内置 1.0 集成了 Micrometer,模型调用的 token 使用量、延迟、错误率全部自动上报,配合 Prometheus + Grafana 开箱即用。
迁移注意:0.8.x 到 1.0 有 breaking change,AiClient 被移除,统一用 ChatClient;部分包路径变了,建议看官方迁移指南。
【面试题】10. Spring AI MCP 支持是什么?它和 Function Calling 有什么区别和联系?
【标准答案】MCP 是 Model Context Protocol,Anthropic 提出的开放标准,定义了 AI 模型与外部工具/数据源的通信协议。Spring AI 从 1.0 开始支持 MCP,可以同时作为 MCP Client 和 MCP Server。
和 Function Calling 的区别:
| 维度 | Function Calling | MCP |
|---|---|---|
| 作用域 | 单个应用内 | 跨应用、跨服务 |
| 注册方式 | @Bean 注册到本地 | 通过 MCP 协议远程发现 |
| 工具发现 | 硬编码声明 | 动态发现,运行时获取工具列表 |
| 通信方式 | 进程内方法调用 | Stdio/SSE 远程通信 |
| 扩展性 | 加工具要改代码重启 | 加工具无需重启,热插拔 |
联系:MCP 是 Function Calling 的超集和升级。底层调度逻辑一样——模型返回 tool_call,框架执行函数回传结果。但 MCP 把工具提供方和消费方解耦了。
实际场景:
- 简单项目:Function Calling 够用,几行代码搞定
- 企业级多团队协作:团队 A 提供 MCP Server 暴露数据库查询工具,团队 B 的 AI Agent 作为 MCP Client 动态调用,不需要团队 B 改代码
- 多 Agent 编排:多个 Agent 通过 MCP 共享工具生态,避免重复开发
Spring AI 中使用 MCP:引入 spring-ai-mcp 依赖,配置 MCP Server 地址,ChatClient 就能自动发现和调用远程工具。未来 MCP 会成为 Agent 生态的"USB 接口",所有工具标准化接入。