Skip to content

Spring AI从零学习路线与工作原理总览

Spring AI 是 Spring 生态中的 AI 应用工程化框架。它不训练大模型,而是把模型调用、Prompt、结构化输出、Embedding、VectorStore、RAG、Chat Memory、Advisor、Tool Calling 和可观测性包装成 Spring 风格的抽象、Bean 与自动配置。

它解决的是“Java 商业系统怎样安全、可测试、可替换、可观测地使用模型”,不是“怎样让模型本身变聪明”。模型仍可能幻觉、超时、限流、生成非法 JSON 或请求危险工具;Spring AI 提供工程接口,但业务边界、权限、评估和兜底仍要由应用负责。

本页是 Spring AI 专栏入口。你会先理解一次请求经过哪些对象、Spring Boot 为什么能够自动创建客户端、最小接口怎样运行、同步与流式有什么区别,再进入 ChatClient、Prompt、RAG、Tool Calling 和生产治理专页。

学习目标

完成本页后,你应该能够:

  1. 说明 Spring AI 与 Spring、Spring Boot、模型厂商 SDK 的关系。
  2. 区分 ChatModelChatClientPromptMessageChatOptionsChatResponseGeneration
  3. 解释 Starter、BOM、自动配置和条件装配如何生成模型 Bean。
  4. 解释从 Controller 到模型 HTTP API,再到响应解析的完整链路。
  5. 写出同步聊天和 SSE 流式响应的最小 Demo。
  6. 说明 Advisor 链怎样添加 Memory、RAG、安全、日志等横切能力。
  7. 区分 Embedding、VectorStore、RAG 和 Tool Calling 的职责。
  8. 理解 Spring AI 1.x、2.x Starter 命名和 API 可能不同,知道怎样避免版本混用。
  9. 知道生产项目为什么还必须补权限、限流、超时、评估、成本和审计。
  10. 根据启动失败、401、429、超时、空响应和解析失败选择第一批证据。

一、Spring AI在整个系统中的位置

mermaid
flowchart TD
    A["业务Controller/Service"] --> B["Spring AI应用抽象"]
    B --> C["ChatClient与Advisor链"]
    B --> D["ChatModel/EmbeddingModel"]
    B --> E["VectorStore与RAG"]
    B --> F["Tool Calling"]
    D --> G["模型厂商适配器"]
    G --> H["云模型API或本地推理服务"]
    E --> I["向量数据库"]
    F --> J["受控业务Service"]
职责不负责什么
Spring BootBean、配置、Web、Actuator、生命周期不定义大模型推理算法
Spring AI模型抽象、Prompt、Advisor、RAG、Tool API不保证模型回答事实正确
Provider Adapter把通用请求转换成厂商协议不决定业务权限和场景边界
模型服务Tokenize、推理、逐Token生成不天然知道企业实时私有数据
业务系统身份、权限、数据、事务、审计、兜底不应让模型直接绕过它操作数据库

Spring AI 位于 AI 栏目而不是 Java 主线:Java/Spring Boot 是前置工程基础,模型、RAG、Agent 和 Spring AI 属于 AI 应用体系。

二、为什么不直接到处写HTTP请求

一个 Demo 可以直接调用:

java
httpClient.post()
        .uri(modelUrl)
        .header("Authorization", "Bearer " + apiKey)
        .bodyValue(payload)
        .retrieve();

当项目变大后会出现:

  • 不同厂商请求/响应结构散落在业务代码。
  • API Key、Base URL、模型名和超时配置重复。
  • 同步、流式、Tool Calling、Embedding 各自造轮子。
  • Prompt 拼接和结构化输出缺少统一规范。
  • 切换模型要修改大量 Controller/Service。
  • Token、耗时、错误和 Trace 无法统一观测。

Spring AI 通过接口和适配器收敛这些变化。但“统一接口”不代表所有模型能力完全等价:Tool Calling、图片输入、JSON Schema、Token 统计、Reasoning 字段和错误码仍可能存在厂商差异。

