【个人学习||spring】spring ai

Spring AI 学习地图

截至 2026-03-30,Spring AI 推荐先按稳定线学习:Spring AI 1.1.x + Spring Boot 3.5.x
2.x 目前属于预览线,适合后续进阶时了解,不建议作为入门主线。

1. 这门学科是干什么的

Spring AI 是一个 面向 AI 应用开发的 Spring 风格框架

它的目标不是"训练模型",而是让你像写 Spring Boot 应用一样,把:

  • 大语言模型(LLM)
  • Embedding
  • Vector Store
  • Tool Calling
  • RAG
  • MCP
  • Observability

这些 AI 能力组织成一个可维护、可扩展、可监控的 Java 工程。

一句话理解:

Spring AI = 用 Spring 的方式开发 AI 应用。


2. 它解决什么问题

Spring AI 主要解决以下工程问题:

2.1 不同模型厂商接入方式不统一

不同模型提供商的 SDK、参数、调用方式不同。

Spring AI 提供统一抽象,减少业务代码和具体厂商 SDK 的强耦合。

2.2 AI 应用不只是"调一次接口"

真实 AI 系统通常不仅有聊天,还会涉及:

  • Prompt 模板
  • 会话上下文
  • 工具调用
  • 结构化输出
  • 知识库检索(RAG)
  • 监控与排错

Spring AI 把这些能力整合进 Spring 生态。

2.3 企业项目需要"工程化"

企业不是只关心"能回答",还关心:

  • 如何配置
  • 如何切换模型
  • 如何记录日志
  • 如何监控调用链
  • 如何控制成本
  • 如何定位报错

Spring AI 的价值就在这里。


3. 它和哪些相关技术有关系

3.1 上游模型与平台

  • OpenAI
  • Anthropic
  • Ollama
  • AWS Bedrock
  • Google Vertex AI
  • Azure OpenAI / Foundry

3.2 AI 应用核心概念

  • Prompt Engineering
  • Tool Calling
  • Structured Output
  • RAG
  • Embedding
  • Vector Search
  • MCP(Model Context Protocol)

3.3 Spring 生态

  • Spring Boot
  • Spring Web MVC / WebFlux
  • Spring Bean / IOC
  • Auto Configuration
  • Actuator
  • Micrometer

3.4 常见外部组件

  • PostgreSQL + pgvector
  • Redis
  • MongoDB
  • OpenSearch / Elasticsearch
  • Milvus / Qdrant / Pinecone

4. 学它之前需要哪些前置知识

必须掌握

  • Java 基础
  • Maven 或 Gradle
  • Spring Boot 基础
  • IOC / DI 基本理解
  • REST API 基础
  • YAML / properties 配置

最好具备

  • HTTP / JSON
  • Docker 基础
  • SQL 基础
  • 面向接口编程思想

先知道即可

  • 响应式编程(Reactive)
  • 各厂商模型差异细节
  • 向量数据库底层实现
  • MCP 协议规范细节

5. 真正重要的 20% 核心内容

这些内容决定你能不能真正上手 Spring AI。

必须吃透

  1. ChatModel
  2. ChatClient
  3. Prompt
  4. ChatOptions
  5. ChatResponse
  6. Spring Boot starter 与自动配置
  7. EmbeddingModel
  8. VectorStore
  9. RAG 的基本链路
  10. Tool Calling
  11. Advisor 机制
  12. 基础可观测性与排错方法

一句话理解主干

先掌握:

聊天调用主线 -> 配置主线 -> RAG 主线 -> 工程排错主线


6. 哪些内容初学者容易陷入,但不值得一开始深挖

不建议一开始深挖

  • 多智能体(Multi-Agent)
  • 复杂工作流编排
  • 所有模型厂商对比
  • 所有向量库对比
  • MCP 全部协议细节
  • 深入源码所有模块
  • 复杂 Prompt 技巧流派

原因

这些内容要么太大,要么变化快,要么依赖你先掌握核心抽象。

初学阶段深挖它们,很容易"懂很多名词,但不会落地"。


学习顺序

推荐按下面顺序学习:

  1. 入门认知

    • Spring AI 是什么
    • 它在 AI 技术栈中的位置
    • 跑通第一个最小示例
  2. 核心概念

    • ChatModel
    • ChatClient
    • Prompt
    • ChatOptions
    • ChatResponse
  3. 核心机制

    • 自动配置
    • Provider 抽象
    • 请求构建
    • 响应封装
    • Streaming 基本机制
  4. 底层原理

    • 消息模型
    • Prompt 渲染
    • Advisor 链
    • 工程设计哲学
  5. 工程实践

    • OpenAI / Ollama 接入
    • 结构化输出
    • Tool Calling
    • RAG
    • 会话记忆
    • MCP 入门
  6. 常见问题与排错

    • API Key 问题
    • 超时 / 限流
    • Token / 成本
    • 模型参数错误
    • 向量维度不匹配
    • 检索效果差
  7. 面试与评估

    • 高频面试题
    • 系统设计题
    • 实战表达题
    • 项目回答套路
  8. 学习总结与知识闭环

    • 做一个完整小项目
    • 用项目巩固核心抽象
    • 形成自己的排错方法论

第一阶段:入门认知

1. 学什么

这一阶段只学最关键的三件事:

  1. Spring AI 到底是什么
  2. Spring AI 在整个 AI 技术栈中处于什么位置
  3. 如何跑通一个最小可运行示例

你要先建立一个正确的认知:

Spring AI 不是模型,不是向量库,不是 AI 产品,而是一个开发框架。


2. 为什么重要

很多人一开始学 Spring AI,会把几个东西混在一起:

  • Spring AI
  • OpenAI / Ollama
  • RAG
  • Agent
  • 向量数据库

一旦混淆,就会出现两个问题:

问题 1:概念学乱

你会记住很多名词,但不知道它们彼此是什么关系。

问题 2:工程落地学偏

你会急着做复杂能力,比如 Agent、RAG、多轮记忆,但连最基础的聊天调用链都没搞清楚。

所以第一阶段最重要的任务,不是"会用很多功能",而是:

先把整个系统的骨架搭起来。


3. 核心概念

先用类比理解,再给技术定义。

3.1 Spring AI 是什么

类比

如果说:

  • Spring JDBC 是"数据库访问的工程化抽象"
  • Spring Data 是"数据访问的统一抽象"

那么:

Spring AI 就是"AI 能力接入与编排的 Spring 风格抽象"。

技术定义

Spring AI 是一个面向 AI 应用开发的 Spring 生态项目,提供统一 API 和 Spring Boot 自动配置,帮助开发者以统一方式接入聊天模型、嵌入模型、向量存储、工具调用、RAG 和 MCP 等能力。


3.2 它与模型的关系

对象 它是什么 例子
模型提供商 提供模型能力的平台 OpenAI、Anthropic、Ollama
模型 真正执行推理的能力 GPT、Claude、Llama、Mistral
Spring AI 调用与组织这些能力的框架 Spring AI

所以要记住:

模型负责"生成能力",Spring AI 负责"工程组织"。


3.3 核心组件初识

组件 作用 当前阶段理解要求
ChatModel 对接具体聊天模型的统一接口 知道它是底层模型抽象
ChatClient 面向业务层更友好的调用入口 知道业务代码通常直接用它
Prompt 一次完整请求的输入描述 知道它包含消息和参数
ChatOptions 模型参数配置 知道它控制模型行为
ChatResponse 模型返回结果封装 知道它比字符串更完整

4. 原理解释

4.1 先讲直觉

你可以把 Spring AI 的一次调用理解成:

"业务代码写一个统一请求,Spring AI 负责把它翻译成具体模型厂商能听懂的话,再把结果统一包装回来。"

4.2 调用流程

text 复制代码
Controller / Service
        ↓
    ChatClient
        ↓
    ChatModel
        ↓
具体 Provider 实现(OpenAI / Ollama / Anthropic)
        ↓
     模型返回结果
        ↓
 Spring AI 统一封装响应
        ↓
 返回给业务代码

4.3 为什么这样设计

这是典型的"抽象隔离变化"的设计思想。

因为变化最大的地方是:

  • 模型厂商不同
  • 参数不同
  • 返回格式不同
  • 协议差异大

如果业务代码直接依赖厂商 SDK,那么:

  • 切换模型麻烦
  • 测试麻烦
  • 维护麻烦
  • 统一治理困难

Spring AI 通过统一抽象,把变化挡在底层。

4.4 必须吃透:三层职责

层级 职责 你怎么理解
业务层 表达业务意图 "我要问一个问题"
ChatClient 方便你构造请求 "帮你组织请求"
ChatModel 真正执行模型调用 "帮你翻译成厂商调用"

4.5 学习本质

Spring AI 的学习本质,不是背 API,而是理解这两个核心思想:

  1. 统一抽象
  2. 工程化集成

5. 示例

下面给你一个最小可运行示例。

入门推荐先用 Ollama,因为本地可跑、门槛低、不需要先申请云平台 Key。

5.1 Maven 依赖

xml 复制代码
<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>

    <dependency>
        <groupId>org.springframework.ai</groupId>
        <artifactId>spring-ai-starter-model-ollama</artifactId>
    </dependency>
</dependencies>

5.2 配置文件

yaml 复制代码
spring:
  ai:
    ollama:
      base-url: http://localhost:11434
      chat:
        options:
          model: mistral

5.3 控制器代码

java 复制代码
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class AiController {

    private final ChatClient chatClient;

    public AiController(ChatClient.Builder builder) {
        this.chatClient = builder.build();
    }

    @GetMapping("/ai/ask")
    public String ask(@RequestParam(defaultValue = "用一句话解释 Spring AI") String q) {
        return chatClient.prompt()
                .user(q)
                .call()
                .content();
    }
}

5.4 运行步骤

  1. 安装 Ollama
  2. 执行:
bash 复制代码
ollama pull mistral
  1. 启动 Ollama 服务
  2. 启动 Spring Boot 应用
  3. 浏览器访问:
text 复制代码
http://localhost:8080/ai/ask?q=什么是Spring AI

6. 工程实践

6.1 企业中通常怎么用它

企业里很少一上来就做复杂 Agent。

更常见的落地路径是:

  1. 先做一个稳定的聊天接口
  2. 外置模型配置
  3. 加日志与调用监控
  4. 再做结构化输出
  5. 再接工具调用
  6. 最后做 RAG / MCP / 更复杂能力

6.2 当前阶段你要做的工程动作

你现在只需要完成这几个动作:

  1. 创建一个 Spring Boot 项目
  2. 引入 Spring AI starter
  3. 配置一个模型提供商
  4. 注入 ChatClient.Builder
  5. 通过 HTTP 接口发起一次调用
  6. 确认能正常返回结果

6.3 正确学习顺序

当前阶段不要想着"一步学完 Spring AI"。

正确顺序是:

  1. 跑通调用
  2. 理解抽象
  3. 理解配置
  4. 理解响应
  5. 再进入进阶能力

7. 常见误区

误区 1:Spring AI 就是大模型

不是。

Spring AI 是框架,大模型是能力提供者。

误区 2:会调接口就等于会 Spring AI

不是。

Spring AI 的重点在于统一抽象、Spring 集成和工程化能力。

误区 3:一开始就该学 RAG / Agent

不对。

这些建立在基础调用链和核心抽象之上。

误区 4:切换 Provider 一定零成本

不完全对。

虽然抽象统一了,但不同模型的:

  • 参数支持
  • 输出风格
  • 速度
  • 成本
  • 工具调用能力

都可能不同。

误区 5:只关注"怎么用",不关注"为什么这么设计"

这会导致你后面一旦出错就不会排查。

因为你只记住 API,没有理解它的职责边界。


8. 面试题

基础题

  1. Spring AI 是什么?
  2. Spring AI 解决了什么问题?
  3. Spring AI 和 OpenAI SDK 的区别是什么?
  4. Spring AI 在 AI 应用技术栈中处于什么位置?

理解题

  1. 为什么 Spring AI 要提供统一抽象?
  2. ChatClientChatModel 有什么区别?
  3. 为什么企业使用 Spring AI 而不是在业务代码里直接写厂商 SDK?

表达题

  1. 如果你向一个不会 Spring AI 的同事解释它,你会怎么说?
  2. 如果模型从 Ollama 切到 OpenAI,哪些代码理论上可以不改?

9. 自测题

请你自己回答下面这些问题:

  1. Spring AI 是模型、平台、还是框架?
  2. Spring AI 和 OpenAI / Ollama 分别是什么关系?
  3. ChatClient 的职责是什么?
  4. ChatModel 的职责是什么?
  5. 为什么说 Spring AI 的核心价值之一是"统一抽象"?
  6. 为什么入门时应该先学最小聊天接口,而不是先学复杂 Agent?
  7. 你能否手写一个最小的 /ai/ask 接口?
  8. 如果接口调用失败,你第一步会检查什么?

10. 学完标志

学完这一节后,你应该能做到:

  • 能清楚说出 Spring AI 是什么,不是什么
  • 能说出 Spring AI 在 AI 技术栈中的位置
  • 能解释 ChatClientChatModel 的基本职责
  • 能独立跑通一个最小聊天接口
  • 能向别人讲清楚 Spring AI 为什么存在
  • 能分清"模型能力"和"框架能力"的边界

第一阶段练习题

一、口头表达练习

请你用 3 句话 向面试官解释:

什么是 Spring AI?

要求:

  • 不要只背定义
  • 要体现它解决的工程问题
  • 要体现它和模型厂商的关系

二、代码练习

把上面的接口改造成一个翻译接口:

text 复制代码
GET /ai/translate?q=hello&lang=zh

要求:

  • 使用 ChatClient
  • 返回翻译结果
  • 自己设计 prompt 内容

三、思考题

如果把当前示例从 Ollama 切换到 OpenAI:

  1. 哪些内容应该改在配置层?
  2. 哪些业务代码理论上可以不改?
  3. 为什么这恰恰体现了 Spring AI 的设计价值?

本阶段学习方法建议

必须掌握

  • Spring AI 的定位
  • 核心调用链
  • 最小可运行示例

知道即可

  • RAG 细节
  • MCP 细节
  • 多模型高级能力
  • 复杂 Advisor 链

初学者最容易学偏的地方

  • 过早追求复杂能力
  • 只会复制代码,不理解分层职责
  • 只关注模型,不关注工程化

参考资料


第二阶段:核心概念

1. 学什么

这一阶段要把 Spring AI 最核心的 5 个概念真正串起来:

  1. ChatModel
  2. ChatClient
  3. Prompt
  4. ChatOptions
  5. ChatResponse

这一节的目标不是只记住"它们分别是什么",而是要看懂:

  • 它们之间的调用关系
  • 为什么要分层
  • 为什么后续的 RAG、Tool Calling、Memory 都建立在这套抽象之上

必须吃透:

  • ChatClientChatModel 的职责边界
  • PromptChatOptions 的组成关系
  • ChatResponse 为什么比直接拿字符串更有工程价值

先知道,后深入:

  • ChatClientResponse
  • responseEntity()
  • Native Structured Output
  • Streaming 下的结构化输出处理

2. 为什么重要

如果第一阶段是在脑子里搭出"Spring AI 是干什么的"这张地图,那第二阶段就是把地图上的主干道路修通。

后面你学:

  • Tool Calling
  • RAG
  • Memory
  • Advisor
  • MCP

本质上都绕不开下面这条主线:

text 复制代码
业务代码 -> ChatClient -> Prompt -> ChatModel -> Provider -> ChatResponse

你如果没把这一条链打通,后面就会出现典型问题:

  • 会抄代码,但不会解释为什么这么写
  • 会调用接口,但不会做分层设计
  • 一旦模型切换、返回异常、token 超支,就不会定位问题

所以这阶段的重要性可以一句话概括:

它决定你后面是在"堆 AI 功能",还是在"做 AI 工程"。


