本轮 Spring AI 面试题库(带答案)
【面试题】1. Spring AI 的 Prompt 抽象层如何支持多轮对话的消息编排?Prompt 类和 Message 列表有什么区别?
【标准答案】Spring AI 有两种构建输入的方式:一是用 Prompt 类,它内部持有一个 Message 列表,可以一次性塞入 SystemMessage、UserMessage、AssistantMessage 组合;二是直接用 ChatClient 的 Fluent API 逐条链式拼接消息。区别在于:Prompt 是"一次性组装"模式,适合模板化场景,比如用 PromptTemplate 渲染变量后生成完整 Prompt;而 Message 列表是"灵活拼接"模式,适合需要动态增删消息的多轮对话场景。实际项目中,简单问答用 ChatClient.prompt().user().call(),复杂多轮用 Prompt + Message 列表手动编排,配合 ChatMemory 做上下文管理。面试时强调:Prompt 是静态组装,Message 列表是动态编排,两者本质都是给 ChatModel 提供 Messages 输入。
【面试题】2. Spring AI 中 VectorStore 的元数据(Metadata)过滤有什么实际用途?怎么在 similaritySearch 中加过滤条件?
【标准答案】元数据过滤是 RAG 精准检索的关键能力。每个 Document 存入 VectorStore 时可以带 metadata(比如文档来源、创建时间、分类标签、部门等),检索时用 Filter.ExpressionBuilder 构建过滤表达式,只返回符合条件的文档。比如:检索公司知识库时加 category == "财务" 过滤,只搜财务相关文档;或者加 date >= "2024-01-01" 只搜最新资料。代码上用 similaritySearch(SearchRequest.builder().query("问题").topK(5).filterExpression(builder.eq("category", "财务")).build())。面试重点:不加元数据过滤的 RAG 就是"大海捞针",加了就是"精准钓鱼"。生产环境必须用元数据过滤,否则召回一堆无关文档,既浪费 Token 又降低回答质量。
【面试题】3. Spring AI 的 @Bean 注册 Function 时,函数名和描述信息是怎么传递给大模型的?函数签名有什么要求?
【标准答案】Spring AI 通过 @Bean 注册的函数,框架会自动做三件事:① 解析函数名(Bean 名字就是 tool name);② 从函数签名提取参数类型和名称,自动生成 JSON Schema;③ 把工具描述(通过 @Description 注解或 Bean 定义时的 description 字段)一起打包发给模型。函数签名要求:参数必须是普通 Java 对象(POJO),字段类型用基本类型 + String + List + 嵌套对象,避免用 Map、Object 等模糊类型(Schema 生成会出问题)。返回值可以是任意类型,框架会序列化为 JSON。面试时说清楚:函数名=Bean 名,参数=JSON Schema 的 properties,@Description=tool description,三者缺一不可。复杂参数建议单独定义 Request DTO 类,别用 Map。
【面试题】4. Spring AI 中如何用 Advisor 实现请求/响应的拦截和增强?能举个例子吗?
【标准答案】Advisor 是 Spring AI 1.0 引入的核心拦截机制,类似 Spring MVC 的 Interceptor,但作用于 AI 调用链。实现方式:定义一个类实现 CallAroundAdvisor(同步)或 StreamAroundAdvisor(流式),在 aroundCall 方法中可以:① 在调用前修改 Prompt(比如注入系统指令、加安全检查);② 在调用后修改响应(比如日志记录、敏感词过滤);③ 决定是否继续调用链(advisorChain.nextAroundCall)。实际例子:比如做个日志 Advisor,在 aroundCall 前后打印请求和响应;做个安全 Advisor,检查用户输入是否包含敏感内容,有就拦截不调用模型;做个缓存 Advisor,相同问题直接返回缓存结果。注册方式:ChatClient.builder().defaultAdvisors(myAdvisor)。面试强调:Advisor 是 Spring AI 的"中间件",所有横切关注点(日志、缓存、安全、限流)都应该用 Advisor 实现,别在业务代码里硬编码。
【面试题】5. Spring AI 对接 Ollama 本地模型时,有哪些关键配置和注意事项?
【标准答案】对接 Ollama 核心配置:① 添加 spring-ai-ollama-spring-boot-starter 依赖;② 配置 spring.ai.ollama.base-url=http://localhost:11434;③ 配置 spring.ai.ollama.chat.model=llama3(或其他已拉取的模型名);④ 可选配置 spring.ai.ollama.chat.options.temperature、top-p 等参数。注意事项:① Ollama 必须先 ollama pull llama3 拉取模型,否则调用报错;② Ollama 默认不支持 Function Calling(只有部分模型如 llama3.1 支持),项目如果强依赖工具调用要注意兼容性;③ 本地模型性能取决于硬件,Mac M系列芯片效果不错,但 Windows 无 GPU 环境下推理速度可能很慢;④ Embedding 模型需要单独配置 spring.ai.ollama.embedding.model=nomic-embed-text。面试亮点:说"我项目开发环境用 Ollama 跑本地模型省 API 费用,生产切 OpenAI/国产模型",体现成本意识。
【面试题】6. Spring AI 的 Structured Output 中,entity() 方法映射 POJO 有什么限制?嵌套对象和枚举怎么处理?
【标准答案】entity() 方法底层调用 BeanOutputConverter,自动根据 POJO 类生成 JSON Schema,然后要求模型按 Schema 输出 JSON,最后反序列化为 Java 对象。限制和注意点:① 嵌套对象可以用,但层级不要太深(3层以上模型容易出错),每个嵌套类也要有清晰的字段描述;② 枚举类型支持,框架会生成 enum 的可选值列表放入 Schema,但模型有时会输出不在枚举里的值,建议加 @JsonProperty + 默认值兜底;③ 集合类型 List<XXX> 支持,但 List 内的对象类型必须明确,不能用 List<Object>;④ 日期类型建议用 String 接收再手动转换,直接用 LocalDate 模型经常格式不对;⑤ 字段加 @JsonProperty 和 @JsonPropertyDescription 注解,帮模型理解每个字段的含义,输出更准确。面试核心:entity() 看着简单,但 POJO 设计直接决定成功率——字段描述要清楚、类型要明确、枚举要兜底。
【面试题】7. Spring AI 1.0 中 ChatClient 的 Fluent API 有哪些常用链式方法?和旧版 Prompt 方式对比有什么优势?
【标准答案】ChatClient Fluent API 核心链式方法:① .prompt() — 创建 Prompt 构建器;② .user("问题") — 设置用户消息;③ .system("系统指令") — 设置系统消息;④ .advisors(advisor) — 注册 Advisor;⑤ .functions("tool1", "tool2") — 绑定工具函数;⑥ .call() — 同步调用;⑦ .stream() — 流式调用;⑧ .entity(MyDTO.class) — 直接返回结构化对象;⑨ .content() — 获取纯文本响应。和旧版 Prompt 方式对比的优势:① 代码更简洁,一行链式调用搞定,不用手动 new Prompt + 组装 Message;② Advisor 和 Function 绑定更自然,不用在 Prompt 里处理;③ entity() 直接映射 POJO,不用手动反序列化;④ 支持默认配置(defaultSystem、defaultAdvisors),避免重复设置。面试要点:Fluent API 是声明式编程,Prompt 是命令式编程,前者更符合 Spring 风格,生产优先用 ChatClient。
【面试题】8. Spring AI 做 RAG 时,文档加载器(DocumentReader)有哪些?PDF/Word/HTML 各用什么加载?
【标准答案】Spring AI 提供多种 DocumentReader:① PagePdfDocumentReader — 加载 PDF,基于 Apache PDFBox,支持按页切分;② JsonReader — 加载 JSON 数据,支持指定提取字段;③ TextReader — 加载纯文本文件;④ MarkdownDocumentReader — 加载 Markdown,保留标题结构作为元数据;⑤ HtmlDocumentReader — 加载 HTML,自动去除标签提取正文;⑥ DocxDocumentReader — 加载 Word 文档;⑦ TikaDocumentReader — 通用加载器,基于 Apache Tika,支持几乎所有格式(PDF/Word/Excel/PPT/HTML 等)。选型建议:单一格式用专用 Reader(如只处理 PDF 就用 PagePdfDocumentReader,控制更精细);多格式混合场景用 TikaDocumentReader 一把梭。所有 Reader 加载后都返回 List<Document>,接着用 TokenTextSplitter 切分,再写入 VectorStore。面试加分:提到 Tika 是万金油但解析质量不如专用 Reader,精度要求高的场景优先专用 Reader。
【面试题】9. Spring AI 的 ChatMemory 在多用户并发场景下怎么隔离?每个用户的对话历史怎么管理?
【标准答案】ChatMemory 的核心概念是 conversationId——每个对话用唯一的 conversationId 标识,底层 InMemoryChatMemory 就是一个 Map<conversationId, List<Message>> 的结构。多用户隔离的方式:① 每个用户用独立的 conversationId(比如 user:{userId}:session:{sessionId}),这样不同用户的对话历史天然隔离;② MessageChatMemoryAdvisor 在调用时传入 conversationId,框架自动从 ChatMemory 取对应对话的上下文消息;③ 如果用 InMemoryChatMemory,要注意内存泄漏——用户量大时需要定期清理过期会话(设置 TTL 或定时任务清理)。生产环境方案:用 Redis 或数据库实现 ChatMemory 接口,conversationId 作为 key,对话历史序列化存入,天然支持 TTL 过期和持久化。面试关键:ChatMemory 隔离靠 conversationId,不是靠线程或请求,设计 conversationId 的命名规范是生产化的第一步。
【面试题】10. Spring AI 的 MCP(Model Context Protocol)支持是什么?和 Agent 编排有什么关系?
【标准答案】MCP 是 Anthropic 提出的标准化协议,让 AI 应用能以统一方式连接外部工具和数据源。Spring AI 对 MCP 的支持体现在:① 可以作为 MCP Client 连接任何 MCP Server,把 MCP Server 暴露的 tools 和 resources 自动映射为 Spring AI 的 Function;② 也可以作为 MCP Server 把自己的 Function 暴露给其他 MCP Client 调用。和 Agent 编排的关系:MCP 解决的是"工具发现和调用"的标准化问题——在多 Agent 系统中,每个 Agent 可能需要不同的工具集,MCP 让工具注册和发现变成协议级能力,不需要硬编码。比如 Agent A 擅长搜索,Agent B 擅长数据库查询,它们通过 MCP 协议互相发现对方的能力并协作。面试说清楚:MCP 是工具层的"USB 协议",Function Calling 是具体的"USB 设备驱动",前者管发现和连接,后者管执行。Spring AI 的 MCP 支持让 Agent 编排从硬编码走向即插即用。