Spring AI 2.0 学习指南企业级智能应用开发实践 环境准备 速查 ⌂ 全部教程

Spring AI 2.0 学习指南
从零到「企业知识问答 + 工单辅助系统」

这份指南把《Spring AI 框架与企业级智能应用开发实践 V2.0》的 11 个章节,拆成一条「看得懂、跑得通、抄得走」的路线: 每一章都告诉你 要学什么 → 环境怎么配 → 代码怎么写 → 为什么这么写 → 跑起来看到什么 → 踩坑怎么排。 所有代码示例都是可以直接复制进 IDEA 运行的完整片段,不是伪代码。

JDK 21 Spring Boot 4.x Spring AI 2.0 Maven MySQL 8 Redis 7 PostgreSQL 16 + pgvector Milvus Docker Micrometer / OpenTelemetry MCP Server
11
章节 · 全部独立可运行
60–80h
建议总学时(含动手)
7
需要启动的基础设施容器
1
最终端到端交付项目

0.1怎么用这份指南

先明确一条原则:这门课不是「读」出来的,是「跑」出来的。大模型应用开发的特点决定了——你不上手调用一次,永远不知道 API 长什么样;你不亲手把文档灌进向量库,永远理解不了 RAG 为什么检索不到。

❌ 低效的学法

  • 把 11 章当成 11 篇技术文档从头读到尾,读完就忘。
  • 代码只复制不抄写,报错全靠搜索引擎。
  • 跳过环境准备,第 4 章装数据库时全线崩溃。
  • 每章独立看完就过,不回头看上一章的成果。

✅ 推荐的学法

  • 每章三段式:读概念(20%)→ 抄代码跑通(50%)→ 改需求做实验(30%)。
  • 代码一定手敲一遍,注释要自己重写,写不出来说明没懂。
  • 先一次性把环境全配好(本章 0.4 节),后面 10 章零中断。
  • 每章验收物留着,第 11 章要把它们组装成一个系统。
关于版本:本指南全部代码以现有最新版 Spring AI 2.0.1 为基准编写 (2.0.0 GA 发布于 2026-06-12,2.0.1 补丁发布于 2026-08-21)。 2.0 是一次架构级重构,不是小版本升级,核心变化有六条,先记住它们能省下大量踩坑时间:

2.0 必须知道的六个变化

  1. 底座换代:要求 Spring Boot 4.0/4.1 + Spring Framework 7.0,Java 17 起。Boot 3.x 的项目不能直接用 2.0。
  2. 工具调用循环上移:从「藏在各 ChatModel 内部」提升为 Advisor 链中的 ToolCallingAdvisor,可选可替换。
  3. internalToolExecutionEnabled 被删除:想自己控制循环,改用 AdvisorParams.toolCallingAdvisorAutoRegister(false)。
  4. 结构化输出可自纠错:.entity(X.class, spec -> spec.validateSchema()) 会在解析失败时把错误回喂给模型并重试。
  5. 记忆的 conversationId 变成必填:不传直接抛 IllegalArgumentException,没有默认值兜底。
  6. 配置去掉了 .options 段:如 spring.ai.openai.embedding.model(旧写法是 embedding.options.model)。

如果报「找不到符号」,按这个顺序查

  1. 打开 https://docs.spring.io/spring-ai/reference/2.0/upgrade-notes.html,这里列全了 2.0 的破坏性变更。
  2. 在 IDEA 里 Ctrl+Alt+B 看接口的实现类,确认当前实际 API 名。
  3. 用 IDE 的 yml 补全展开 spring.ai.*,核对配置键是否还叫这个名字。
  4. 最后才去搜索引擎——网上大量 Spring AI 内容是 1.x 的,容易看错。

你已经学过的 1.x 教程并非作废:概念(RAG、工具调用、记忆、Advisor)完全一致,变的只是 API 名与配置写法。

2.0.1 又补了一批变更,升级时别漏。2026-08-21 发布的 2.0.1 除修 bug 外还包含 「additional 2.0.1 breaking changes」,与本课程相关的有:
· 工具调用次数上限可配置(spring.ai.tools.limits.*,见 7.4 节末尾)——这条对 Agent 很重要;
· Media builder 改为强类型 data 重载(第 2 章多模态部分);
· TokenTextSplitter 的 builder 参数开始做校验(第 5 章切分部分,参数写错会直接报错而不是静默生效);
· PagePdfDocumentReader 支持页码范围;
· OpenAI 转写(transcription)相关选项与响应字段有增补。
完整的 2.0.1 变更清单看 https://docs.spring.io/spring-ai/reference/2.0/upgrade-notes.html。

0.211 章学习路线

这 11 章不是并列关系,而是层层叠加的:第 1 章拿到「模型能说话」的能力,第 2–3 章把它变成「能按格式说话」,第 4–5 章给它接上「自己的知识」,第 6–8 章给它装上「记忆、工具和外部系统」,第 9 章把它组织成「能自己规划的执行体」,第 10 章保证它「出问题能看得见」,第 11 章把所有东西拼成一个真实系统。