三、核心对象关系

mermaid
flowchart TD
    A["ChatClient:面向应用的流式API"] --> B["Prompt:一次模型输入"]
    B --> C["System/User/Assistant Message"]
    B --> D["ChatOptions:模型名、温度、最大输出等"]
    A --> E["Advisor Chain:调用前后增强"]
    E --> F["ChatModel:模型调用抽象"]
    F --> G["Provider请求"]
    G --> H["ChatResponse"]
    H --> I["Generation与AssistantMessage"]
    H --> J["Usage/Metadata"]

3.1 ChatModel

模型能力的底层抽象。接受 Prompt,返回 ChatResponse。不同 Provider Starter 提供具体实现。

3.2 ChatClient

面向应用的 Fluent Client。负责更方便地组合 system/user 文本、模板参数、Options、Advisor、Tool 和输出转换,再调用 ChatModel。

它不是远程模型本身,也不应该直接散落在 Controller 中承载业务权限和数据库操作。

3.3 Prompt

一次完整模型输入,通常包含多条 Message 和 ChatOptions。Prompt 不只是用户一句话,还包含系统规则、历史、RAG 资料和工具结果。

3.4 Message

常见角色:

  • System:定义角色、规则和边界。
  • User:当前用户输入。
  • Assistant:历史模型输出或工具调用意图。
  • Tool:工具执行结果,具体对象模型随版本适配。

3.5 ChatOptions

模型参数,例如 model、temperature、maxTokens。不是所有 Provider 都支持相同参数或相同范围。

3.6 ChatResponse和Generation

ChatResponse 通常包含一个或多个候选 Generation、元数据和 Token Usage。只调用 .content() 很方便,但会丢失 finish reason、usage、tool call 等诊断信息。

四、Spring Boot自动配置为什么能创建Bean

加入 Starter 后,Spring Boot 启动大致执行:

mermaid
flowchart TD
    A["Maven/Gradle引入Provider Starter"] --> B["自动配置类进入候选集合"]
    B --> C["读取spring.ai.*配置属性"]
    C --> D["检查Classpath类和Conditional条件"]
    D --> E{"是否满足创建条件"}
    E -->|"否"| F["Bean不创建或启动校验失败"]
    E -->|"是"| G["创建Provider API Client"]
    G --> H["创建ChatModel/EmbeddingModel Bean"]
    H --> I["创建或注入ChatClient.Builder"]
    I --> J["业务配置构建ChatClient"]

自动配置不是魔法,依赖四类输入:

  1. Classpath 中存在正确 Starter 和传递依赖。
  2. Spring Boot/Spring AI 版本兼容。
  3. 配置属性能够绑定。
  4. @ConditionalOnClass@ConditionalOnMissingBean、Provider 开关等条件满足。

如果 ChatClient.Builder 注入失败,先查看 Condition Evaluation Report 和依赖树,不要先怀疑 API Key。

五、BOM和Starter版本为什么必须成套

Spring AI 版本迭代中,Artifact 名称和 API 会变化。常见差异示意:

版本线常见Starter命名示意风险
较早1.x文档spring-ai-openai-spring-boot-starter与新文档的包/API混用可能找不到类
新2.x文档spring-ai-starter-model-openai需要匹配对应Boot和BOM

不能同时复制两套教程。项目必须选定一条版本线,并使用 BOM 统一 Spring AI 模块版本。

2.x 风格示例:

xml
<properties>
    <java.version>21</java.version>
    <spring-ai.version>2.0.0</spring-ai.version>
</properties>

<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.springframework.ai</groupId>
            <artifactId>spring-ai-bom</artifactId>
            <version>${spring-ai.version}</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>

<dependencies>
    <dependency>
        <groupId>org.springframework.ai</groupId>
        <artifactId>spring-ai-starter-model-openai</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
</dependencies>

