Skip to content

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,原因三点:

  1. Fluent API 链式调用,代码可读性强:chatClient.prompt().user("你好").call().content()
  2. Advisor 机制只在 ChatClient 层生效,RAG、Memory、日志切面全部挂在这条链上
  3. 结构化输出 .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-1000
  • minChunkSizeChars:最小字符数,过滤太短的碎片
  • 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 注册函数的原理是什么? ​

【标准答案】完整流程四步走:

  1. 注册:用 @Bean 定义一个返回 Function<I, O> 的 Bean,Spring AI 自动扫描注册
  2. Schema 生成:Spring AI 根据函数的入参类型 I,自动生成 JSON Schema(包括字段名、类型、描述),作为 tool 定义发给模型
  3. 模型决策:模型判断需要调工具时,返回 tool_call 响应,包含函数名和参数
  4. 框架调度: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

java
var converter = new BeanOutputConverter<>(Order.class);
String format = converter.getFormat(); // 拿到 JSON Schema 指令
// 拼到 prompt 里让模型按格式输出
// 然后 converter.fromModelOutput(result) 反序列化

坑:format 指令是追加到 Prompt 末尾的,模型可能不遵守格式,尤其是小模型。需要显式在 prompt 中强调"严格按 JSON 格式输出"。

方式二:ChatClient 的 .entity() 方法

java
Order order = chatClient.prompt().user("生成订单").call().entity(Order.class);

一行搞定,底层自动用 BeanOutputConverter + JSON 解析。坑:只支持同步调用,流式场景不能用;解析失败直接抛异常,没有降级。

方式三:OpenAI 原生 structured output(json_schema 模式)

java
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 接口非常简洁:

java
public interface ChatMemory {
    void add(String conversationId, List<Message> messages);
    List<Message> get(String conversationId, int lastN);
    void clear(String conversationId);
}

核心就是三个操作:存、取、清。默认提供 InMemoryChatMemory,用 ConcurrentHashMap 存,重启全丢,只能开发测试用。

生产持久化方案:

  1. Redis 方案:自己实现 ChatMemory,用 Redis List 存消息,LPUSH 追加、LRANGE 取最近 N 条。优点是天然支持 TTL 过期清理,适合高并发场景。

  2. 数据库方案:建 chat_memory 表,字段 conversation_id, message_type, content, timestamp,查询用 ORDER BY timestamp DESC LIMIT N。适合需要审计日志和复杂查询的场景。

  3. 混合方案:热数据放 Redis(最近 20 条),冷数据落库(完整历史),兼顾性能和合规。

关键设计点:

  • lastN 参数:不能无限拉历史,token 超了模型直接报错。一般取最近 10-20 条,配合模型的 context window 计算
  • 消息裁剪:系统消息永远保留,只裁剪中间的历史对话
  • 并发安全:同一个 conversationId 可能并发写,Redis 天然原子性,数据库要加乐观锁或用 INSERT 不 UPDATE

【面试题】7. Spring AI 多模型切换怎么实现?spring.ai.* 配置前缀的规则是什么? ​

【标准答案】Spring AI 用 spring.ai.<provider>.* 的配置前缀区分不同模型提供商,每个 provider 有独立的自动配置类。

配置示例:

yaml
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

切换方式三种:

  1. 依赖切换:只引入一个 starter(如 spring-ai-openai-spring-boot-starter),Spring Boot 自动配置只生效一个 ChatModel Bean。最简单,但换模型要改依赖重启。

  2. 多 Bean + @Primary:引入多个 starter,用 @Primary 指定默认 Bean,其他用 @Qualifier 按需注入。

  3. 运行时动态路由:自己封装一个 RoutingChatModel,内部维护 Map<String, ChatModel>,根据请求参数动态选择。适合 A/B 测试或降级场景。

踩坑:多 starter 同时引入时,自动配置可能冲突。用 spring.autoconfigure.exclude 排除不需要的,或者用 @ConditionalOnProperty 精确控制。


【面试题】8. Spring AI 在微服务架构中部署,API Key 管理和限流熔断怎么做? ​

【标准答案】

API Key 管理:

  1. 绝对不能硬编码,用 Spring Cloud Config 或 Vault 统一管理,spring.ai.openai.api-key 用 ${VAULT_API_KEY} 引入
  2. 多租户场景:不要每个租户一个配置文件,用 Key Pool(Key 池),运行时轮询/随机选取,一个 Key 限流了自动切下一个
  3. Key 轮转:配置中心热更新,不需要重启服务。Spring Cloud Config 配合 @RefreshScope 或 Nacos 动态推送

限流熔断:

  1. 外层限流:用 Sentinel 或 Resilience4j 在 ChatClient 调用外面包一层,QPS 阈值按模型 API 的 RPM 限制设(如 OpenAI gpt-4o 是 500 RPM)
  2. 熔断降级:连续 N 次调用失败或超时,熔断器打开,直接返回预设的兜底回答,避免雪崩
  3. 超时设置:模型调用默认超时可能很长,必须手动设。Spring AI 支持通过 spring.ai.openai.chat.options.max-tokens 控制输出长度,超时用 HTTP Client 层控制
  4. 排队机制:突发流量先入队,用 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 CallingMCP
作用域单个应用内跨应用、跨服务
注册方式@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 接口",所有工具标准化接入。