一、SpringAI 概述
1.1 背景与定位
目前大模型应用开发最常见的框架是 LangChain,但它基于 Python 语言。虽然存在 LangChain4j,可对于大量使用 Spring 生态的 Java 项目来说,适配性稍差。
Spring 官方推出的 SpringAI 框架,充分利用了 Spring 框架中 AOP、IOC 的能力,可以与现有 Java 项目无缝融合,上手方便。
1.2 环境要求
| 框架 | 最低 JDK 版本 | SpringBoot 要求 |
|---|---|---|
| SpringAI | JDK 17 | SpringBoot 3.x |
| LangChain4j | JDK 8 | 无强制要求 |
如果是比较老的项目(JDK 8),可使用 LangChain4j;若要使用 SpringAI,必须先升级 JDK 与 SpringBoot 版本。
1.3 大模型的使用方式
大模型应用开发并不是在浏览器中跟 AI 聊天,而是通过访问模型对外暴露的 API 接口实现与大模型的交互。企业通常有三种选择:
- 使用开放的大模型 API(本次演示方式):选择合适的大模型,申请自己的 API Key 即可免费试用较长时间。
- 在云平台部署私有大模型。
- 在本地服务器部署私有大模型。
二、SpringAI 新手入门
2.1 配置 pom.xml 文件
(1)引入起步依赖
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-openai-spring-boot-starter</artifactId>
</dependency>
(2)声明版本号
<spring-ai.version>1.0.0-M6</spring-ai.version>
(3)添加依赖管理
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-bom</artifactId>
<version>${spring-ai.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
(4)完整 pom.xml 示例
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.4.5</version>
<relativePath/>
</parent>
<groupId>com.xbs</groupId>
<artifactId>springAI-openAi</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>springAI-openAi</name>
<description>springAI-openAi</description>
<properties>
<java.version>17</java.version>
<spring-ai.version>1.0.0-M6</spring-ai.version>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-bom</artifactId>
<version>${spring-ai.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<!-- Web -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- Lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.22</version>
</dependency>
<!-- SpringAI OpenAI 起步依赖 -->
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-openai-spring-boot-starter</artifactId>
</dependency>
<!-- MySQL -->
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<scope>runtime</scope>
</dependency>
<!-- Test -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!-- MyBatis-Plus(SpringBoot3) -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-spring-boot3-starter</artifactId>
<version>3.5.10.1</version>
</dependency>
<!-- PDF 文档读取器(RAG 用) -->
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-pdf-document-reader</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
除 SpringAI 依赖外,额外引入了 Web、Lombok、MySQL、MyBatis-Plus、PDF Reader 等后续开发会用到的依赖。
2.2 配置 application.yaml 文件
以阿里云 DashScope(兼容 OpenAI 接口模式)为例:
spring:
application:
name: ai-demo
ai:
openai:
base-url: https://dashscope.aliyuncs.com/compatible-mode
api-key: 在这里写你自己申请的 API-Key
chat:
options:
model: qwen-max-latest # 选择模型:https://help.aliyun.com/zh/model-studio/getting-started/models
temperature: 0.8 # 模型温度,影响生成结果随机性,越小越稳定
embedding:
options:
model: text-embedding-v3
dimensions: 1024
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3144/ai?serverTimezone=Asia/Shanghai&useSSL=false&useUnicode=true&characterEncoding=utf-8&zeroDateTimeBehavior=convertToNull&transformedBitIsBoolean=true&tinyInt1isBit=false&allowPublicKeyRetrieval=true&allowMultiQueries=true&useServerPrepStmts=false
username: root
password: 你猜猜看
logging:
level:
org.springframework.ai: debug # AI 对话日志级别
com.xbs.springaiopenai: debug # 本项目日志级别
server:
port: 8087
mybatis:
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
2.3 配置 ChatClient
package com.itheima.ai.config;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.chat.client.advisor.SimpleLoggerAdvisor;
import org.springframework.ai.ollama.OllamaChatModel;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class CommonConfiguration {
// 参数中的 model 即所用模型,这里用 Ollama,也可换成 OpenAIChatModel
@Bean
public ChatClient chatClient(OllamaChatModel model) {
return ChatClient.builder(model) // 创建 ChatClient 工厂
.build(); // 构建 ChatClient 实例
}
}
代码解读:
ChatClient.builder(...):得到一个ChatClient.Builder工厂对象,利用它可以自由选择模型、添加各种自定义配置。
2.4 同步调用
定义一个 Controller,接收用户提示词,发送给大模型,拿到结果后返回:
package com.itheima.ai.controller;
import lombok.RequiredArgsConstructor;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
@RequiredArgsConstructor
@RestController
@RequestMapping("/ai")
public class ChatController {
private final ChatClient chatClient;
// 请求方式和路径不要改动,将来要与前端联调
@RequestMapping("/chat")
public String chat(@RequestParam(defaultValue = "讲个笑话") String prompt) {
return chatClient
.prompt(prompt) // 传入 user 提示词
.call() // 同步请求,等待 AI 全部输出完才返回
.content(); // 返回响应内容
}
}
基于 call() 方法的调用属于同步调用,必须等所有响应结果全部返回后才能返回给前端。
启动项目,浏览器访问:
http://localhost:8080/ai/chat?prompt=你好
2.5 流式调用
同步调用需要等待较长时间,用户体验差。SpringAI 基于 WebFlux 实现流式调用:
// 返回值是 Flux<String>,即流式结果;
// 另外需要设定响应类型和编码,否则前端会乱码
@RequestMapping(value = "/chat", produces = "text/html;charset=UTF-8")
public Flux<String> chat(@RequestParam(defaultValue = "讲个笑话") String prompt) {
return chatClient
.prompt(prompt)
.stream() // 流式调用
.content();
}
重启项目后再次访问即可看到逐字输出效果。
2.6 System 设定
询问 AI “你是谁”时,它会按底层模型设定回答(如 DeepSeek-R1)。若希望 AI 按新设定工作,需要为其设置 System 背景信息。
在 SpringAI 中,设置 System 信息非常方便——不需要每次发送时封装到 Message,而是在创建 ChatClient 时指定:
@Bean
public ChatClient chatClient(OllamaChatModel model) {
return ChatClient.builder(model)
.defaultSystem("你的名字叫小板。请以友好、乐于助人和愉快的方式解答学生的各种问题。")
.defaultAdvisors(new SimpleLoggerAdvisor())
.build();
}
2.7 日志功能
默认情况下,与 AI 的交互不记录日志,无法得知 SpringAI 组织的提示词长什么样,不利于调试。
SpringAI 基于 AOP 机制实现对大模型对话过程的增强、拦截、修改等功能。所有增强通知都需要实现 Advisor 接口。Spring 提供了一些默认实现:
| Advisor | 作用 |
|---|---|
SimpleLoggerAdvisor | 日志记录 |
MessageChatMemoryAdvisor | 会话记忆 |
QuestionAnswerAdvisor | 实现 RAG |
在配置 ChatClient 时添加日志 Advisor:
@Bean
public ChatClient chatClient(OllamaChatModel model) {
return ChatClient.builder(model)
.defaultSystem("你是一个热心、可爱的智能助手")
.defaultAdvisors(new SimpleLoggerAdvisor()) // 添加默认 Advisor,记录日志
.build();
}
同时修改日志级别:
logging:
level:
org.springframework.ai: debug # AI 对话的日志级别
com.itheima.ai: debug # 本项目的日志级别
重启项目后,再次与 AI 聊天即可在控制台看到完整的请求/响应日志。
2.8 会话记忆功能
默认情况下聊天机器人没有记忆,上一轮对话的内容下一轮就会被遗忘。传统做法是把每次历史对话拼接到 Prompt 中一起发送,比较繁琐。SpringAI 自带会话记忆功能,会自动保存并拼接历史会话。
2.8.1 ChatMemory
会话记忆同样基于 AOP 实现,由 MessageChatMemoryAdvisor 提供。该 Advisor 需要指定一个 ChatMemory 实例,即会话历史的保存方式。
ChatMemory 接口声明如下:
public interface ChatMemory {
default void add(String conversationId, Message message) {
this.add(conversationId, List.of(message));
}
// 添加会话信息到指定 conversationId 的会话历史中
void add(String conversationId, List<Message> messages);
// 根据 conversationId 查询历史会话
List<Message> get(String conversationId, int lastN);
// 清除指定 conversationId 的会话历史
void clear(String conversationId);
}
所有会话记忆都与 conversationId(会话 ID) 关联,不同会话 ID 的记忆自然分开管理。
目前 SpringAI 提供两个 ChatMemory 实现:
| 实现类 | 存储方式 | 说明 |
|---|---|---|
InMemoryChatMemory | 内存 | 简单易用,重启丢失 |
CassandraChatMemory | Cassandra 数据库 | 需额外依赖,且绑定向量数据库,不够灵活 |
2.8.2 添加会话记忆功能
第一步:注册 chatMemory Bean
@Bean
public ChatMemory chatMemory() {
return new InMemoryChatMemory();
}
第二步:添加到 ChatClient
@Bean
public ChatClient chatClient(OllamaChatModel model, ChatMemory chatMemory) {
return ChatClient.builder(model)
.defaultSystem("你的名字叫小板。请以友好、乐于助人和愉快的方式解答学生的各种问题。")
.defaultAdvisors(new SimpleLoggerAdvisor()) // 记录日志
.defaultAdvisors(new MessageChatMemoryAdvisor(chatMemory)) // 会话记忆
.build();
}
第三步:调用时传入 chatId 区分用户
为区分每个用户对应的不同会话记录,需要在请求时传入用户 ID:
@RequestMapping(value = "/chat", produces = "text/html;charset=UTF-8")
public Flux<String> chat(@RequestParam(defaultValue = "讲个笑话") String prompt, String chatId) {
return chatClient
.prompt(prompt)
.advisors(a -> a.param(CHAT_MEMORY_CONVERSATION_ID_KEY, chatId))
.stream()
.content();
}
通过 CHAT_MEMORY_CONVERSATION_ID_KEY 将 chatId 传递给 MessageChatMemoryAdvisor,SpringAI 会自动根据该 ID 加载历史对话并拼接到本次请求中。

暂无评论内容