阶段一 · 打通「能说」:第 1–3 章约 12h
Chapter 1 建立 Spring AI 的核心抽象心智模型(ChatModel / ChatClient / Prompt / Message),跑通第一个 Hello AI 服务。
Chapter 2 学会控制输入:PromptTemplate 参数化、System/User/Assistant 消息分工、多轮上下文。
Chapter 3 学会控制输出:把自由文本变成 Java 对象(结构化输出),用 Advisor 做横切治理(日志、拦截、改写)。
阶段验收:能用自然语言 + 严格 JSON 两种方式稳定拿到模型输出。
阶段二 · 接上「知识」:第 4–5 章约 16h
Chapter 4 理解 Embedding 与向量检索:文本怎么变成 1024 维向量,pgvector / Milvus 怎么建库建表,VectorStore API 怎么用。
Chapter 5 串起 RAG 全链路:加载 → 切分 → 嵌入 → 存储 → 检索 → 重排 → 组装提示 → 生成 → 引用溯源。
阶段验收:能对一份 50 页 PDF 提问,并给出带出处页码的回答。
阶段三 · 装上「记忆与手脚」:第 6–8 章约 20h
Chapter 6 会话隔离(谁在跟谁说话)+ 多模型路由与降级(便宜模型干粗活,贵模型干细活,贵模型挂了自动兜底)。
Chapter 7 Tool Calling:让模型能查数据库、调接口,理解「模型只输出意图,执行由你的代码负责」这条铁律。
Chapter 8 MCP:把工具从「写在同一个工程里」升级为「跨进程、可复用的标准协议」。
阶段验收:一个能记住用户是谁、能自己决定去查订单还是查天气的助手。
阶段四 · 变成「系统」:第 9–11 章约 24h
Chapter 9 Agent:任务拆解 → 工具编排 → 执行循环 → 人工确认,自己写一个 ReAct 循环。
Chapter 10 可观测性与评估:Trace / Span / Token 成本 / 效果评测集,把「玄学调参」变成「数据驱动」。
Chapter 11 综合项目:需求 → 架构 → 数据模型 → 部署 → 验收,交付企业知识问答与工单辅助系统。
阶段验收:能部署上线、能演示、能回答「成本多少、准确率多少、怎么证明」。

章节依赖关系一览

章章节核心要学的东西(一句话)本章产出物依赖
1Spring AI 入门Spring AI 的抽象分层与最小可运行调用链Hello AI 服务—
2提示词与对话用模板和角色消息精确控制输入智能客服对话接口1
3结构化输出与 Advisors把文本输出约束成对象;用 Advisor 做统一治理订单信息提取1,2
4嵌入模型与向量数据库向量化原理 + 向量库读写 + 相似度检索文档向量索引1
5RAG知识增强生成的全链路与引用溯源知识库问答3,4
6记忆与多模型会话状态管理与模型路由/降级多轮工单咨询2,5
7工具调用让模型调用你的 Java 方法(含边界处理)订单/天气查询工具3,6
8MCP工具的外部化与标准化(Client / Server)MCP 日程或文件助手7
9智能体任务拆解、编排、循环执行、人工确认工单处理智能体7,8
10可观测性与评估Trace / 指标 / 成本 / 效果评测调用链与评测报告9
11综合项目端到端工程化:架构、部署、验收知识问答 + 工单系统全部

0.3学时与节奏建议

🚀 冲刺版(4 周 / 全职)

周一至周五每天 6h:上午 1 章概念 + 敲代码,下午做实验和排错。 周六做本周章节的综合小练习,周日复盘 + 预习下一章。
适合:赶项目、有 Java 经验

📚 标准版(10 周 / 业余)

每周 1–2 章,每章配 2–3 个自测题。第 5、7、9、11 章各多留一周, 因为 RAG、工具调用、Agent、综合项目是难度陡增点。
适合:在校学生、在职转岗

🎯 应试/教学版(一学期)

按 16 教学周排:每章 1–1.5 周,期中做第 1–5 章串讲实验, 期末以第 11 章项目作为大作业答辩。
适合:高校课程、训练营

每章请固定留出 30% 的时间做「改需求」实验。例如第 3 章跑通订单提取后, 把 OrderInfo 加一个 List<String> tags 字段、把金额改成 BigDecimal、 给它加 JSR-303 校验,观察模型和框架各有什么反应。这一步是区分「会抄」和「会做」的分水岭。

0.4环境准备(一次性配好,后面 11 章零中断)

这一节是整份指南最容易被跳过、也最不能跳过的部分。请严格按 0.4.1 → 0.4.8 的顺序执行,每一步都有验证命令,验证不通过不要往下走。

统一约定(后面所有章节都按这个来,请先确认):
  • 工作根目录:D:\springai-lab(Windows)或 ~/springai-lab(macOS/Linux)。位置可以随意,本课程统一用它举例 —— 你放在别处也行,但后面所有命令里的路径请按自己的实际位置替换。不要放 C 盘,Docker 镜像和数据卷会吃掉几十 GB。
  • 统一包名:com.example.springai;统一端口:应用 8080。
  • 所有密钥一律走环境变量,绝不写死在 application.yml 里提交到 Git。
  • MySQL 端口 3306、Redis 6379、PostgreSQL 5432、Milvus 19530、Zipkin 9411。

0.4.1 JDK 21(2.0 的硬性底线其实是 17)

先把一件事说清楚,免得你搜到错误信息:Spring AI 2.0 并不强制要求 JDK 21。 网上有中文博客写「2.0 强制 JDK 21、不再支持 Java 17」——这个说法是错的。 这类文章大多写于 2026 年初、基于 2.0.0-M1/M2 里程碑版本,而且引用的还是 1.x 时代的依赖名 (如 spring-ai-openai-spring-boot-starter),不建议参考。以官方原文为准:
  • Spring Boot 官方系统要求页:「Spring Boot 4.1.1 requires at least Java 17 and is compatible with versions up to and including Java 26.」
  • Spring AI 2.0.0-M1 Release Notes:「Java 17 is still the baseline for consuming the Spring AI 2.x binaries」——Java 21 只在你从源码构建 Spring AI 自身时才需要。

所以结论是:底线 JDK 17,用 17 运行时完全没问题。 本课程统一用 JDK 21(LTS),这是一个教学选择而非硬性要求,理由有三条: 虚拟线程在 21 已正式化(17 还只是预览)、生态兼容性最稳、IDEA 的静态分析提示更准。 你的团队如果已在用 JDK 25 也完全可以——Spring Boot 4.1.1 支持到 Java 26,AI 场景下虚拟线程的吞吐收益更明显。

