Spring AI 面试题库(带答案)
生成时间:2026-05-21 23:57 | 共10题
【面试题】1. Spring AI中ChatClient和直接用ChatModel有什么区别?生产环境该选哪个?
【标准答案】ChatModel是最底层的模型调用抽象,你给它Prompt它给你响应,简单直接但能力有限。ChatClient是Spring AI 1.0推出的统一高级入口,基于Fluent API链式调用,内置了Advisor机制、对话记忆、结构化输出等能力。打个比方,ChatModel是裸引擎,ChatClient是装好方向盘、仪表盘的整车。
生产环境强烈推荐ChatClient,原因有三:第一,Advisor链让你可以在不改动业务逻辑的前提下横切关注点(日志、鉴权、限流);第二,entity()和call()一行搞定结构化输出,省去手动解析;第三,对话记忆通过MessageChatMemoryAdvisor声明式接入,不用自己拼Message列表。ChatModel适合轻量级场景或需要极致控制的地方,但大多数业务用ChatClient就够了。
【面试题】2. Spring AI的Advisor机制是什么?能不能自定义一个Advisor?说下执行流程。
【标准答案】Advisor是Spring AI借鉴了Spring MVC拦截器/Filter的设计思想,在ChatClient调用链上插入前后置处理逻辑。每个Advisor有两个核心方法:adviseRequest()处理请求进入、adviseResponse()处理响应返回。多个Advisor按Ordered接口排序组成链式调用。
自定义Advisor很简单,实现CallAdvisor或StreamAdvisor接口就行。举个实战例子——日志Advisor:在adviseRequest里记录用户输入和参数,在adviseResponse里记录模型输出和耗时,这样所有AI调用的审计日志就统一了,不用每个业务方法里重复写。另一个常见场景是敏感词过滤Advisor,请求进来先检查,有敏感词直接拦截不调模型。
执行流程:用户调用ChatClient → 按顺序执行各Advisor的adviseRequest → 调用ChatModel → 按逆序执行各Advisor的adviseResponse → 返回给用户。这个设计让你可以像搭积木一样组合能力。
【面试题】3. RAG流程中TokenTextSplitter的chunkSize和overlap怎么设?设不好会有什么问题?
【标准答案】chunkSize控制每个文本块的大小,overlap控制相邻块之间的重叠字符数。这个参数直接影响检索质量和存储成本。
设置原则:chunkSize一般500-1000个token,取决于你的模型上下文窗口和语义完整性。太小(比如100),一句话被切成几段,检索时语义不完整,回答断章取义;太大(比如3000),一个chunk塞了太多内容,相似度搜索时噪声大,匹配不精准。
overlap通常设为chunkSize的10%-20%。它的作用是防止关键信息正好落在切割边界上导致丢失。比如chunkSize=800,overlap=100,每两个相邻块共享100字符,确保边界处的内容不会凭空消失。
实际踩坑经验:文档是技术手册这种结构化内容,可以按标题/段落先做语义切分再走TokenTextSplitter,比暴力按字符切好得多。另外overlap不是越大越好,太大导致重复内容多,向量库存储翻倍,检索时冗余chunk多,反而降低效率。
【面试题】4. Spring AI Function Calling的调度流程是怎样的?函数注册有哪几种方式?
【标准答案】调度流程分四步:第一步,用户发Prompt,ChatClient把可用函数列表(函数名+描述+参数Schema)告诉大模型;第二步,大模型判断需要调用某个函数,返回tool_call响应(包含函数名和参数JSON);第三步,Spring AI自动解析tool_call,根据函数名找到注册的Bean,反序列化参数后执行;第四步,把函数返回值拼回Prompt再发给模型,模型生成最终回答。
函数注册方式主要有两种:一是@Bean注册,最常用。写一个返回函数描述的Bean,Spring AI自动生成JSON Schema、自动发现和调度,零配置。二是通过ChatClient的.tools()方法动态指定,适合运行时才确定可用工具的场景。
关键细节:JSON Schema是自动从函数签名推导的,但复杂对象可能推导不准,可以用@Description注解补充字段描述;函数返回值会被自动序列化为字符串喂给模型;如果模型一次返回多个tool_call,Spring AI会并行执行再汇总。生产环境注意给函数调用加超时和异常兜底,别让一个函数卡死整条链路。
【面试题】5. Spring AI对接多个大模型时,如何实现动态切换和灰度路由?
【标准答案】Spring AI通过spring.ai.*配置前缀管理不同模型的连接,每个模型有独立的ChatModel实现类(OpenAiChatModel、OllamaChatModel等)。Spring Boot自动配置会根据classpath和properties创建对应的Bean。
动态切换有三种方案:第一,@ConditionalOnProperty配合Profile,不同环境用不同模型,最简单但不够灵活;第二,自定义RoutingChatModel,内部维护一个Map<String, ChatModel>,根据请求参数或上下文动态delegate,这是最推荐的方式;第三,用Spring AI的ChatClient通过.advisors()在Advisor层做路由决策。
灰度路由实战:在RoutingChatModel里实现,根据用户ID哈希或AB标签分流,比如10%流量走新模型、90%走旧模型。关键点:每个模型的Prompt格式可能不同(OpenAI和智谱的system message处理有差异),路由层要做适配;还要考虑模型能力差异,某些Function Calling只在特定模型上支持,路由时要校验。
【面试题】6. Structured Output中BeanOutputConverter有什么坑?entity()和直接用Converter有什么区别?
【标准答案】BeanOutputConverter的核心原理是把POJO的类定义转成JSON Schema,塞到Prompt里告诉模型"按这个格式输出",然后解析模型返回的JSON映射到对象。
主要坑有三个:第一,Schema推导不准。泛型、嵌套对象、枚举类型的Schema经常推导错误,模型拿到的Schema和你预期不一致,输出就乱了。解法是用@JsonPropertyDescription注解显式描述每个字段,或者手动传Schema。第二,模型不听话。模型可能输出额外解释文字或Markdown代码块包裹JSON,导致解析失败。BeanOutputConverter内部有正则提取逻辑,但不是万能的,复杂场景要自己加后处理。第三,日期格式、BigDecimal精度这类细节,JSON Schema默认不约束,模型输出格式五花八门,需要在Prompt里额外强调。
entity()是ChatClient提供的便捷方法,底层也是用BeanOutputConverter,但它把Converter的创建、Schema注入、解析映射全封装了,一行代码搞定。直接用Converter更灵活,可以自定义Schema、自定义解析策略,适合复杂场景。简单映射用entity(),复杂映射用Converter,这是基本选择逻辑。
【面试题】7. ChatMemory的持久化方案怎么选?InMemoryChatMemory能上生产吗?
【标准答案】InMemoryChatMemory就是一个ConcurrentMap,应用重启数据全丢,严格来说不适合生产。但也不是绝对不行——如果你的对话是短会话(比如一次性问答),不需要跨重启保留记忆,那InMemory够用,而且性能最好。
持久化方案按场景选:关系型数据库(MySQL/PostgreSQL),最稳妥,适合大多数业务,ChatMemory接口就CRUD几个方法,实现简单;Redis,适合高并发短对话,TTL天然支持过期清理,但要注意序列化格式;向量数据库,把对话历史也做embedding存进去,检索时语义匹配召回相关记忆,适合超长对话场景,但成本高。
推荐架构:ChatMemory接口+MessageChatMemoryAdvisor组合。Advisor自动在请求前注入历史消息、响应后保存新消息,业务代码零感知。持久化实现可以先用JDBC版本上线,遇到性能瓶颈再换Redis,因为接口不变,切换成本极低。
关键提醒:对话历史不能无限增长,必须设上限。MessageChatMemoryAdvisor支持配置最大消息数,超出自动裁剪最早的。否则token消耗会指数级增长,模型也会因为上下文太长而"迷失"。
【面试题】8. Spring AI微服务部署中,API Key怎么安全管理?超时和限流怎么搞?
【标准答案】API Key管理三原则:一不在代码里硬编码,二不在Git里出现,三运行时动态获取。具体方案:Spring AI的spring.ai.openai.api-key等配置支持从环境变量读取,最基础;进一步用Spring Cloud Config或Vault集中管理,应用启动时拉取;最严格的是用临时Token方案,应用通过STS服务获取短期有效Token访问模型API,Token过期自动刷新。
超时配置:Spring AI的RestClient底层支持连接超时和读取超时配置,在application.yml里通过spring.ai.openai.connect-timeout和read-timeout设置。读取超时很关键,大模型响应慢是常态,设太短频繁超时,设太长用户等不起。建议30-60秒,同时用Streaming模式分块返回,体感好很多。
限流熔断:外部API限流用Resilience4j的RateLimiter,配置每秒请求数,超限直接降级返回兜底答案;熔断用CircuitBreaker,连续N次失败后熔断,过一会儿半开探测恢复。内部限流按用户维度,用Redis+Lua脚本实现滑动窗口限流,防止恶意用户打爆配额。
【面试题】9. Spring AI 1.0正式版相比0.8/0.x系列有哪些关键变化?升级要注意什么?
【标准答案】核心变化四个方面:第一,ChatClient成为统一入口,之前的ChatModel直接调用方式虽然还支持,但官方推荐全部走ChatClient,Fluent API是1.0的主推风格。第二,Advisor架构正式定型,0.x版本的各种拦截器、回调机制统一收敛到Advisor体系,实现了请求/响应的双向拦截。第三,VectorStore接口统一,之前各向量库的接口差异大,1.0统一了add/delete/similaritySearch等方法签名,切换向量库只需换依赖和配置。第四,spring.ai.配置前缀规范化,0.x版本配置前缀混乱,1.0统一为spring.ai.{model-type}.{provider}.格式。
升级注意事项:一是API breaking changes,0.x的PromptTemplate、OutputParser等部分类被废弃或迁移,需要对照迁移指南改代码;二是配置前缀变了,application.yml要改,不然启动报错;三是Advisor替换了旧的拦截机制,如果你自定义了拦截器需要重写为Advisor;四是依赖版本对齐,Spring AI 1.0要求Spring Boot 3.2+,JDK 17+,老项目先升级基础框架。
实战建议:别着急全量升级,先在非核心业务上验证,确认各模型Provider的ChatModel实现类行为一致,尤其是Function Calling和Structured Output在1.0下的表现。
【面试题】10. Spring AI的Observability监控怎么接入?能监控哪些指标?
【标准答案】Spring AI 1.0内置了Micrometer指标支持,跟Spring Boot Actuator无缝集成,开箱即用。你只要引入spring-ai-openai-spring-boot-starter(或其他模型starter)和spring-boot-starter-actuator依赖,配置management.endpoints.web.exposure.include=prometheus,指标就自动暴露了。
核心监控指标分几类:一是模型调用指标,包括ai.model.call.count(调用次数)、ai.model.call.latency(响应延迟P50/P95/P99)、ai.model.call.tokens(token消耗量,分input/output统计);二是向量库指标,vectorstore.search.latency(检索延迟)、vectorstore.search.result.count(返回结果数);三是Function Calling指标,tool.call.count(工具调用次数)、tool.call.latency(工具执行耗时)。
实战配置建议:一是必配告警规则,模型调用延迟P99超过5秒告警、token消耗量突增告警、错误率超1%告警;二是Dashboard分层展示,全局概览(QPS/成本/延迟)+ 单模型详情 + 单用户追踪;三是Tracing用Micrometer Tracing + Zipkin/Jaeger,把AI调用链路和业务链路串起来,排查问题快。
注意点:Streaming模式下延迟指标的含义和同步模式不同,是首token时间还是末token时间要明确;采样率别设100%,高并发下指标基数太大影响性能,1%-5%通常够用。