本轮 Spring AI 面试题库(带答案)
【面试题】1. Spring AI 中 Advisor 机制的核心设计思想是什么?它解决了什么问题?
【标准答案】Advisor 是 Spring AI 1.0 引入的核心拦截机制,本质上是一个围绕 ChatClient 调用链的拦截器模式。它解决的问题很明确:把横切关注点从业务逻辑中剥离出来。比如对话记忆、RAG检索、日志追踪、重试熔断这些逻辑,如果都堆在业务代码里,代码会非常臃肿且难以复用。Advisor 让这些能力变成可插拔的组件,通过链式调用串联起来,每个 Advisor 可以在请求发出前和响应返回后做处理。面试时要强调:Advisor 不是 AOP,它是在 ChatClient 内部的调用链上的,比 AOP 更轻量、更语义化。而且 Advisor 是有顺序的,可以通过 @Order 或实现 Ordered 接口控制执行顺序。实际项目中 QuestionAnswerAdvisor、MessageChatMemoryAdvisor 都是内置 Advisor 的典型实现。
【面试题】2. RAG 场景下 TokenTextSplitter 的切分策略有哪些?如何选择合适的 chunk size?
【标准答案】TokenTextSplitter 是 Spring AI 提供的文档切分器,它按 token 数量切分而非字符数,这对 LLM 场景至关重要,因为模型的上下文窗口是按 token 计算的。核心参数有三个:chunkSize(每块最大 token 数)、overlapSize(相邻块重叠 token 数)、separator(切分分隔符)。chunk size 的选择是个权衡:太小会丢失上下文语义,搜索到的片段信息不足;太大则检索精度下降,噪声多,还会浪费 token 额度。一般经验值在 500-1500 token 之间,具体要看文档类型——技术文档偏大(800-1200),FAQ 类偏小(300-500)。overlapSize 一般设为 chunkSize 的 10%-20%,保证跨块语义不被硬切断。面试中要提到一点:切分前最好先按段落或标题做语义级预切分,再用 TokenTextSplitter 做精细控制,效果远好于暴力切分。
【面试题】3. Spring AI 的 Function Calling 流程中,JSON Schema 自动生成是怎么工作的?有哪些常见坑?
【标准答案】Spring AI 的 Function Calling 核心流程:当你在配置中声明一个 @Bean 函数,Spring AI 会自动根据函数参数类型生成 JSON Schema,然后把 schema 信息作为 tools 参数传给大模型。大模型识别到需要调用工具时,返回 tool_call 响应(包含函数名和参数),Spring AI 框架自动反序列化参数并调用对应函数,再把结果喂回大模型完成最终回答。JSON Schema 自动生成的坑主要有三个:第一,复杂嵌套对象可能生成不准确的 schema,建议函数参数尽量用扁平结构或简单 POJO;第二,Optional 字段的处理容易出问题,不同模型对 optional 的理解不一致;第三,枚举类型某些模型不支持从 schema 自动识别,需要手动加 @Schema 注解描述。面试中再加一句:函数注册名默认取 Bean 名,但可以通过属性 spring.ai.function.name 自定义,多模型场景下注意命名冲突。
【面试题】4. ChatMemory 接口的设计思路是什么?InMemoryChatMemory 适合生产环境吗?持久化方案怎么做?
【标准答案】ChatMemory 是 Spring AI 对话记忆的抽象接口,核心方法就是 add(添加消息)和 get(获取历史消息),设计非常轻量。InMemoryChatMemory 是它的内存实现,数据存 HashMap 里,重启就丢了,绝对不适合生产环境。生产环境的持久化方案需要自己实现 ChatMemory 接口,常见选择:Redis(适合高并发、需要 TTL 自动过期)、PostgreSQL(适合需要事务保证和复杂查询)、MongoDB(适合文档型存储)。实现时关键点:一是要考虑消息截断策略,对话太长要按 token 预算裁剪,不能全量加载;二是要区分会话维度,用 conversationId 隔离不同对话的历史;三是要设置合理的过期策略,避免历史无限膨胀。实际项目中,推荐用 Redis + TTL 方案,简单高效,还能配合 ChatMemoryAdvisor 自动管理上下文窗口。
【面试题】5. Spring AI 如何实现多模型切换?在一个项目中同时对接 OpenAI 和 Ollama 本地模型怎么做?
【标准答案】Spring AI 的多模型切换核心靠 spring.ai.* 配置前缀和自动配置类实现。每个模型提供商有独立的 starter(如 spring-ai-openai-spring-boot-starter、spring-ai-ollama-spring-boot-starter),引入后各自配置 api-key、base-url 等参数。同时对接 OpenAI 和 Ollama 很简单:pom 里加两个 starter,yml 里分别配 spring.ai.openai.* 和 spring.ai.ollama.*,Spring Boot 自动注入各自的 ChatModel Bean。使用时通过 @Qualifier 注入指定模型,或者用 ChatClient.builder() 指定底层 ChatModel。更灵活的做法是封装一个路由服务,根据请求参数动态选择 ChatModel 实例。面试中要提一个注意点:多模型并存时 Bean 命名可能冲突,Spring AI 默认按类型注入,如果只注入 ChatModel 接口会报歧义,必须用 @Qualifier 明确指定。
【面试题】6. BeanOutputConverter 在 Structured Output 中的作用是什么?和直接用 entity() 有什么区别?
【标准答案】BeanOutputConverter 是 Spring AI 结构化输出的底层转换器,它把大模型返回的文本通过 JSON Schema 约束,解析成目标 Java 对象。它的核心工作:一是根据目标类自动生成 JSON Schema,作为 Prompt 的一部分告诉模型输出格式;二是把模型返回的 JSON 字符串反序列化成目标对象。entity() 是 ChatClient 提供的 Fluent API 封装,底层就是用 BeanOutputConverter 实现的,只是封装更简洁——一行代码 .entity(MyClass.class) 就搞定。区别在于:BeanOutputConverter 更灵活,你可以自定义 Schema、加校验逻辑、处理复杂嵌套;entity() 更方便但灵活性低,适合简单场景。面试要说的坑:模型输出不是 100% 遵守 Schema 的,尤其是复杂嵌套对象,可能返回格式错误的 JSON,必须加异常处理。还有一点,entity() 默认会在 Prompt 末尾追加格式指令,如果你的自定义 Prompt 已有格式要求,可能冲突,这时建议用 BeanOutputConverter 手动控制。
【面试题】7. Spring AI 的 VectorStore 接口统一了哪些操作?切换向量库需要改代码吗?
【标准答案】VectorStore 接口定义了向量存储的核心操作:add(添加文档向量)、delete(删除)、similaritySearch(相似度搜索),以及可选的 update。这个接口的意义在于屏蔽了不同向量库的 API 差异——PGVector 用 SQL、Redis 用 RediSearch、Pinecone 用 gRPC、Milvus 用 SDK,但上层代码看到的都是同一套 VectorStore 方法。切换向量库的答案是:业务代码基本不用改,只需要换依赖和配置。比如从 PGVector 切到 Redis,把 starter 从 spring-ai-pgvector-store 换成 spring-ai-redis-store,yml 配置改一下连接信息,注入的 VectorStore Bean 自动切换实现类。但有例外:一是不同向量库支持的索引类型和搜索参数不同,比如 Pinecone 支持命名空间、Milvus 支持分区,这些高级特性需要用各实现的扩展 API;二是向量维度必须匹配,换库后需要重新生成 Embedding。
【面试题】8. Spring AI 1.0 正式版相比之前的 Milestone 版本,有哪些破坏性变更和关键升级?
【标准答案】Spring AI 1.0 正式版最大的变化是 ChatClient 成为统一入口,之前的 ChatModel 直接调用方式虽然还支持,但官方推荐通过 ChatClient.builder() 构建调用链。Advisor 架构也是 1.0 正式引入的,之前版本的拦截能力很弱。配置前缀统一为 spring.ai.*,之前有些 provider 用的是独立前缀,升级时必须改配置。VectorStore 接口做了统一规范化,部分实现的方法签名有调整。还有几个重要变更:ChatMemory 从独立模块并入了核心;Structured Output 的 API 更简洁,entity() 方法是新加的;Streaming 响应的 Flux 封装做了重构。面试时要强调迁移要点:配置前缀必须改、ChatClient API 要适配、自定义 Advisor 要实现新接口。总体来说 1.0 是一次架构层面的成熟化,API 设计更一致,但 Milestone 用户升级确实有成本。
【面试题】9. 在微服务架构下部署 Spring AI 应用,API Key 管理和安全方面有哪些最佳实践?
【标准答案】API Key 管理是 Spring AI 微服务部署的头等大事,核心原则:永远不要硬编码在代码或配置文件里。最佳实践分几层:第一,用 Spring Cloud Config 或 Vault 做密钥集中管理,应用启动时动态拉取;第二,配置中心本身要加密存储,启用传输加密(HTTPS);第三,API Key 按服务/环境隔离,不同微服务用不同 Key,方便审计和轮换;第四,Key 轮换策略要自动化,定期轮换,旧 Key 设置短过期窗口。安全方面还要注意:对外暴露的 API 接口要加限流(防滥用消耗 token 额度)、熔断(模型服务不可用时的降级策略)、请求签名验证(防伪造)。向量库也要考虑安全——如果用 PGVector,数据库连接要加密;如果用 Pinecone 这类云服务,API Key 权限要最小化。面试加分点:提到 Observability,用 Micrometer + Prometheus 监控 token 消耗、请求延迟、错误率,异常时告警。
【面试题】10. Spring AI 的 MCP 支持是什么?它和 Function Calling 有什么关系和区别?
【标准答案】MCP 是 Model Context Protocol 的缩写,是 Anthropic 提出的一个开放协议,标准化了 AI 模型与外部工具/数据源的交互方式。Spring AI 对 MCP 的支持意味着它可以作为 MCP Client,连接任何实现了 MCP Server 的工具服务。MCP 和 Function Calling 的关系:Function Calling 是单模型维度的工具调用能力,你注册的函数只对当前模型可用;MCP 是跨模型、跨服务的标准协议,一个 MCP Server 暴露的工具可以被任何支持 MCP 的模型使用。区别在于:Function Calling 是 Spring AI 框架内部机制,函数定义在应用代码里,模型通过 JSON Schema 发现和调用;MCP 是外部服务协议,工具定义在独立的 MCP Server 里,通过标准化的 capability 握手发现。面试中要说的趋势:MCP 代表了 Agent 编排的未来方向——工具不再绑定特定模型,而是作为独立服务存在,任何模型都可以发现和使用。Spring AI 同时支持两种方式,短期内 Function Calling 更简单直接,长期 MCP 更灵活可扩展。