先确认一件事:你现有的项目能不能上 2.0? Spring AI 2.0 只支持 Spring Boot 4.1,与 Spring Boot 3.x 的向后兼容是断开的。 如果你的存量项目还停在 Boot 3.5.x,官方建议继续用 Spring AI 1.1.x 维护版本, 先把 Boot 4 的迁移做掉,再切到 Spring AI 2.0。新项目、教学项目直接上 Boot 4.1 + Spring AI 2.0。
  1. 下载安装:推荐 Eclipse Temurin 21(https://adoptium.net)或 Oracle JDK 21。
    Windows 选 .msi,安装时勾选 Set JAVA_HOME variable 与 Add to PATH。
  2. 验证:
    java -version
    # 期望输出(关键是 21):
    # openjdk version "21.0.5" 2024-10-15 LTS
    # OpenJDK Runtime Environment Temurin-21.0.5+11 (build 21.0.5+11-LTS)
    
    echo %JAVA_HOME%      # Windows CMD,应指向 JDK 目录(不是 bin,不是 jre)
    echo $JAVA_HOME       # Git Bash / macOS / Linux
  3. 为什么课程选 21 而不是 17:
    · 第 9 章 Agent 并行调用多个工具会用 Executors.newVirtualThreadPerTaskExecutor()(JDK 21 才正式化,17 是预览);
    · 第 3 章结构化输出大量使用 record + 密封接口 + Record Pattern;
    · Spring AI 2.0 全代码库加了 JSpecify 空安全注解,IDEA 的高版本 JDK 对这类静态分析的提示更准。
常见坑:装完 JDK 21 但 IDE 里仍报 java: invalid target release: 21。 原因:机器上还有 JDK 8/11,JAVA_HOME 指向了旧的。解决:改环境变量后重启 IDEA, 并在 IDEA 的 File → Project Structure → SDK 里手动选中 21。 另外 maven-compiler-plugin 也要显式声明 21(见 0.4.7)。

0.4.2 Maven 3.9+

# 验证
mvn -v
# Apache Maven 3.9.9 (或更高)
# Maven home: D:\dev\apache-maven-3.9.9
# Java version: 21.0.5, vendor: Eclipse Adoptium

接着配置国内镜像,否则拉 Spring AI 依赖会很慢甚至超时。编辑 ~/.m2/settings.xml(没有就新建):

<?xml version="1.0" encoding="UTF-8"?>
<settings xmlns="http://maven.apache.org/SETTINGS/1.0.0">
  <mirrors>
    <mirror>
      <id>aliyun-central</id>
      <name>Aliyun Public Mirror</name>
      <url>https://maven.aliyun.com/repository/public</url>
      <mirrorOf>central</mirrorOf>
    </mirror>
    <mirror>
      <!-- Spring AI 的里程碑/快照版本需要这条;正式版走 aliyun 即可 -->
      <id>spring-milestones</id>
      <url>https://repo.spring.io/milestone</url>
      <mirrorOf>spring-milestones</mirrorOf>
    </mirror>
  </mirrors>
</settings>
验证镜像是否生效:执行 mvn help:evaluate -Dexpression=settings.mirrors -q -DforceStdout, 或在拉依赖时观察控制台是否出现 Downloading from aliyun-central。

0.4.3 IntelliJ IDEA 与必备插件

配置项 / 插件作用怎么装 / 在哪设
Lombok省掉 getter/setter,示例代码更短更聚焦Settings → Plugins → 搜 Lombok;同时开启 Annotation Processors → Enable
Spring Boot 助手(可选)yml 配置项自动补全、@ConfigurationProperties 跳转Settings → Plugins → Spring
HTTP Client / Apifox(可选)直接跑 .http 文件测接口,不用 PostmanIDEA 内置 HTTP Client 即可
Maven Runner → JDK保证 Maven 用 JDK 21 编译Settings → Build Tools → Maven → Runner → JRE: 21
编码防止中文乱码Settings → Editor → File Encodings 全部设为 UTF-8

0.4.4 Docker 与全套中间件

第 4 章之后要用到 5 个中间件,全部用 Docker 起,不要本机装(本机装 MySQL + PostgreSQL + Redis 是最常见的翻车点)。Windows/macOS 装 Docker Desktop;Linux 装 docker engine + compose 插件。

验证 Docker:

docker version
docker compose version   # 需要 v2,命令是 "docker compose" 而不是 "docker-compose"

在 D:\springai-lab 下创建 docker-compose.yml。这份文件从第 4 章用到第 11 章,请一次配好:

# docker-compose.yml —— Spring AI 课程全套基础设施
services:

  # ---------- 关系型数据库:存业务数据(工单、用户、会话元信息) ----------
  mysql:
    image: mysql:8.4
    container_name: sai-mysql
    ports: ["3306:3306"]
    environment:
      MYSQL_ROOT_PASSWORD: root123456
      MYSQL_DATABASE: springai_lab
      TZ: Asia/Shanghai
    command:
      - --character-set-server=utf8mb4
      - --collation-server=utf8mb4_unicode_ci
    volumes: ["mysql-data:/var/lib/mysql"]
    healthcheck:
      test: ["CMD", "mysqladmin", "ping", "-h", "localhost", "-proot123456"]
      interval: 10s
      retries: 10

  # ---------- 缓存:存会话记忆、限流、幂等键 ----------
  redis:
    image: redis:7.4-alpine
    container_name: sai-redis
    ports: ["6379:6379"]
    command: ["redis-server", "--appendonly", "yes", "--requirepass", "redis123456"]
    volumes: ["redis-data:/data"]

  # ---------- 向量数据库方案 A:PostgreSQL + pgvector(轻量,推荐先学这个) ----------
  pgvector:
    image: pgvector/pgvector:pg16
    container_name: sai-pgvector
    ports: ["5432:5432"]
    environment:
      POSTGRES_USER: ai
      POSTGRES_PASSWORD: ai123456
      POSTGRES_DB: vectordb
      TZ: Asia/Shanghai
    volumes:
      - pgvector-data:/var/lib/postgresql/data
      # 首次启动自动执行:创建扩展 + 建表
      - ./init/pgvector-init.sql:/docker-entrypoint-initdb.d/init.sql:ro

  # ---------- 向量数据库方案 B:Milvus 单机版(大规模,第 4/5/11 章用它做对比) ----------
  etcd:
    image: quay.io/coreos/etcd:v3.5.16
    container_name: sai-etcd
    environment:
      - ETCD_AUTO_COMPACTION_MODE=revision
      - ETCD_AUTO_COMPACTION_RETENTION=1000
      - ETCD_QUOTA_BACKEND_BYTES=4294967296
      - ETCD_SNAPSHOT_COUNT=50000
    command: etcd -advertise-client-urls=http://etcd:2379 -listen-client-urls http://0.0.0.0:2379 --data-dir /etcd
    volumes: ["etcd-data:/etcd"]

  minio:
    image: minio/minio:RELEASE.2024-09-13T20-26-02Z
    container_name: sai-minio
    environment:
      MINIO_ROOT_USER: minioadmin
      MINIO_ROOT_PASSWORD: minioadmin
    command: minio server /minio_data --console-address ":9001"
    ports: ["9000:9000", "9001:9001"]
    volumes: ["minio-data:/minio_data"]

  milvus:
    image: milvusdb/milvus:v2.4.15
    container_name: sai-milvus
    command: ["milvus", "run", "standalone"]
    environment:
      ETCD_ENDPOINTS: etcd:2379
      MINIO_ADDRESS: minio:9000
    ports: ["19530:19530", "9091:9091"]
    depends_on: [etcd, minio]
    volumes: ["milvus-data:/var/lib/milvus"]

  # ---------- 链路追踪后端(第 10 章用来查看 Trace) ----------
  zipkin:
    image: openzipkin/zipkin:3
    container_name: sai-zipkin
    ports: ["9411:9411"]

volumes:
  mysql-data:
  redis-data:
  pgvector-data:
  etcd-data:
  minio-data:
  milvus-data:

创建 pgvector 的初始化脚本 init/pgvector-init.sql:

-- init/pgvector-init.sql
-- 1) 启用向量扩展。没这一步后续建 vector 列会直接报错。
CREATE EXTENSION IF NOT EXISTS vector;

