SpringAI-01-基础入门

一、Spring AI 是什么

​ Spring AI 是 Spring 官方推出的 AI 应用开发框架,主要目的是简化 AI 应用的开发。它提供了统一的 API,不管你用的是 DeepSeek、阿里百炼还是 OpenAI,代码写法都一样,只需要改配置就行。

​ 目前 Spring AI 支持的主要功能:

  • 统一的 ChatModel 接口,支持多种大模型
  • 流式响应(Streaming Response)
  • Function Call(工具调用)
  • RAG(检索增强生成)
  • MCP 协议支持

二、项目搭建

2.1 创建父工程

​ 首先创建一个 Maven 父工程,统一管理版本。这里用的是 Spring Boot 3.5.7 和 Spring AI 1.0.1。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<groupId>org.study.ai</groupId>
<artifactId>spring-ai-study</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>pom</packaging>

<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.5.7</version>
</parent>

<properties>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<spring-ai.version>1.0.1</spring-ai.version>
<spring-ai-alibaba.version>1.0.0.4</spring-ai-alibaba.version>
</properties>

<dependencyManagement>
<dependencies>
<!-- Spring AI 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>
<!-- Spring AI Alibaba BOM,管理阿里百炼相关依赖 -->
<dependency>
<groupId>com.alibaba.cloud.ai</groupId>
<artifactId>spring-ai-alibaba-bom</artifactId>
<version>${spring-ai-alibaba.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
</project>

注意点:

  • 必须使用 Java 17 或以上版本
  • dependencyManagement 中引入 BOM 后,子模块就不需要指定版本了

2.2 子模块依赖配置

DeepSeek 接入

​ 在子模块的 pom.xml 中添加:

1
2
3
4
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-starter-model-deepseek</artifactId>
</dependency>

​ 这个 starter 会自动配置 DeepSeekChatModel,只需要在配置文件中设置 API Key 就能用。

阿里百炼接入

1
2
3
4
<dependency>
<groupId>com.alibaba.cloud.ai</groupId>
<artifactId>spring-ai-alibaba-starter-dashscope</artifactId>
</dependency>

​ 阿里百炼的依赖是 spring-ai-alibaba 提供的,配置方式类似。

Ollama 接入(本地模型)

1
2
3
4
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-starter-model-ollama</artifactId>
</dependency>

​ Ollama 适合本地部署,不需要 API Key,但需要本地安装 Ollama 服务。

2.3 配置文件

​ 在 application.properties 中配置:

1
2
3
4
5
6
7
8
9
10
11
12
13
spring.application.name=quick-start

# DeepSeek 配置
spring.ai.deepseek.api-key=sk-your-api-key-here
spring.ai.deepseek.chat.options.model=deepseek-chat

# DashScope(阿里百炼)配置
spring.ai.dashscope.api-key=sk-your-api-key-here
spring.ai.dashscope.chat.options.model=qwen-plus

# 日志配置(调试时开启)
logging.level.org.springframework.ai=INFO
logging.level.org.springframework.ai.chat.client.advisor.SimpleLoggerAdvisor=DEBUG

配置说明:

  • api-key:从对应平台获取的 API Key
  • chat.options.model:使用的模型名称,DeepSeek 常用 deepseek-chat,阿里百炼常用 qwen-plus
  • 日志级别建议开发时设为 DEBUG,生产环境设为 INFO

获取 API Key:

三、快速上手

3.1 同步调用

​ 最简单的用法,直接调用 call() 方法:

1
2
3
4
5
6
7
8
9
10
11
12
@SpringBootTest
public class DeepSeekTest {

@Autowired
private DeepSeekChatModel deepSeekChatModel;

@Test
public void call() {
String response = deepSeekChatModel.call("你好,你是谁");
System.out.println(response);
}
}

​ 这种方式会等待 AI 完整回复后再返回,适合简单场景。如果回复很长,会等很久。

实际运行结果:

1
你好!我是 DeepSeek,一个由深度求索(DeepSeek)开发的 AI 助手...

3.2 流式调用

​ 流式调用可以实时返回内容,用户体验更好。返回的是 Flux<ChatResponse>,需要处理响应流:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
@Test
public void testDeepSeekStream(@Autowired DeepSeekChatModel deepSeekChatModel) {
// 创建选项,设置温度值
DeepSeekChatOptions options = new DeepSeekChatOptions();
options.setTemperature(2.0); // 温度越高,输出越随机

// 创建 Prompt
Prompt prompt = new Prompt("写一首上班加班太累的打油诗", options);

// 流式调用
Flux<ChatResponse> stream = deepSeekChatModel.stream(prompt);

// 处理流:提取文本内容并打印
stream.mapNotNull(e -> e.getResult().getOutput().getText())
.filter(Objects::nonNull)
.toIterable()
.forEach(System.out::print);
}

关键点:

  • mapNotNull:提取每个响应中的文本内容,过滤掉 null
  • filter(Objects::nonNull):再次过滤,确保不为空
  • toIterable().forEach:转换为可迭代对象,逐个打印

实际效果:
​ 会逐字逐句打印出来,而不是一次性返回全部内容。

3.3 深度思考模式

​ DeepSeek 支持深度思考模式(Reasoner),可以看到模型的思考过程。这在调试和优化 Prompt 时很有用。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
@Test
public void testDeepSeekThink(@Autowired DeepSeekChatModel deepSeekChatModel) {
DeepSeekChatOptions options = new DeepSeekChatOptions();
options.setTemperature(2.0);
Prompt prompt = new Prompt("写一首上班加班太累的打油诗", options);

Flux<ChatResponse> stream = deepSeekChatModel.stream(prompt);

stream.mapNotNull(e -> {
AssistantMessage output = e.getResult().getOutput();
return output;
})
.filter(Objects::nonNull)
.toIterable()
.forEach(e -> {
// 获取思考过程(如果有)
if (Objects.nonNull(e.getMetadata().get("reasoningContent"))) {
System.out.print(e.getMetadata().get("reasoningContent"));
}
// 获取最终回复
if (Objects.nonNull(e.getText())) {
System.out.print(e.getText());
}
});
}

关键点:

  • 思考内容在 metadatareasoningContent 字段中
  • 最终回复在 getText() 方法中
  • 思考内容和最终回复是分开返回的

实际效果:

1
2
[思考过程] 用户想要一首关于加班累的打油诗,我需要用幽默的方式表达...
[最终回复] 上班加班累成狗,代码写到手发抖...

阿里百炼的思考模式

​ 阿里百炼也支持思考模式,但需要显式开启:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
@Test
public void testDashScopeThink(@Autowired DashScopeChatModel dashScopeChatModel) {
DashScopeChatOptions options = new DashScopeChatOptions();
options.setTemperature(1.9);
options.setEnableThinking(true); // 必须显式开启

Prompt prompt = new Prompt("写一首上班加班太累的打油诗", options);
Flux<ChatResponse> stream = dashScopeChatModel.stream(prompt);

StringBuilder reasoningContent = new StringBuilder();
StringBuilder finalContent = new StringBuilder();

stream.mapNotNull(e -> {
if (Objects.nonNull(e.getResult())) {
return e.getResult().getOutput();
}
return null;
})
.filter(Objects::nonNull)
.toIterable()
.forEach(e -> {
// 收集思考内容
if (Objects.nonNull(e.getMetadata().get("reasoningContent"))) {
reasoningContent.append(e.getMetadata().get("reasoningContent"));
}
// 收集最终回复
if (Objects.nonNull(e.getText())) {
finalContent.append(e.getText());
}
});

System.out.println("【思考】" + reasoningContent);
System.out.println("【回复】" + finalContent);
}

区别:

  • DeepSeek:默认支持思考模式
  • 阿里百炼:需要设置 enableThinking(true) 才能看到思考过程

3.4 ChatOptions 参数说明

DeepSeekChatOptions

1
2
3
4
DeepSeekChatOptions options = new DeepSeekChatOptions();
options.setTemperature(2.0); // 0-2,控制随机性,越大越随机
options.setMaxTokens(2000); // 最大输出 token 数
options.setTopP(0.9); // 核采样参数,0-1

参数建议:

  • temperature:创作类任务用 1.5-2.0,问答类用 0.7-1.0
  • maxTokens:根据需求设置,一般 1000-2000 够用
  • topP:一般用默认值就行

DashScopeChatOptions

1
2
3
4
DashScopeChatOptions options = new DashScopeChatOptions();
options.setTemperature(1.9);
options.setEnableThinking(true); // 是否启用思考模式
options.setMaxTokens(2000);

四、常见问题

4.1 API Key 配置不生效

问题: 配置了 API Key 但启动报错,提示找不到配置。

原因:

  • API Key 配置错误
  • 配置文件路径不对
  • 环境变量覆盖了配置文件

解决:

  1. 检查配置文件中的 Key 是否正确
  2. 确认配置文件在 src/main/resources 目录下
  3. 检查是否有环境变量覆盖(如 SPRING_AI_DEEPSEEK_API_KEY

4.2 流式调用没有输出

问题: 调用 stream() 方法后没有任何输出。

原因:

  • 没有订阅流(Flux 是惰性的)
  • 异常被吞掉了

解决:

1
2
3
4
5
6
7
8
9
// 错误写法:没有订阅
Flux<ChatResponse> stream = deepSeekChatModel.stream(prompt);
// 这样不会执行

// 正确写法:必须订阅
stream.mapNotNull(...)
.filter(...)
.toIterable() // 这里会触发订阅
.forEach(...);

4.3 思考模式看不到思考内容

问题: 开启了思考模式但看不到思考过程。

原因:

  • DeepSeek:某些模型不支持思考模式
  • 阿里百炼:忘记设置 enableThinking(true)

解决:

  • DeepSeek:确认使用的是支持思考的模型(如 deepseek-reasoner
  • 阿里百炼:必须显式设置 options.setEnableThinking(true)

4.4 中文乱码

问题: 返回的中文内容乱码。

原因:

  • 编码问题
  • HTTP 响应头没有设置编码

解决:

1
2
3
4
@GetMapping(value = "/stream", produces = "text/stream;charset=utf-8")
public Flux<String> streamChat(...) {
// produces 中指定 charset=utf-8
}

4.5 依赖冲突

问题: 引入 Spring AI 后出现依赖冲突。

原因:

  • Spring Boot 版本不兼容
  • 其他依赖版本冲突

解决:

  1. 确认 Spring Boot 版本是 3.x(Spring AI 1.0.1 需要 Spring Boot 3.5+)
  2. 使用 mvn dependency:tree 查看依赖树
  3. 在父工程中统一管理版本

五、总结

  1. 统一接口:Spring AI 提供了统一的 ChatModel 接口,切换模型只需要改配置
  2. 同步 vs 流式:简单场景用同步调用,需要实时反馈用流式调用
  3. 思考模式:DeepSeek 默认支持,阿里百炼需要显式开启
  4. 配置要点:API Key 和模型名称是必须的,其他参数按需设置
  5. 常见坑:流式调用必须订阅、中文编码问题、依赖版本冲突

​ 下一篇文章会介绍 ChatClient 的使用,这是 Spring AI 提供的高级 API,比直接使用 ChatModel 更方便。