Skip to content

Spring AI 面试题库 ​

生成时间:2026-05-21 20:59


本轮 Spring AI 面试题库(带答案) ​

【面试题】1. Spring AI中ChatClient和ChatModel有什么区别?什么时候用哪个? ​

【标准答案】 这是个很好的架构设计问题。简单说,ChatModel是底层抽象,ChatClient是高层封装。

ChatModel直接对接各家AI厂商的API,比如OpenAIChatModel、OllamaChatModel,它负责发请求、收响应,是最基础的调用入口。你用它就得自己拼Prompt、自己处理响应。

ChatClient是Spring AI 1.0推出的统一入口,它内部用的是ChatModel,但给你封装了Fluent API,比如chatClient.prompt().user("问题").call().content(),链式调用更优雅。

什么时候用ChatClient?

  • 大部分业务场景,用ChatClient就够了,代码简洁、可读性好
  • 需要Advisor机制拦截处理(比如加对话记忆、日志、安全校验)
  • 需要用Fluent API快速实现功能

什么时候用ChatModel?

  • 需要深度定制,比如自己实现重试逻辑、自己封装Advisor
  • 需要直接访问底层模型能力,比如获取token使用量、原始响应头
  • 迁移老代码,原来用的是ChatModel

实际项目里,90%的情况用ChatClient,特殊场景才下沉到ChatModel。


【面试题】2. Spring AI的Advisor机制是怎么工作的?能解决什么问题? ​

【标准答案】 Advisor是Spring AI 1.0的核心架构之一,类似于Spring AOP的切面,但专门针对AI调用链。

工作原理: 每个Advisor可以在调用前和调用后拦截:

  • aroundCall:拦截同步调用
  • aroundStream:拦截流式调用
  • getOrder:定义执行顺序

调用链是这样的:ChatClient收到请求 → 按Order顺序执行所有Advisor的前置逻辑 → 调用ChatModel → 按逆序执行Advisor的后置逻辑 → 返回结果。

能解决什么问题?

  1. 对话记忆:MessageChatMemoryAdvisor在请求前自动注入历史消息,在响应后保存新消息
  2. RAG检索:QuestionAnswerAdvisor在请求前先查向量库,把相关知识拼到Prompt里
  3. 安全校验:请求前检查用户输入是否有敏感词、是否越权
  4. 日志监控:记录每次调用的耗时、token数、成功失败
  5. 限流熔断:在Advisor里集成Resilience4j,实现调用量控制

怎么自定义Advisor? 实现CallAroundAdvisor接口,重写aroundCall方法,在里面写拦截逻辑。比如:

java
public class LoggingAdvisor implements CallAroundAdvisor {
    @Override
    public AdvisedResponse aroundCall(AdvisedRequest advisedRequest, CallAroundAdvisorChain chain) {
        long start = System.currentTimeMillis();
        AdvisedResponse response = chain.nextAroundCall(advisedRequest);
        long duration = System.currentTimeMillis() - start;
        log.info("AI调用耗时: {}ms", duration);
        return response;
    }
}

Advisor让AI调用的横切关注点可以复用,不用在每个业务代码里重复写。


【面试题】3. Spring AI做RAG时,VectorStore选型要考虑哪些因素?PGVector、Redis、Pinecone怎么选? ​

【标准答案】 这是个很实际的架构决策问题,没有标准答案,要看你的场景。

选型考虑因素:

  1. 数据量级

    • 几万条:Redis、PGVector都行
    • 百万级以上:Pinecone、Milvus、Chroma这种专门的向量库更合适
  2. 查询频率和延迟要求

    • 高频低延迟:Pinecone(托管服务,全球CDN加速)、Redis(内存级)
    • 低频可接受稍慢:PGVector(磁盘存储)
  3. 部署方式

    • 不想运维:Pinecone全托管,开箱即用
    • 必须私有化:PGVector(复用现有PostgreSQL)、Milvus(自建)
  4. 成本

    • 已有PostgreSQL:PGVector零额外成本,装个插件就行
    • 大规模高并发:Pinecone按调用量计费,成本可控
    • Redis:占内存,向量数据量大了成本会上去
  5. 生态和稳定性

    • Pinecone:成熟稳定,Spring AI官方支持好
    • PGVector:PostgreSQL生态,适合已有PG基础架构的团队
    • Milvus:开源社区活跃,但自建有运维成本