3. 核心概念

先给你一个全局对照表。

概念 直觉类比 技术职责 你通常在业务里怎么用
ChatModel 数据库驱动 / HTTP 底层客户端 对接具体模型提供商,实现真正的调用 通常不直接拼细节,而是作为底层能力被 ChatClient 使用
ChatClient JdbcClient / RestClient 提供 fluent API,负责更友好的请求组织 业务代码最常直接面向它编程
Prompt 一次完整请求报文 包含消息列表和可选模型参数 表达"这次到底问什么、怎么问"
ChatOptions 请求参数 控制模型、温度、token 等行为 做默认配置和请求级覆盖
ChatResponse 完整响应对象 不仅有文本,还有 generation、usage、metadata 做日志、成本、排错、结构化处理

3.1 ChatModel

定义:
ChatModel 是统一的聊天模型接口,屏蔽不同模型提供商之间的差异。

官方 API 核心形态可以概括为:

java 复制代码
public interface ChatModel {
    String call(String message);
    ChatResponse call(Prompt prompt);
}

你要抓住一句话:

ChatModel 负责"真正发请求给模型"。

它更靠近底层,强调的是统一模型调用能力,而不是更高层的业务体验。

3.2 ChatClient

定义:
ChatClient 是建立在 ChatModel 之上的更高层 fluent API,用来更方便地构造 Prompt、绑定模板参数、挂接 Advisor、决定返回内容格式。

你要抓住一句话:

ChatClient 负责"让你更舒服地组织一次 AI 调用"。

它不是替代 ChatModel,而是建立在 ChatModel 之上的使用层抽象。

3.3 Prompt

定义:
Prompt 是一次模型请求的完整输入容器,本质上是:

  • 多条 Message
  • 可选的 ChatOptions

你不要把 Prompt 简单理解成"一段字符串"。

在 Spring AI 里,一个 Prompt 更准确地说是:

"带角色的消息集合 + 本次请求参数"。

3.4 ChatOptions

定义:
ChatOptions 是传给模型的参数集合,用来控制本次调用行为。

常见便携参数包括:

  • model
  • temperature
  • maxTokens
  • topP
  • topK
  • stopSequences

注意两点:

  1. Spring AI 提供的是可移植的通用选项接口
  2. 各 Provider 还会有自己特有的 options

所以它的设计不是"彻底抹平差异",而是:

先统一公共部分,再允许各家扩展。

3.5 ChatResponse

定义:
ChatResponse 是模型返回结果的统一封装。

它不只是一个字符串,还包含:

  • 返回的文本结果
  • 可能的多条 Generation
  • token usage 等 metadata
  • 供应商返回的一些附加信息

所以:

content() 适合快速拿答案,ChatResponse 适合工程化处理。

3.6 容易混淆的概念对比

对比项 ChatModel ChatClient
所在层级 更底层 更上层
关注点 统一模型调用 组织调用体验
常见使用者 框架层、封装层 业务层
是否支持更丰富 fluent 组织 相对少
是否便于挂 Advisor / 模板 / 实体映射 不如 ChatClient 方便 更方便
对比项 Prompt ChatOptions
本质 请求整体 请求参数的一部分
包含什么 Message 列表 + 可选 Options 模型参数
解决什么问题 "发什么内容" "怎么发、用什么参数发"
对比项 content() chatResponse()
返回值 String ChatResponse
优点 简单直接 信息完整
适用场景 Demo、简单接口 生产日志、成本分析、排错

4. 原理解释

4.1 先讲直觉

可以把这 5 个核心对象理解成一次"标准化 AI 请求流水线":

  1. 你先决定要问什么,这形成 Prompt
  2. 你决定这次怎么问,这些参数属于 ChatOptions
  3. 你用 ChatClient 把这次请求组织好
  4. ChatClient 把请求交给 ChatModel
  5. ChatModel 转成各厂商自己的原生请求格式
  6. 模型返回后,Spring AI 再统一包装成 ChatResponse

4.2 运行流程拆解

text 复制代码
1. Spring Boot 根据 starter 和配置创建 ChatModel
2. Spring Boot 自动提供 ChatClient.Builder
3. 业务代码用 ChatClient 组织 system/user 消息
4. 如果用了模板变量,先渲染成最终 Prompt
5. 合并默认 ChatOptions 与本次运行时 ChatOptions
6. ChatModel 把 Prompt 转成厂商原生请求
7. Provider 返回原生响应
8. Spring AI 转成统一 ChatResponse
9. 业务代码选择 content() / chatResponse() / entity()

4.3 为什么 ChatClient 不直接等于 ChatModel

这是一个很关键的设计点。

如果只有 ChatModel,那么业务代码就要承担很多额外工作:

  • 自己组织 Prompt
  • 自己处理模板变量
  • 自己处理返回值映射
  • 自己扩展日志、Memory、RAG 等增强能力

Spring AI 没把这些职责硬塞进 ChatModel,而是新增了 ChatClient 这一层。

这样做的好处是:

  • ChatModel 保持统一、稳定、底层
  • ChatClient 专注业务友好和增强能力

这就是典型的:

"底层接口保持小而稳,上层接口强调易用性和扩展性。"

4.4 为什么 Prompt 要设计成 Message 列表

因为现代 LLM 并不只是接收一段字符串,它更依赖"角色化消息结构"。

常见角色包括:

  • system
  • user
  • assistant
  • tool

这样设计的好处是:

  • 可以明确区分系统约束和用户输入
  • 可以支持多轮对话
  • 可以支持工具调用返回内容
  • 可以和不同 Provider 的消息协议对齐

所以,Prompt 的本质不是"文本块",而是:

"结构化对话上下文"。

4.5 ChatOptions 为什么要分"启动默认值"和"运行时覆盖"

这是 Spring AI 非常工程化的一点。

官方文档里的流程是:

  1. 启动时给 ChatModel 一组默认 options
  2. 请求时 Prompt 可以再带一组运行时 options
  3. 二者合并,运行时覆盖默认值

这样设计的意义是:

  • 全局统一默认模型和默认温度
  • 个别请求还能按需覆盖
  • 避免把所有差异都硬编码在配置文件里

这套机制非常适合企业应用,因为真实系统里经常会出现:

  • 大多数请求用便宜模型
  • 少数复杂请求切换更强模型
  • 默认温度较低,但创意生成时临时调高

4.6 ChatResponse 为什么不能只当字符串看

很多初学者只盯着:

java 复制代码
.call().content()

这当然能跑,但它会让你丢掉很多工程上非常重要的信息:

  • 这次用了多少 token
  • 响应元数据是什么
  • 有几条 generation
  • 是否需要做结构化解析

真实系统里,ChatResponse 的价值非常大,因为它直接关系到:

  • 成本统计
  • 性能分析
  • 故障定位
  • 质量评估

4.7 ChatClient 模板机制

ChatClient 支持把 user/system 内容写成模板,然后在运行时填参数。

这背后的设计思想是:

  • 让 Prompt 更可复用
  • 让输入和模板结构分离
  • 让复杂 Prompt 不再全靠字符串拼接

官方文档说明,ChatClient 内部默认通过 PromptTemplateStTemplateRenderer 来渲染模板。

所以推荐你形成习惯:

  • 固定指令写模板
  • 动态值走参数
  • 不要手工拼接长字符串

5. 示例

下面这个例子一次性把第二阶段最关键的几个概念串起来:

  • ChatClient
  • Prompt
  • 模板参数
  • ChatResponse
  • usage metadata

5.1 示例代码

java 复制代码
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.chat.model.ChatResponse;
import org.springframework.stereotype.Service;

@Service
public class SpringAiTutorService {

    private final ChatClient chatClient;

    public SpringAiTutorService(ChatClient.Builder builder) {
        this.chatClient = builder.build();
    }

    public String explainConcept(String concept) {
        ChatResponse response = chatClient.prompt()
                .system("你是一名 Java 和 Spring AI 导师,回答要准确、简洁、适合初学者。")
                .user(user -> user
                        .text("请用 3 点解释 {concept},并补充一个常见误区。")
                        .param("concept", concept))
                .call()
                .chatResponse();

        String content = response.getResult().getOutput().getText();
        Long totalTokens = response.getMetadata().getUsage().getTotalTokens();

        return "回答内容:\n" + content + "\n\n总 Token:" + totalTokens;
    }
}

5.2 这个例子里每个对象在干什么

代码片段 它对应哪个概念 作用
builder.build() ChatClient 创建业务调用入口
.system(...) + .user(...) Prompt 里的消息 构造本次请求内容
.param("concept", concept) 模板变量 运行时填充 Prompt
.call().chatResponse() ChatResponse 获取完整响应对象
response.getMetadata().getUsage() metadata 查看 token 消耗

5.3 如果要体现 ChatOptions 的运行时覆盖

不同 Provider 有自己的 Options 类型。

例如你用 OpenAI 时,常见写法会是:

java 复制代码
.options(OpenAiChatOptions.builder()
        .temperature(0.2)
        .build())

这表示:

  • 启动配置里可能已经设了默认温度
  • 但这一次请求要临时覆盖成 0.2

这就是"默认配置 + 请求级覆盖"的体现。


6. 工程实践

6.1 企业里通常怎么落地这 5 个概念

真实项目里,通常不是在 Controller 里直接把所有 Prompt 都拼出来,而是:

  1. Controller 只接收请求参数
  2. Service 负责组织 ChatClient 调用
  3. Prompt 模板集中管理
  4. 默认模型参数放配置文件
  5. 特殊请求再做运行时覆盖
  6. 关键接口记录 ChatResponse metadata

推荐你从现在开始就按这个思路写代码。

6.2 一个真实工程场景

场景:你要做一个"接口文档智能解释器"。

用户输入一段接口定义,系统要返回:

  • 这个接口是干什么的
  • 参数含义
  • 返回值解释
  • 一个调用示例

这时候可以这样分层:

  • ChatClient:统一调用入口
  • Prompt:system 里约束回答格式,user 里放接口定义
  • ChatOptions:解释型任务把温度调低
  • ChatResponse:记录 token 和返回 metadata

这就是为什么第二阶段这些概念不是"名词题",而是工程设计题。

6.3 当前阶段的操作建议

你现在练习时,建议固定按这套动作来:

  1. 每次都先想清楚 system 和 user 分别放什么
  2. 动态内容尽量用模板参数,不要字符串乱拼
  3. 默认先用 .chatResponse() 看完整返回
  4. 确认没问题后,简单接口再简化成 .content()
  5. 每次都问自己:这里应该写在配置层,还是写在请求层?

7. 常见误区

误区 1:ChatClientChatModel 只是两个名字不同的同一个东西

不是。
ChatModel 是统一模型接口,ChatClient 是更高层的业务友好 API。

误区 2:Prompt 就是一段字符串

不对。

在 Spring AI 里,Prompt 更准确地说是"消息集合 + 可选参数"。

误区 3:所有参数都应该写在配置文件里

不对。

配置文件适合默认值;请求级差异更适合运行时覆盖。

误区 4:只用 .content() 就够了

Demo 可以,工程里不够。

你会丢掉 usage、metadata、generation 等关键排错信息。

误区 5:system 和 user 放一起拼成一大段字符串也一样

不建议。

角色分离是现代 Prompt 结构的重要基础,混在一起会降低可维护性。

误区 6:模板参数只是语法糖

不只是。

它本质上是在把"Prompt 结构"和"运行时数据"分离,这是可维护性的关键。


8. 面试题

基础题

  1. ChatModelChatClient 的区别是什么?
  2. Prompt 在 Spring AI 中由哪些部分组成?
  3. 为什么 ChatResponse 比直接返回字符串更有价值?
  4. ChatOptions 解决的是什么问题?

理解题

  1. Spring AI 为什么要把 ChatClient 设计在 ChatModel 之上?
  2. 为什么 Prompt 要用多消息结构,而不是简单字符串?
  3. 默认配置和运行时配置合并的设计,有什么工程价值?
  4. 如果需要统计 token 消耗,你应该拿哪个对象上的什么信息?

进阶表达题

  1. 如果让你设计一个"稳定的 AI Service 层",你会如何组织 ChatClient、Prompt 和配置?
  2. 如果业务要求"绝大多数请求用便宜模型,少量复杂请求切到强模型",Spring AI 的哪套机制最适合支持它?

9. 自测题

请你自己尝试回答:

  1. 用你自己的话解释 ChatModelChatClientPromptChatOptionsChatResponse 各自职责。
  2. 为什么说 Prompt 不是简单字符串?
  3. .content().chatResponse() 你会分别在什么场景下使用?
  4. 为什么 ChatOptions 需要支持"默认值 + 请求覆盖"?
  5. 如果 system prompt、user prompt、temperature 都写死在 Controller 里,会带来什么问题?
  6. 你能否解释一次 Spring AI 请求从 ChatClientChatResponse 的完整链路?
  7. 如果模型输出质量忽高忽低,你会优先检查 Prompt、Options 还是 Provider?为什么?

10. 学完标志

学完这一阶段,你应该能做到:

  • 能准确解释 ChatModelChatClientPromptChatOptionsChatResponse
  • 能画出 Spring AI 一次聊天调用的完整链路
  • 能说清楚为什么要把 system、user、options 分开组织
  • 能在代码里使用模板参数构造 Prompt
  • 能从 ChatResponse 中读取文本和 usage
  • 能解释"默认配置 + 请求覆盖"的设计价值
  • 能回答基础到中级面试里的核心概念题

第二阶段练习题

一、代码练习

把你第一阶段的 /ai/ask 接口升级成下面这个版本:

text 复制代码
GET /ai/explain?concept=ChatClient

要求:

  • 增加一个 system prompt,限定回答风格
  • user prompt 使用模板变量 {concept}
  • 不要直接返回 .content(),改成先拿 ChatResponse
  • 把"回答内容 + 总 token 数"一起返回

二、分析练习

请你口头回答下面两个问题:

  1. 为什么 ChatClient 更适合业务层,而 ChatModel 更像底层抽象?
  2. 为什么工程里不能把 ChatResponse 永远简化成字符串?

三、设计练习

假设你要做两个 AI 接口:

  1. "解释代码"接口,要求稳定、准确
  2. "生成宣传文案"接口,要求更有创造性

请你思考:

  1. 两个接口的 Prompt 应该怎么区分?
  2. 两个接口的 ChatOptions 应该怎么区分?
  3. 哪些东西适合配成默认值,哪些适合请求时覆盖?

回复 继续,我下一阶段按同样的 Markdown 结构,带你进入:

第三阶段:核心机制

1. 学什么

这一阶段要搞清楚 Spring AI 是如何真正"跑起来"的。

重点包括:

  1. 为什么加一个 starter 再配几行 properties,模型就能用
  2. starter + properties + autoconfiguration 到底是怎么串起来的
  3. ChatModelStreamingChatModelChatClient.Builder 是怎么被创建出来的
  4. 多 Provider 场景下应该怎么组织
  5. streaming 为什么不是"普通调用换个返回值"那么简单

这一节你要建立的是"框架执行机制视角",而不只是"业务怎么调"。

必须吃透:

  • starter 的作用不只是"导依赖",更是"带入自动配置"
  • properties 不只是配置文件,而是默认模型行为的来源
  • 自动配置的核心是"条件装配 + 属性绑定 + 默认 Bean 暴露"
  • streaming 走的是另一条模型调用分支

先知道,后深入:

  • 各 Provider 自动配置源码细节
  • @ConditionalOnClass@ConditionalOnMissingBean 的全部组合
  • 具体 SDK HTTP 客户端实现差异

2. 为什么重要

这一阶段非常重要,因为真实开发里你会频繁遇到下面这些问题:

  • 为什么我明明配了 api-key,却没有 ChatModel Bean?
  • 为什么换了 starter,配置前缀也要跟着改?
  • 为什么 .call() 能用,.stream() 却报错或行为不符合预期?
  • 为什么项目里同时接了两个模型后,注入开始冲突?
  • 为什么有的参数写在配置里有效,有的要请求时覆盖?

