Spring-AI入门与Spring-Boot接入笔记
Spring AI 入门笔记:模型接入、RAG、聊天记忆与工具调用
一、Spring AI 是什么
Spring AI 是 Spring 生态中的 AI 应用开发框架,提供模型调用、向量检索、工具调用等抽象,帮助应用连接 AI 模型、企业数据和业务接口。
它不是一个大模型,也不会因为加入依赖就自动拥有模型推理能力。应用仍然需要连接模型服务,例如云端模型 API,或者本地 Ollama 服务。
可以按下面的结构理解:
用户问题
↓
Spring Boot 应用
↓
Spring AI:组织消息、检索资料、调用工具等
↓
模型服务:执行推理、生成响应
↓
应用处理结果并返回
Spring AI 支持聊天、Embedding、部分图像和音频能力,以及向量存储、RAG、对话记忆、MCP 和可观测性等功能。具体能力取决于所用模块和模型提供方。Spring AI 官方介绍
二、Spring AI、Spring Boot 与大模型的关系
| 名称 | 主要作用 |
|---|---|
| Spring Boot | 应用启动、Web 接口、配置和依赖注入 |
| Spring AI | 对接模型,并组织 AI 调用流程 |
| 大模型 | 根据输入生成文本或其他响应 |
| Ollama | 在本地或指定服务器运行所支持的模型 |
| 向量数据库 | 保存向量及相关数据,支持相似度检索 |
Spring AI 通过统一 API 减少接入不同提供方的重复代码。不过,切换模型后仍要核对参数、上下文长度、工具调用和结构化输出支持,并重新评估效果。
三、先理解几个 AI 概念
1. Prompt:给模型的输入
Prompt 不只是用户输入的一句话,还可能包含角色要求、历史消息、检索资料、工具描述等内容。
例如:
角色要求:你是一位 Java 学习助手,使用中文,先解释概念,再给示例。
用户问题:Spring Boot 的依赖注入是什么?
提示词应表达任务、输入背景和输出要求,而不是依赖模糊指令。
2. 消息角色
| 角色 | 常见用途 |
|---|---|
| System | 应用预设的行为要求和任务背景 |
| User | 用户问题 |
| Assistant | 模型回复 |
| Tool | 工具执行结果,实际表示方式取决于提供方 |
System 消息不是业务权限系统。不能仅靠“禁止访问其他用户数据”的提示词实现数据隔离。
3. Token 与上下文窗口
Token 是模型处理文本等输入的计量单位,不等于一个汉字或一个英文单词。其划分取决于模型的分词方式。
上下文窗口限制模型一次能处理的上下文规模。系统提示、历史消息、检索材料、工具结果和输出预算都会消耗资源。历史越长,不代表回答一定越好。
4. Temperature
Temperature 是部分模型支持的采样参数。降低它通常使输出更集中,提高它通常增加多样性。
低 temperature 不保证答案正确,也不保证每次输出完全相同。参数范围和支持情况需要核对模型文档。
5. Embedding
Embedding 将文本等内容转换为向量,用于语义检索。例如,“退款要多久”和“退货后什么时候到账”文字不同,但可能在向量空间中较接近。
它主要用于匹配和检索,不是直接生成聊天答案。聊天模型与 Embedding 模型承担不同任务。
四、Spring AI 的核心组件
| 组件 | 用途 |
|---|---|
| ChatModel | 模型聊天调用的底层抽象 |
| ChatClient | 使用链式 API 构建和执行聊天请求 |
| Prompt / Message | 表示输入和消息 |
| Advisor | 在调用流程中组织记忆、检索等附加行为 |
| ChatMemory | 管理需要保留的对话消息 |
| EmbeddingModel | 将内容转换成向量 |
| VectorStore | 存储文档向量并执行相似度查询 |
| ToolCallback / @Tool | 定义应用允许模型请求使用的工具 |
下面这条调用链最适合入门:
String answer = chatClient.prompt()
.user("用一个例子解释依赖注入")
.call()
.content();
prompt() 开始构建请求,user() 设置用户消息,call() 发起调用,content() 获取文本内容。需要用量、结束原因等元数据时,应获取更完整的响应对象。ChatClient 官方文档
五、接入前先匹配版本
官方当前文档说明,Spring AI 2.0.x 支持 Spring Boot 4.0.x 与 4.1.x。官方快速开始
本文采用:
| 项目项 | 本文设置 |
|---|---|
| Java | 17 或满足所选 Spring Boot 要求的更高版本 |
| Spring Boot | 选择兼容的 4.0.x / 4.1.x 正式版本 |
| Spring AI | 2.0.1 |
| 构建工具 | Maven |
| 模型运行服务 | Ollama |
已有 Spring Boot 3 项目,应核对 Spring AI 1.x 对应版本的兼容说明,不要直接将本文 BOM 复制进去。
还要区分版本文档:例如当前 Ollama 配置使用 spring.ai.ollama.chat.model,旧教程可能使用其他属性层次。框架 API、Starter 名称和配置属性变化时,优先以项目版本对应的文档为准。
六、Spring Boot 接入 Ollama 示例
这个示例用于理解一次基础聊天调用。使用本地模型前,需要确认机器内存、磁盘和推理性能适合所选模型。
1. 准备 Ollama 与模型
先安装并启动 Ollama,参考官方 Ollama 入口。选择一个适合本机、支持聊天的模型,然后在终端下载:
# 将“模型名称”替换成模型库中的实际标识
ollama pull 模型名称
# 查看已安装模型
ollama list
本文用环境变量 OLLAMA_CHAT_MODEL 指定实际模型名称,避免将不同机器的选择写死。
Ollama 常见本地地址为:
http://localhost:11434
Spring AI 依赖不会自动安装 Ollama,也不代表模型文件已经下载。Spring AI Ollama 接入文档
2. 创建 Spring Boot 项目
可以在 Spring Initializr 选择兼容的 Spring Boot 正式版本,添加 Spring Web 和 Ollama 相关依赖。
项目结构示例:
src/main/java/com/example/ai/
├── AiApplication.java
└── ChatController.java
src/main/resources/
└── application.yml
3. 管理 Spring AI 依赖版本
在已有 Spring Boot 项目的 pom.xml 中加入 BOM:
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-bom</artifactId>
<version>2.0.1</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
BOM 统一管理 Spring AI 模块版本,不会替你管理 Spring Boot 版本。已有 dependencyManagement 时应合并配置。
在 <dependencies> 中添加:
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-starter-model-ollama</artifactId>
</dependency>
项目还需要 Spring Web 依赖,按所选 Spring Boot 版本由 Initializr 生成。正式发布的 Spring AI 依赖可从 Maven Central 获取。依赖管理说明
4. 配置 application.yml
server:
port: 8080
spring:
application:
name: spring-ai-demo
ai:
model:
chat: ollama
ollama:
base-url: http://localhost:11434
chat:
model: ${OLLAMA_CHAT_MODEL}
temperature: 0.3
启动应用之前,将环境变量设为 ollama list 中实际存在的聊天模型名称。
Linux / macOS 的 Bash 示例:
export OLLAMA_CHAT_MODEL='实际模型名称'
Windows PowerShell 示例:
$env:OLLAMA_CHAT_MODEL = '实际模型名称'
这两种设置都只影响对应终端及之后启动的子进程。使用 IDEA 启动时,可以在运行配置的环境变量中设置。
应用如果运行在容器或其他机器上,localhost 指应用自身所在环境,需要改成应用可访问的 Ollama 地址。
5. 创建接口
创建 ChatController.java:
package com.example.ai;
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 ChatController {
private final ChatClient chatClient;
public ChatController(ChatClient.Builder builder) {
this.chatClient = builder
.defaultSystem("你是一位 Java 学习助手。使用中文,先解释概念,再给简短示例。")
.build();
}
@GetMapping("/ai/chat")
public String chat(@RequestParam("message") String message) {
return chatClient.prompt()
.user(message)
.call()
.content();
}
}
在满足自动配置条件且只有合适的聊天模型配置时,Spring AI 会提供 ChatClient.Builder。本例仍需正常的 @SpringBootApplication 启动类,并将 Controller 放在其扫描范围内。
6. 验证接口
启动应用后,在 Bash 等终端中使用:
curl --get 'http://localhost:8080/ai/chat' \
--data-urlencode 'message=用一个例子解释Spring的依赖注入'
上面的反斜线换行写法属于 Bash,不直接适用于 PowerShell。也可以使用 API 调试工具,设置 GET 参数 message。
预期调用链为:
HTTP 请求 → Controller → ChatClient → Ollama → 模型生成 → 返回文本
GET 适合这个最小演示;实际聊天接口可使用 POST 请求体,便于承载消息、会话标识等数据。输出内容由模型生成,不能期待固定答案。
七、流式输出:逐段返回生成内容
非流式调用通常等响应生成后再返回;流式调用允许应用逐段收到结果并发送给前端。
在上述 Controller 中可以追加:
@GetMapping(value = "/ai/stream", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
public Flux<String> stream(@RequestParam("message") String message) {
return chatClient.prompt()
.user(message)
.stream()
.content();
}
还需导入:
import org.springframework.http.MediaType;
import reactor.core.publisher.Flux;
此例使用 SSE 媒体类型,前端需要按事件流处理。分块内容不一定与一个汉字或一个 Token 一一对应。
网关、代理缓冲、超时和客户端取消都会影响流式体验,应一起验证。Flux 也不代表任意业务处理都可以忽略阻塞操作。ChatClient 流式 API
八、结构化输出:将结果映射成 Java 对象
如果应用需要字段而不是整段文本,可以定义一个结果类型:
public record TechnologySummary(String name, String purpose) {
}
在业务代码中请求映射:
TechnologySummary summary = chatClient.prompt()
.user("介绍 Docker,name 填技术名称,purpose 填一句话用途。")
.call()
.entity(TechnologySummary.class);
结构化转换帮助组织输出,并不保证内容真实,也不保证所有提供方都以相同方式约束输出。应用要处理空值、转换失败,并对业务字段进行校验。
提供方原生 JSON Schema 支持与提示词加转换器是不同机制,应核对实际模型能力。结构化输出文档
九、聊天记忆:让多轮对话关联起来
前面的基础接口默认没有加入对话记忆。第二次请求不自动知道第一次用户问过什么。
例如:
第一轮:我正在学习 Spring Boot。
第二轮:它和 Spring MVC 有什么关系?
应用需要在第二轮提供必要的历史消息,模型才能理解“它”的上下文。
Spring AI 提供 ChatMemory 及相应 Advisor 来组织历史。通常需要:
- 选择记忆存储与窗口策略。
- 为每个对话关联 conversation ID。
- 在 ChatClient 调用中接入记忆 Advisor。
- 对会话所属用户进行服务端授权校验。
不要为所有用户复用一个固定 conversation ID,否则可能混入他人的消息。内存存储也不等于持久化,应用重启后可能丢失。
聊天记忆主要提供模型需要的上下文,不应当作完整审计记录;长对话要限制窗口或摘要,避免不断增加成本和噪声。Chat Memory 官方文档
十、RAG:让模型参考自己的知识库
RAG 是 Retrieval-Augmented Generation,即检索增强生成。它先从资料库找到相关内容,再让模型结合这些内容回答。
例如希望模型回答“公司退款规则是什么”,模型未必知道公司的最新制度;可以先检索制度文档,再将相关段落提供给模型。
1. 建库流程
读取资料
↓
清理内容、保留来源与权限元数据
↓
切分成文档片段
↓
Embedding 模型生成向量
↓
写入 VectorStore
2. 问答流程
flowchart LR
U[用户问题] --> R[检索相关文档]
V[向量存储及权限过滤] --> R
R --> P[问题与检索内容组成上下文]
P --> M[聊天模型]
M --> A[答案与来源]
Spring AI 可以通过 VectorStore 和检索相关 Advisor 组织此流程,具体模块和依赖应按版本选择。RAG 官方文档
3. RAG 不等于训练模型
RAG 通常在请求时提供额外上下文,不修改模型参数。微调则涉及训练过程,两者解决的问题不同。
RAG 也不保证回答一定正确:资料可能过期,切分可能破坏上下文,检索可能选错段落,模型可能误解内容。
应关注来源、更新机制、权限过滤和检索评估。聊天模型可以与 Embedding 模型不同,但同一向量索引的建库和查询应使用匹配的 Embedding 模型与向量维度;换模型时通常需要重建索引。
找不到可靠资料时,应明确表达证据不足,而不是让模型自行补全制度或业务事实。
十一、工具调用:让模型请求使用业务能力
RAG 适合从资料中查知识,工具调用适合查询实时信息或执行受控业务动作。
例如用户问“订单 2001 目前是什么状态”,应用可以向模型提供一个订单查询工具。
工具调用的基本过程:
- 应用提供工具名称、说明和参数结构。
- 模型可能返回工具调用请求及参数。
- 应用验证请求,执行允许的工具。
- 工具结果返回模型,由模型组织回复。
**执行 Java 方法的是应用,不是模型直接获得数据库或 API 权限。**Spring AI 可以帮助处理调用循环。工具调用说明
@Tool 的基本写法示意:
import org.springframework.ai.tool.annotation.Tool;
import org.springframework.stereotype.Component;
@Component
public class OrderTools {
@Tool(description = "按订单编号查询演示订单状态,仅支持编号 2001")
public String queryOrderStatus(Long orderId) {
if (orderId == null || orderId != 2001L) {
return "未找到演示订单";
}
return "订单 2001:已发货";
}
}
上面返回的是固定演示数据,不代表真实数据库查询。将工具对象注入业务类后,可通过相应版本的 .tools(orderTools) API 提供给 ChatClient;模型必须支持工具调用才可使用。
仅将工具类注册成 Bean,不代表每次请求都自动拥有它。工具说明要清楚,执行时还需参数校验和用户授权;实际订单权限应根据服务端登录身份检查,不要相信模型生成的用户 ID。
写入型工具还需要幂等、审计和适当的确认机制,避免重复或越权执行。简单查询场景可先从只读工具练习。
十二、MCP 与 Agent 如何理解
MCP 是连接应用与工具、资源等能力的一种协议。Spring AI 支持相应客户端和服务端集成:可以消费外部 MCP 服务,也可以将 Spring 应用中的能力通过 MCP 暴露。
MCP 不是大模型,也不是 RAG 本身。它解决能力连接和交互方式的问题。
Agent 通常描述模型结合工具、状态和控制循环执行任务的应用模式。一次普通聊天调用不会自动成为能可靠完成复杂任务的 Agent;需要设计终止条件、工具范围、失败恢复和资源预算。
十三、实际项目需要补充什么
| 方面 | 需要关注 |
|---|---|
| 超时与限流 | 模型可能响应慢,需要整体时限和并发控制 |
| 重试 | 控制次数,避免重复工具动作与额外成本 |
| 可观测性 | 记录延迟、用量、失败类型,避免默认记录完整敏感输入 |
| 输出处理 | 校验字段,处理空响应、格式错误和内容不可靠的情况 |
| 数据隔离 | 会话、文档检索和业务工具都要关联真实权限 |
| 评估 | 用固定测试问题检查回答质量、来源准确性和工具行为 |
| 模型配置 | 模型名称、上下文长度和参数不能仅凭统一 API 推断 |
提示词和检索文档都可能包含误导模型的内容。业务授权与重要操作约束应由确定的应用逻辑执行。
十四、常见问题排查
| 问题 | 排查方向 |
|---|---|
| 找不到 ChatClient.Builder | 检查 Starter、模型选择和自动配置条件 |
| 连接 Ollama 失败 | 检查服务是否启动、地址、端口及网络 |
| 提示模型不存在 | 用 ollama list 核对名称,先下载对应模型 |
| 配置没有生效 | 检查是否复制了其他版本的属性名称 |
| 每次对话都没有上下文 | 检查 ChatMemory、Advisor 和会话标识 |
| 模型不调用工具 | 检查模型支持、工具是否提供、描述与参数是否清楚 |
| RAG 检索不到资料 | 检查建库、Embedding 一致性、过滤条件和阈值 |
| 输出无法映射成对象 | 检查模型输出、约束方式和目标类型,处理转换异常 |
| 流式响应直到最后才显示 | 检查客户端处理、代理缓冲和服务端流式链路 |
| 结果有事实错误 | 检查输入与证据,完善检索及评估,不只调整 temperature |