我的建议:

  • 小项目、原型验证:PGVector,复用现有数据库,省事
  • 中型项目、要稳定:Pinecone,托管服务不用运维
  • 大厂、私有化要求:Milvus,自己掌控数据
  • 已有Redis基础设施:用Redis Vector,统一技术栈

关键是不要过度设计,从简单开始,量级上来再迁移。


【面试题】4. Spring AI的Function Calling是怎么实现的?@Bean注册函数后,模型怎么知道该调哪个? ​

【标准答案】 Function Calling是让AI模型能"动手做事"的关键机制。Spring AI的实现分三步:

第一步:注册函数 写一个普通的Java方法,用@Bean注册到Spring容器:

java
@Bean
public Function<WeatherRequest, WeatherResponse> weatherFunction() {
    return request -> {
        // 调用天气API
        return new WeatherResponse("北京晴天,25度");
    };
}

第二步:自动生成JSON Schema Spring AI会自动扫描这个Function,读取泛型参数类型(WeatherRequest),生成JSON Schema,包含:

  • 函数名(默认是bean名)
  • 函数描述(从方法名或@Description注解提取)
  • 参数结构(参数名、类型、是否必填)

这个Schema会作为tools参数发给AI模型。

第三步:模型决策和调度 用户问"北京今天天气怎么样",模型看到有weatherFunction可用,判断该调它,返回tool_call指令。Spring AI收到后:

  1. 解析tool_call,拿到函数名和参数
  2. 从Spring容器找到对应的Function bean
  3. 反序列化参数为WeatherRequest对象
  4. 调用函数,拿到返回值
  5. 把结果作为tool消息发回给模型
  6. 模型生成最终回答:"北京今天晴天,气温25度"

关键点:

  • 你不用写调度逻辑,Spring AI自动完成
  • 函数描述很重要,模型靠它判断什么时候该调
  • 可以注册多个函数,模型自己选
  • 支持多轮tool_call,一个函数的结果可以触发另一个函数

这就是为什么Spring AI的Function Calling这么好用,你只需要写业务函数,其他都交给框架。


【面试题】5. Spring AI的BeanOutputConverter有什么坑?怎么避免结构化输出失败? ​

【标准答案】 BeanOutputConverter能把AI返回的文本自动转成Java对象,听起来很美好,但确实有坑。

常见坑:

  1. Schema生成不准确 如果POJO字段名不清晰,生成的JSON Schema描述模糊,模型不知道该填什么,容易乱填或漏填。

    解决办法:给字段加@Description注解,明确说明每个字段的含义和格式要求。

  2. 模型输出不稳定 同一个Prompt,模型有时候返回完整JSON,有时候返回带解释的文本,导致解析失败。

    解决办法:在Prompt里明确要求"只返回JSON,不要任何解释",用format方法把Schema注入Prompt。

  3. 复杂嵌套结构处理差 如果POJO里有List、Map、嵌套对象,模型容易搞错结构,尤其是数组为空时。

    解决办法:简化结构,避免深层嵌套;或者用Map<String, Object>兜底,自己再转。

  4. 特殊字符和格式问题 JSON里的引号、换行符可能被模型转义或不转义,导致解析失败。

    解决办法:用entity()方法替代BeanOutputConverter,它更稳定。

  5. 中文字段名支持差 有些模型对中文字段名支持不好,生成的JSON可能乱码。

    解决办法:字段名用英文,@Description里写中文描述。

最佳实践:

java
// 推荐:直接用entity()
Person person = chatClient.prompt()
    .user(u -> u.text("提取信息:{text}").param("text", text))
    .call()
    .entity(Person.class);