这些问题本质上都不是"Prompt 写得不对",而是:

你没有看懂 Spring AI 是如何借助 Spring Boot 自动装配完成模型接入的。

所以这一节的价值在于:

把"会调用"升级成"会搭、会配、会排、会解释"。


3. 核心概念

先给你一个总览表。

组件 它解决什么问题 发生在什么时候
starter 把所需依赖和自动配置带进项目 启动前 / 构建期
properties 提供模型默认配置 启动时绑定
Auto Configuration 按条件创建 Bean 应用启动时
ChatModel 提供统一模型调用能力 运行时调用
StreamingChatModel 提供流式输出能力 运行时调用
ChatClient.Builder 提供更高层 fluent API 构造能力 启动后可注入

3.1 starter

类比理解:

starter 就像"某类能力的总开关包"。

它通常做两件事:

  1. 带入这个 Provider 所需的依赖
  2. 带入 Spring Boot 自动配置

比如常见场景:

Provider 常见 starter 常见配置前缀
Ollama spring-ai-starter-model-ollama spring.ai.ollama.*
OpenAI SDK spring-ai-starter-model-openai-sdk spring.ai.openai-sdk.*

注意:

starter 和 properties 前缀是配套的。

你换了 Provider,往往不仅是换依赖,也要换配置前缀。

3.2 properties

properties 负责承载默认模型配置,比如:

  • base URL
  • API Key
  • model
  • temperature
  • max tokens
  • timeout 或重试相关配置

你可以把它理解为:

"启动时给模型准备的默认作战参数"。

3.3 Auto Configuration

这是 Spring AI 真正 Spring 化的关键。

自动配置本质上做三件事:

  1. 判断当前类路径和配置是否满足某个 Provider 的装配条件
  2. 把配置文件绑定成配置对象
  3. 创建默认可注入的 Bean

最重要的设计思想是:

  • 约定优于配置
  • 条件装配
  • 默认值可覆盖

3.4 ChatModelStreamingChatModel

它们是两类不同的模型能力抽象:

抽象 用途 常见调用方式
ChatModel 一次性返回完整结果 .call()
StreamingChatModel 逐步返回结果片段 .stream()

要注意:

并不是所有 Provider、所有模型、所有场景对 streaming 的支持都完全一致。

所以 streaming 不是只把返回值从 String 变成 Flux<String> 这么简单,它依赖底层 Provider 能力和 Spring AI 的流式封装。

3.5 ChatClient.Builder

为什么注入的是 ChatClient.Builder,而不是直接只给你一个 ChatClient

因为 Builder 更适合:

  • 设置默认 system prompt
  • 设置默认 advisors
  • 设置默认 options
  • 构造不同用途的 ChatClient

这体现的是:

把"底层模型能力"与"上层业务调用风格"解耦。

3.6 启动阶段与运行阶段对比

阶段 主要动作 关键对象
启动阶段 加载依赖、匹配自动配置、绑定属性、创建 Bean starter、properties、Auto Configuration
运行阶段 构造 Prompt、合并 options、调用模型、返回结果 ChatClient、Prompt、ChatModel、ChatResponse

4. 原理解释

4.1 先讲直觉

你可以把 Spring AI 的启动机制理解为:

"Spring Boot 先根据你项目里有什么依赖、配了什么参数,自动把模型客户端和相关 Bean 组好;业务代码只是拿来用。"

4.2 启动到可调用的完整链路

text 复制代码
1. 你在 pom.xml / build.gradle 中引入某个 Spring AI starter
2. Spring Boot 启动时发现该 starter 带来的自动配置入口
3. 自动配置根据类路径和配置项判断是否生效
4. Spring 把 application.yml 中的属性绑定到对应配置对象
5. 自动配置创建 Provider 所需底层客户端和 ChatModel / StreamingChatModel
6. Spring 再暴露 ChatClient.Builder 等上层 Bean
7. 业务代码注入 ChatClient.Builder 并 build()
8. 运行时用 Prompt + Options 发起调用
9. 如果是普通调用,走 ChatModel
10. 如果是流式调用,走 StreamingChatModel

4.3 为什么 starter 能触发自动配置

因为 starter 不只是一个"依赖集合包",它通常还会把自动配置类带进 Spring Boot 的自动装配体系。

所以:

  • 没有对应 starter,通常就没有对应自动配置
  • 没有自动配置,很多 Bean 就不会自动创建

这也是为什么你常看到这样的现象:

  • 代码没变
  • 只换了依赖
  • Bean 注入结果就变了

4.4 为什么 properties 能控制模型行为

因为 Spring Boot 会把配置文件内容绑定到配置对象上,然后自动配置再拿这些配置对象去创建底层模型客户端。

比如你配:

yaml 复制代码
spring:
  ai:
    ollama:
      base-url: http://localhost:11434
      chat:
        options:
          model: qwen2.5:7b

这并不是"业务代码读取 YAML 再自己处理",而是:

  1. Spring 先做属性绑定
  2. 自动配置读取绑定后的对象
  3. 用这些值构造默认 ChatModel

所以配置能改变模型行为,是因为:

配置参与了 Bean 创建,而不只是运行时字符串读取。

4.5 为什么 ChatClient.Builder 比直接暴露单个 ChatClient 更合理

如果框架只给你一个全局 ChatClient,很多业务差异就不好处理:

  • 解释类接口和创意类接口默认 prompt 不同
  • 有的接口要加 advisors,有的不要
  • 有的接口走普通调用,有的走 stream

Builder 的好处是:

  • 默认能力可以共用
  • 局部能力可以按需 build 出不同客户端

所以这是一个典型的"默认统一 + 局部定制"的工程设计。

4.6 streaming 是怎么进调用链的

普通调用和流式调用的最大区别在于返回模型数据的时机不同。

普通调用:

text 复制代码
请求发出 -> 等模型完整生成 -> 返回完整响应

流式调用:

text 复制代码
请求发出 -> 模型边生成边返回片段 -> 应用逐段消费

在 Spring AI 里,你通常会这样写:

java 复制代码
chatClient.prompt()
    .user("解释一下 RAG")
    .stream()
    .content();

它背后意味着:

  1. 调用不再走一次性完整返回的那条路径
  2. 底层需要 Provider 支持流式响应
  3. Web 层通常要配合 SSE / WebFlux 等方式向前端输出

所以 streaming 的关键不只是 API,而是:

调用链、返回类型、Web 输出模型都发生了变化。

4.7 为什么 Spring AI 能做到"统一抽象 + Provider 扩展"

这是它设计里很值得学的一点。

它并没有强行要求所有模型都支持完全一样的能力,而是用了两层策略:

  1. 抽象公共能力

    比如 ChatModelPromptChatOptions

  2. 保留 Provider 扩展点

    比如各家特有的 options、不同的流式支持、不同的 SDK 实现

这和很多 Spring 项目的哲学一致:

先抽象稳定共性,再通过扩展点承载差异。


5. 示例

这一节给你两个最小示例:

  1. 看懂 starter + properties + 自动装配的基本闭环
  2. 看懂 streaming 怎么进入调用链

5.1 示例一:最小自动装配闭环

依赖
xml 复制代码
<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>

    <dependency>
        <groupId>org.springframework.ai</groupId>
        <artifactId>spring-ai-starter-model-ollama</artifactId>
    </dependency>
</dependencies>
配置
yaml 复制代码
spring:
  ai:
    ollama:
      base-url: http://localhost:11434
      chat:
        options:
          model: qwen2.5:7b
          temperature: 0.2
代码
java 复制代码
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.stereotype.Service;

@Service
public class AiExplainService {

    private final ChatClient chatClient;

    public AiExplainService(ChatClient.Builder builder) {
        this.chatClient = builder.build();
    }

    public String explain(String question) {
        return chatClient.prompt()
                .user(question)
                .call()
                .content();
    }
}

这个例子真正要你看懂的是:

  1. 你没有手写 ChatModel Bean
  2. 你没有手写 ChatClient.Builder Bean
  3. 但它们都能注入

这就是自动配置在生效。

5.2 示例二:流式输出

如果你要把回答边生成边返回给前端,可以这样写:

xml 复制代码
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
java 复制代码
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import reactor.core.publisher.Flux;

@RestController
public class AiStreamController {

    private final ChatClient chatClient;

    public AiStreamController(ChatClient.Builder builder) {
        this.chatClient = builder.build();
    }

    @GetMapping(value = "/ai/stream", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
    public Flux<String> stream(@RequestParam String q) {
        return chatClient.prompt()
                .user(q)
                .stream()
                .content();
    }
}

这个例子说明:

  • .call() 对应完整响应路径
  • .stream() 对应流式响应路径
  • Web 层要能承接流式返回

6. 工程实践

6.1 企业里通常怎么组织配置

推荐做法:

  1. 把 Provider 的地址、Key、模型名、默认温度都放配置文件
  2. ChatClient 的使用集中在 service 层
  3. Controller 不要直接决定模型细节
  4. 特殊请求再做运行时 options 覆盖
  5. 对关键接口记录模型名、耗时、token、失败原因

6.2 多模型接入时怎么组织

初学者最容易犯的错,是一上来就在一个项目里把多个 Provider 混着注入,最后 Bean 冲突、职责混乱。

更好的做法是:

方案一:单 Provider 起步

最适合学习和大多数中小项目。

特点:

  • 配置简单
  • Bean 单一
  • 排错容易
方案二:多 Provider,但明确分服务封装

例如:

  • CheapModelAiService 负责低成本问答
  • PremiumModelAiService 负责复杂任务

而不是在 Controller 里写:

java 复制代码
if (provider.equals("openai")) { ... } else if (provider.equals("ollama")) { ... }

因为那会把 Provider 差异直接泄漏到业务入口层。

6.3 streaming 的工程注意点

  1. 前端是否真的需要边生成边展示
  2. 后端是否准备好 SSE / WebFlux 输出模型
  3. 日志和错误处理是否能覆盖流式场景
  4. 是否需要对中断、超时、取消订阅做处理

很多项目不是不能用 streaming,而是没把它当成一条独立链路来设计。

6.4 当前阶段正确的练习顺序

  1. 先跑通单 Provider 的普通调用
  2. 看懂 starter 和 properties 的绑定关系
  3. 故意改错配置前缀,观察 Bean 是否还能注入
  4. 再尝试 .stream()
  5. 最后再考虑多模型和更复杂封装

7. 常见误区

误区 1:starter 只是一个"方便导包"的依赖

不对。

它通常还携带自动配置能力,是 Bean 能自动出现的重要原因。

误区 2:properties 只是给代码读字符串用的

不对。

在 Spring Boot 体系下,properties 会参与属性绑定和 Bean 创建。

误区 3:有 ChatClient.Builder 就说明我手动写过相关 Bean

不一定。

很多时候它来自 Spring AI 的自动配置。

误区 4:.stream() 就是 .call() 的另一个名字

不对。

它背后要求不同的模型调用路径和 Web 输出方式。

误区 5:多 Provider 时直接在 Controller 里分支就行

不建议。

这会让业务入口层直接承担模型路由和 Provider 差异,后期很难维护。

误区 6:换了 starter 但配置前缀不改也能继续工作

通常不行。

starter 和配置前缀通常是成套设计的。

误区 7:版本不匹配只是"小问题"

不是。

Spring Boot 与 Spring AI 版本线不匹配时,很容易出现自动配置失效、类冲突、Bean 缺失等问题。


8. 面试题

基础题

  1. Spring AI 的 starter 在工程里起什么作用?
  2. 自动配置为什么能让你不手写 ChatModel Bean?
  3. ChatClient.Builder 为什么适合作为注入入口?
  4. .call().stream() 的差别是什么?

理解题

  1. Spring AI 是如何把配置文件中的属性变成模型默认行为的?
  2. 为什么说 Spring AI 的核心机制离不开 Spring Boot 自动配置?
  3. 为什么 streaming 不只是返回类型不同,而是调用链不同?
  4. 如果项目里同时接两个 Provider,应该如何避免职责混乱和 Bean 冲突?

进阶题

  1. 为什么 Spring AI 能做到"统一抽象"和"Provider 扩展"同时成立?
  2. 如果一个接口要求稳定低温度输出,另一个要求高创造性输出,你会把差异放在配置层还是请求层?为什么?

9. 自测题

请你自己尝试回答:

  1. 只加 starter 和 properties,为什么模型相关 Bean 就能注入?
  2. 自动配置在这个过程中至少做了哪三件事?
  3. ChatClient.Builder 为什么不是多余的一层?
  4. 为什么 StreamingChatModel 可以看成是另一条能力链?
  5. 如果 .call() 正常、.stream() 不正常,你会从哪些层面排查?
  6. 多模型接入时,为什么不建议把 provider 路由逻辑写在 Controller?
  7. 如果配置文件里 model 改了,但接口输出风格没变,你会先检查什么?

10. 学完标志

学完这一阶段,你应该能做到:

  • 能解释 starter、properties、autoconfiguration 在 Spring AI 中的配合关系
  • 能说清模型相关 Bean 为什么会自动出现
  • 能解释 ChatClient.Builder 的存在价值
  • 能区分普通调用链和流式调用链
  • 能说明多 Provider 场景下的基本组织策略
  • 能回答"为什么 Spring AI 看起来只配配置就能跑"的原理题
  • 遇到 Bean 缺失、配置无效、streaming 异常时有基本排查方向

第三阶段练习题

一、配置练习

请你自己完成下面动作:

  1. 用 Ollama starter 跑通一个普通接口
  2. 把配置里的 temperature 改成不同值,观察输出风格变化
  3. 故意把配置前缀改错一次,观察是否还能正常注入和调用

你的目标是亲自体会:

"自动配置不是魔法,它依赖正确的 starter 和正确的 properties。"


二、流式练习

实现一个接口:

text 复制代码
GET /ai/stream?q=解释一下Spring AI的自动配置

要求:

  • 使用 .stream().content()
  • 输出类型使用 SSE
  • 自己描述它和 .call().content() 在体验上的区别

三、设计练习

假设你的项目里要同时接入:

  1. 本地 Ollama,负责低成本开发调试
  2. 云端 OpenAI,负责线上高质量回答

请你思考:

  1. 这两种模型如何在工程里分层组织?
  2. 哪些配置应该放环境配置里?
  3. 哪些逻辑不应该直接出现在 Controller 里?
  4. 你会如何向面试官解释这种组织方式?

回复 继续,我下一阶段按同样的 Markdown 结构,带你进入:

第四阶段:底层原理

1. 学什么

这一阶段我们不再停留在"怎么用",而是专门回答:

  • 为什么 Prompt 不是普通字符串,而是 role-based message
  • 为什么 Spring AI 要引入 PromptTemplateTemplateRenderer
  • 为什么 Advisor 链能承载 RAG、Memory、Tool Calling 这些增强能力
  • 为什么 ChatResponse / ChatClientResponse 里的 metadata 和 context 很重要
  • Spring AI 的设计哲学到底是什么

这一节的目标是让你建立一种更稳定的理解方式:

以后看到新功能时,你能先判断它属于消息层、模板层、增强链层,还是模型层。

必须吃透:

  • role-based message 的意义
  • 模板渲染的职责边界
  • Advisor 链的"请求前 + 响应后"双向处理模型
  • metadata / context 对排错和 RAG 的价值

先知道,后深入:

  • Recursive Advisors
  • Modular RAG Architecture 细节
  • 各 Provider 在 tool/message 协议层的特殊差异

2. 为什么重要

这一阶段重要,是因为很多初学者学到这里会进入一个误区:

"Spring AI 不就是把 Prompt 发给模型,再把结果拿回来吗?"

这句话只对了 30%。

真实的 AI 应用调用,通常还包括:

  • 消息结构化
  • 模板变量替换
  • Memory 注入
  • 检索结果注入
  • 工具调用过程管理
  • metadata 采集
  • 追踪调用上下文

Spring AI 之所以能承载这些能力,不是因为它"功能多",而是因为它在底层抽象上提前留好了扩展点。

所以这一节的关键价值是:

让你理解 Spring AI 不是"功能堆砌",而是一套可扩展的分层设计。


3. 核心概念

3.1 Message 与 Role

类比理解:

如果普通字符串 Prompt 像"一段没有标注角色的聊天记录",

那么 role-based message 像"每句话都注明是谁说的、扮演什么角色"。

在 Spring AI 中,Prompt 本质上由多条 Message 组成,不同 message 可能对应不同 role。

常见 role 包括:

  • system
  • user
  • assistant
  • tool

它解决的问题是:

  • 区分系统规则和用户输入
  • 表达多轮对话
  • 表达工具调用结果
  • 兼容现代模型 API 的结构化消息格式

3.2 PromptTemplate

PromptTemplate 的作用不是"让字符串替换更方便",而是:

把 Prompt 的结构和运行时数据分离。

你可以把它理解成:

  • 模板 = 固定指令骨架
  • 参数 = 每次变化的数据

这比手工拼接字符串更可维护,因为:

  • 可复用
  • 可测试
  • 可读性更高
  • 更适合长 Prompt 和团队协作

3.3 TemplateRenderer

Spring AI 使用 TemplateRenderer 来真正完成模板渲染。

官方文档说明默认实现是 StTemplateRenderer,基于 StringTemplate 引擎。

这说明 Spring AI 在模板层也做了抽象:

  • 上层只关心"模板 + 参数"
  • 底层可以替换具体渲染实现

所以设计思想是:

对上暴露统一模板接口,对下保留渲染实现可替换性。

3.4 Advisor 链

Advisor 是 Spring AI 里非常关键的扩展机制。

它不是简单的"工具类",而更像:

AI 调用链上的增强拦截器。

官方文档里说明,Advisor 可以:

  • 在请求发给模型前检查和修改请求
  • 决定是否继续往下调用
  • 在响应回来后再处理结果
  • 在链路里共享 context

因此它非常适合封装:

  • Chat Memory
  • RAG
  • Tool Calling
  • 安全过滤
  • 推理增强

3.5 ChatResponseChatClientResponse

这两个对象容易混淆:

对象 核心作用 什么时候用
ChatResponse 模型统一响应对象,含内容与 metadata 普通调用、日志、token、排错
ChatClientResponse ChatResponse 基础上再带执行上下文 需要查看 Advisor 链附加数据时

官方文档特别提到,ChatClientResponse 能拿到 ChatClient execution context,例如 RAG 过程中检索到的相关文档。

这意味着:

普通聊天只看答案,复杂 AI 流程要看"答案是怎么来的"。

3.6 Spring AI 的设计哲学

这一阶段你要开始形成一句总总结:

Spring AI 的核心哲学是:把 AI 能力拆成可组合的稳定抽象,再用 Spring 风格把它们工程化。

它的几个设计关键词是:

  • 统一抽象
  • 条件装配
  • 分层职责
  • 可扩展增强链
  • 保留 Provider 差异
  • 面向工程而不是面向 Demo

4. 原理解释

4.1 为什么消息要按 role 组织

先讲直觉:

如果你把 system、user、tool 返回结果都拼成一个大字符串,那么模型只看见"混在一起的一坨文本"。

这样会带来几个问题:

  • 系统约束不够明确
  • 工具输出和用户问题边界不清晰
  • 多轮对话难维护
  • 不同模型协议难适配

而 role-based message 的设计,相当于告诉模型:

  • 这条是系统规则
  • 这条是用户问题
  • 这条是工具返回结果
  • 这条是历史回答

所以它的本质不是"格式好看",而是:

让上下文结构可计算、可组合、可移植。

4.2 PromptTemplate 的工作机制

它的运行流程可以拆成 4 步:

  1. 先定义一段带占位符的模板
  2. 运行时传入参数 map
  3. TemplateRenderer 根据模板语法做替换
  4. 生成最终 message 文本,再放进 Prompt

可以画成这样:

text 复制代码
模板文本 + 参数
      ↓
TemplateRenderer
      ↓
最终 message 文本
      ↓
Prompt
      ↓
ChatModel

这就是为什么模板层和模型层是分离的。

模型并不关心 {concept} 是怎么替换的,它只接收最终 Prompt。

4.3 Advisor 链为什么能挂 RAG、Memory、Tool Calling

这是底层设计最关键的一点。

官方文档描述的链路可以概括为:

  1. Spring AI 先根据用户的 Prompt 创建 ChatClientRequest
  2. 再创建一个空的 advisor context
  3. Advisors 按顺序处理请求
  4. 每个 advisor 都可以修改请求,甚至阻断请求
  5. 最终框架内置的最后一个 advisor 才真正把请求发给模型
  6. 模型返回后,响应再沿着链路反向经过每个 advisor
  7. 最终形成 ChatClientResponse

这条链的价值非常大,因为它天然适合做"调用前增强"和"调用后处理"。

Memory 为什么适合放 Advisor

因为它本质上是在请求前补充历史上下文,或者在响应后保存本轮对话。

RAG 为什么适合放 Advisor

因为它本质上是在请求前做检索,把相关文档注入上下文。

Tool Calling 为什么也适合放 Advisor

因为它通常要在模型输出中识别工具调用意图,再触发工具执行,再把工具结果回填到上下文,属于典型的链式增强流程。

4.4 Advisor 顺序为什么重要

官方文档明确说明,Advisor 按 getOrder() 排序,数值越小优先级越高。

但要特别注意:

请求阶段和响应阶段的执行顺序是"栈式"的。

也就是说:

  • 优先级高的 advisor 会先处理请求
  • 但会后处理响应

这和 Servlet Filter / AOP 拦截链的思路很像。

所以如果你后面自己写 Advisor,一定要想清楚:

  • 我需要先改请求还是后改响应
  • 我需要拿到下游处理后的结果吗
  • 我的顺序应该在 Memory 前还是 RAG 后

4.5 metadata 为什么重要

很多人刚接触时觉得 metadata 没那么重要,因为最直观的是文本内容。

但真实工程里,metadata 往往直接决定你能不能把系统维护下去。

比如:

  • token 用量可以做成本核算
  • rate limit 信息可以帮助限流与重试
  • generation metadata 可以帮助调优模型行为
  • provider response metadata 可以辅助故障定位

如果没有 metadata,你只能看到"回答差不多对不对";

有了 metadata,你才能进一步判断:

  • 为什么这次贵
  • 为什么这次慢
  • 为什么这次被限流
  • 为什么这次检索上下文没进来

4.6 ChatClientResponse 为什么是复杂流程的关键

普通流程里:

java 复制代码
.call().content()

你只拿到了"结果文本"。

但复杂流程里,尤其是 RAG,你经常还想知道:

  • 检索到了哪些文档
  • 某个 advisor 是否改写了 prompt
  • 上下文里放了什么中间状态

这就是 ChatClientResponse 的价值,它把:

  • ChatResponse
  • Advisor 执行上下文

放在一起返回。

这对调试复杂 AI 系统非常关键。

4.7 Spring AI 的设计哲学到底是什么

可以总结成 4 句话:

  1. 公共能力抽象化

    把聊天、提示、向量检索等共性能力做成稳定接口

  2. Provider 差异扩展化

    不强行抹平一切差异,而是保留扩展点

  3. 增强能力链式化

    用 Advisor 承载 Memory、RAG、Safety、Reasoning 等增强逻辑

  4. Spring 工程化

    用 starter、自动配置、Bean、Micrometer、Actuator 接入企业应用体系

所以 Spring AI 不是在做"某一种 AI 玩法",而是在做:

"让 AI 能力像 Spring 生态里的其他能力一样可组合、可治理、可维护。"


5. 示例

这一阶段给你两个最小示例:

  1. 一个模板渲染示例
  2. 一个 Advisor 链示意示例

5.1 示例一:PromptTemplate 最小示例

java 复制代码
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.stereotype.Service;

@Service
public class ConceptExplainService {

    private final ChatClient chatClient;

    public ConceptExplainService(ChatClient.Builder builder) {
        this.chatClient = builder.build();
    }

    public String explain(String concept, String level) {
        return chatClient.prompt()
                .system("你是一名 Spring AI 导师,回答必须清晰、准确。")
                .user(user -> user
                        .text("请用{level}难度解释{concept},并给一个 Java 工程例子。")
                        .param("level", level)
                        .param("concept", concept))
                .call()
                .content();
    }
}

这个例子里,ChatClient 内部会用模板渲染机制把 {level}{concept} 替换成最终文本。

5.2 示例二:Advisor 链示意

java 复制代码
ChatMemory chatMemory = ...;
VectorStore vectorStore = ...;

var chatClient = ChatClient.builder(chatModel)
        .defaultAdvisors(
                MessageChatMemoryAdvisor.builder(chatMemory).build(),
                QuestionAnswerAdvisor.builder(vectorStore).build()
        )
        .build();

String response = chatClient.prompt()
        .advisors(advisor -> advisor.param(ChatMemory.CONVERSATION_ID, "user-1001"))
        .user("总结一下我们前面讨论过的 Spring AI 核心概念")
        .call()
        .content();

这个例子虽然比前面复杂,但它能非常直观地说明:

  • Memory 不是你手动拼历史消息
  • RAG 不是你手动把检索文本拼接到 prompt
  • 它们都可以通过 Advisor 链接入调用过程

5.3 如果想拿执行上下文

在复杂流程里,可以考虑拿 chatClientResponse() 而不是只拿 content()

这样你不仅能拿答案,还能拿到执行上下文,用于:

  • 调试 RAG
  • 查看中间状态
  • 分析 Advisor 执行结果

6. 工程实践

6.1 企业里通常怎么用消息模型

推荐习惯:

  1. system 只放规则、身份、输出约束
  2. user 只放用户输入或任务请求
  3. tool / history 交给框架能力或 Advisor 管理
  4. 不要把所有内容都拼成一段大字符串

6.2 模板的工程实践

建议你在项目里这样做:

  1. 短 Prompt 可以直接写在代码里
  2. 长 Prompt 尽量抽成模板文件或集中模板定义
  3. 动态变量永远走参数,不要字符串拼接
  4. 模板需要版本化和可测试

这会直接影响:

  • 维护成本
  • 团队协作效率
  • Prompt 调优效率

6.3 Advisor 的工程实践

推荐原则:

  1. 一个 Advisor 尽量只做一件事
  2. Memory、RAG、安全过滤尽量拆开
  3. 提前设计好 Advisor 顺序
  4. 复杂链路尽量保留 context,方便调试

如果你后面进入真实项目,这几条会非常重要。

6.4 一个真实工程场景

场景:做企业知识库问答助手。

一次调用背后可能会发生:

  1. 读取当前会话 ID
  2. 用 Memory Advisor 注入历史上下文
  3. 用 RAG Advisor 到向量库检索相关文档
  4. 把检索结果和问题一起送给模型
  5. 模型返回回答
  6. 记录 token、耗时、检索文档数量
  7. 保存本轮消息到 Memory

如果没有消息结构、模板机制、Advisor 链和 metadata,这样的流程会很难维护。


7. 常见误区

误区 1:Prompt 结构化只是"写法更优雅"

不只是。

它本质上是在为多轮对话、工具调用、模型协议兼容做准备。

误区 2:模板渲染只是为了少写字符串拼接

不只是。

它真正解决的是 Prompt 结构和动态数据解耦问题。

误区 3:Advisor 就是普通工具类

不对。

Advisor 运行在调用链上,能前置增强、后置处理、共享上下文。

误区 4:RAG 就是"查库后手工拼 prompt"

从原理上看可以这么做,但工程上更好的做法是把它放进可复用的增强链里。

误区 5:只要拿到回答文本,metadata 无所谓

不对。

没有 metadata,你很难做成本控制、性能分析和复杂排错。

误区 6:所有增强逻辑都应该写在一个大 Advisor 里

不建议。

这会让顺序、职责、调试都变得很混乱。


8. 面试题

基础题

  1. 为什么 Spring AI 的 Prompt 要按 role 组织 message?
  2. PromptTemplate 和普通字符串拼接相比有什么优势?
  3. Advisor 在 Spring AI 中扮演什么角色?
  4. ChatResponseChatClientResponse 的区别是什么?

理解题

  1. 为什么 RAG、Memory、Tool Calling 适合通过 Advisor 实现?
  2. Advisor 顺序为什么重要?
  3. 为什么 metadata 对 AI 系统的工程化很关键?
  4. TemplateRenderer 的存在体现了怎样的设计思想?

进阶题

  1. 如果一个知识库问答系统回答不稳定,你会如何从消息结构、模板、Advisor 和 metadata 四层去排查?
  2. 你如何向面试官解释 Spring AI 的设计哲学,而不是只背 API 名称?

9. 自测题

请你自己尝试回答:

  1. 为什么现代 Prompt 更适合用 message 列表而不是单字符串?
  2. 模板机制到底解决了什么"工程问题"?
  3. Advisor 链和 Servlet Filter / AOP 拦截链有哪些相似之处?
  4. 为什么说 ChatClientResponse 对复杂 AI 流程特别重要?
  5. 如果你做一个带 RAG 的问答系统,哪些能力适合放在 Advisor 层?
  6. 如果 token 成本突然上升,你会从 metadata 里关注哪些信息?
  7. 你能否用自己的话总结 Spring AI 的设计哲学?

10. 学完标志

学完这一阶段,你应该能做到:

  • 能解释 role-based message 为什么是现代 Prompt 的基础
  • 能说清 PromptTemplateTemplateRenderer 的职责
  • 能说明 Advisor 链为什么能挂接 Memory、RAG、Tool Calling
  • 能理解 ChatResponseChatClientResponse 的工程价值
  • 能从设计层面解释 Spring AI 为什么这样分层
  • 面对复杂 AI 调用链时,知道该从消息层、模板层、增强层、metadata 层分别看什么

第四阶段练习题

一、Prompt 结构练习

请你把一个"解释 Spring AI"的 Prompt 分成两种写法:

  1. 全部拼成一个大字符串
  2. system + user 分开写

然后回答:

  1. 哪种更容易维护?
  2. 哪种更容易扩展到多轮对话?
  3. 哪种更适合工具调用和 RAG?

二、模板练习

实现一个接口:

text 复制代码
GET /ai/teach?topic=Prompt&level=beginner

要求:

  • system 里定义导师角色
  • user 使用模板变量 {topic}{level}
  • 让模型输出"定义 + 类比 + 一个例子"

做完后,请你自己总结:

  • 模板方式比字符串拼接到底好在哪里

三、架构练习

假设你要做一个"带历史上下文 + 知识库检索"的 AI 助手,请你自己画出一条调用链:

text 复制代码
用户问题 -> Memory -> RAG -> 模型 -> 返回结果

然后回答:

  1. 哪些步骤适合做成 Advisor?
  2. 哪些信息适合放进 context?
  3. 哪些信息你希望最终能从 ChatClientResponse 里看到?

回复 继续,我下一阶段按同样的 Markdown 结构,带你进入:

第五阶段:工程实践

1. 学什么

这一阶段进入真正"能上手做项目"的部分。

重点掌握 5 件事:

  1. OpenAI / Ollama 这两条最常见接入路径怎么落地
  2. Structured Output 怎么把模型输出变成 Java 对象
  3. Tool Calling 怎么把模型和外部能力连起来
  4. RAG 的最小工程闭环应该怎么搭
  5. 项目结构、配置分层、日志、监控应该怎么组织

这一节学完,你的目标不再只是"理解概念",而是要达到:

能搭出一个基础可用的 Spring AI 小项目。

必须吃透:

  • Provider 接入和配置分层
  • entity() / Structured Output 的基本落地方式
  • Tool Calling 的调用闭环
  • RAG 的最小链路:切分 -> embedding -> 入库 -> 检索 -> 注入 prompt

先知道,后深入:

  • 高级 Agent 编排
  • 多阶段推理链
  • 复杂 RAG 重排 / 查询重写 / reranker
  • 复杂多工具协作

2. 为什么重要

前四个阶段帮你建立了:

  • 地图
  • 核心对象
  • 运行机制
  • 底层设计

但如果没有这一阶段,你很容易停留在:

  • 会讲概念
  • 会抄 Demo
  • 不会搭真实项目

企业真正看重的是:

  • 你能不能接通模型
  • 能不能把结果映射成业务结构
  • 能不能接知识库
  • 能不能调工具
  • 能不能做日志、限流、排错

所以第五阶段的意义是:

把"理解 Spring AI"转成"能交付一个最小 AI 功能模块"。


3. 核心概念

3.1 OpenAI 路线与 Ollama 路线

这是最常见的两条入门路线。

路线 特点 适合场景
Ollama 本地可跑、成本低、方便学习和开发调试 本地实验、内网、低成本开发
OpenAI / 云端模型 质量更稳定、能力更强、线上常见 正式项目、生产环境、高质量生成

学习顺序建议:

  1. 先用 Ollama 跑通本地闭环
  2. 再学 OpenAI / 云端接入
  3. 最后比较模型质量、延迟、成本和适用场景

3.2 Structured Output

类比理解:

普通文本输出像"模型给你一段自然语言",

Structured Output 像"模型给你一份按 schema 组织的数据"。

它解决的问题是:

  • 避免自己手工解析文本
  • 让模型输出更适合业务处理
  • 减少"回答看起来像 JSON,但其实不规范"的问题

Spring AI 提供两类常见方式:

  1. 直接 .entity(Class<T>)
  2. 使用 StructuredOutputConverter

3.3 Tool Calling

Tool Calling 的本质不是"模型真的有工具权限",而是:

模型提出工具调用请求,应用负责执行工具,再把结果回传给模型。

这点非常重要,因为它关系到安全边界。

也就是说:

  • 模型不会直接访问数据库/接口
  • 真正执行动作的是你的应用
  • Spring AI 负责把这套流程串起来

3.4 RAG

RAG 的本质是:

先从你的知识库检索相关内容,再把这些内容作为上下文提供给模型。

最小闭环通常包括:

  1. 原始数据准备
  2. 文档切分
  3. 生成 embedding
  4. 写入 Vector Store
  5. 查询时做 embedding 检索
  6. 把检索结果注入 Prompt
  7. 模型生成答案

3.5 工程组织

Spring AI 项目不是"先把所有 AI 功能塞进 Controller",而应该像正常 Spring 项目一样分层。

推荐角色分工:

职责
Controller 收参、返回结果
Service 组织 Prompt、ChatClient、Tool、RAG 调用
Config 模型 Bean、自定义 ChatClient、Tool 注册、Advisor 配置
Data / Ingestion 文档导入、切分、向量入库
Observability 日志、metrics、trace、成本统计

4. 原理解释

4.1 OpenAI / Ollama 两条接入路径的共同点

虽然 Provider 不同,但工程主线很像:

text 复制代码
starter -> properties -> 自动配置 -> ChatClient -> Prompt -> Response

共同点:

  • 都通过 Spring AI starter 接入
  • 都通过配置文件指定模型和连接参数
  • 都通过统一的 ChatClient / ChatModel 调用

不同点:

  • 认证方式不同
  • 能力支持不同
  • 默认模型行为不同
  • 成本、延迟、部署方式不同

这再次说明:

Spring AI 做的是"统一主线",不是"抹平所有差异"。

4.2 Structured Output 的工作机制

它的核心思路是:

  1. 你告诉模型希望输出什么结构
  2. 模型按结构返回结果
  3. Spring AI 把返回内容映射到 Java 类型

最常见使用方式:

java 复制代码
ActorFilms actorFilms = chatClient.prompt()
    .user("Generate the filmography for a random actor.")
    .call()
    .entity(ActorFilms.class);

它背后的价值是:

  • 避免业务层自己写 JSON 解析
  • 让 AI 输出更接近传统业务对象
  • 更适合接口编排和持久化处理

但你要记住:

Structured Output 不是"100% 不会出错",只是大幅降低非结构化输出带来的混乱。

4.3 Tool Calling 的工作闭环

官方文档的工具调用流程可以概括为:

text 复制代码
1. 应用把工具定义告诉模型
2. 模型决定是否调用工具,并给出工具名和参数
3. 应用根据工具名找到对应 ToolCallback
4. 应用执行工具
5. 工具结果被序列化后回传给模型
6. 模型基于工具结果生成最终回答

你一定要吃透一句话:

模型只会"请求调用工具",不会"直接执行工具"。

这也是为什么 Tool Calling 在工程里既强大又必须谨慎。

4.4 RAG 的最小闭环原理

不要把 RAG 理解成"把文档直接拼进去"。

一个更准确的最小工程闭环是:

text 复制代码
原始文档
  ↓
切分成较小片段
  ↓
用 EmbeddingModel 生成向量
  ↓
写入 VectorStore
  ↓
用户提问
  ↓
将问题向量化并检索相似文档
  ↓
把相关文档放进 Prompt / Advisor
  ↓
模型回答

这里最常见的问题不是"代码不会写",而是:

  • 文档没切好
  • embedding 模型和存储维度不匹配
  • 检索条数不合理
  • 注入 prompt 的方式混乱

所以 RAG 本质上是"检索系统 + Prompt 组织"的组合。

4.5 为什么工程里要分"导入链路"和"问答链路"

很多初学者做 RAG 时,把"写入向量库"和"在线问答"混在一个接口里。

这是很常见的设计错误。

更合理的拆分是:

  • 导入链路:读文档、切分、embedding、入库
  • 问答链路:接问题、检索、组 Prompt、生成答案

原因很简单:

  • 导入通常是批处理或后台任务
  • 问答通常是在线低延迟请求

这两个链路的性能目标和失败处理方式完全不同。

4.6 为什么项目一开始就要考虑日志和监控

因为 AI 应用比普通 CRUD 更"不稳定":

  • 输出不完全确定
  • token 成本可波动
  • Provider 可能限流
  • 模型响应时间变化大
  • 工具调用和 RAG 会增加额外链路

所以从第一版开始,你就应该考虑记录:

  • 请求耗时
  • 模型名称
  • token 使用
  • 检索文档数量
  • Tool Calling 次数
  • 失败原因

5. 示例

5.1 示例一:OpenAI 最小接入

依赖
xml 复制代码
<dependency>
    <groupId>org.springframework.ai</groupId>
    <artifactId>spring-ai-starter-model-openai-sdk</artifactId>
</dependency>
配置
yaml 复制代码
spring:
  ai:
    openai-sdk:
      api-key: ${OPENAI_API_KEY}
      chat:
        options:
          model: gpt-5-mini
          temperature: 0.2
调用
java 复制代码
String answer = chatClient.prompt()
        .user("用 3 点解释什么是 Spring AI")
        .call()
        .content();

这个例子说明:

  • 云端模型接入和本地模型接入在业务调用层几乎一样
  • 差异主要体现在 starter、配置和模型能力上

5.2 示例二:Structured Output

定义输出对象
java 复制代码
public record ConceptSummary(
        String definition,
        String analogy,
        String example
) {}
调用
java 复制代码
ConceptSummary summary = chatClient.prompt()
        .user("请按 definition、analogy、example 三个字段解释 Spring AI")
        .call()
        .entity(ConceptSummary.class);

这个例子很适合做:

  • 智能表单填充
  • 信息抽取
  • 摘要结构化
  • AI 结果进入业务流程

5.3 示例三:Tool Calling

定义工具
java 复制代码
import org.springframework.ai.tool.annotation.Tool;
import org.springframework.stereotype.Component;

import java.time.LocalDateTime;

@Component
public class DateTimeTools {

    @Tool(description = "获取当前系统时间")
    public String getCurrentTime() {
        return LocalDateTime.now().toString();
    }
}
调用
java 复制代码
String result = chatClient.prompt()
        .user("现在几点了?请先获取系统时间再回答。")
        .tools(new DateTimeTools())
        .call()
        .content();

这里最重要的不是语法,而是你要理解:

  • 工具描述会暴露给模型
  • 模型决定要不要调用
  • 真正执行工具的是应用

5.4 示例四:RAG 最小闭环示意

导入链路
java 复制代码
List<Document> documents = List.of(
        new Document("Spring AI provides abstractions for chat models, embeddings, vector stores, and tool calling.")
);

vectorStore.add(documents);
问答链路
java 复制代码
String answer = chatClient.prompt()
        .advisors(new QuestionAnswerAdvisor(vectorStore))
        .user("Spring AI 主要解决什么问题?")
        .call()
        .content();

这个例子只展示最小主线,但真实项目里你还会补:

  • 文档切分
  • metadata
  • 检索过滤
  • 文档来源标注

6. 工程实践

6.1 推荐的项目结构

一个基础 Spring AI 项目,可以先按下面结构组织:

text 复制代码
com.example.ai
├── controller
├── service
├── config
├── tool
├── rag
├── ingestion
└── model

含义:

  • controller:HTTP 接口
  • service:对话、结构化输出、业务编排
  • config:ChatClient、自定义配置、Provider 配置
  • tool@Tool 方法或 ToolCallback
  • rag:检索相关封装
  • ingestion:文档导入、切分、向量入库
  • model:结构化输出对象、请求响应对象

6.2 推荐的学习落地顺序

正确顺序:

  1. 普通聊天接口
  2. Structured Output
  3. Tool Calling
  4. 最小 RAG
  5. 日志与监控
  6. 再考虑会话记忆和复杂编排

不要一开始就:

  • 多工具
  • 多模型
  • 多轮记忆
  • 混合 RAG
  • Agent 工作流

6.3 配置分层建议

推荐分三层:

第一层:环境配置
  • API Key
  • base URL
  • 模型名
  • 超时
第二层:应用默认配置
  • 默认 system prompt
  • 默认 temperature
  • 默认 advisors
第三层:请求级覆盖
  • 特殊 Prompt
  • 特殊 model
  • 特殊 tool 集合
  • 特殊结构化输出需求

6.4 企业里通常怎么用 Tool Calling

企业最常见的不是"让模型做任意动作",而是给它有限、明确、可审计的工具集合。

例如:

  • 查订单
  • 查库存
  • 查天气
  • 生成工单
  • 调用内部知识检索

最佳实践:

  1. 工具描述写清楚
  2. 参数 required 状态定义准确
  3. 对外部动作型工具做权限和幂等控制
  4. 工具返回值尽量结构化、可序列化

6.5 RAG 的最低可用实践

如果你第一次做 RAG,最推荐的顺序是:

  1. 先只导入少量高质量文档
  2. 验证检索结果是否靠谱
  3. 再把检索接入问答
  4. 再观察 hallucination 是否下降
  5. 再去调 chunk 大小、topK、过滤条件

不要一开始就导入海量杂乱文档。

否则你根本分不清是检索差、切分差、还是 Prompt 差。

6.6 日志与监控建议

起步阶段至少记录:

  • 接口名
  • 模型名
  • 响应耗时
  • token 数
  • 是否命中工具调用
  • 检索文档数
  • 异常类型

如果进入生产环境,再进一步结合:

  • Micrometer
  • Actuator
  • trace / span
  • 成本报表

7. 常见误区

误区 1:只要能返回文本,就说明项目已经可用了

不对。

真实项目往往还需要结构化输出、日志、失败处理、权限控制、监控。

误区 2:Structured Output 就等于绝对可靠的 JSON

不对。

它能显著提升稳定性,但仍需要对异常输出和字段缺失做好兜底。

误区 3:Tool Calling 是模型自己去访问外部系统

不对。

模型只提出调用请求,真正执行的是你的应用。

误区 4:RAG 就是把文档塞给模型

过于简化。

真正的 RAG 至少包含 embedding、向量检索和上下文注入。

误区 5:导入向量库和在线问答可以随便混在一起

不建议。

它们的职责和性能目标不同,应该拆链路。

误区 6:项目一开始不用管日志监控,后面再补

风险很大。

AI 应用的问题比普通 CRUD 更难追踪,越晚补越难定位问题。

误区 7:本地 Ollama 跑通了,线上切 OpenAI 基本不用想别的

不完全对。

模型能力、响应风格、token 成本、工具支持、延迟都可能不同。


8. 面试题

基础题

  1. Spring AI 中 Structured Output 解决了什么问题?
  2. Tool Calling 的执行闭环是什么?
  3. RAG 的最小工程闭环包括哪些步骤?
  4. 为什么企业项目里常把模型接入、Tool、RAG 分层组织?

理解题

  1. 为什么模型并不会直接执行工具?
  2. .entity(Class<T>) 和直接拿文本再手工解析相比,有什么优缺点?
  3. 为什么 RAG 项目里要把导入链路和问答链路拆开?
  4. 为什么本地 Ollama 与云端 OpenAI 虽然调用方式相似,但工程策略不一定相同?

进阶题

  1. 如果要做一个"订单查询助手",你会优先选择 Tool Calling、RAG 还是两者结合?为什么?
  2. 如果 AI 输出要进入正式业务流程,你会如何设计结构化输出、校验和兜底策略?

9. 自测题

请你自己尝试回答:

  1. 什么时候应该优先用 Structured Output?
  2. Tool Calling 的安全边界在哪里?
  3. 你能否画出一个最小 RAG 调用链?
  4. 为什么向量入库更适合做成单独导入流程?
  5. 如果 RAG 效果差,你会先检查文档质量、切分、embedding、检索还是 Prompt?为什么?
  6. 如果你现在要搭一个最小 Spring AI 项目,目录结构会怎么分?
  7. 如果要把 AI 输出写入数据库,为什么不建议直接依赖自然语言文本?

10. 学完标志

学完这一阶段,你应该能做到:

  • 能独立接通本地模型或云端模型
  • 能把 AI 输出映射成 Java 对象
  • 能解释 Tool Calling 的完整执行闭环
  • 能搭出一个最小 RAG 闭环
  • 能按合理分层组织 Spring AI 项目
  • 能说明日志、token、检索、工具调用为什么都要监控
  • 已具备做一个基础 AI 功能模块的工程能力

第五阶段练习题

一、Structured Output 练习

实现一个接口:

text 复制代码
GET /ai/summary?topic=Spring AI

要求:

  • 输出结构为 definition / analogy / example
  • 不要只返回纯文本
  • 使用 .entity(...) 或 Structured Output Converter

然后思考:

  1. 如果模型漏了一个字段,你准备怎么处理?
  2. 为什么这种方式更适合进入业务流程?

二、Tool Calling 练习

实现一个最小工具:

  • 获取当前时间

然后实现一个接口:

text 复制代码
GET /ai/time

要求:

  • 让模型通过工具获取当前时间再回答
  • 解释"模型请求工具"和"应用执行工具"的区别

三、RAG 练习

做一个最小知识库问答 Demo:

  1. 准备 3 到 5 条关于 Spring AI 的知识文本
  2. 写入 Vector Store
  3. 做一个问答接口
  4. QuestionAnswerAdvisor 或类似方式接入检索

然后回答:

  1. 如果回答效果差,你第一步怎么排查?
  2. 如果检索到了无关文档,你会优先调哪里?

第六阶段:常见问题与排错

1. 学什么

这一阶段的目标不是继续增加新功能,而是建立一套真正可复用的排错方法。

重点包括:

  1. API Key、base URL、starter、版本不匹配怎么排
  2. 为什么 ChatModel / ChatClient.Builder Bean 注入失败
  3. 为什么模型输出不稳定
  4. 为什么 Structured Output、Tool Calling、RAG 不按预期工作
  5. 如何把"AI 应用排错"拆成固定层次

这一节学完后,你要达到的状态是:

不是只会说"好像出错了",而是能快速判断问题在哪一层。

必须吃透:

  • 排错要按层分:依赖层、配置层、Bean 层、请求层、模型层、增强层
  • 先排"有没有接通",再排"为什么效果差"
  • 输出质量问题和系统接入问题不是一类问题

先知道,后深入:

  • 高级 trace 体系
  • 大规模线上限流与重试策略
  • 多租户模型路由问题

2. 为什么重要

很多人学 AI 框架时有一个典型问题:

  • Demo 能跑
  • 一到自己项目里就开始报错
  • 报错后不知道先查依赖、查配置、还是查 Prompt

Spring AI 的问题来源通常分成两大类:

第一类:系统没接通

例如:

  • Bean 没创建
  • API Key 错
  • base URL 错
  • starter 错
  • 版本不匹配

第二类:系统接通了,但结果不对

例如:

  • 回答很飘
  • Structured Output 映射失败
  • 工具没被调用
  • RAG 检索结果不相关

这两类问题的排法完全不同。

如果你不先分类,就会陷入"所有地方一起猜"的低效状态。

所以这一阶段最重要的价值是:

把排错从"凭感觉乱试"变成"按层定位"。


3. 核心概念

3.1 六层排错模型

我建议你以后把 Spring AI 问题固定拆成下面六层:

层级 核心问题 常见现象
依赖层 starter / 版本是否正确 类找不到、自动配置不生效
配置层 properties 是否正确绑定 401、404、连接失败、模型不对
Bean 层 Bean 是否成功创建和注入 NoSuchBeanDefinitionException
请求层 Prompt / Options / 参数是否合理 输出异常、字段丢失、风格不稳定
增强层 Tool / Advisor / RAG / Memory 是否按预期工作 工具不触发、检索无效
模型层 Provider 能力边界、限流、token、性能 429、超时、结果不稳定

3.2 "接通问题"与"效果问题"

这是最常混淆的一组概念。

问题类型 本质 例子
接通问题 系统没有正确跑起来 Bean 不存在、401、连接失败
效果问题 系统跑起来了,但结果不好 回答不准、RAG 效果差、结构化输出不稳

你要养成一个习惯:

先确认链路通,再优化效果。

3.3 "框架问题"与"模型问题"

类型 本质 例子
框架问题 Spring AI 接入、配置、调用链问题 starter 错、Bean 缺失、Advisor 没挂上
模型问题 模型本身能力或限制问题 小模型理解差、工具能力弱、structured output 不稳定

很多排错失败,不是因为不会看日志,而是因为把框架问题和模型问题混在一起。

3.4 最重要的排错原则

  1. 先最小化问题
  2. 先去掉复杂能力
  3. 先验证最短路径
  4. 再逐层把复杂能力加回来

比如一个 RAG + Tool Calling + Structured Output 的接口出问题时,不要一上来全查。

应该先退化成:

text 复制代码
纯聊天能不能通?

如果纯聊天都不通,就不要先怀疑 RAG。


4. 原理解释

4.1 排错总流程

建议你固定按下面顺序排:

text 复制代码
1. 依赖对不对
2. 配置对不对
3. Bean 有没有
4. 最小聊天调用通不通
5. Prompt / Options 合不合理
6. Tool / RAG / Structured Output 单独是否正常
7. metadata / 日志 / token / trace 有没有异常

这个顺序非常重要,因为它遵循的是:

从基础设施到业务行为,从确定性问题到非确定性问题。

4.2 API Key / base URL / 模型名错误怎么排

这类问题一般发生在配置层。

常见现象:

  • 401 Unauthorized
  • 403 Forbidden
  • 404 Not Found
  • 连接超时
  • 调到错误模型

排查步骤:

  1. 确认使用的 starter 与 Provider 对应
  2. 确认 properties 前缀正确
  3. 确认环境变量是否真的注入
  4. 确认 base URL 是否指向正确服务
  5. 确认模型名是否是目标 Provider 真正支持的名字

典型例子:

  • 用了 openai-sdk starter,却还写 spring.ai.openai.*
  • 本地 Ollama 没启动,但还在请求 http://localhost:11434
  • OpenAI key 没注入环境变量

4.3 Bean 注入失败怎么排

如果你看到:

  • NoSuchBeanDefinitionException
  • 注入 ChatClient.Builder 失败
  • 注入 ChatModel 失败

优先看三件事:

  1. starter 是否引入了正确模块
  2. Spring Boot 与 Spring AI 版本是否匹配
  3. 自动配置是否因为条件不满足而没生效

底层原理其实很简单:

  • 没有正确依赖,自动配置类不会进来
  • 没有正确配置,条件装配可能不会创建 Bean
  • 版本不匹配,类路径和自动配置入口可能出问题

所以 Bean 问题大多数不是业务代码问题,而是:

依赖与配置问题。

4.4 输出不稳定怎么排

如果系统能返回结果,但风格忽左忽右、内容时好时坏,优先看:

  1. system prompt 是否稳定
  2. user prompt 是否过于含糊
  3. temperature 是否过高
  4. 是否切换了不同模型
  5. 是否把历史上下文、RAG 文档、工具结果混乱地拼在了一起

也就是说,这类问题大多不在"连通性",而在:

  • Prompt 设计
  • Options 设计
  • 上下文组织

4.5 Structured Output 不稳定怎么排

典型现象:

  • JSON 不完整
  • 字段缺失
  • 类型不匹配
  • .entity(...) 转换失败

优先检查:

  1. 输出 schema 是否过于复杂
  2. Prompt 是否明确要求结构化字段
  3. 模型是否足够适合结构化输出
  4. 是否使用了合适的 Structured Output 方式
  5. 是否给业务层做了兜底校验

经验原则:

  • 先从小对象开始
  • 字段名尽量清晰
  • 少做层级过深的嵌套
  • 不要过早要求模型稳定输出复杂数组对象

4.6 Tool Calling 不触发怎么排

典型现象:

  • 模型明明应该查工具,却直接瞎答
  • 工具参数不对
  • 工具方法根本没执行

排查顺序:

  1. 工具是否真的注册给了本次调用
  2. 工具描述是否足够清晰
  3. 模型是否具备较好的工具调用能力
  4. 用户 prompt 是否明确提示要使用工具
  5. 工具返回结果是否可被模型继续利用

注意:

"没调用工具"不一定是框架坏了,也可能是模型判断"不需要调用"。

4.7 RAG 效果差怎么排

RAG 问题最容易让人误判成"模型太笨"。

但大量情况下,真正问题在前面几步:

  1. 文档质量差
  2. 文档切分不合理
  3. embedding 模型不合适
  4. 向量维度不匹配
  5. topK 不合理
  6. 检索结果虽然有,但注入 prompt 的方式不对

所以排 RAG 时一定要分开看:

text 复制代码
导入链路正常吗?
检索链路正常吗?
生成链路正常吗?

不要把它们混成一个整体。

4.8 性能和限流问题怎么排

典型问题:

  • 响应很慢
  • 429 限流
  • token 成本突然上涨
  • streaming 中途中断

优先看:

  1. metadata 中的 token usage
  2. 请求耗时
  3. rate limit 信息
  4. Prompt 长度
  5. RAG 注入文档数量
  6. Tool Calling 是否造成了额外链路开销

这类问题的本质是:

不是"答不答得对",而是"系统能不能稳定、可控地运行"。

4.9 一套可复用的排错方法论

以后你可以固定套下面这套模板:

第一步:判断是哪一类问题
  • 接通问题
  • 效果问题
  • 性能问题
第二步:缩小问题范围
  • 去掉 RAG
  • 去掉 Tool Calling
  • 去掉 Structured Output
  • 退回纯聊天
第三步:检查最关键观测点
  • Bean 是否存在
  • 配置是否生效
  • 最终 Prompt 长什么样
  • metadata 和 token 怎么样
  • 工具和检索是否真的执行
第四步:逐项恢复复杂能力
  • 先加 Structured Output
  • 再加 Tool
  • 再加 RAG
  • 最后加 Memory / 复杂 advisors

这就是一种"最小可复现 + 分层恢复"的排错思想。


5. 示例

5.1 示例一:Bean 注入失败时的最小排查

假设你有这样的代码:

java 复制代码
@RestController
public class AiController {

    private final ChatClient.Builder builder;

    public AiController(ChatClient.Builder builder) {
        this.builder = builder;
    }
}

如果启动时报注入失败,最先检查:

  1. 是否引入了某个 spring-ai-starter-model-*
  2. Spring Boot 版本和 Spring AI 版本是否匹配
  3. application.yml 是否使用了对应 Provider 的正确前缀

这时不要先改 Controller。

因为大概率不是 Controller 有问题,而是 Bean 根本没自动创建。

5.2 示例二:Structured Output 映射失败

java 复制代码
public record UserIntent(String intent, String confidence) {}

UserIntent intent = chatClient.prompt()
        .user("识别这句话的意图:帮我查一下订单状态")
        .call()
        .entity(UserIntent.class);

如果这里经常失败,你的排查方向应该是:

  1. confidence 是否应该是数值而不是字符串
  2. 字段是否太抽象
  3. Prompt 是否明确要求固定字段输出
  4. 模型是否适合做结构化输出

5.3 示例三:RAG 效果差的排查顺序

不要上来就说"模型不行",先按这个顺序查:

  1. 检索出来的文档是不是相关
  2. 检索条数是否过多或过少
  3. 文档切分是否太大或太碎
  4. Prompt 是否真的把检索文档纳入上下文
  5. 最后再考虑换模型

这就是一个典型的"先查检索,再查生成"的例子。


6. 工程实践

6.1 推荐的排错顺序

真实项目里,建议固定按下面顺序排:

  1. 看异常类型
  2. 看配置和环境变量
  3. 看 Bean 注入和启动日志
  4. 跑最小聊天接口
  5. 再看 Structured Output / Tool / RAG
  6. 最后看性能、token、限流

6.2 建议保留的观测信息

每个核心接口至少保留:

  • 请求 ID
  • 会话 ID
  • 模型名
  • temperature
  • token 用量
  • 耗时
  • 是否命中工具调用
  • 检索到的文档数
  • 异常摘要

这样你后面定位问题时,就不是"猜",而是"对照数据排"。

6.3 一个真实工程场景

场景:知识库助手回答总是不准。

错误做法:

  • 直接换模型
  • 直接加更多 Prompt
  • 直接调高 topK

更好的做法:

  1. 先看检索文档是否相关
  2. 再看切分是否合理
  3. 再看 Prompt 是否明确要求"优先依据检索内容回答"
  4. 再看模型是否足够理解该任务

这说明排错时要先查"前置环节",而不是总盯着最后的模型输出。

6.4 初学者最值得养成的习惯

  1. 每做一个复杂能力,都先保留一个纯聊天对照接口
  2. 每做一个 RAG 能力,都保留"只看检索结果"的调试入口
  3. 每做一个 Tool Calling,都先单独测试工具方法本身
  4. 每做一个 Structured Output,都先从最简单对象开始

这会极大降低你后面排错的成本。


7. 常见误区

误区 1:只要结果不对,就先调 Prompt

不对。

如果系统根本没接通,调 Prompt 没意义。

误区 2:只要报 Bean 错误,就是 Spring 本身有问题

大多数时候不是。

更多是 starter、版本、配置条件没有满足。

误区 3:Structured Output 出错说明这个功能不能用

不对。

很多时候是 schema 设计过复杂,或者模型/Prompt 没对齐。

误区 4:Tool Calling 没触发说明 Spring AI 没有执行工具

不一定。

也可能是模型根本没有决定调用工具。

误区 5:RAG 回答差,一定是模型质量不够

不一定。

文档质量、切分策略、检索命中、上下文注入方式往往更关键。

误区 6:排错时所有能力一起看更快

恰恰相反。

越复杂越应该回到最小链路。

误区 7:日志以后再补

这是很危险的习惯。

没有日志和 metadata,很多 AI 问题根本没有证据可查。


8. 面试题

基础题

  1. Spring AI 项目中 Bean 注入失败通常先检查什么?
  2. 如何区分"接通问题"和"效果问题"?
  3. Structured Output 映射失败时,你会优先看哪些点?
  4. Tool Calling 不触发时,可能有哪些原因?

理解题

  1. 为什么排错要先退回最小聊天链路?
  2. RAG 效果差时,为什么不应该第一时间换模型?
  3. 如果输出不稳定,你会从 Prompt、Options、上下文、模型四个角度怎么排?
  4. 为什么日志、metadata、token usage 对排错特别重要?

进阶题

  1. 设计一套你自己的 Spring AI 排错 checklist,你会包含哪些层?
  2. 如果线上 AI 接口突然成本暴涨,你会如何定位是 Prompt 过长、RAG 注入过多,还是模型切换导致的?

9. 自测题

请你自己尝试回答:

  1. 你能否用"六层排错模型"解释 Spring AI 常见问题?
  2. 如果 ChatClient.Builder 注入失败,你的前三步检查是什么?
  3. 如果 .entity(...) 经常失败,你会怎么缩小问题范围?
  4. 如果工具没触发,你会如何区分是模型选择问题还是框架接入问题?
  5. 如果 RAG 回答偏离知识库,你会按什么顺序排?
  6. 如果响应很慢,你会优先看哪些观测指标?
  7. 你能否写出一套"从纯聊天到复杂链路逐步恢复"的排错步骤?

10. 学完标志

学完这一阶段,你应该能做到:

  • 能按层次排查 Spring AI 常见问题
  • 能区分"接通问题""效果问题""性能问题"
  • 遇到 Bean、配置、模型、工具、RAG 相关问题时有固定排查路径
  • 知道什么时候该退回最小链路
  • 知道哪些日志和 metadata 必须保留
  • 已具备基础到中级工程师水平的排错思路

第六阶段练习题

一、接通排查练习

请你故意制造下面任意一个问题:

  1. 写错 properties 前缀
  2. 写错模型名
  3. 不启动 Ollama

然后自己回答:

  1. 现象是什么?
  2. 它属于依赖层、配置层还是 Bean 层问题?
  3. 你是如何一步步确认问题位置的?

二、效果排查练习

做一个简单解释接口,然后分别尝试:

  1. 把 system prompt 写得非常模糊
  2. 把 temperature 调高
  3. 把 user prompt 写得过于含糊

然后比较输出差异,并总结:

  1. 哪些属于 Prompt 问题?
  2. 哪些属于 Options 问题?
  3. 哪些不是框架 bug,而是使用方式问题?

三、RAG / Tool 排查练习

请你任选一个方向:

方向 A:RAG

  1. 故意放入一条无关文档
  2. 测试回答效果
  3. 分析是检索问题还是生成问题

方向 B:Tool Calling

  1. 写一个"获取当前时间"的工具
  2. 分别测试"明确要求调用工具"和"模糊提问"两种 Prompt
  3. 观察工具触发情况

然后总结:

  1. 你如何判断是模型没有决定调用,还是工具没有正确接入?

第七阶段:面试与评估

1. 学什么

这一阶段的重点不再是"继续学新能力",而是把你前面学过的内容转化成:

  1. 能解释
  2. 能表达
  3. 能答题
  4. 能证明自己具备工程能力

重点包括:

  1. 面试官常问哪些 Spring AI 概念题、原理题、实战题
  2. 怎么回答"你做过 Spring AI 项目吗"
  3. 怎么把 Structured Output、Tool Calling、RAG 讲成工程实践,而不是名词堆砌
  4. 如何判断自己处于入门、初级还是中级水平

这一节的核心目标是:

把"我会用"升级成"我能让别人相信我会用"。

必须吃透:

  • 面试回答不是背定义,而是讲"问题 - 方案 - 原理 - 权衡"
  • 概念题和项目题的回答方式不同
  • 中级面试的关键不是功能多,而是你能解释设计选择和排错路径

先知道,后深入:

  • 系统设计级别的 AI 架构面试
  • 线上容量规划与成本治理
  • 复杂 Agent / 多模型路由设计

2. 为什么重要

很多人学完技术以后,会出现一种"隐性断层":

  • 自己做的时候感觉懂
  • 一到面试就说不清
  • 面试官一追问为什么这样设计,就开始卡住

Spring AI 尤其容易这样,因为它涉及:

  • 框架抽象
  • 模型能力
  • 工程实践
  • RAG / Tool / Structured Output 等多种模式

如果你只是"记住 API",面试时很容易被追问垮:

  • 为什么要用 ChatClient 而不是直接 SDK?
  • Tool Calling 的安全边界是什么?
  • RAG 项目里你怎么排错?
  • Structured Output 为什么比直接解析文本更稳?

所以这一节的意义是:

帮你把知识点整理成"面试可输出的结构化表达"。


3. 核心概念

3.1 面试官通常在考什么

Spring AI 面试问题,通常不是只考"会不会写一个 Demo",而是会看这四类能力:

维度 面试官想知道什么
概念理解 你是否真的理解核心抽象
原理理解 你是否知道它为什么这么设计
工程能力 你是否能把它落到项目里
排错与权衡 你是否能处理真实问题,而不是只会 Happy Path

3.2 概念题回答框架

回答概念题时,推荐你固定按下面顺序说:

  1. 它是什么
  2. 它解决什么问题
  3. 它和相近概念的区别
  4. 在工程里通常怎么用

例如回答 ChatClient

  • 它是 Spring AI 提供的上层 fluent API
  • 用来更方便地组织 Prompt、模板参数、Advisor 和返回形式
  • 它建立在 ChatModel 之上,不是底层模型实现本身
  • 业务层通常直接面向它编程

3.3 原理题回答框架

原理题不要只讲定义,要讲"设计动机"。

推荐结构:

  1. 先说现象
  2. 再说问题
  3. 再说 Spring AI 的设计方案
  4. 再说这种设计带来的好处和限制

例如回答"为什么 Spring AI 要做统一抽象":

  • 因为不同模型厂商 SDK 差异很大
  • 直接依赖厂商 SDK 会让业务代码耦合严重
  • Spring AI 通过 ChatModelEmbeddingModel 等抽象统一公共能力
  • 好处是业务层更稳定,缺点是不能完全抹平 Provider 差异

3.4 项目题回答框架

项目题最怕"讲功能清单"。

更好的回答结构是:

  1. 项目目标是什么
  2. 为什么选 Spring AI
  3. 核心架构怎么分层
  4. 关键能力怎么落地
  5. 遇到什么问题,怎么排
  6. 最终效果和权衡是什么

这比说"我们做了 RAG、Tool、Prompt"更像工程回答。

3.5 初级与中级的区别

层级 典型表现
入门 能跑通最小示例,知道核心概念名字
初级 能做普通聊天、Structured Output、最小 Tool / RAG
中级 能解释原理、分层设计、做排错、讲清权衡与边界

所以中级并不是"你会的功能更多",而是:

你对机制、设计和工程问题的解释能力更强。

3.6 Spring AI 面试常考模块

你要重点准备下面这些模块:

  1. Spring AI 是什么,解决什么问题
  2. ChatModelChatClient 的区别
  3. Prompt、Options、Response 的职责
  4. starter、properties、自动配置机制
  5. Structured Output 原理与适用场景
  6. Tool Calling 的执行闭环和安全边界
  7. RAG 的最小工程链路
  8. 常见问题与排错
  9. 为什么企业里要做日志、token、监控

4. 原理解释

4.1 面试官为什么喜欢追问 Spring AI 的"为什么"

因为 Spring AI 这个主题很容易让人只停留在表层:

  • 会配依赖
  • 会写接口
  • 会调模型

但这不足以证明你真正掌握了它。

面试官真正想判断的是:

  • 你是不是理解 Spring 风格抽象
  • 你是不是知道统一接口背后的权衡
  • 你是不是做过真实工程,而不是只复制了一个 Demo

所以当面试官追问"为什么"时,他不是在故意刁难你,而是在判断你有没有中级工程师的理解深度。

4.2 为什么概念题不能只背定义

因为定义太短,不足以证明你理解了使用场景和边界。

比如问:

"什么是 Tool Calling?"

如果你只答:

"Tool Calling 是调用工具的能力。"

这几乎没有信息量。

更好的回答应该是:

  • Tool Calling 是让模型根据上下文决定是否请求调用外部工具的一种机制
  • 模型不会直接执行工具,真正执行的是应用侧注册的工具逻辑
  • 这样做能把模型推理能力和系统外部能力连接起来
  • 但也必须控制权限、参数校验和幂等性

这就体现出你理解了:

  • 概念
  • 原理
  • 边界
  • 工程风险

4.3 为什么项目题最能拉开差距

因为概念可以背,项目细节很难背得像真的。

比如问你:

"你做过 RAG 吗?"

如果你只回答:

  • 做过
  • 就是把文档放进向量库再检索

这很弱。

如果你能回答:

  • 我们把 RAG 拆成导入链路和问答链路
  • 导入链路负责切分、embedding、入库
  • 问答链路负责检索、Prompt 注入和回答生成
  • 排错时我会先看检索结果是否相关,再看模型回答质量

这就非常像真实做过的人。

4.4 如何把一个功能讲成工程实践

无论是 Structured Output、Tool Calling 还是 RAG,你都可以固定套下面这套说法:

  1. 业务为什么需要它
  2. 技术上怎么实现
  3. 为什么不用更简单的方法
  4. 遇到什么问题
  5. 怎么排错和优化

例如 Structured Output:

  • 业务需要把 AI 输出进入后续流程
  • 纯文本难解析且不稳定
  • 所以用 .entity(...) 或转换器把输出映射成对象
  • 实践中要防字段缺失和类型不匹配
  • 需要做 schema 设计和业务校验兜底

这就是"工程表达"。

4.5 如何判断自己是不是达到中级

你可以用下面几个标准自检:

  1. 能否不用看文档,解释 ChatClientPromptChatOptionsChatResponse
  2. 能否讲清 starter、properties、自动配置主线
  3. 能否独立设计一个最小 Tool / RAG / Structured Output 模块
  4. 能否用层次化思路排错
  5. 能否把一个项目讲成"架构 + 权衡 + 问题 + 结果"

如果这些你都能做到,基本就已经接近中级水平了。


5. 示例

这一节的"示例"不是代码,而是面试表达示例。

5.1 示例一:回答"什么是 Spring AI"

一个较好的回答版本:

Spring AI 是一个用 Spring Boot 风格开发 AI 应用的框架。

它主要解决不同模型厂商接入方式不统一,以及 AI 应用缺乏工程化组织的问题。

在项目里我通常会用它来统一接聊天模型、结构化输出、工具调用和 RAG,而不是直接在业务代码里依赖某家模型 SDK。

这个回答好在:

  • 说了是什么
  • 说了解决什么问题
  • 说了工程落点

5.2 示例二:回答"ChatClientChatModel 有什么区别"

一个较好的回答版本:

ChatModel 更像 Spring AI 的底层统一模型接口,负责真正发起模型调用。
ChatClient 是建立在它之上的上层 fluent API,更适合业务层组织 Prompt、模板参数、Advisor 和不同返回形式。

所以实际项目里,底层能力统一依赖 ChatModel,但大多数业务代码会直接面向 ChatClient 编写。

5.3 示例三:回答"你做过 Spring AI 项目吗"

一个较好的项目型回答:

我做过一个知识库问答方向的 Spring AI Demo,并把它按工程方式拆成了模型接入、问答服务、RAG 导入链路和日志监控几个部分。

模型层我先用 Ollama 做本地开发,再预留 OpenAI 接入;问答链路上用 ChatClient 统一组织 Prompt 和响应;知识库部分通过向量存储做最小 RAG;同时保留 token、耗时和检索文档数等观测信息。

在这个过程中我比较关注分层和排错,比如 RAG 效果差时我会先看检索是否命中,再看 Prompt 和模型,而不是直接换模型。

这类回答比"我写过一个接口"强很多。

5.4 示例四:回答"RAG 怎么做、怎么排错"

一个较好的回答:

我会把 RAG 分成导入链路和问答链路。

导入链路负责文档切分、embedding 和向量入库;问答链路负责将用户问题向量化、检索相关文档,再把检索结果注入 Prompt 或 Advisor。

如果效果不好,我不会先怀疑模型,而是先看检索文档是否相关、切分是否合理、topK 和 Prompt 注入方式是否合适。


6. 工程实践

6.1 企业里通常怎么问 Spring AI

企业面试里,通常不会只问"API 会不会写",更常见的是:

  1. 你为什么选 Spring AI 而不是直接 SDK?
  2. 你做过哪些 AI 工程能力,而不只是聊天?
  3. 你怎么做 Structured Output / Tool Calling / RAG?
  4. 你怎么排错?
  5. 如果上线后成本高、效果差、工具乱调怎么办?

所以准备面试时,要优先准备"工程问题回答"。

6.2 推荐的答题顺序

当你被问一个技术点时,推荐顺序是:

  1. 定义
  2. 作用
  3. 原理
  4. 场景
  5. 边界 / 风险

例如回答 Tool Calling,就不要停在"可以调用工具",而要补上:

  • 模型只发起调用请求
  • 应用侧执行工具
  • 要做权限和参数控制

6.3 一个真实面试场景

题目:

"如果让你做一个企业知识库助手,你会怎么设计?"

推荐回答骨架:

  1. 先定目标:是问答、摘要,还是流程辅助
  2. 模型接入:先用 Spring AI 统一抽象接 Provider
  3. 问答层:用 ChatClient 组织 Prompt
  4. 检索层:引入 embedding + vector store 做 RAG
  5. 工具层:对需要查实时数据的能力用 Tool Calling
  6. 监控层:记录 token、耗时、检索文档数、错误率
  7. 排错策略:把问题拆成接通、检索、生成、成本几层

这就比"我会用 Spring AI 做知识库问答"强得多。

6.4 企业最看重的不是"高级名词",而是稳定表达

很多候选人喜欢一上来讲:

  • Agent
  • MCP
  • 多模型路由
  • 推理链

但如果基础抽象和工程逻辑讲不稳,反而会减分。

更好的策略是:

  • 先把主线讲清
  • 再讲你掌握的进阶点
  • 永远围绕"为什么这样设计"

7. 常见误区

误区 1:面试准备就是背定义

不够。

面试官更关心你是否理解设计动机、使用边界和工程问题。

误区 2:项目题只要说"做过"就行

远远不够。

你要能讲架构、链路、问题、排错和权衡。

误区 3:功能说得越多越厉害

不一定。

如果说不清原理和分层,反而会暴露理解浅。

误区 4:中级就是会更多高级名词

不对。

中级更看重的是解释能力、设计能力和排错能力。

误区 5:只准备 Happy Path

风险很大。

Spring AI 很容易被追问错误场景和边界问题。

误区 6:回答时只讲"怎么做",不讲"为什么这样做"

这会让回答显得很机械。

中级面试更看重设计因果关系。


8. 面试题

基础题

  1. Spring AI 是什么?它解决了什么问题?
  2. ChatClientChatModel 的区别是什么?
  3. PromptChatOptionsChatResponse 各自负责什么?
  4. 为什么 Spring AI 更适合企业应用,而不是直接在业务代码里依赖模型 SDK?

原理题

  1. Spring AI 为什么要做统一抽象,而不是直接透传各家 SDK?
  2. starter、properties、自动配置是怎么串起来的?
  3. 为什么 Prompt 要按 role 组织 message?
  4. Advisor 为什么适合承载 Memory、RAG、Tool Calling?

实战题

  1. 你会如何实现一个 Structured Output 接口?
  2. Tool Calling 的执行闭环是什么?它的安全边界在哪里?
  3. 你会如何设计一个最小 RAG 闭环?
  4. 如果一个 RAG 系统效果差,你会怎么排错?

项目题

  1. 你做过 Spring AI 项目吗?请介绍一下架构和关键能力。
  2. 如果让你做一个企业知识库助手,你会怎么设计?
  3. 如果线上模型成本突然升高、回答质量下降,你会怎么定位?

9. 自测题

请你自己尝试回答:

  1. 你能否用 1 分钟清楚解释什么是 Spring AI?
  2. 你能否用 3 分钟讲清一次 Spring AI 调用链?
  3. 你能否解释 Structured Output、Tool Calling、RAG 三者分别解决什么问题?
  4. 你能否把一个项目讲成"目标 -> 架构 -> 关键能力 -> 问题 -> 优化"?
  5. 你能否回答"为什么不用直接 SDK,而选 Spring AI"?
  6. 你能否说出自己目前最弱的是概念、原理、实践还是排错?
  7. 你能否判断自己现在更像入门、初级还是中级?

10. 学完标志

学完这一阶段,你应该能做到:

  • 能稳定回答 Spring AI 的高频概念题和原理题
  • 能把 Structured Output、Tool Calling、RAG 讲成工程实践
  • 能把一个项目讲出分层、链路、问题和权衡
  • 能区分入门、初级、中级的能力边界
  • 已具备基础到中级面试的表达框架

第七阶段练习题

一、1 分钟表达练习

请你练习用 1 分钟回答:

text 复制代码
什么是 Spring AI?它解决了什么问题?

要求:

  • 不超过 3 句话
  • 必须包含"框架定位"和"工程价值"

二、3 分钟项目表达练习

请你假设自己做过一个"Spring AI 知识库助手"项目,并按下面结构讲一遍:

  1. 项目目标
  2. 技术选型
  3. 核心架构
  4. 关键能力
  5. 一个实际问题与排查过程

三、模拟问答练习

请你自己回答下面 3 个问题:

  1. 为什么 ChatClient 比直接 SDK 更适合业务层?
  2. Tool Calling 的安全边界在哪里?
  3. 如果 RAG 效果差,你第一步先查什么?

然后对照检查:

  • 你有没有讲"为什么"
  • 你有没有讲"工程边界"
  • 你有没有讲"排错思路"

回复 继续,我下一阶段按同样的 Markdown 结构,带你进入:

第八阶段:学习总结与知识闭环

1. 学什么

这一阶段不再新增核心功能,而是做三件更重要的事:

  1. 把整门技术的主干再收束一遍
  2. 把正确学习顺序再固定一遍
  3. 把"知识"真正转化成"能力"

这一节的目标是让你形成最终闭环:

能理解、能解释、能上手、能排错、能通过基础到中级面试。

这一阶段重点包括:

  • Spring AI 的整体知识主干
  • 正确学习顺序回顾
  • 必须掌握与知道即可的再划分
  • 企业里通常怎么真正使用它
  • 下一步继续深入应该学什么

必须吃透:

  • 学习主线一定是"聊天主线 -> 工程主线 -> 增强能力 -> 排错 -> 面试表达"
  • 真正掌握不是"会调接口",而是"会分层、会取舍、会定位问题"

先知道,后深入:

  • 多 Agent / 工作流编排
  • MCP 的深度生态使用
  • 复杂评测体系与 LLM-as-a-Judge
  • 生产级多模型路由与成本治理

2. 为什么重要

很多人学技术时,前面学得很多,最后却没有形成能力闭环。

典型表现是:

  • 看过很多概念
  • 写过一些 Demo
  • 真做项目还是发散
  • 一到面试表达就碎片化

所以最后这一阶段真正解决的问题是:

问题 1:知识没有主干

学过很多点,但彼此之间没连起来。

问题 2:没有优先级

不知道哪些必须掌握,哪些只是了解即可。

问题 3:不会迁移

学过的知识没法转成项目能力和面试表达能力。

这一节的意义,就是把前面七个阶段压缩成一条真正能落地的主线。


3. 核心概念

3.1 Spring AI 的知识主干

到这里,你应该把 Spring AI 总结成下面这条主线:

text 复制代码
模型接入
  ↓
ChatModel / ChatClient
  ↓
Prompt / ChatOptions / ChatResponse
  ↓
Structured Output / Tool Calling / RAG / Memory
  ↓
日志 / metadata / 排错 / 监控
  ↓
工程分层 / 面试表达 / 项目落地

这条主线里,前半部分是"调用模型",后半部分是"把模型变成工程能力"。

3.2 正确学习顺序再回顾

推荐你最终记住的顺序是:

  1. 先理解 Spring AI 的定位
  2. 再学 ChatModelChatClientPrompt
  3. 再学 starter、自动配置、properties
  4. 再学 Structured Output、Tool Calling、RAG
  5. 再学排错、监控和成本意识
  6. 最后训练项目表达和面试回答

这个顺序的本质是:

先学主干,再学增强;先学确定性,再学复杂性。

3.3 必须掌握 vs 知道即可

类型 内容
必须掌握 ChatClientChatModelPromptChatOptionsChatResponse
必须掌握 starter、properties、自动配置主线
必须掌握 Structured Output、Tool Calling、RAG 的最小闭环
必须掌握 分层设计、日志、token、排错方法
必须掌握 面试中的概念解释、原理解释、项目表达
知道即可 多 Agent、高级工作流编排
知道即可 复杂 rerank、query rewrite、评测平台
知道即可 深层源码细节、所有 Provider 差异
知道即可 复杂 MCP 生态和生产级多模型路由

3.4 企业里通常怎么用它

企业里更常见的落地方式,不是"做一个会聊天的页面",而是把 Spring AI 接进已有业务流程。

典型用法包括:

  • 智能问答
  • 结构化信息抽取
  • 内部知识库助手
  • 工单/订单/库存查询助手
  • AI 辅助表单生成与数据整理
  • 研发辅助工具

所以企业真正看重的是:

  • 可接入
  • 可治理
  • 可监控
  • 可排错
  • 可维护

3.5 学习本质

学 Spring AI 的本质,不是学"某家模型怎么调",而是学会:

  • 如何用 Spring 风格组织 AI 能力
  • 如何把不稳定的大模型能力纳入稳定工程体系
  • 如何把 Prompt、Tool、RAG、监控、排错串成完整应用

4. 原理解释

4.1 为什么正确顺序能大幅降低学习成本

如果你先学复杂 Agent,再回头补 ChatClient、Prompt、自动配置,你会一直觉得知识点很多、很碎。

但如果顺序正确:

  1. 先学最小聊天链路
  2. 再学框架机制
  3. 再学增强能力
  4. 再学排错和表达

你会发现后面很多能力只是"主干上的插件",而不是全新体系。

4.2 为什么必须区分"必须掌握"和"知道即可"

因为技术学习最容易出现两个极端:

  • 只会最浅的部分,做不了项目
  • 一头扎进太深的高级主题,反而主干没掌握

所以正确策略是:

  • 先把 80% 最常用、最有实战价值的内容吃透
  • 再根据业务场景选修更深主题

这也是工程学习里很重要的"主干优先"原则。

4.3 什么叫真正形成知识闭环

真正闭环至少要满足下面五个条件:

  1. 你能解释核心概念
  2. 你能写最小示例
  3. 你能做一个基础项目
  4. 你能对常见问题排错
  5. 你能在面试中稳定表达

缺少其中任何一项,都不算真正掌握。

4.4 下一步继续深入应该学什么

当你把当前笔记吃透后,推荐按这个顺序继续深入:

  1. 生产级 RAG

    包括 chunk 策略、metadata filter、rerank、query rewrite

  2. 观测与评测

    包括 token 成本、trace、LLM-as-a-Judge、质量评测

  3. MCP

    包括 MCP Client / Server、工具与资源标准化接入

  4. 源码阅读

    重点看 ChatClient、Prompt、Advisor、Provider 自动配置

  5. 生产治理

    包括限流、降级、重试、多模型选择、成本控制

4.5 如何把它真正转化成自己的能力

最有效的方法不是继续看更多文章,而是做下面这三件事:

  1. 自己手写一个最小项目
  2. 自己做一次从接入到排错的完整练习
  3. 自己录音或口述回答高频面试题

因为只有把"理解"转成"输出",知识才真正稳定。


5. 示例

5.1 终局版 30 秒总结

你最终应该能这样总结 Spring AI:

Spring AI 是一个用 Spring Boot 方式开发 AI 应用的框架,它把聊天模型、结构化输出、工具调用、RAG 和可观测性这些能力整合进统一抽象里。

它的核心价值不只是"能调模型",而是帮助 Java 团队把 AI 能力工程化、可维护、可监控地接入业务。

真正掌握它的标志,不是会写一个 Demo,而是能分层设计、能排错、能讲清为什么这样设计。

5.2 一个完整学习闭环示例

text 复制代码
看懂学习地图
  ↓
跑通最小聊天接口
  ↓
理解 ChatClient / Prompt / Response
  ↓
做 Structured Output
  ↓
做 Tool Calling
  ↓
做最小 RAG
  ↓
练习排错
  ↓
练习面试表达
  ↓
完成一个小项目

这个路径就是最值得重复复习的"闭环路径"。

5.3 一个真实工程场景

场景:你要做一个企业知识助手。

你真正会经历的是:

  1. 先接模型
  2. 再设计 Prompt 与返回结构
  3. 再决定是否需要 Tool 或 RAG
  4. 再加日志、token、监控
  5. 再处理错误场景
  6. 最后才是持续优化效果和成本

这正是这份学习路径想训练你的能力。


6. 工程实践

6.1 建议的最终学习落地动作

如果你想把这份笔记真正学完,建议你按下面顺序落地:

  1. 手写一个最小聊天接口
  2. 再手写一个 Structured Output 接口
  3. 再手写一个 Tool Calling 接口
  4. 再手写一个最小 RAG Demo
  5. 给这几个接口都补日志和基本排错信息
  6. 最后自己讲一遍项目架构

6.2 建议的复习方式

不要从头到尾机械重看。

更好的复习顺序是:

  1. 先看学习地图
  2. 再看第二、三阶段主干
  3. 再看第五、六阶段工程实践与排错
  4. 最后看第七阶段面试表达

这样复习效率更高。

6.3 你现在最该做的不是继续扩知识面

而是先用当前这份笔记完成一个最小项目。

因为对于大多数初学者来说,最大的短板不是"知道太少",而是"闭环太少"。


7. 常见误区

误区 1:学完很多概念就等于掌握了

不对。

真正掌握一定包含代码实践、排错和表达能力。

误区 2:继续看更多资料比做项目更重要

通常不是。

在主干已经明确之后,项目实践更能暴露真实短板。

误区 3:只有学高级主题才算进步

不一定。

把基础主干、工程分层和排错真正吃透,往往比追高级概念更有价值。

误区 4:面试准备和项目实践是两件分开的事

其实不是。

最好的面试素材往往就来自你真实做过、排过、优化过的项目。

误区 5:知识闭环就是把笔记看完

不是。

闭环的标志是"你能输出、能实现、能复盘、能改进"。


8. 面试题

  1. 如果让你用一句话概括 Spring AI 的核心价值,你会怎么说?
  2. Spring AI 的学习主干应该怎么排顺序?为什么?
  3. 为什么说真正掌握 Spring AI 不等于会写一个聊天接口?
  4. 企业里通常怎么把 Spring AI 接入实际业务?
  5. 你认为初级和中级 Spring AI 工程师的差别主要体现在哪里?

9. 自测题

  1. 你能否画出 Spring AI 的完整知识主干?
  2. 你能否说出哪些是必须掌握,哪些是知道即可?
  3. 你现在最薄弱的是接入、原理、工程实践、排错还是表达?
  4. 如果明天让你做一个最小项目,你会按什么顺序开始?
  5. 如果两周后要面试,你会优先复习哪几部分?

10. 学完标志

学完这一阶段,你应该能做到:

  • 能把整门 Spring AI 的知识主干压缩成一条清晰主线
  • 知道正确学习顺序和继续深入路径
  • 能区分哪些必须掌握,哪些暂时知道即可
  • 能把当前所学转成项目实践和面试表达
  • 已形成完整的学习闭环

Spring AI 学习评估体系

1. 入门达标标准

满足下面大部分条件,说明你达到入门:

  • 能解释 Spring AI 是什么,不是什么
  • 能说出 ChatClientChatModelPromptChatResponse 的基本职责
  • 能跑通一个最小聊天接口
  • 知道 starter、配置文件、模型接入的基本关系
  • 知道 Structured Output、Tool Calling、RAG 分别是什么

2. 初级达标标准

满足下面大部分条件,说明你达到初级:

  • 能独立接入一个本地或云端模型
  • 能写出一个 Structured Output 接口
  • 能做一个最小 Tool Calling 示例
  • 能做一个最小 RAG 闭环
  • 能按分层思路组织项目目录
  • 能排查常见的配置错误、Bean 注入错误、Prompt 问题
  • 能稳定回答基础面试题

3. 中级达标标准

满足下面大部分条件,说明你接近中级:

  • 能解释 Spring AI 的核心抽象和设计动机
  • 能讲清 starter、properties、自动配置主线
  • 能说明 Structured Output、Tool Calling、RAG 的适用边界和设计权衡
  • 能搭出一个带日志与基本监控的 AI 功能模块
  • 能按层排查问题,而不是到处猜
  • 能把项目讲成"目标 - 架构 - 能力 - 问题 - 优化 - 权衡"
  • 能在面试里回答基础到中级问题

4. 一套自测题

基础自测

  1. Spring AI 的定位是什么?
  2. ChatClientChatModel 的区别是什么?
  3. Prompt 为什么不是简单字符串?
  4. ChatResponse 为什么比纯文本更有工程价值?

进阶自测

  1. starter、properties、自动配置是怎么串起来的?
  2. Structured Output 适合解决什么问题?
  3. Tool Calling 的执行闭环是什么?
  4. RAG 的最小链路包括哪些步骤?

工程自测

  1. 如果 Bean 注入失败,你先查什么?
  2. 如果 RAG 效果差,你先查什么?
  3. 如果输出不稳定,你先看 Prompt、Options 还是模型?为什么?
  4. 如果要做一个企业知识库助手,你会怎么分层?

5. 一套面试题

概念题

  1. Spring AI 是什么?解决什么问题?
  2. ChatClientChatModelPromptChatOptionsChatResponse 各自职责是什么?
  3. 为什么 Spring AI 比直接依赖厂商 SDK 更适合企业项目?

原理题

  1. Spring AI 为什么要做统一抽象?
  2. starter、properties、autoconfiguration 是如何协同工作的?
  3. 为什么 Prompt 要按 role 组织 message?
  4. Advisor 为什么适合承载 RAG 和 Memory?

实战题

  1. 你会如何实现一个 Structured Output 接口?
  2. Tool Calling 的安全边界在哪里?
  3. 你会如何做一个最小 RAG 闭环?
  4. 如果线上输出质量波动,你会如何排查?

项目题

  1. 请介绍一个你做过的 Spring AI 项目或 Demo
  2. 如果让你做一个企业知识库助手,你的技术方案是什么?
  3. 如果系统成本升高、响应变慢,你如何定位问题?

6. 一套实战任务

按顺序完成下面 4 个任务:

任务 1:最小聊天接口

实现:

text 复制代码
GET /ai/ask?q=...

要求:

  • 能正常调用模型
  • 可切换本地 Ollama 或 OpenAI

任务 2:结构化输出接口

实现:

text 复制代码
GET /ai/summary?topic=...

要求:

  • 返回 Java 对象
  • 至少包含 definition / analogy / example

任务 3:工具调用接口

实现:

text 复制代码
GET /ai/time

要求:

  • 通过工具返回当前时间
  • 能解释工具执行闭环

任务 4:最小 RAG 问答

实现:

text 复制代码
GET /ai/qa?q=...

要求:

  • 预先导入知识文本到向量库
  • 接口能基于检索结果回答
  • 能观察检索效果

7. 一套项目任务

做一个完整小项目:

项目名称

Spring AI 企业知识助手

项目目标

  • 回答 Spring AI / Java / 内部文档相关问题
  • 对部分问题返回结构化结果
  • 对实时查询类问题支持工具调用

最小功能要求

  1. 普通问答
  2. Structured Output
  3. 一个最小工具
  4. 一个最小 RAG
  5. 基本日志与 token 观测

建议模块

  • controller
  • service
  • config
  • tool
  • rag
  • ingestion
  • model

验收标准

  • 能跑通
  • 能解释架构
  • 能演示工具调用
  • 能演示 RAG
  • 能说明一个你自己遇到过的排错问题

8. 对回答的评分标准

建议按 100 分评分:

维度 分值 评估点
概念理解 20 是否真的理解核心概念和边界
原理理解 20 是否能解释为什么这样设计
工程实践 20 是否能把能力落到代码和项目结构
排错能力 20 是否有分层排错思路
表达能力 20 是否能清楚、稳定地讲出来

可以按下面标准判断:

  • 90-100:接近中级,能讲原理、做项目、会排错
  • 75-89:达到初级,主线清晰,能独立做基础功能
  • 60-74:达到入门,概念知道但实践和表达还不稳
  • <60:说明主干还没有打牢,需要回到基础阶段补课

9. 如何根据错误结果反向补课

如果你在自测或面试中暴露出问题,可以按下面方式回补:

暴露问题 说明短板 回补阶段
说不清 Spring AI 是什么 地图和定位不清 第一阶段
分不清 ChatClient / ChatModel / Prompt 核心抽象不牢 第二阶段
说不清 starter 和自动配置 框架机制不清 第三阶段
说不清 Advisor / metadata / 模板渲染 底层设计不清 第四阶段
不会做 Structured Output / Tool / RAG 工程落地能力不足 第五阶段
遇到问题只会乱试 排错方法缺失 第六阶段
面试时回答发散、没有结构 表达框架不足 第七阶段

再进一步,你可以这样修复:

  1. 先回到对应阶段重读主干
  2. 立刻做一个最小代码练习
  3. 再用口头方式复述一遍
  4. 最后重新做同类自测题

这套"学 -> 写 -> 讲 -> 再测"的循环,是最快的补课方式。


到这里,这份 springai.md 已经完成了从:

  • 学习地图
  • 推荐路径
  • 八个阶段教学
  • 每阶段练习题
  • 最终评估体系

的一整套闭环内容。

相关推荐
做个文艺程序员2 小时前
Spring AI 1.1 三件套实战:Structured Output + Tool Calling + Memory 从踩坑到生产落地
java·大数据·人工智能
云烟成雨TD2 小时前
Spring AI 1.x 系列【21】ToolCallbackProvider 动态工具集成
java·人工智能·spring
杰克尼2 小时前
SpringCloud_day04
后端·spring·spring cloud
beyond阿亮2 小时前
OpenClaw接入企业微信
人工智能·ai·企业微信·openclaw
芯智工坊2 小时前
第4章 Mosquitto命令行工具快速上手
网络·人工智能·mqtt·开源
咚咚王者2 小时前
人工智能之语音领域 语音处理 第五章 语音处理实践落地与常见问题解决
人工智能
VBsemi-专注于MOSFET研发定制2 小时前
面向电动车直流快充桩的功率MOSFET选型分析——以高功率密度、高可靠电源与模块化系统为例
人工智能
夏沫の梦2 小时前
Agent Skills技术详解与实战
人工智能·a·skill
财迅通Ai2 小时前
科创芯片ETF(589100)大涨超3.5%,AI+涨价潮点燃芯片景气
人工智能·科创芯片etf