2.0.0 是本知识库当前示例基线,不代表永远适合所有项目。复制前确认项目 JDK、Spring Boot 和官方兼容矩阵。JDK 8 老项目通常不能直接使用新 Spring AI 版本,应评估升级、独立 AI 服务或兼容 HTTP Client 层。

六、查看依赖冲突的证据

Maven:

bash
mvn dependency:tree -Dincludes=org.springframework.ai

检查:

  • 是否同时出现多个 Spring AI 版本。
  • BOM 是否真正管理到每个模块。
  • 是否混入 1.x 和 2.x Starter。
  • Spring Boot 管理的 Jackson/Reactor/HTTP Client 是否冲突。
  • 运行时 Classpath 是否与 IDE 编译 Classpath 一致。

常见异常:

text
ClassNotFoundException
NoSuchMethodError
NoClassDefFoundError
BeanDefinitionOverrideException

这些通常首先指向依赖/版本问题,不是模型推理问题。

七、最小配置

yaml
spring:
  ai:
    openai:
      api-key: ${MODEL_API_KEY}
      base-url: ${MODEL_BASE_URL:https://api.openai.com}
      chat:
        options:
          model: ${MODEL_NAME}
          temperature: 0.2

注意:

  • API Key 只放环境变量、Secret Manager 或受控配置中心,不提交 Git。
  • OpenAI-compatible 服务不代表完全兼容所有路径和字段。
  • base-url 是否需要包含 /v1 取决于适配器与目标服务约定。
  • temperature 低只能减少随机性,不能保证事实正确。
  • 模型名错误通常在第一次远程调用时暴露,不一定阻止应用启动。

八、创建ChatClient Bean

java
@Configuration
public class AiClientConfiguration {

    @Bean
    ChatClient businessChatClient(ChatClient.Builder builder) {
        return builder
                .defaultSystem("""
                        你是企业技术助手。
                        只根据用户提供的事实和已授权资料回答。
                        不确定时明确说明不知道,不得编造。
                        """)
                .build();
    }
}

文本块需要 JDK 15+。JDK 8 项目应使用普通字符串:

java
String systemText = "你是企业技术助手。"
        + "只根据已授权资料回答。"
        + "不确定时明确说明不知道。";

defaultSystem 是默认规则,不是不可覆盖的安全边界。高风险权限必须由 Java 代码和数据查询层强制执行。

九、同步聊天完整Demo

DTO:

java
public record ChatRequest(
        @NotBlank
        @Size(max = 2000)
        String message) {
}

public record ChatResult(
        String answer,
        String requestId) {
}

JDK 8 使用普通 POJO 替代 record。

Service:

java
@Service
public class TechnicalAssistantService {

    private final ChatClient chatClient;

    public TechnicalAssistantService(ChatClient chatClient) {
        this.chatClient = chatClient;
    }

    public ChatResult ask(String message, String requestId) {
        String answer = chatClient.prompt()
                .user(user -> user.text("""
                        请回答下面的技术问题:
                        {question}

                        要求:
                        1. 先给结论;
                        2. 再解释原因;
                        3. 不知道时明确拒答。
                        """)
                        .param("question", message))
                .call()
                .content();

        if (answer == null || answer.trim().isEmpty()) {
            throw new IllegalStateException("模型返回空内容");
        }

        return new ChatResult(answer, requestId);
    }
}

Controller:

java
@RestController
@RequestMapping("/api/ai")
public class TechnicalAssistantController {

    private final TechnicalAssistantService assistantService;

    public TechnicalAssistantController(
            TechnicalAssistantService assistantService) {
        this.assistantService = assistantService;
    }

    @PostMapping("/chat")
    public ChatResult chat(
            @Valid @RequestBody ChatRequest request,
            @RequestHeader(value = "X-Request-Id", required = false)
            String requestId) {

        String effectiveRequestId = requestId == null
                ? UUID.randomUUID().toString()
                : requestId;

        return assistantService.ask(
                request.message(),
                effectiveRequestId);
    }
}

Controller 只接收参数和转换响应。场景路由、RAG 权限、Tool 权限、审计和降级放 Service/专门组件。

十、一次同步请求的内部过程

mermaid
flowchart TD
    A["Controller校验message"] --> B["Service调用chatClient.prompt"]
    B --> C["合并defaultSystem和本次User模板"]
    C --> D["绑定question模板变量"]
    D --> E["执行Advisor调用前链"]
    E --> F["构造Prompt和ChatOptions"]
    F --> G["ChatModel转换为Provider请求"]
    G --> H["HTTP Client发送并等待模型"]
    H --> I["Provider完成逐Token推理"]
    I --> J["适配器解析ChatResponse和Metadata"]
    J --> K["执行Advisor调用后链"]
    K --> L["content提取文本并返回"]

.call() 是阻塞式业务语义。底层实现即使使用异步 HTTP Client,当前 Web 请求仍要等待完整模型输出。

十一、为什么不能只取content

需要排查和成本治理时,应读取完整响应。具体 API 以版本为准,思路如下:

java
ChatResponse response = chatClient.prompt()
        .user(message)
        .call()
        .chatResponse();

if (response == null || response.getResult() == null) {
    throw new IllegalStateException("模型未返回Generation");
}

String content = response.getResult()
        .getOutput()
        .getText();

ChatResponseMetadata metadata = response.getMetadata();

可观察:

  • 实际模型名。
  • Prompt/Completion/Total Token。
  • Finish Reason。
  • Provider Request ID。
  • Tool Call 元数据。

不同版本中 getText()/getContent() 和 Metadata API 可能不同,复制时以当前 Javadoc 为准。

十二、流式响应是什么

模型仍然逐 Token 推理,流式只是把已生成片段尽早发送给客户端,降低首字等待时间,不会必然降低模型总计算时间。

mermaid
flowchart TD
    A["浏览器建立SSE连接"] --> B["Controller返回Flux"]
    B --> C["ChatClient.stream发起流式模型请求"]
    C --> D["Provider逐步返回Token/Chunk"]
    D --> E["应用按背压和连接状态转发"]
    E --> F["浏览器增量渲染"]
    F --> G["完成/错误/取消时清理资源"]

WebFlux 示例:

java
@RestController
@RequestMapping("/api/ai")
public class StreamingChatController {

    private final ChatClient chatClient;

    public StreamingChatController(ChatClient chatClient) {
        this.chatClient = chatClient;
    }

    @GetMapping(
            value = "/chat/stream",
            produces = MediaType.TEXT_EVENT_STREAM_VALUE)
    public Flux<String> stream(
            @RequestParam
            @Size(max = 2000)
            String message) {

        return chatClient.prompt()
                .user(message)
                .stream()
                .content()
                .timeout(Duration.ofSeconds(60));
    }
}

生产还要处理:

  • 客户端断开后取消上游订阅。
  • 网关/Nginx 缓冲和超时。
  • SSE 心跳。
  • 流中途失败后不能改 HTTP 状态码的边界。
  • 内容安全检查是逐块还是完整后执行。
  • Token/成本在流完成或取消时怎样记录。

十三、Advisor是什么

Advisor 在 ChatClient 调用前后增强请求,类似 AI 调用链中的中间件,但不要简单等同于 Servlet Filter 或 Spring AOP。

mermaid
flowchart TD
    A["原始用户请求"] --> B["安全/租户Advisor"]
    B --> C["Memory Advisor"]
    C --> D["RAG Advisor"]
    D --> E["观测/审计Advisor"]
    E --> F["ChatModel"]
    F --> G["响应按Advisor链返回处理"]

顺序会影响结果:

  • 先做权限,再检索,避免召回越权资料。
  • 问题改写应明确使用哪些历史。
  • RAG 上下文添加后再统计 Prompt Token。
  • 日志不能记录未脱敏 Prompt。

不要把所有业务写成一个巨型 Advisor。权限、检索、记忆、观测各自保持可测试职责。

十四、Memory不等于模型记住了用户

模型 API 通常是无状态的。Chat Memory 是应用保存历史,并在下一次请求时重新放入 Prompt。

mermaid
flowchart TD
    A["本轮用户消息"] --> B["按conversationId读取历史"]
    B --> C["裁剪/摘要/权限校验"]
    C --> D["历史与本轮问题拼成Prompt"]
    D --> E["调用模型"]
    E --> F["保存本轮User/Assistant消息"]

风险:历史无限增长、Token 成本上升、不同用户 conversationId 越权、旧敏感数据进入新请求、摘要丢失事实。Memory 专栏内容在生产路线中继续展开。

十五、Embedding、VectorStore和RAG关系

mermaid
flowchart TD
    A["企业文档"] --> B["解析、清洗、切Chunk"]
    B --> C["EmbeddingModel生成向量"]
    C --> D["VectorStore保存向量和权限元数据"]
    E["用户问题"] --> F["同一Embedding空间生成查询向量"]
    F --> G["按权限过滤并召回Chunk"]
    D --> G
    G --> H["重排、阈值和引用选择"]
    H --> I["RAG Advisor/Prompt加入资料"]
    I --> J["ChatModel基于资料生成回答"]
  • Embedding 负责语义表示。
  • VectorStore 负责向量存储和相似检索。
  • RAG 负责“检索资料 + 组装上下文 + 生成 + 引用/拒答”的完整链路。

向量相似不等于资料有答案,RAG 也不能自动解决权限和幻觉。详见 RAG 深层页面。

十六、Tool Calling关系

模型只产生“想调用哪个工具及参数”的结构化意图。真正的 Java 方法由后端执行:

mermaid
flowchart TD
    A["用户请求查询资产"] --> B["模型生成Tool Call"]
    B --> C["Spring AI解析工具名和参数"]
    C --> D["后端校验身份、权限、参数和风险"]
    D --> E["执行Java业务Service"]
    E --> F["最小化工具结果"]
    F --> G["结果回传模型继续生成"]

模型不能决定用户是否有权限,也不能直接接受其生成的 tenantId/userId 作为可信身份。完整内容见:Spring AI Tool Calling

十七、模型适配不等于无成本切换

统一 ChatModel 接口降低代码耦合,但切换模型仍需回归:

  • Prompt 指令遵循差异。
  • Tokenizer 和上下文窗口差异。
  • Tool Calling Schema 支持差异。
  • JSON/结构化输出稳定性。
  • 图片、音频等多模态能力。
  • Safety Filter 和拒答差异。
  • 价格、TTFT、吞吐、限流与地区合规。

切换模型必须跑固定评估集和安全门槛,不能只看接口编译通过。

十八、生产请求应有哪些层

mermaid
flowchart TD
    A["认证用户请求"] --> B["参数、大小和内容类型校验"]
    B --> C["租户、场景和数据权限"]
    C --> D["限流、并发和成本预算"]
    D --> E["场景路由:直接/RAG/Tool/异步"]
    E --> F["Prompt/Advisor/模型调用"]
    F --> G["输出解析、Schema和业务规则校验"]
    G --> H["引用、安全和敏感信息检查"]
    H --> I["返回或人工审核"]
    I --> J["记录版本、Token、耗时、结果和反馈"]

Spring AI 主要帮助 E–G 的框架集成;A–D、H–J 仍需要业务工程。

十九、错误分层

典型错误第一批证据
依赖/启动Bean不存在、NoSuchMethodErrordependency tree、Condition Report
配置API Key/Base URL/model未配置脱敏配置来源、绑定结果
网络/TLSDNS、握手、连接超时HTTP Client错误、DNS/TLS证据
Provider认证401/403Provider requestId、密钥权限/区域
限流配额429Retry-After、配额、并发、Token速率
模型服务5xx、过载Provider错误码、模型、区域、时间线
Prompt/上下文超长、指令冲突Token统计、Prompt版本、截断记录
输出空内容、非法JSON原始响应脱敏样本、finish reason
RAG无召回/错召回/越权query、filter、TopK、score、chunk版本
Tool参数错、越权、超时、重复写toolCallId、Schema、权限、幂等记录

二十、故障一:ChatClient.Builder注入失败

排查:

  1. 当前版本是否真的提供该自动配置 Bean。
  2. 是否引入了正确 Provider Starter,而不是只有 core 包。
  3. mvn dependency:tree 是否混用版本。
  4. 自动配置是否被 exclude。
  5. 是否定义了冲突自定义 Bean。
  6. Condition Evaluation Report 哪个条件未满足。

二十一、故障二:请求返回401或403

检查:

  • Key 是否从正确 Secret 注入,是否有不可见空格/换行。
  • Base URL 和 Key 是否属于同一 Provider/区域。
  • 模型是否需要额外项目、组织或资源权限。
  • 代理是否移除了 Authorization Header。
  • 不要把完整 Key 打进日志。

二十二、故障三:429后重试导致雪崩

错误做法:所有线程立即固定间隔重试三次。流量高峰会把一次 429 放大为更多请求。

正确思路:

  • 尊重 Retry-After。
  • 指数退避加随机抖动。
  • 设置总重试预算和截止时间。
  • 区分请求速率、Token速率和账户配额。
  • 对非幂等 Tool 写操作不自动重试。
  • 限流、排队、模型降级和友好失败组合。

二十三、故障四:模型返回空内容

可能原因:

  • 响应主要是 Tool Call,而不是文本。
  • Safety Filter 拦截。
  • Finish Reason 表示长度截断。
  • Provider 兼容层字段映射不完整。
  • 流式响应被提前取消。
  • 代码只读第一个 Generation,但实际结构不同。

需要看完整 ChatResponse/Provider 元数据,不只判断 .content()==null

二十四、可观测性最小字段

结构化日志/Trace:

text
requestId, traceId, tenantId(脱敏/受控), scene,
promptVersion, modelProvider, modelName, modelParameters,
ragIndexVersion, embeddingModel, topK, retrievedChunkIds,
toolNames, toolResultCodes,
promptTokens, completionTokens, totalTokens,
ttftMs, totalDurationMs, finishReason, errorCode,
safetyResult, evaluationSampleFlag

不记录完整 API Key、密码、医疗原文、身份证、未脱敏 Prompt 和完整工具返回值。

指标 Label 只使用低基数 scene/provider/model/result,不使用 userId、requestId、conversationId。

二十五、完整学习顺序

  1. 当前总览:对象、自动配置、版本、首个同步/流式请求。
  2. 从零到生产级掌握:串完整工程主线。
  3. 快速入门:验证依赖、配置和最小接口。
  4. ChatClient:深入同步、流式、Message、Options和响应。
  5. Prompt与结构化输出:模板、Schema、校验和注入风险。
  6. RAG知识库:建库、检索、权限、重排、引用和排查。
  7. Tool Calling:工具Schema、后端执行、权限、幂等和审计。
  8. 生产化治理:限流、超时、降级、观测、成本和评估。
  9. 商业生产场景:企业知识库、异常分析和业务工具。
  10. 从零到精通验收清单:逐项验收。

AI 通用原理先看:

二十六、常见误区

误区准确结论后果
Spring AI用来训练模型它是AI应用工程化框架学错方向
引入Starter就自动生产可用只完成Bean和协议接入无权限、评估、兜底
ChatClient等于模型它是应用客户端,最终调用远程/本地模型排障层级混乱
统一接口让模型无损切换能力、参数和效果仍有差异切换后质量/Tool退化
temperature=0就不会幻觉只降低随机性,不保证事实高风险回答误用
defaultSystem是安全边界Prompt规则可被攻击/冲突越权工具和泄密
流式让模型计算更快主要改善TTFT体验总耗时/成本误判
Memory是模型永久记忆应用每次重新注入历史上下文膨胀和越权
RAG召回相似文档就够还需权限、重排、阈值、引用和评估错答/越权
Tool参数来自模型可直接信任模型输出是不可信输入越权和错误写操作
混用1.x/2.x教程没关系Starter/API可能已变化编译或启动失败

二十七、面试标准回答

Spring AI是什么

Spring AI是Spring生态的AI应用工程化框架,用Starter和自动配置创建ChatModel、EmbeddingModel、VectorStore等Bean,用ChatClient、Prompt、Advisor、RAG和Tool Calling把模型能力接入Java业务。它不训练模型,也不保证回答正确;权限、数据、事务、评估、安全、成本和兜底仍由业务系统负责。

ChatClient和ChatModel有什么区别

ChatModel是底层模型调用抽象,接受Prompt并返回ChatResponse;ChatClient是面向应用的Fluent API,在ChatModel之上组合system/user消息、模板参数、Options、Advisor、Tool和输出转换。ChatClient方便业务使用,但实际Provider能力差异仍要评估。

Spring AI自动配置原理是什么

Provider Starter把自动配置类和实现放入Classpath,Spring Boot读取spring.ai配置,通过Conditional检查类、属性和缺失Bean条件,创建Provider API Client及ChatModel/EmbeddingModel,再提供ChatClient.Builder。注入失败先查BOM/Starter依赖树和Condition Report,而不是先查模型Key。

Advisor是什么

Advisor是ChatClient调用前后的增强链,可加入Memory、RAG、安全、日志和观测。顺序会改变输入和结果,例如权限应在检索前生效,RAG加入上下文后再统计Token。Advisor是工程扩展点,不应把所有业务逻辑堆进一个巨型Advisor。

为什么Spring AI版本不能混用

Spring AI不同版本线的Starter名称、包、配置和API可能变化,例如旧1.x和新2.x风格Artifact不同。应选择与JDK/Spring Boot兼容的BOM统一管理全部模块,用dependency tree确认只有一套版本,再以该版本官方文档和Javadoc为准。

二十八、学习实验与验收

  1. 用 BOM 和 Provider Starter 启动应用,打印 Condition Report 解释 Bean 来源。
  2. 故意混入另一个 Spring AI 版本,观察 dependency tree 和异常,再统一版本。
  3. 调用 ChatModel 和 ChatClient,比较代码职责和完整响应元数据。
  4. 编写同步 Controller,限制输入长度并隐藏 API Key。
  5. 编写 SSE 流式接口,模拟客户端中断和上游超时。
  6. 添加两个 Advisor,交换顺序并观察 Prompt/Token变化。
  7. 使用错误 Base URL、Key、模型名分别观察网络、401和Provider错误。
  8. 模拟 429,验证指数退避、抖动和总重试预算。
  9. 让模型返回 Tool Call/空文本,证明不能只检查content。
  10. 切换两个模型,用固定评估集比较结构化输出、RAG和Tool能力。

验收时必须能回答:

  • Spring AI、Spring Boot和模型服务分别负责什么?
  • ChatModel、ChatClient、Prompt、Message和ChatResponse怎样关联?
  • Starter和自动配置怎样产生Bean?
  • 为什么BOM仍不能保证Boot/JDK一定兼容?
  • .call().stream()在延迟和错误处理上有什么区别?
  • Advisor顺序为什么影响权限、RAG和Token统计?
  • Memory为什么仍然消耗上下文Token?
  • RAG和Tool Calling为什么都不能让模型决定权限?
  • 401、429、空内容和Bean不存在分别从哪层取证?
  • 为什么模型切换必须做回归评估?

关联知识点