// 如果用BeanOutputConverter,记得加描述
@Bean
public static class Person {
    @Description("姓名,2-4个中文字符")
    private String name;
    
    @Description("年龄,正整数")
    private Integer age;
}

结构化输出这块,1.0版本比早期版本稳定多了,但还是要写好Prompt和Schema,不要完全依赖自动转换。


【面试题】6. Spring AI的ChatMemory怎么持久化?生产环境怎么设计对话记忆方案? ​

【标准答案】 ChatMemory是对话体验的关键,但默认的InMemoryChatMemory重启就没了,生产环境必须持久化。

持久化方案:

  1. 数据库存储 最常见的方案。Spring AI提供ChatMemoryRepository接口,可以自己实现:

    java
    public class JdbcChatMemoryRepository implements ChatMemoryRepository {
        public void add(String conversationId, Message message) {
            jdbcTemplate.update(
                "INSERT INTO chat_memory (conv_id, role, content, created_at) VALUES (?, ?, ?, ?)",
                conversationId, message.getMessageType(), message.getContent(), new Date()
            );
        }
    }

    表结构设计:conversation_id、message_type、content、created_at、metadata。

  2. Redis存储 适合高频访问场景。用Redis的List存储消息,conversation_id作为key:

    java
    public void add(String conversationId, Message message) {
        redisTemplate.opsForList().rightPush(
            "chat:" + conversationId, 
            message.getContent()
        );
    }

    设置过期时间,避免无限增长。

  3. 混合方案

    • 最近10条消息放Redis,快速读取
    • 历史消息存数据库,需要时再查
    • 定期归档到对象存储

生产环境设计要点:

  1. 消息数量控制 不能无限存消息,token数会爆。通常保留最近20-50条,或者用滑动窗口。

  2. 去重和压缩 相似消息去重,长消息压缩摘要,节省token和存储。

  3. 用户隔离 每个用户/会话独立的conversation_id,互不干扰。

  4. 性能优化

    • 分页加载历史消息
    • 缓存热点会话
    • 异步写入数据库
  5. 合规性

    • 敏感消息加密存储
    • 按法规要求定期清理
    • 用户可删除自己的对话记录

Spring AI的MessageChatMemoryAdvisor会自动调用ChatMemory的add和get方法,你只需要实现持久化层,上层逻辑不用改。


【面试题】7. Spring AI怎么实现多模型切换?同一个项目里怎么同时用OpenAI和通义千问? ​

【标准答案】 多模型切换是Spring AI的强项,配置层面和代码层面都能做。

配置方式:

application.yml里配置多个模型:

yaml
spring:
  ai:
    openai:
      api-key: ${OPENAI_API_KEY}
      base-url: https://api.openai.com
    dashscope:
      api-key: ${DASHSCOPE_API_KEY}

Spring AI会自动创建两个ChatModel的bean:openAiChatModel和dashscopeChatModel。

代码层切换:

java
@Service
public class AiService {
    @Autowired
    private ChatModel openAiChatModel;
    
    @Autowired
    private ChatModel dashscopeChatModel;
    
    public String chatWithOpenAi(String question) {
        return openAiChatModel.call(new Prompt(question)).getResult().getOutput().getContent();
    }
    
    public String chatWithDashscope(String question) {
        return dashscopeChatModel.call(new Prompt(question)).getResult().getOutput().getContent();
    }
}

动态切换:

如果要根据用户或场景动态选模型,可以用Map注入:

java
@Service
public class AiRouterService {
    private final Map<String, ChatModel> chatModels;
    
    public AiRouterService(List<ChatModel> models) {
        this.chatModels = models.stream()
            .collect(Collectors.toMap(
                m -> m.getClass().getSimpleName().replace("ChatModel", "").toLowerCase(),
                Function.identity()
            ));
    }
    
