Spring AI 面试题库
生成时间:2026-05-21 22:52
【面试题】1. Spring AI中ChatClient和直接用ChatModel有什么区别?什么场景用哪个?
【标准答案】ChatModel是最底层的模型调用接口,你给它Prompt它给你返回ChatResponse,相当于一个纯粹的"模型代理"。ChatClient是在ChatModel之上封装的Fluent API入口,提供链式调用、Advisor插拔、结构化输出、对话记忆等高级能力。实际项目中95%的场景用ChatClient就够了,因为它把Prompt模板、Advisor编排、entity()映射都串起来了。只有当你需要极简调用、做底层适配或测试时才直接用ChatModel。一句话:ChatModel是引擎,ChatClient是方向盘。
【面试题】2. Advisor机制的设计思路是什么?如何自定义一个Advisor?
【标准答案】Advisor是Spring AI借鉴了Spring MVC Interceptor的设计,在ChatClient调用链中插入前置/后置处理逻辑。核心接口是CallAdvisor(同步)和StreamAdvisor(流式),每个Advisor可以修改请求、拦截响应、决定是否继续传递。自定义步骤:实现Advisor接口,在advise()方法里写逻辑,然后通过ChatClient.builder().defaultAdvisors(...)注册。经典用法比如日志Advisor记录请求耗时、内容审查Advisor过滤敏感词、缓存Advisor做响应短路。关键点是Advisor有顺序,通过Ordered接口控制执行链路,类似Filter链。
【面试题】3. RAG流程中TokenTextSplitter的chunkSize和overlap怎么配?配不好会有什么问题?
【标准答案】chunkSize决定每段文本的token数,overlap是相邻段的重叠token数。配置原则:chunkSize一般500-1000之间,太大了召回不精准(噪音多),太小了语义被截断(上下文丢失)。overlap一般设chunkSize的10%-20%,作用是避免关键信息恰好落在切分边界导致丢失。常见坑:overlap设太大等于重复入库浪费向量空间且搜索时重复命中;chunkSize不匹配Embedding模型的最大输入长度会报错或被静默截断。实操建议先用默认值跑,根据召回率调试,用测试集验证recall@5指标。
【面试题】4. Spring AI的Function Calling是怎么把Java函数暴露给大模型的?底层调度流程是什么?
【标准答案】分三步:第一步,用@Bean注册一个返回类型为Function的Bean,Spring AI自动扫描;第二步,框架根据函数签名+参数类型自动生成JSON Schema,随请求发给大模型;第三步,大模型返回tool_call时,Spring AI自动反序列化参数、调用对应Bean、把结果回传给模型完成闭环。关键配置是spring.ai.openai.chat.options.functions指定启用哪些函数。底层调度是ChatModel实现类解析tool_calls字段,通过FunctionCallbackRegistry找到对应函数执行。注意:函数命名要语义化,因为模型靠名字和Schema描述决定何时调用。
【面试题】5. 对比PGVector、Redis、Milvus作为Spring AI VectorStore的优劣,生产环境怎么选?
【标准答案】PGVector:如果你已有PostgreSQL,零额外组件,适合中小规模(百万级以内),支持HNSW索引,查询性能够用,优势是事务一致性和运维简单。Redis:适合需要极低延迟的在线场景,内存成本高,大规模数据贵,持久化需额外配置,适合缓存层而非主存储。Milvus:分布式架构,十亿级向量毫秒级检索,适合大规模生产,但运维复杂(依赖etcd/MinIO),团队需要有分布式经验。选型建议:起步用PGVector,日活百万级考虑Milvus,Redis做热数据缓存层。不要一上来就上Milvus,过度架构是面试减分项。
【面试题】6. BeanOutputConverter做结构化输出时,嵌套对象或List字段容易踩什么坑?怎么解决?
【标准答案】主要坑有三个:第一,嵌套对象内部字段如果是复杂类型(如Map<String,Object>),JSON Schema生成可能不完整,模型返回格式不对;第二,List字段如果泛型擦除严重(如List不带泛型),Schema会退化成array of any,模型输出不可控;第三,大模型有时在JSON外面包一层markdown代码块(json ... ),BeanOutputConverter解析直接报错。解决方案:嵌套对象用显式DTO类而非Map;List必须带明确泛型;自定义OutputConverter继承BeanOutputConverter重写解析逻辑加一层stripMarkdownWrapper;必要时用@JsonIgnoreProperties(ignoreUnknown=true)做容错。
【面试题】7. ChatMemory的InMemoryChatMemory能不能用于生产?持久化方案怎么设计?
【标准答案】InMemoryChatMemory绝对不能直接上生产——应用重启对话全丢,多实例部署时各实例记忆不共享。持久化设计思路:实现ChatMemory接口,底层对接你的存储。方案一:Redis存储,用conversationId做key,消息列表做value,设置TTL自动过期,适合高并发短对话场景。方案二:数据库(MySQL/PG),建表存conversation_id + message_order + role + content,查询时按order排序,适合需要长期存档和审计的场景。方案三:混合方案,热数据Redis加速读取,冷数据落库。关键点:无论哪种方案,都要配合MessageChatMemoryAdvisor设置maxMessages限制上下文窗口,否则对话太长token爆掉。
【面试题】8. Spring AI 1.0正式版相比0.8/0.x版本有哪些Breaking Change?迁移要注意什么?
【标准答案】最大的几个变化:第一,ChatClient成为统一入口,原来散落在各处的ChatModel直接调用都被收拢到ChatClient的Fluent API;第二,spring.ai.*配置前缀统一规范化,0.x版一些spring.ai.model.xxx的配置项改名或移动了位置;第三,VectorStore接口重新设计,add/delete/search方法签名有调整;第四,Advisor架构替代了之前的RequestResponseAdvisor旧体系,老的自定义拦截器需要重写;第五,部分实验性API被移除或重命名。迁移建议:先升级依赖版本,看启动报错逐个修配置项,然后跑单元测试验证ChatClient调用链路,最后检查自定义Advisor是否需要适配新接口。强烈建议先在测试环境验证再切生产。
【面试题】9. 多模型切换场景下,怎么设计路由策略避免硬编码?Spring AI的配置怎么配合?
【标准答案】不要在代码里if-else写模型选择逻辑。设计思路:定义一个ModelRouter接口,根据请求特征(任务类型、成本预算、延迟要求)路由到不同ChatModel。实现方式一:基于spring.ai.*的Properties外部化配置,用@ConditionalOnProperty动态注入不同ChatModel的Bean;方式二:运行时路由,在自定义Advisor里根据Prompt内容动态切换委托的ChatModel实例;方式三:用Spring的Map注入(Map<String, ChatModel>),按key动态获取。配置层面,每个模型用不同的spring.ai.openai/anthropic/ollama前缀配好,然后通过自定义Properties类映射模型名到配置。关键是把路由规则也外部化到配置文件或数据库,做到热切换不改代码。
【面试题】10. Spring AI的Observability监控怎么做?生产上需要关注哪些指标?
【标准答案】Spring AI 1.0原生集成了Micrometer,所有ChatModel调用自动产生指标。核心指标:ai.chat.model.calls(调用次数)、ai.chat.model.tokens.prompt(输入token数)、ai.chat.model.tokens.completion(输出token数)、ai.chat.model.latency(调用延迟)。配置方式:引入spring-boot-starter-actuator + micrometer-registry-prometheus,spring.ai会自动注册指标到MeterRegistry。生产关注维度:按模型名分组看成本分布、P99延迟判断是否需要降级、token消耗趋势做预算控制、error rate判断是否触发熔断。进阶做法:自定义ObservationHandler在Advisor层记录业务维度(如用户ID、场景类型),配合Grafana看板做细粒度监控。别只看平均延迟,P95/P99和error rate才是生产生命线。