-- 2) 建一张「通用文档向量表」,第 4、5、11 章都复用它。
--    1536 维 = OpenAI text-embedding-3-small 的维度;
--    如果你用 BGE / text-embedding-3-large,要改成 1024 / 3072。
CREATE TABLE IF NOT EXISTS vector_store (
    id        UUID        PRIMARY KEY DEFAULT gen_random_uuid(),
    content   TEXT,
    metadata  JSON,
    embedding VECTOR(1536)
);

-- 3) HNSW 索引:近似最近邻检索,比全表扫描快几个数量级。
--    vector_cosine_ops 对应「余弦距离」,和 Spring AI 默认的 COSINE_DISTANCE 保持一致。
CREATE INDEX IF NOT EXISTS idx_vector_store_hnsw
    ON vector_store USING hnsw (embedding vector_cosine_ops);
Milvus 不是必须的。Milvus standalone 会额外拉起 etcd + minio,内存占用 2–4 GB。 如果你的电脑只有 16 GB 内存,请用 docker compose up -d mysql redis pgvector zipkin 只起必要的四个,Milvus 相关章节改成读代码 + 看对比表,或用 --profile 按需启动。

启动与验证:

cd D:/springai-lab

# 只起核心服务(推荐配置一般的同学)
docker compose up -d mysql redis pgvector zipkin

# 全部起(含 Milvus)
docker compose up -d

# 看状态,等 STATUS 变成 healthy
docker compose ps

# 逐个连通性验证
docker exec -it sai-mysql mysql -uroot -proot123456 -e "SELECT VERSION();"
docker exec -it sai-redis redis-cli -a redis123456 ping        # 期望 PONG
docker exec -it sai-pgvector psql -U ai -d vectordb -c "\dx"    # 应看到 vector 扩展
curl http://localhost:9411/health                               # Zipkin
四个高频坑:
  1. 端口被占用(Bind for 0.0.0.0:3306 failed):本机已装 MySQL。要么停掉本机服务 (Windows:services.msc 停 MySQL80),要么把 compose 里改成 "13306:3306" 并同步改应用配置。
  2. Windows 下 Docker 启动失败:需要开启 WSL2 与虚拟化(BIOS 里的 VT-x/AMD-V)。 wsl --update 后重启。
  3. 镜像拉不动:在 Docker Desktop → Settings → Docker Engine 里配镜像加速器,或改用国内 registry 前缀。
  4. pgvector 表没建出来:docker-entrypoint-initdb.d 只在数据卷为空时执行。 如果你先起过容器再放脚本,需要 docker compose down -v 清卷重来(会删数据,注意)。

0.4.5 大模型服务与密钥

你需要至少一个可用的模型服务。Spring AI 的一大优势是「同一套 API 换模型只改配置」,所以课程里我们会同时配好两三个,用来演示第 6 章的多模型路由。三条路线任选:

2.0 的模型支持面收敛了,选型前先看一眼。 2.0 核心内置支持的 Chat 模型提供方是这 7 家:OpenAI、Anthropic、Amazon Bedrock、Google GenAI、Mistral AI、DeepSeek、Ollama。 其中 OpenAI / Anthropic / Google 已改为直接使用厂商官方 Java SDK(不再自维护 HTTP 实现),所以厂商新特性跟进更快。
被移出主仓库的有:Azure OpenAI(已并入 spring-ai-openai,用 deployment 方式访问)、 智谱 AI(ZhipuAI)、OCI GenAI、Azure Cosmos DB、Vertex AI(仅保留 embedding), 这些改用独立仓库或厂商自维护模块。同时 MiniMax 走 Anthropic 兼容协议访问。 如果你原本打算用智谱,请改选其他家,或引它自己的独立集成仓库。
方案适用场景关键配置
云端 API
(OpenAI / DeepSeek / 通义千问 / Kimi 等)
效果最好、上手最快,适合课堂与作业。绝大多数国内厂商都兼容 OpenAI 协议,可以复用同一个 starter。 只需 base-url + api-key + model 三项
Anthropic Claude
2.0 原生 SDK
需要长上下文、强推理;2.0 已换成官方 anthropic-java SDK,并支持 prompt caching、thinking 展示、内置联网搜索。 换 spring-ai-starter-model-anthropic,配 spring.ai.anthropic.api-key
Ollama 本地 不想花钱、断网环境演示、需要保证数据不出内网。 本机跑 ollama serve,默认 http://localhost:11434
混合(推荐) 云端做强模型(规划、复杂推理),本地做弱模型(分类、摘要、向量化)。第 6 章路由实验最理想。 两个 starter 共存;2.0 下注入多模型 ChatClient 要用 ChatClientBuilderConfigurer 才能保留可观测性

方案一:云端 API(以 DeepSeek + 通义千问为例,均兼容 OpenAI 协议)

设置环境变量。Windows 用 PowerShell(永久生效):

# 用户级环境变量,重启终端后生效
[Environment]::SetEnvironmentVariable("OPENAI_API_KEY", "sk-你的DeepSeek密钥", "User")
[Environment]::SetEnvironmentVariable("DASHSCOPE_API_KEY", "sk-你的通义密钥", "User")

# 验证(重开一个终端窗口)
echo $env:OPENAI_API_KEY

macOS / Linux(写入 ~/.zshrc 或 ~/.bashrc,然后 source):

echo 'export OPENAI_API_KEY="sk-你的DeepSeek密钥"' >> ~/.zshrc
echo 'export DASHSCOPE_API_KEY="sk-你的通义密钥"' >> ~/.zshrc
source ~/.zshrc
echo $OPENAI_API_KEY
为什么要用环境变量?Spring Boot 的配置优先级里,环境变量高于 application.yml, 所以你可以在 yml 里写 api-key: ${OPENAI_API_KEY},本地运行靠环境变量注入, 容器部署靠 K8s Secret / Docker -e 注入,代码零改动、密钥永不出现在仓库里。

方案二:Ollama 本地模型

# 1. 安装:https://ollama.com/download ,装完验证
ollama --version

# 2. 拉取模型(按需,注意磁盘占用)
ollama pull qwen2.5:7b            # 通用对话,约 4.7GB
ollama pull llama3.1:8b           # 备选
ollama pull nomic-embed-text      # 向量模型,约 274MB —— 第 4 章要用!

# 3. 验证服务可用
curl http://localhost:11434/api/tags

# 4. 命令行试聊一句
ollama run qwen2.5:7b "用一句话解释什么是向量数据库"
本地模型的取舍:7B 模型在「结构化输出」和「工具调用」上的稳定性明显弱于云端大模型。 建议:第 3、7、9 章(结构化输出、工具调用、Agent)用云端模型, 其余章节用本地模型也够;向量化一律推荐本地 nomic-embed-text / BGE,因为文档量大时走 API 又慢又贵。

0.4.6 创建项目骨架

用 Spring Initializr 生成,或直接手写 pom.xml。课程统一一个工程,11 章用不同的包名分目录:

springai-lab/ ├── docker-compose.yml # 0.4.4 那份 ├── init/pgvector-init.sql # 0.4.4 那份 ├── src/main/java/com/example/springai/ │ ├── SpringAiLabApplication.java # 启动类 │ ├── common/ # 全局:异常处理、统一响应、配置类 │ ├── ch01/ # 第 1 章:Hello AI 服务 │ ├── ch02/ # 第 2 章:提示词与对话 │ ├── ch03/ # 第 3 章:结构化输出与 Advisor │ ├── ch04/ … ch11/ # 依此类推 │ └── mcp/ # 第 8 章:MCP Server 独立模块(可选,单独工程) ├── src/main/resources/ │ ├── application.yml │ ├── application-dev.yml # 开发:云端模型 │ ├── application-local.yml # 开发:Ollama │ ├── mcp-servers.json # 第 8 章 MCP 客户端配置 │ ├── docs/ # 第 5 章知识库原始文档(PDF/MD/TXT) │ └── prompts/ # 第 2 章:提示词模板文件(可选,外置更好维护) └── src/test/java/com/example/springai/ # 单元测试 + 第 10 章评测集

0.4.7 一份可以直接用的 pom.xml