    public String chat(String model, String question) {
        ChatModel chatModel = chatModels.get(model);
        if (chatModel == null) {
            throw new IllegalArgumentException("不支持的模型: " + model);
        }
        return chatModel.call(new Prompt(question)).getResult().getOutput().getContent();
    }
}

配置前缀切换(Spring AI 1.0):

Spring AI 1.0统一了配置前缀spring.ai.*,你可以:

yaml
spring:
  ai:
    model: openai  # 默认用openai

运行时通过环境变量切换:SPRING_AI_MODEL=dashscope

实际应用场景:

  • 国内用户用通义千问,国外用户用OpenAI
  • 简单问题用小模型(快、便宜),复杂问题用大模型
  • 某模型故障时,自动切换备用模型

Spring AI的多模型支持很灵活,关键是设计好路由策略,别让模型选型变成if-else地狱。


【面试题】8. Spring AI做RAG时,TokenTextSplitter怎么配置分块策略?太大太小有什么问题? ​

【标准答案】 分块是RAG的关键,分得好不好直接影响检索效果。

TokenTextSplitter的配置参数:

java
TokenTextSplitter splitter = new TokenTextSplitter(
    500,    // defaultChunkSize: 每块最大token数
    100,    // minChunkSizeChars: 每块最小字符数
    50,     // minChunkLengthToEmbed: 太小的块不处理
    1000,   // maxNumChunks: 最大块数,防爆炸
    true    // keepSeparator: 是否保留分隔符
);

分块太大的问题:

  • 检索时噪声多,相关性差,相似度分数被稀释
  • 超过模型的context window,被截断
  • 每块信息量太大,模型抓不住重点

分块太小的问题:

  • 语义完整性破坏,一句话拆成两块,上下文断裂
  • 检索命中率下降,关键词可能分布在多块
  • 向量库压力增大,块数爆炸,查询变慢

最佳实践:

  1. 根据内容类型调整

    • 技术文档:500-800 tokens,通常一个概念一个段落
    • 法律合同:1000-1500 tokens,条款完整性更重要
    • 新闻文章:300-500 tokens,新闻段落短
  2. 设置合适的重叠 TokenTextSplitter默认没有重叠,可以自己实现滑动窗口:

    java
    // 伪代码:每块重叠20%
    List<String> chunks = new ArrayList<>();
    for (int i = 0; i < text.length(); i += chunkSize - overlap) {
        chunks.add(text.substring(i, Math.min(i + chunkSize, text.length())));
    }

    重叠能保证边界处的上下文不丢失,推荐10-20%。

  3. 按语义分块 更高级的做法是按段落、章节分,而不是按token硬切。可以先用LLM做摘要,再按摘要分块。

  4. 监控检索效果 生产环境要监控:

    • 每块的平均token数
    • 检索命中率(召回的块是否包含答案)
    • 用户反馈的相关性评分

分块没有万能公式,要根据自己的数据调优。我的经验是先从默认500开始,看检索效果再调整。


【面试题】9. Spring AI项目怎么接入Micrometer做监控?关键指标有哪些? ​

【标准答案】 Spring AI天然集成Micrometer,开箱就能用,但得知道看什么指标。

接入步骤:

  1. 添加依赖:

    xml
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-actuator</artifactId>
    </dependency>
    <dependency>
        <groupId>io.micrometer</groupId>
        <artifactId>micrometer-registry-prometheus</artifactId>
    </dependency>
  2. 配置暴露端点:

    yaml
    management:
      endpoints:
        web:
          exposure:
            include: prometheus, health, metrics
  3. 访问/metrics端点,能看到Spring AI自动注册的指标。

关键指标:

  1. 调用次数

    • spring.ai.chat.model.calls:ChatModel调用次数
    • 按模型分类:OpenAI、通义千问各有计数
  2. 延迟和耗时

    • spring.ai.chat.model.latency:P50、P95、P99耗时
    • 关注P99是否超过用户可接受的等待时间(通常3-5秒)
  3. Token使用量

    • spring.ai.chat.model.tokens.prompt:输入token数
    • spring.ai.chat.model.tokens.completion:输出token数
    • 按用户、按模型分类统计成本
  4. 错误率

    • spring.ai.chat.model.errors:调用失败次数
    • 按错误类型分类:超时、限流、模型错误
  5. 向量库指标

    • spring.ai.vectorstore.search.latency:向量检索耗时
    • spring.ai.vectorstore.insert.count:向量插入数量

