Spring AI 2.0 学习指南
从零到「企业知识问答 + 工单辅助系统」
这份指南把《Spring AI 框架与企业级智能应用开发实践 V2.0》的 11 个章节,拆成一条「看得懂、跑得通、抄得走」的路线: 每一章都告诉你 要学什么 → 环境怎么配 → 代码怎么写 → 为什么这么写 → 跑起来看到什么 → 踩坑怎么排。 所有代码示例都是可以直接复制进 IDEA 运行的完整片段,不是伪代码。
0.1怎么用这份指南
先明确一条原则:这门课不是「读」出来的,是「跑」出来的。大模型应用开发的特点决定了——你不上手调用一次,永远不知道 API 长什么样;你不亲手把文档灌进向量库,永远理解不了 RAG 为什么检索不到。
❌ 低效的学法
- 把 11 章当成 11 篇技术文档从头读到尾,读完就忘。
- 代码只复制不抄写,报错全靠搜索引擎。
- 跳过环境准备,第 4 章装数据库时全线崩溃。
- 每章独立看完就过,不回头看上一章的成果。
✅ 推荐的学法
- 每章三段式:读概念(20%)→ 抄代码跑通(50%)→ 改需求做实验(30%)。
- 代码一定手敲一遍,注释要自己重写,写不出来说明没懂。
- 先一次性把环境全配好(本章 0.4 节),后面 10 章零中断。
- 每章验收物留着,第 11 章要把它们组装成一个系统。
2.0 必须知道的六个变化
- 底座换代:要求 Spring Boot 4.0/4.1 + Spring Framework 7.0,Java 17 起。Boot 3.x 的项目不能直接用 2.0。
- 工具调用循环上移:从「藏在各 ChatModel 内部」提升为 Advisor 链中的
ToolCallingAdvisor,可选可替换。 internalToolExecutionEnabled被删除:想自己控制循环,改用AdvisorParams.toolCallingAdvisorAutoRegister(false)。- 结构化输出可自纠错:
.entity(X.class, spec -> spec.validateSchema())会在解析失败时把错误回喂给模型并重试。 - 记忆的 conversationId 变成必填:不传直接抛
IllegalArgumentException,没有默认值兜底。 - 配置去掉了
.options段:如spring.ai.openai.embedding.model(旧写法是embedding.options.model)。
如果报「找不到符号」,按这个顺序查
- 打开
https://docs.spring.io/spring-ai/reference/2.0/upgrade-notes.html,这里列全了 2.0 的破坏性变更。 - 在 IDEA 里 Ctrl+Alt+B 看接口的实现类,确认当前实际 API 名。
- 用 IDE 的 yml 补全展开
spring.ai.*,核对配置键是否还叫这个名字。 - 最后才去搜索引擎——网上大量 Spring AI 内容是 1.x 的,容易看错。
你已经学过的 1.x 教程并非作废:概念(RAG、工具调用、记忆、Advisor)完全一致,变的只是 API 名与配置写法。
· 工具调用次数上限可配置(
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 章把所有东西拼成一个真实系统。
Chapter 2 学会控制输入:PromptTemplate 参数化、System/User/Assistant 消息分工、多轮上下文。
Chapter 3 学会控制输出:把自由文本变成 Java 对象(结构化输出),用 Advisor 做横切治理(日志、拦截、改写)。
阶段验收:能用自然语言 + 严格 JSON 两种方式稳定拿到模型输出。
Chapter 5 串起 RAG 全链路:加载 → 切分 → 嵌入 → 存储 → 检索 → 重排 → 组装提示 → 生成 → 引用溯源。
阶段验收:能对一份 50 页 PDF 提问,并给出带出处页码的回答。
Chapter 7 Tool Calling:让模型能查数据库、调接口,理解「模型只输出意图,执行由你的代码负责」这条铁律。
Chapter 8 MCP:把工具从「写在同一个工程里」升级为「跨进程、可复用的标准协议」。
阶段验收:一个能记住用户是谁、能自己决定去查订单还是查天气的助手。
Chapter 10 可观测性与评估:Trace / Span / Token 成本 / 效果评测集,把「玄学调参」变成「数据驱动」。
Chapter 11 综合项目:需求 → 架构 → 数据模型 → 部署 → 验收,交付企业知识问答与工单辅助系统。
阶段验收:能部署上线、能演示、能回答「成本多少、准确率多少、怎么证明」。
章节依赖关系一览
| 章 | 章节 | 核心要学的东西(一句话) | 本章产出物 | 依赖 |
|---|---|---|---|---|
| 1 | Spring AI 入门 | Spring AI 的抽象分层与最小可运行调用链 | Hello AI 服务 | — |
| 2 | 提示词与对话 | 用模板和角色消息精确控制输入 | 智能客服对话接口 | 1 |
| 3 | 结构化输出与 Advisors | 把文本输出约束成对象;用 Advisor 做统一治理 | 订单信息提取 | 1,2 |
| 4 | 嵌入模型与向量数据库 | 向量化原理 + 向量库读写 + 相似度检索 | 文档向量索引 | 1 |
| 5 | RAG | 知识增强生成的全链路与引用溯源 | 知识库问答 | 3,4 |
| 6 | 记忆与多模型 | 会话状态管理与模型路由/降级 | 多轮工单咨询 | 2,5 |
| 7 | 工具调用 | 让模型调用你的 Java 方法(含边界处理) | 订单/天气查询工具 | 3,6 |
| 8 | MCP | 工具的外部化与标准化(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 章项目作为大作业答辩。
适合:高校课程、训练营
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、Redis6379、PostgreSQL5432、Milvus19530、Zipkin9411。
0.4.1 JDK 21(2.0 的硬性底线其实是 17)
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 场景下虚拟线程的吞吐收益更明显。
-
下载安装:推荐 Eclipse Temurin 21(
https://adoptium.net)或 Oracle JDK 21。
Windows 选.msi,安装时勾选Set JAVA_HOME variable与Add to PATH。 -
验证:
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 -
为什么课程选 21 而不是 17:
· 第 9 章 Agent 并行调用多个工具会用Executors.newVirtualThreadPerTaskExecutor()(JDK 21 才正式化,17 是预览);
· 第 3 章结构化输出大量使用record+ 密封接口 + Record Pattern;
· Spring AI 2.0 全代码库加了 JSpecify 空安全注解,IDEA 的高版本 JDK 对这类静态分析的提示更准。
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 文件测接口,不用 Postman | IDEA 内置 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);
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
- 端口被占用(
Bind for 0.0.0.0:3306 failed):本机已装 MySQL。要么停掉本机服务 (Windows:services.msc停 MySQL80),要么把 compose 里改成"13306:3306"并同步改应用配置。 - Windows 下 Docker 启动失败:需要开启 WSL2 与虚拟化(BIOS 里的 VT-x/AMD-V)。
wsl --update后重启。 - 镜像拉不动:在 Docker Desktop → Settings → Docker Engine 里配镜像加速器,或改用国内 registry 前缀。
- pgvector 表没建出来:
docker-entrypoint-initdb.d只在数据卷为空时执行。 如果你先起过容器再放脚本,需要docker compose down -v清卷重来(会删数据,注意)。
0.4.5 大模型服务与密钥
你需要至少一个可用的模型服务。Spring AI 的一大优势是「同一套 API 换模型只改配置」,所以课程里我们会同时配好两三个,用来演示第 6 章的多模型路由。三条路线任选:
被移出主仓库的有: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
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 "用一句话解释什么是向量数据库"
0.4.6 创建项目骨架
用 Spring Initializr 生成,或直接手写 pom.xml。课程统一一个工程,11 章用不同的包名分目录:
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>
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 升级说明的模块变更表。
Spring Boot 4 做了模块化重构,顺手改了一批 starter 的名字。官方迁移指南的 「Deprecated Starters」表里明确写着:这些旧 starter 仍然存在,但应视为已废弃,将在未来版本中移除。
| 已废弃(3.x 里的写法) | 应改为(4.x) |
|---|---|
spring-boot-starter-web | spring-boot-starter-webmvc |
spring-boot-starter-web-services | spring-boot-starter-webservices |
spring-boot-starter-oauth2-client | spring-boot-starter-security-oauth2-client |
spring-boot-starter-oauth2-resource-server | spring-boot-starter-security-oauth2-resource-server |
spring-boot-starter-oauth2-authorization-server | spring-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 代替裸打印。
- 把 embedding 的
.options照抄过来:2.0 已移除该层级, 写成spring.ai.openai.embedding.options.model不会报错,但配置静默不生效, 你会用上默认模型甚至报维度不匹配。改完一定要启动后确认实际生效的模型名。 - 以为
internal-tool-execution-enabled还能用:这个属性连同底层的internalToolExecutionEnabled()方法都已被删除,写了会被当成未知属性忽略。 - Ollama 的
think-option:2.0 改名为spring.ai.ollama.chat.think。
0.4.9 环境验证 Checklist(务必逐条打勾再进第 1 章)
| # | 验证项 | 命令 / 操作 | 通过标准 |
|---|---|---|---|
| 1 | JDK 21(2.0 最低 17) | java -version | 输出 21.x,且 JAVA_HOME 指向 JDK 根目录 |
| 2 | Maven | mvn -v | Maven 3.9+,Java version 显示 21 |
| 3 | Maven 镜像 | mvn -U clean compile | 能在几分钟内拉完依赖,不出现连接超时 |
| 4 | Docker | docker compose version | v2.x |
| 5 | MySQL | docker exec -it sai-mysql mysql -uroot -proot123456 -e "SELECT 1" | 返回 1 |
| 6 | Redis | docker exec -it sai-redis redis-cli -a redis123456 ping | PONG |
| 7 | pgvector | docker exec -it sai-pgvector psql -U ai -d vectordb -c "\dx" | 列表里有 vector |
| 8 | (可选)Milvus | 浏览器打开 http://localhost:9091/healthz | 返回 OK |
| 9 | Zipkin | 浏览器打开 http://localhost:9411 | 页面能打开 |
| 10 | 模型密钥 | 新开终端 echo $OPENAI_API_KEY | 能打印出密钥(不为空) |
| 11 | 模型联通 | 见下方 curl 命令 | 返回一段 JSON,含 choices |
| 12 | 工程可编译 | IDEA 里 mvn clean compile | BUILD SUCCESS |
| 13 | 确认跑的是 2.0 | mvn 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();
}
}
开始学习
环境就绪后,按顺序点开下面 11 个章节。每章结尾都有「自测题」和「下一章」按钮。