这是整个课程通用的依赖清单。你不用一次全打开,注释里标了「第 N 章」的可以到那一章再取消注释——但建议直接全部保留,Maven 会一次性把依赖下好,避免后面反复等下载。

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0">
  <modelVersion>4.0.0</modelVersion>

  <parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>4.1.1</version>      <!-- 以 start.spring.io 当前稳定版为准 -->
    <relativePath/>
  </parent>

  <groupId>com.example</groupId>
  <artifactId>springai-lab</artifactId>
  <version>1.0.0</version>
  <name>springai-lab</name>

  <properties>
    <java.version>21</java.version>
    <!-- ★ 版本变量:升级 Spring AI 只改这一行 -->
    <spring-ai.version>2.0.1</spring-ai.version>
  </properties>

  <dependencies>

    <!-- ========== 基础 Web / 工具 ========== -->
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-webmvc</artifactId>
    </dependency>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-validation</artifactId>  <!-- 第3章:输出校验 -->
    </dependency>
    <dependency>
      <groupId>org.projectlombok</groupId>
      <artifactId>lombok</artifactId>
      <optional>true</optional>
    </dependency>

    <!-- ========== 第 1 章:核心 + 模型接入 ========== -->
    <dependency>
      <groupId>org.springframework.ai</groupId>
      <artifactId>spring-ai-starter-model-openai</artifactId>   <!-- OpenAI 及所有兼容协议 -->
    </dependency>
    <dependency>
      <groupId>org.springframework.ai</groupId>
      <artifactId>spring-ai-starter-model-ollama</artifactId>   <!-- 第6章:本地模型做路由/降级 -->
    </dependency>

    <!-- ========== 第 2、6 章:会话记忆持久化 ========== -->
    <dependency>
      <groupId>org.springframework.ai</groupId>
      <artifactId>spring-ai-starter-model-chat-memory-repository-jdbc</artifactId>
    </dependency>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-jdbc</artifactId>
    </dependency>
    <dependency>
      <groupId>com.mysql</groupId>
      <artifactId>mysql-connector-j</artifactId>
      <scope>runtime</scope>
    </dependency>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-data-redis</artifactId>  <!-- 第6章:Redis 存记忆 -->
    </dependency>

    <!-- ========== 第 4、5 章:向量库(两种方案,二选一或都留) ========== -->
    <dependency>
      <groupId>org.springframework.ai</groupId>
      <artifactId>spring-ai-starter-vector-store-pgvector</artifactId>
    </dependency>
    <dependency>
      <groupId>org.springframework.ai</groupId>
      <artifactId>spring-ai-starter-vector-store-milvus</artifactId>
    </dependency>

    <!-- ========== 第 5 章:RAG 用的 Advisor + 文档解析 ========== -->
    <dependency>
      <groupId>org.springframework.ai</groupId>
      <artifactId>spring-ai-vector-store-advisor</artifactId>  <!-- QuestionAnswerAdvisor 等 -->
    </dependency>
    <dependency>
      <groupId>org.springframework.ai</groupId>
      <artifactId>spring-ai-tika-document-reader</artifactId>   <!-- 读 PDF/Word/HTML/PPT -->
    </dependency>
    <dependency>
      <groupId>org.springframework.ai</groupId>
      <artifactId>spring-ai-markdown-document-reader</artifactId>
    </dependency>

    <!-- ========== 第 8 章:MCP(2.0 起 MCP Java SDK 已升到 1.0.x 线) ========== -->
    <dependency>
      <groupId>org.springframework.ai</groupId>
      <artifactId>spring-ai-starter-mcp-client</artifactId>     <!-- 作为 MCP 客户端(Host 侧) -->
    </dependency>
    <dependency>
      <!-- 把自己的能力暴露成 MCP Server:WebMVC 版本即可,无需额外引 transport -->
      <groupId>org.springframework.ai</groupId>
      <artifactId>spring-ai-starter-mcp-server-webmvc</artifactId>
    </dependency>

    <!-- ========== 2.0 新增:工具很多时用它做渐进式披露(第 7 章) ========== -->
    <dependency>
      <groupId>org.springframework.ai</groupId>
      <artifactId>spring-ai-starter-tool-search-advisor</artifactId>
      <!-- 工具数 < 15 时不需要它;接了很多 MCP Server 再打开,能省 34%~64% token -->
    </dependency>

    <!-- ========== 第 10 章:可观测性 ========== -->
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-actuator</artifactId>
    </dependency>
    <dependency>
      <groupId>io.micrometer</groupId>
      <artifactId>micrometer-tracing-bridge-otel</artifactId>
    </dependency>
    <dependency>
      <groupId>io.opentelemetry</groupId>
      <artifactId>opentelemetry-exporter-zipkin</artifactId>
    </dependency>
    <dependency>
      <groupId>io.micrometer</groupId>
      <artifactId>micrometer-registry-prometheus</artifactId>
    </dependency>

    <!-- ========== 测试 ========== -->
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-test</artifactId>
      <scope>test</scope>
    </dependency>
    <dependency>
      <groupId>org.springframework.ai</groupId>
      <artifactId>spring-ai-spring-boot-testcontainers</artifactId>
      <scope>test</scope>
    </dependency>
  </dependencies>

  <dependencyManagement>
    <dependencies>
      <!-- ★ 关键:导入 BOM 后,上面所有 spring-ai-* 依赖都不用写版本号 -->
      <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>

  <build>
    <plugins>
      <plugin>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-maven-plugin</artifactId>
      </plugin>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-compiler-plugin</artifactId>
        <configuration>
          <release>21</release>
          <annotationProcessorPaths>
            <path>
              <groupId>org.projectlombok</groupId>
              <artifactId>lombok</artifactId>
            </path>
          </annotationProcessorPaths>
        </configuration>
      </plugin>
    </plugins>
  </build>
</project>
2.0 的依赖坐标有哪些变化?命名体系本身没再大改(spring-ai-starter-model-* 这一套继续有效), 但有几处必须注意:
  • 模块改名:spring-ai-advisors-vector-store → spring-ai-vector-store-advisor。 沿用旧名会直接 Could not resolve。
  • MCP 传输模块换 groupId:mcp-spring-webmvc / mcp-spring-webflux 从 io.modelcontextprotocol.sdk 移到了 org.springframework.ai。 如果你只用 starter,就不用管——starter 会带进来。
  • 一批模块被移除:spring-ai-azure-openai(并入 spring-ai-openai)、 spring-ai-openai-sdk(已合并)、spring-ai-oci-genai、Azure Cosmos DB 系列、spring-ai-hanadb-store。 其中 OCI 与 Cosmos DB 转为厂商独立维护的仓库。
  • 报 Could not resolve 时的排查顺序:去 https://central.sonatype.com 搜 spring-ai-starter 确认真实坐标 → 在 IDEA 里输入 artifactId 后按 Ctrl+Space 让它补全 → 查 2.0 升级说明的模块变更表。
★ 一个改了名、但几乎所有旧教程都还在写错的 starter

Spring Boot 4 做了模块化重构,顺手改了一批 starter 的名字。官方迁移指南的 「Deprecated Starters」表里明确写着:这些旧 starter 仍然存在,但应视为已废弃,将在未来版本中移除。