告警配置:

yaml
# Prometheus告警规则示例
groups:
  - name: spring-ai
    rules:
      - alert: HighErrorRate
        expr: rate(spring_ai_chat_model_errors[5m]) > 0.1
        for: 2m
        annotations:
          summary: "AI调用错误率过高"
      
      - alert: HighLatency
        expr: histogram_quantile(0.99, rate(spring_ai_chat_model_latency_bucket[5m])) > 5
        annotations:
          summary: "AI调用P99延迟超过5秒"

可视化面板:

推荐用Grafana,导入Spring Boot官方dashboard,加上AI相关指标的面板:

  • 实时QPS曲线
  • Token消耗柱状图
  • 错误率饼图
  • 各模型性能对比

监控这块,Spring AI做得挺好,指标都有,关键是把告警和可视化搭起来,出了问题第一时间知道。


【面试题】10. Spring AI 1.0相比之前版本有什么重大更新?对开发者意味着什么? ​

【标准答案】 Spring AI 1.0是里程碑版本,架构和API都有大变化。

重大更新:

  1. ChatClient统一入口 之前调用AI有好几种方式,ChatModel、AiClient、PromptTemplate,容易混乱。1.0统一成ChatClient,Fluent API风格,代码更清晰:

    java
    chatClient.prompt()
        .system("你是一个助手")
        .user("你好")
        .call()
        .content();
  2. Advisor架构 之前对话记忆、RAG、安全校验都要自己实现拦截逻辑。1.0引入Advisor机制,像Spring AOP一样,横切关注点可插拔。写一个Advisor,到处复用。

  3. VectorStore接口统一 之前各家向量库的API不一致,切换成本高。1.0统一了VectorStore接口,增删改查方法标准化,切换向量库只需要换个bean。

  4. spring.ai.*配置前缀 配置项统一了,之前是spring.openai.、spring.ollama.,现在都是spring.ai.*前缀,多模型配置更清晰:

    yaml
    spring:
      ai:
        openai:
          api-key: xxx
        dashscope:
          api-key: xxx
  5. Structured Output增强 BeanOutputConverter更稳定,entity()方法一行代码实现结构化输出。Schema生成更智能,复杂对象也能处理。

  6. Observability内置 之前监控要自己埋点。1.0内置Micrometer支持,自动上报调用次数、延迟、token数。

对开发者意味着什么?

  • 代码更简洁:ChatClient的Fluent API,代码可读性提升
  • 扩展更容易:Advisor让横切逻辑可插拔,代码不耦合
  • 切换成本低:VectorStore接口统一,换个向量库改个配置就行
  • 运维更友好:监控指标内置,搭Grafana dashboard半小时搞定

迁移建议:

如果是新项目,直接用1.0,别回头看旧版本。

如果是老项目要升级,注意:

  • ChatModel还能用,但推荐迁移到ChatClient
  • PromptTemplate被ChatClient的prompt()方法替代
  • 检查配置文件,改成spring.ai.*前缀
  • 自定义的拦截逻辑,改成Advisor实现

Spring AI 1.0是成熟的标志,API稳定了,架构清晰了,可以放心在生产环境大规模使用。


本轮题目统计:

  • 技术基础:题1、题4、题5
  • 架构设计:题2、题6、题7
  • 场景实操:题3、题8
  • 性能优化:题9
  • 版本更新:题10

覆盖考点: ChatClient、ChatModel、Advisor、RAG、VectorStore、Function Calling、BeanOutputConverter、ChatMemory、多模型切换、TokenTextSplitter、Micrometer监控、Spring AI 1.0新特性