Spring AI 面试题库
生成时间:2026-05-24 21:49 (Asia/Shanghai)
【面试题】1. Spring AI中ChatClient和直接用ChatModel有什么区别?生产环境该用哪个?
【标准答案】ChatModel是底层模型调用接口,只负责发请求拿响应,是最原始的API。ChatClient是Spring AI 1.0推出的统一高级入口,它封装了ChatModel,提供了Fluent API链式调用,还能自动编排Advisor链(比如记忆、RAG、函数调用),一行代码就能把多个能力串起来。生产环境强烈推荐用ChatClient,原因三个:第一,解耦——业务代码不直接依赖具体模型实现,换模型只改配置;第二,Advisor机制让横切关注点(日志、记忆、限流)可插拔,不用污染业务逻辑;第三,Fluent API可读性好,维护成本低。简单说,ChatModel是发动机,ChatClient是整车,你开车肯定用整车不是直接踩发动机。
【面试题】2. RAG流程中TokenTextSplitter的作用是什么?chunkSize和overlap怎么配才合理?
【标准答案】TokenTextSplitter负责把长文档切分成合适大小的文本块,因为大模型上下文窗口有限,向量检索也是按chunk做相似度匹配的,文档太长检索不精准,太短又丢失上下文。chunkSize一般建议500-1000个token,overlap建议chunkSize的10%-20%。为什么要有overlap?因为关键信息如果正好在切割边界,会被截断成两半,overlap让相邻chunk有重叠区域,检索时能兜住边界信息。实际调优思路:如果检索结果经常答非所问,先看chunk是不是太大了导致噪声多,缩小chunkSize;如果答案不完整,可能是chunk太小丢失了上下文,加大overlap或chunkSize。没有银弹,得拿你的实际文档跑几轮评估。
【面试题】3. Spring AI的Function Calling是怎么调度的?@Bean注册函数后底层发生了什么?
【标准答案】分三步走。第一步:你用@Bean注册一个返回函数描述的Bean,Spring AI自动读取函数的入参类型,通过Jackson生成JSON Schema,连同函数名和描述一起作为tool定义发给大模型。第二步:大模型判断需要调用函数时,不会直接执行,而是返回一个tool_call响应,里面包含函数名和序列化好的参数JSON。第三步:Spring AI框架拦截到tool_call,根据函数名从Spring容器找到对应Bean,反序列化参数,通过反射调用函数拿到结果,再把结果作为tool message拼回对话上下文,重新请求大模型生成最终回答。关键点:函数是框架端执行的,不是模型端执行的,模型只是"决定调什么、传什么参"。这个设计保证了安全性——你的函数逻辑不会暴露给模型,也不受模型沙箱限制。
【面试题】4. Spring AI对接多个大模型时,如何做到运行时动态切换?配置上怎么搞?
【标准答案】Spring AI用spring.ai.*配置前缀来区分不同模型,比如spring.ai.openai.api-key、spring.ai.zhipu.api-key。多模型同时生效的方式是每个模型的starter都引入,各自配自己的key和参数。运行时切换有两种主流方案:第一,用@Qualifier注入不同的ChatModel Bean,比如@Qualifier("openAiChatModel")和@Qualifier("zhipuChatModel"),代码里按需选择;第二,更优雅的做法是结合Spring的@Conditional或自定义路由Advisor,根据请求特征(比如用户等级、问题类型)动态选择底层ChatModel。生产建议再包一层ChatModelRouter,内部维护模型优先级和降级策略——主模型超时自动切备用模型,这才是生产级的多模型管理。别硬编码模型选择逻辑,后期加模型会改到崩溃。
【面试题】5. Structured Output用BeanOutputConverter映射POJO时有哪些常见的坑?
【标准答案】三个大坑。坑一:模型输出不符合Schema。大模型本质是概率模型,你让它严格输出JSON,它偶尔会多出注释、多余逗号、甚至加段解释文字。BeanOutputConverter内部会做JSON解析,格式不对直接报错。解法:在Prompt里明确要求"只输出JSON,不要任何其他内容",必要时加few-shot示例。坑二:嵌套对象和集合类型的Schema生成问题。复杂嵌套结构生成的JSON Schema可能跟模型理解有偏差,导致输出字段缺失或类型错误。解法:尽量保持POJO扁平,嵌套不超过两层,集合用List不用Map。坑三:entity()方法依赖模型能力。不是所有模型都支持结构化输出,某些小模型或本地模型可能不支持JSON mode或function calling,entity()会静默失败。解法:先确认目标模型支持结构化输出,Ollama要选支持JSON mode的模型版本。
【面试题】6. ChatMemory的InMemoryChatMemory能上生产吗?持久化方案怎么设计?
【标准答案】InMemoryChatMemory绝对不能直接上生产——应用一重启对话历史全没了,多实例部署时不同实例之间记忆不共享,用户换个节点就失忆。生产级持久化方案设计:第一层,选存储介质——推荐Redis(高性能、天然支持TTL过期清理)或JDBC(关系型数据库,方便查询审计);第二层,实现ChatMemory接口——核心就是两个方法:add存消息、get取历史,把InMemory的ConcurrentMap替换成Redis Hash或数据库表;第三层,消息裁剪策略——不能无限存,一般保留最近10-20轮对话,或者按token数裁剪,超过上下文窗口就截断最早的消息;第四层,多实例一致性——Redis天然解决,数据库加会话ID索引就行。Spring AI的MessageChatMemoryAdvisor已经帮你做了消息注入对话上下文这一步,你只需要提供可靠的ChatMemory实现。
【面试题】7. VectorStore选型:PGVector vs Redis vs Pinecone vs Milvus,各自适合什么场景?
【标准答案】按场景分。PGVector:适合已有PostgreSQL基础设施的团队,零额外运维成本,SQL+向量混合查询是独门绝技(比如先按业务条件过滤再向量检索),但纯向量性能比专业引擎弱,千万级以上数据量会吃力。Redis:适合对延迟极度敏感的场景,StackSearch模块做向量检索速度极快,但向量检索能力相对简单,不支持复杂过滤,适合小规模高并发场景。Pinecone:全托管,零运维,适合不想管基础设施的团队,自动扩缩容,但数据出海外、费用按查询量计费成本不可控。Milvus:适合大规模向量检索(亿级),开源可自建,架构上支持分布式,但运维复杂度高,需要专职团队。选型口诀:小团队用PGVector省事,高并发低延迟用Redis,不想运维用Pinecone,海量数据自建用Milvus。
【面试题】8. Spring AI的Advisor机制解决了什么问题?自定义Advisor该怎么写?
【标准答案】Advisor机制解决的是横切关注点的解耦问题。没有Advisor之前,日志、限流、记忆、RAG这些能力全得写在业务代码里,一坨if-else,改一个功能影响一片。Advisor本质是请求拦截器,类似Servlet Filter或Spring Interceptor,但作用于AI调用链路。它在请求发给模型前和模型返回后各有一个拦截点,可以修改Prompt、拦截响应、注入上下文。自定义Advisor写法:实现CallAroundAdvisor接口(同步)或StreamAroundAdvisor接口(流式),核心就两个方法——aroundCall里做前置和后置处理,getOrder控制Advisor执行顺序。举个例子:写一个TokenCountAdvisor,aroundCall里统计Prompt的token数记日志,aroundCall返回后统计响应token数,order设成最高优先级最先执行。Spring AI内置的MessageChatMemoryAdvisor和QuestionAnswerAdvisor都是这个模式。
【面试题】9. Spring AI在微服务架构下,API Key管理和安全性怎么做?
【标准答案】API Key管理是生产级Spring AI应用的命门,泄露了就是别人的账单。方案分四层。第一层:配置中心——API Key绝不写死在application.yml里,用Spring Cloud Config、Vault或Nacos管理,运行时动态拉取。第二层:环境隔离——dev/staging/prod各用各的Key,不同环境配额独立,测试别把生产额度打满。第三层:网关层代理——不在业务服务直连模型API,而是走API Gateway统一代理,Key存在网关侧,业务服务无感,还能在网关层做限流和审计。第四层:最小权限——不同业务线用不同Key,设置独立额度上限和模型访问白名单,某个Key泄露了影响范围可控。再加一个兜底:Key轮转机制,定期更换Key,Vault支持自动轮转。一句话总结:Key不入代码、不入镜像、不跨环境、不走业务层。
【面试题】10. Spring AI 1.0正式版相比之前的Milestone版本有哪些关键变化?升级要注意什么?
【标准答案】三大核心变化。第一,ChatClient成为统一入口。之前调用模型有ChatModel、PromptTemplate各种方式,1.0统一收敛到ChatClient的Fluent API,Prompt模板也集成进来了,用法从chatModel.call(prompt)变成chatClient.prompt().user("xxx").call()。第二,Advisor架构正式落地。之前的拦截器模式不统一,1.0定义了标准的Advisor接口和执行链,内置的Memory、RAG、函数调用都重构为Advisor实现,扩展性大幅提升。第三,VectorStore接口统一。之前不同向量库的API差异大,1.0抽象了统一的VectorStore接口,add/delete/similaritySearch方法签名一致,切换向量库只需换依赖和配置。升级注意事项:API包名有变化,部分类迁移了位置,编译会报错逐个修;PromptTemplate的变量语法从${}变成了{},模板全要改;ChatMemory相关类从experimental包毕业到了正式包,import路径变了。建议:先跑单元测试,再全量回归,配置文件里的spring.ai.*前缀大部分兼容但也要检查。