已废弃(3.x 里的写法)应改为(4.x)
spring-boot-starter-webspring-boot-starter-webmvc
spring-boot-starter-web-servicesspring-boot-starter-webservices
spring-boot-starter-oauth2-clientspring-boot-starter-security-oauth2-client
spring-boot-starter-oauth2-resource-serverspring-boot-starter-security-oauth2-resource-server
spring-boot-starter-oauth2-authorization-serverspring-boot-starter-security-oauth2-authorization-server

为什么这个坑特别隐蔽:写成旧名不会立刻报错——Maven 仍能解析, 程序通常也能跑起来。它会一直潜伏着,直到某个未来版本被真正移除时才炸。 所以照抄 3.x 教程的 pom 能编译通过,你根本察觉不到自己写的是废弃坐标。 本节 pom 里用的就是 spring-boot-starter-webmvc。

另外测试坐标也拆细了:官方 Initializr 为 Web 项目生成的是 spring-boot-starter-webmvc-test(而不是笼统的 spring-boot-starter-test), 对应技术有对应的 test starter。具体名单见官方迁移指南。

0.4.8 基础 application.yml(第 1–3 章就能跑)

# ============ src/main/resources/application.yml ============
spring:
  application:
    name: springai-lab

  # ---------- 模型:OpenAI 及其兼容协议(DeepSeek / 通义 / Kimi / Groq…) ----------
  ai:
    openai:
      # 密钥从环境变量读取,冒号后是「取不到时的默认空值」,防止未配置时启动直接崩
      api-key: ${OPENAI_API_KEY:}
      # ★ 换厂商只改这一行:DeepSeek=https://api.deepseek.com
      #   通义兼容模式=https://dashscope.aliyuncs.com/compatible-mode
      base-url: https://api.deepseek.com
      chat:
        # ★ 2.0 注意:chat 这层仍然保留 options,只有 embedding/image/audio 等去掉了它
        options:
          model: deepseek-chat          # 通义填 qwen-plus;OpenAI 填 gpt-4o-mini
          temperature: 0.7              # 0=最确定,1=最发散;做结构化输出时建议 0.1~0.3
          max-tokens: 2048
        # 连接超时 / 读取超时,官方接口偶尔抖动,给足余量
        connect-timeout: 30000
        read-timeout: 120000
      embedding:
        # ★★ 2.0 破坏性变更:这里不再有 options 这一层,直接就是 model
        #    1.x 写法:spring.ai.openai.embedding.options.model
        #    2.0 写法:spring.ai.openai.embedding.model
        model: text-embedding-3-small # 第 4 章用;DeepSeek 暂无 embedding,需换厂商或本地模型

    # ---------- 本地模型(第 6 章路由/降级;第 4 章向量化) ----------
    ollama:
      base-url: http://localhost:11434
      chat:
        options:
          model: qwen2.5:7b
      embedding:
        model: nomic-embed-text      # 同样去掉了 options 层
      init:
        pull-model-strategy: never     # 不要自动拉模型,否则启动会卡很久

    # ---------- ★ 2.0 自动化工具调用循环(第 7、9 章重点) ----------
    chat:
      client:
        tool-calling:
          # 默认 true:ChatClient 会自动注册 ToolCallingAdvisor 处理工具调用循环。
          # 想做"用户控制的循环"(Agent 场景),把它设成 false,或单次调用时用
          # AdvisorParams.toolCallingAdvisorAutoRegister(false) 关掉。
          enabled: true
          # 自动注册的 ToolCallingAdvisor 在链中的位置,默认 HIGHEST_PRECEDENCE + 300。
          # 想让某个 Advisor 在"每次工具迭代"里都执行,就把它的 order 设得比这个大。
          # advisor-order: 100
        tool-search-advisor:
          # 工具超过 15 个(尤其接了很多 MCP Server)时打开:渐进式工具披露,
          # 模型用内置 toolSearchTool 按需检索工具,官方实测省 34%~64% token。
          enabled: false
          # 索引类型:regex(默认,零依赖)/ lucene(需 lucene-core)/ vector(需 VectorStore)
          tool-index-type: regex

    # ---------- 工具调用保护(2.0 新增,默认值见注释) ----------
    tools:
      limits:
        max-calls-per-tool-default: 40    # 单个工具每轮最多调用次数,-1 关闭
        max-total-tool-calls: 150         # 所有工具合计上限,防止失控循环烧钱
        on-limit-exceeded: THROW          # 或 RETURN_ERROR_RESPONSE(把错误当结果回给模型)
      resolution:
        fallback:
          # 2.0 默认 false:只有本次请求显式附带的工具才允许执行。
          # 打开它意味着"模型报出任何工具名都能执行",会放大越权风险,生产建议保持 false。
          enabled: false

  # ---------- MySQL:业务数据 ----------
  datasource:
    url: jdbc:mysql://localhost:3306/springai_lab?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&useSSL=false
    username: root
    password: root123456
    driver-class-name: com.mysql.cj.jdbc.Driver

  # ---------- Redis:会话缓存 ----------
  data:
    redis:
      host: localhost
      port: 6379
      password: redis123456

server:
  port: 8080

# ---------- 日志:把 Spring AI 的请求/响应体打出来,调试必备 ----------
logging:
  level:
    root: info
    com.example.springai: debug
    # 想要看到发给模型的完整 JSON(Prompt 和原始返回),把这个打开:
    org.springframework.ai: debug
    # 只看 Advisor 链(含工具调用循环的每次迭代),比全开更清爽:
    org.springframework.ai.chat.client.advisor: debug
    # 想看 HTTP 层面的报文(含请求头、耗时),打开这两个:
    org.springframework.web.client.RestClient: debug
    reactor.netty.http.client: debug
