1. 项目概述与背景
最近在开发一个需要集成AI能力的Java应用,经过技术选型后决定使用Spring AI框架对接DeepSeek的大模型服务。Spring AI是Spring官方推出的AI应用开发框架,它抽象了不同AI服务提供商的接口,让我们可以用统一的方式调用各种大模型。而DeepSeek作为国内优秀的AI服务提供商,其模型在中文场景下表现优异。
这个项目将展示如何在IntelliJ IDEA中从零开始搭建一个Spring Boot应用,集成Spring AI和DeepSeek服务,实现基础的对话功能。我会详细介绍每个步骤的注意事项和实际开发中可能遇到的问题。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 环境准备与项目创建
2.1 开发环境要求
在开始之前,确保你的开发环境满足以下要求:
- JDK 17+:Spring Boot 3.x需要Java 17或更高版本
- IntelliJ IDEA 2022.3+:推荐使用专业版,社区版也能满足基本需求
- Maven 3.6+:用于项目依赖管理
- DeepSeek API Key:需要提前在DeepSeek官网申请
提示:如果你之前使用的是JDK 8或11,需要先升级JDK。可以在终端运行
java -version检查当前JDK版本。
2.2 创建Spring Boot项目
在IntelliJ IDEA中创建新项目的步骤如下:
- 打开IDEA,点击"New Project"
- 选择"Spring Initializr"
- 设置项目基本信息:
- Name: spring-ai-deepseek
- Location: 选择你的项目存储路径
- Language: Java
- Type: Maven
- Group: com.springai
- Artifact: spring-ai-deepseek
- Package name: com.springai.deepseek
- Java: 17
- 在依赖选择界面,添加以下依赖:
- Spring Web
- MySQL Driver (可选,根据项目需求)
- Lombok (简化代码)
关键点:Spring Boot版本需要选择3.0到4.0之间的版本,我使用的是3.5.12。这是因为Spring AI 1.x版本对Spring Boot的版本有特定要求。
3. 项目配置与依赖管理
3.1 修改pom.xml文件
创建项目后,需要修改pom.xml添加Spring AI和DeepSeek相关的依赖。以下是完整的pom.xml配置:
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.5.12</version>
<relativePath/>
</parent>
<groupId>com.springai</groupId>
<artifactId>spring-ai-deepseek</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>spring-ai-deepseek</name>
<description>Spring AI integration with DeepSeek</description>
<properties>
<java.version>17</java.version>
<spring-ai.version>1.1.2</spring-ai.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- Spring AI DeepSeek Starter -->
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-starter-model-deepseek</artifactId>
</dependency>
<!-- 其他依赖 -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<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>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
<repositories>
<repository>
<id>spring-snapshots</id>
<name>Spring Snapshots</name>
<url>https://repo.spring.io/snapshot</url>
<releases>
<enabled>false</enabled>
</releases>
</repository>
</repositories>
</project>
关键配置说明:
spring-ai.version指定了Spring AI的版本- 通过
dependencyManagement引入Spring AI的BOM,统一管理所有Spring AI相关依赖的版本 - 添加了
spring-ai-starter-model-deepseek依赖,这是Spring AI对DeepSeek的官方支持
3.2 配置application.yaml
在resources目录下创建application.yaml文件,添加DeepSeek的配置:
yaml复制spring:
application:
name: spring-ai-deepseek
ai:
deepseek:
api-key: ${DEEPSEEK_API_KEY} # 从环境变量读取
base-url: https://dashscope.aliyuncs.com/compatible-mode/v1
chat:
options:
model: deepseek-r1
temperature: 0.7
配置说明:
api-key建议通过环境变量配置,不要在代码中硬编码敏感信息base-url是DeepSeek的API端点temperature参数控制生成文本的随机性,值越高结果越有创造性
安全提示:永远不要将API密钥直接提交到代码仓库。可以通过环境变量或专门的密钥管理工具来管理敏感信息。
4. 核心代码实现
4.1 配置类实现
创建一个配置类来初始化ChatClient:
java复制package com.springai.deepseek.config;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.deepseek.DeepSeekChatModel;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class CommonConfiguration {
@Bean
public ChatClient chatClient(DeepSeekChatModel model) {
return ChatClient.builder(model)
.defaultSystem("你是由深度求索(DeepSeek)开发的俏皮可爱的人工智能助手,名字叫小深,可以帮助我解决各种问题,比如学习、写作、编程、翻译、资料整理等等。")
.build();
}
}
这个配置类做了两件事:
- 注入DeepSeekChatModel,这是Spring AI提供的DeepSeek模型客户端
- 创建ChatClient并设置默认的系统消息,定义AI助手的角色和性格
4.2 控制器实现
创建ChatController处理用户请求:
java复制package com.springai.deepseek.controller;
import lombok.RequiredArgsConstructor;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import reactor.core.publisher.Flux;
@RestController
@RequestMapping("/ai")
@RequiredArgsConstructor
public class ChatController {
private final ChatClient chatClient;
/**
* 阻塞式对话接口
* @param prompt 用户输入的问题或提示
* @return AI生成的完整回答
*/
@GetMapping("/chat")
public String chat(@RequestParam String prompt) {
return chatClient.prompt()
.user(prompt)
.call()
.content();
}
/**
* 流式对话接口
* @param prompt 用户输入的问题或提示
* @return 流式响应的AI回答
*/
@GetMapping(value = "/streamChat", produces = "text/html;charset=UTF-8")
public Flux<String> streamChat(@RequestParam String prompt) {
return chatClient.prompt()
.user(prompt)
.stream()
.content();
}
}
这个控制器提供了两个接口:
/ai/chat- 阻塞式接口,等待AI生成完整回答后一次性返回/ai/streamChat- 流式接口,实时返回AI生成的每个词
5. 项目测试与调试
5.1 设置环境变量
在运行项目前,需要设置DeepSeek的API密钥。在Linux/macOS上:
bash复制export DEEPSEEK_API_KEY=your_api_key_here
在Windows上:
cmd复制setx DEEPSEEK_API_KEY "your_api_key_here"
设置完成后需要重启IntelliJ IDEA使环境变量生效。
5.2 启动项目
在IDEA中直接运行主类,或使用Maven命令:
bash复制mvn spring-boot:run
5.3 测试接口
- 测试阻塞式接口:
code复制http://localhost:8080/ai/chat?prompt=你好,你是谁?
- 测试流式接口:
code复制http://localhost:8080/ai/streamChat?prompt=你好,你是谁?
流式接口会实时显示AI的回答,适合需要即时反馈的场景。
6. 常见问题与解决方案
6.1 依赖下载失败
如果遇到Spring AI依赖下载失败,可能是因为没有配置正确的仓库。确保pom.xml中包含Spring的snapshot仓库:
xml复制<repositories>
<repository>
<id>spring-snapshots</id>
<name>Spring Snapshots</name>
<url>https://repo.spring.io/snapshot</url>
<releases>
<enabled>false</enabled>
</releases>
</repository>
</repositories>
6.2 API密钥无效
如果收到认证失败的错误,检查:
- API密钥是否正确
- 环境变量是否设置正确
- 是否重启了IDEA使环境变量生效
6.3 流式接口返回乱码
确保在流式接口的@RequestMapping中指定了produces:
java复制@GetMapping(value = "/streamChat", produces = "text/html;charset=UTF-8")
6.4 模型响应慢
可以尝试调整temperature参数,较低的值会使响应更快但更保守:
yaml复制spring:
ai:
deepseek:
chat:
options:
temperature: 0.3
7. 项目优化与扩展
7.1 添加对话历史
为了实现多轮对话,可以修改控制器保存对话上下文:
java复制@GetMapping("/chatWithHistory")
public String chatWithHistory(@RequestParam String prompt, HttpSession session) {
List<Message> history = (List<Message>) session.getAttribute("chatHistory");
if (history == null) {
history = new ArrayList<>();
}
ChatResponse response = chatClient.prompt()
.messages(history)
.user(prompt)
.call();
history.add(new UserMessage(prompt));
history.add(new AssistantMessage(response.getResult().getOutput().getContent()));
session.setAttribute("chatHistory", history);
return response.getResult().getOutput().getContent();
}
7.2 添加速率限制
为了防止滥用,可以添加速率限制:
java复制@Bean
public ChatClient chatClient(DeepSeekChatModel model) {
return ChatClient.builder(model)
.defaultSystem("...")
.withRateLimiter(RateLimiter.create(10)) // 每秒10个请求
.build();
}
7.3 添加日志记录
记录所有AI交互用于分析和调试:
java复制@Bean
public ChatClient chatClient(DeepSeekChatModel model) {
return ChatClient.builder(model)
.defaultSystem("...")
.withLogging(new Slf4jLogger(ChatClient.class))
.build();
}
8. 实际开发中的经验分享
-
版本兼容性:Spring AI的版本与Spring Boot版本有严格的对应关系,选择版本时要特别注意。我最初使用了Spring Boot 3.2.0,结果发现与Spring AI 1.1.2不兼容,后来降级到3.5.12才解决问题。
-
环境变量管理:在团队开发中,建议使用统一的.env文件管理环境变量,而不是每个人都手动设置。可以使用dotenv-java库来加载.env文件。
-
流式响应优化:在前端对接流式接口时,发现某些浏览器对分块传输编码的支持不一致。最终我们决定在前端使用EventSource API来接收流式响应,兼容性更好。
-
超时设置:默认情况下,Spring Web的响应超时时间可能不够长,特别是处理复杂问题时。可以在application.yaml中调整:
yaml复制server:
servlet:
async:
request-timeout: 30000 # 30秒
-
模型选择:DeepSeek提供了多个模型,不同模型在速度和效果上有差异。经过测试,deepseek-r1在中文场景下表现良好,而deepseek-r2在代码生成方面更强。可以根据具体需求选择合适的模型。
-
温度参数调优:temperature参数对生成结果影响很大。对于事实性问题,建议使用较低的值(0.3-0.5);对于创意性任务,可以使用较高的值(0.7-1.0)。我们在项目中根据不同的接口需求设置了不同的temperature值。