把 org.springframework.ai 设成 debug 会打印完整提示词,里面可能包含用户隐私或密钥。 本地调试可以开,上线前务必降到 info,第 10 章会讲怎么用日志脱敏 + Trace 代替裸打印。
2.0 配置迁移最容易踩的三个坑:
  1. 把 embedding 的 .options 照抄过来:2.0 已移除该层级, 写成 spring.ai.openai.embedding.options.model 不会报错,但配置静默不生效, 你会用上默认模型甚至报维度不匹配。改完一定要启动后确认实际生效的模型名。
  2. 以为 internal-tool-execution-enabled 还能用:这个属性连同底层的 internalToolExecutionEnabled() 方法都已被删除,写了会被当成未知属性忽略。
  3. Ollama 的 think-option:2.0 改名为 spring.ai.ollama.chat.think。

0.4.9 环境验证 Checklist(务必逐条打勾再进第 1 章)

#验证项命令 / 操作通过标准
1JDK 21(2.0 最低 17)java -version输出 21.x,且 JAVA_HOME 指向 JDK 根目录
2Mavenmvn -vMaven 3.9+,Java version 显示 21
3Maven 镜像mvn -U clean compile能在几分钟内拉完依赖,不出现连接超时
4Dockerdocker compose versionv2.x
5MySQLdocker exec -it sai-mysql mysql -uroot -proot123456 -e "SELECT 1"返回 1
6Redisdocker exec -it sai-redis redis-cli -a redis123456 pingPONG
7pgvectordocker exec -it sai-pgvector psql -U ai -d vectordb -c "\dx"列表里有 vector
8(可选)Milvus浏览器打开 http://localhost:9091/healthz返回 OK
9Zipkin浏览器打开 http://localhost:9411页面能打开
10模型密钥新开终端 echo $OPENAI_API_KEY能打印出密钥(不为空)
11模型联通见下方 curl 命令返回一段 JSON,含 choices
12工程可编译IDEA 里 mvn clean compileBUILD SUCCESS
13确认跑的是 2.0mvn dependency:tree -Dincludes=org.springframework.ai版本号显示 2.0.0,且 Boot 父 POM 是 4.1.x
14确认配置生效启动日志里搜 text-embedding-3-small能搜到,说明 embedding.model 新写法被正确读取

第 11 项——不写一行 Java 直接验证模型是否可用(这一步能帮你把「网络问题」和「代码问题」彻底分开):

# Windows Git Bash / macOS / Linux
curl https://api.deepseek.com/chat/completions \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $OPENAI_API_KEY" \
  -d '{
    "model": "deepseek-chat",
    "messages": [{"role":"user","content":"用一句话说明你是什么模型"}],
    "stream": false
  }'

# 期望:返回 JSON,choices[0].message.content 是一句人话
# 如果返回 401 → 密钥错;404 → base-url 或路径错;超时 → 网络/代理问题

用一个真实的最小集成测试代替「感觉装好了」——这是课程要求的第一个可交付验证:

// src/test/java/com/example/springai/SmokeTest.java
@SpringBootTest
class SmokeTest {

    @Autowired
    // ChatModel 是 Spring AI 最底层、最核心的接口(第 1 章详解)
    ChatModel chatModel;

    @Test
    void 模型应该能正常返回内容() {
        // 注意:必须显式传 key,最后一个参数是 conversationId
        String result = chatModel.call("你好,请回复四个字:环境就绪");
        System.out.println("模型返回:" + result);
        assertThat(result).isNotBlank();
    }
}
这个测试跑通了,0.4 节就全部通过。它同时验证了:依赖能下载、Spring 容器能装配 ChatModel、 密钥能读取、网络能通到模型服务。后面 11 章遇到任何诡异问题,第一反应都应该是「先跑一遍这个 SmokeTest」, 用来判断是环境退化还是新代码有 bug。

开始学习

环境就绪后,按顺序点开下面 11 个章节。每章结尾都有「自测题」和「下一章」按钮。

Chapter 01
Spring AI 入门
核心抽象:ChatModel / ChatClient / Prompt / Message / Advisor 各自负责什么;用统一抽象连接不同厂商模型。
产出:Hello AI 服务(HTTP 接口 + 流式输出)
Chapter 02
提示词与对话
PromptTemplate 参数化、System/User/Assistant 三种消息的职责、多轮对话与上下文窗口、消息类型与多模态内容。
产出:智能客服对话接口
Chapter 03
结构化输出与 Advisors
让模型稳定吐 JSON 并映射成 Java 对象;BeanOutputConverter 原理;Advisor 切面机制与自定义拦截器。
产出:订单信息提取(含校验与失败兜底)
Chapter 04
嵌入模型与向量数据库
Embedding 原理与维度、相似度算法、pgvector / Milvus 建库建索引、VectorStore 的增删查与元数据过滤。
产出:文档向量索引(可检索)
Chapter 05
RAG
加载→切分→嵌入→存储→检索→重排→组装提示→生成→引用溯源;QuestionAnswerAdvisor 与模块化 RAG。
产出:知识库问答(回答带出处)
Chapter 06
记忆与多模型
会话隔离、ChatMemory 三种实现、上下文裁剪、多模型路由策略、降级与熔断。
产出:多轮工单咨询(会话隔离 + 路由)
Chapter 07
工具调用
@Tool 注解、ToolCallback 机制、参数校验与边界、异常处理、幂等与安全约束。
产出:订单 / 天气查询工具
Chapter 08
MCP
MCP 协议与分层、Server 端暴露工具、Client 端发现与调用、stdio 与 HTTP 两种传输、与 Agent 结合。
产出:MCP 日程 / 文件助手
Chapter 09
智能体
任务拆解、ReAct 循环、工具编排、状态机、人工确认(Human-in-the-loop)、失败重规划。
产出:工单处理智能体
Chapter 10
可观测性与评估
Trace / Span 埋点、Token 与成本指标、Prompt 版本管理、评测集与自动化评分。
产出:调用链看板与评测报告
Chapter 11
综合项目
需求与架构设计、数据模型、接口契约、Docker 部署、性能与成本控制、验收标准。
产出:企业知识问答 + 工单辅助系统(端到端)
Appendix
速查手册
常用命令、完整配置模板、异常排查对照表、术语表、学习资源与进阶方向。
随时回来查