Spring Boot接入DeepSeek:5分钟给你的接口加上AI大脑
·
📖 目录
- 一、为什么选择 DeepSeek?
- 二、准备工作
- 三、创建 Spring Boot 项目
- 四、场景一:智能对话接口
- 五、场景二:文本翻译接口
- 六、场景三:文章摘要接口
- 七、流式输出(SSE)实现
- 八、异常处理与超时策略
- 九、总结与扩展
一、为什么选择 DeepSeek?
┌─────────────────────────────────────────────────────┐
│ 主流 AI 大模型对比(2026) │
├──────────┬──────────┬──────────┬─────────────────────┤
│ 模型 │ 价格 │ 中文能力 │ 特点 │
├──────────┼──────────┼──────────┤─────────────────────┤
│ DeepSeek │ ¥1/百万token │ ⭐⭐⭐⭐⭐ │ 性价比之王,Java友好 │
│ GPT-4o │ ¥30/百万token│ ⭐⭐⭐⭐ │ 生态最好 │
│ Claude │ ¥24/百万token│ ⭐⭐⭐⭐ │ 代码能力强 │
│ 文心一言 │ ¥12/百万token│ ⭐⭐⭐⭐ │ 国内合规 │
└──────────┴──────────┴──────────┴─────────────────────┘
DeepSeek 对 Java 开发者的优势:
- API 兼容 OpenAI 格式,直接用 HTTP 调用,无需额外 SDK
- 中文能力强,适合国内业务场景
- 价格低,开发和测试成本几乎可以忽略
- 响应快,普通对话 1-3 秒
二、准备工作
2.1 获取 API Key
- 访问 DeepSeek 开放平台
- 注册/登录账号
- 进入「API Keys」页面,创建新的 Key
- 复制保存(只显示一次!)
2.2 技术栈
Spring Boot 3.2.x + Java 17 + OkHttp + Jackson
不引入额外的 AI SDK,纯 HTTP 调用,方便理解和定制。
三、创建 Spring Boot 项目
3.1 项目结构
springboot-deepseek/
├── src/main/java/com/example/deepseek/
│ ├── DeepseekApplication.java # 启动类
│ ├── config/
│ │ └── DeepseekConfig.java # 配置类
│ ├── model/
│ │ ├── ChatRequest.java # 请求模型
│ │ ├── ChatResponse.java # 响应模型
│ │ └── ChatMessage.java # 消息模型
│ ├── service/
│ │ └── DeepseekService.java # AI 服务
│ └── controller/
│ └── AiController.java # 接口层
├── src/main/resources/
│ └── application.yml # 配置文件
└── pom.xml
3.2 依赖配置
<!-- pom.xml -->
<dependencies>
<!-- Spring Boot Web -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- OkHttp(HTTP 客户端,比 RestTemplate 更现代) -->
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp</artifactId>
<version>4.12.0</version>
</dependency>
<!-- Jackson(JSON 处理) -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</dependency>
<!-- Lombok(简化代码) -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
</dependencies>
3.3 配置文件
# application.yml
deepseek:
api-key: ${DEEPSEEK_API_KEY:sk-your-api-key}
base-url: https://api.deepseek.com
model: deepseek-chat
timeout: 30 # 超时时间(秒)
server:
port: 8080
3.4 配置类
package com.example.deepseek.config;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;
@Data
@Configuration
@ConfigurationProperties(prefix = "deepseek")
public class DeepseekConfig {
/** API Key */
private String apiKey;
/** API 基础URL */
private String baseUrl = "https://api.deepseek.com";
/** 模型名称 */
private String model = "deepseek-chat";
/** 请求超时时间(秒) */
private int timeout = 30;
}
3.5 数据模型
package com.example.deepseek.model;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.List;
/**
* 对话消息
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class ChatMessage {
/** 角色:system(系统)、user(用户)、assistant(助手) */
private String role;
/** 消息内容 */
private String content;
}
/**
* 请求体
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class ChatRequest {
private String model;
private List<ChatMessage> messages;
/** 温度:0-2,越低越确定,越高越随机 */
@Builder.Default
private double temperature = 0.7;
/** 最大生成 token 数 */
@Builder.Default
private int maxTokens = 1024;
public static ChatRequest of(String model, List<ChatMessage> messages) {
return ChatRequest.builder()
.model(model)
.messages(messages)
.build();
}
}
/**
* 响应体
*/
@Data
public class ChatResponse {
private String id;
private String object;
private long created;
private List<Choice> choices;
private Usage usage;
@Data
public static class Choice {
private int index;
private ChatMessage message;
@JsonProperty("finish_reason")
private String finishReason;
}
@Data
public static class Usage {
@JsonProperty("prompt_tokens")
private int promptTokens;
@JsonProperty("completion_tokens")
private int completionTokens;
@JsonProperty("total_tokens")
private int totalTokens;
}
/** 提取回复内容 */
public String getContent() {
if (choices != null && !choices.isEmpty()) {
return choices.get(0).getMessage().getContent();
}
return "";
}
}
四、场景一:智能对话接口
4.1 Service 层
package com.example.deepseek.service;
import com.example.deepseek.config.DeepseekConfig;
import com.example.deepseek.model.*;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import okhttp3.*;
import org.springframework.stereotype.Service;
import java.io.IOException;
import java.util.List;
import java.util.concurrent.TimeUnit;
@Slf4j
@Service
@RequiredArgsConstructor
public class DeepseekService {
private final DeepseekConfig config;
private final ObjectMapper objectMapper;
/** OkHttp 客户端(单例复用) */
private final OkHttpClient httpClient = new OkHttpClient.Builder()
.connectTimeout(30, TimeUnit.SECONDS)
.readTimeout(30, TimeUnit.SECONDS)
.writeTimeout(30, TimeUnit.SECONDS)
.build();
/**
* 普通对话(同步返回完整结果)
*/
public String chat(String userMessage, String systemPrompt) {
// 1. 构建消息列表
ChatMessage systemMsg = ChatMessage.builder()
.role("system")
.content(systemPrompt)
.build();
ChatMessage userMsg = ChatMessage.builder()
.role("user")
.content(userMessage)
.build();
ChatRequest request = ChatRequest.of(config.getModel(), List.of(systemMsg, userMsg));
// 2. 发送 HTTP 请求
try {
String jsonBody = objectMapper.writeValueAsString(request);
Request httpRequest = new Request.Builder()
.url(config.getBaseUrl() + "/v1/chat/completions")
.addHeader("Authorization", "Bearer " + config.getApiKey())
.addHeader("Content-Type", "application/json")
.post(RequestBody.create(jsonBody, MediaType.parse("application/json")))
.build();
try (Response response = httpClient.newCall(httpRequest).execute()) {
String responseBody = response.body().string();
if (!response.isSuccessful()) {
log.error("DeepSeek API 调用失败: status={}, body={}", response.code(), responseBody);
throw new RuntimeException("AI 服务暂不可用,请稍后重试");
}
// 3. 解析响应
ChatResponse chatResponse = objectMapper.readValue(responseBody, ChatResponse.class);
log.info("Token 使用: prompt={}, completion={}",
chatResponse.getUsage().getPromptTokens(),
chatResponse.getUsage().getCompletionTokens());
return chatResponse.getContent();
}
} catch (IOException e) {
log.error("调用 DeepSeek 异常", e);
throw new RuntimeException("AI 服务异常: " + e.getMessage());
}
}
}
4.2 Controller 层
package com.example.deepseek.controller;
import com.example.deepseek.model.ChatMessage;
import com.example.deepseek.service.DeepseekService;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.*;
import java.util.*;
@RestController
@RequestMapping("/api/ai")
@RequiredArgsConstructor
@CrossOrigin(origins = "*")
public class AiController {
private final DeepseekService deepseekService;
/**
* 场景一:智能对话
* POST /api/ai/chat
*/
@PostMapping("/chat")
public Map<String, String> chat(@RequestBody Map<String, String> request) {
String userMessage = request.get("message");
if (userMessage == null || userMessage.isBlank()) {
return Map.of("error", "消息不能为空");
}
String systemPrompt = "你是一个有帮助的AI助手,用简洁的中文回答问题。";
String reply = deepseekService.chat(userMessage, systemPrompt);
return Map.of("reply", reply);
}
}
4.3 测试
curl -X POST http://localhost:8080/api/ai/chat \
-H "Content-Type: application/json" \
-d '{"message": "用Java怎么实现单例模式?"}'
# 响应
{"reply": "Java实现单例模式有以下几种方式:\n\n1. 饿汉式(线程安全,推荐)..."}
五、场景二:文本翻译接口
// 在 AiController 中添加
/**
* 场景二:文本翻译
* POST /api/ai/translate
*/
@PostMapping("/translate")
public Map<String, String> translate(@RequestBody Map<String, String> request) {
String text = request.get("text");
String targetLang = request.getOrDefault("targetLang", "英文");
if (text == null || text.isBlank()) {
return Map.of("error", "文本不能为空");
}
String systemPrompt = String.format(
"你是一个专业翻译。将用户输入的文本翻译为%s。"
+ "只输出翻译结果,不要加任何解释。", targetLang
);
String translation = deepseekService.chat(text, systemPrompt);
return Map.of(
"original", text,
"translation", translation,
"targetLang", targetLang
);
}
# 测试翻译
curl -X POST http://localhost:8080/api/ai/translate \
-H "Content-Type: application/json" \
-d '{"text": "人工智能正在改变世界", "targetLang": "英文"}'
# 响应
{"original":"人工智能正在改变世界","translation":"Artificial Intelligence is changing the world.","targetLang":"英文"}
六、场景三:文章摘要接口
// 在 AiController 中添加
/**
* 场景三:文章摘要
* POST /api/ai/summarize
*/
@PostMapping("/summarize")
public Map<String, String> summarize(@RequestBody Map<String, String> request) {
String article = request.get("article");
String style = request.getOrDefault("style", "简洁");
if (article == null || article.isBlank()) {
return Map.of("error", "文章内容不能为空");
}
String systemPrompt = String.format(
"你是一个文章摘要助手。请用%s的风格,对用户提供的文章生成摘要。"
+ "摘要应包含:核心观点、关键数据和结论。"
+ "控制在200字以内。", style
);
String summary = deepseekService.chat(article, systemPrompt);
return Map.of(
"summary", summary,
"style", style,
"originalLength", String.valueOf(article.length())
);
}
七、流式输出(SSE)实现
对于长文本生成(如写文章、写代码),等待完整结果太慢了。SSE(Server-Sent Events)可以实现逐字输出,用户体验好得多。
7.1 Service 层添加流式方法
// 在 DeepseekService 中添加
/**
* 流式对话(SSE,逐 token 返回)
*/
public void chatStream(String userMessage, String systemPrompt,
Consumer<String> onToken) {
ChatMessage systemMsg = ChatMessage.builder()
.role("system").content(systemPrompt).build();
ChatMessage userMsg = ChatMessage.builder()
.role("user").content(userMessage).build();
ChatRequest request = ChatRequest.of(config.getModel(), List.of(systemMsg, userMsg));
try {
String jsonBody = objectMapper.writeValueAsString(request);
// 流式请求需要 stream=true
var requestNode = objectMapper.readTree(jsonBody);
((com.fasterxml.jackson.databind.node.ObjectNode) requestNode).put("stream", true);
Request httpRequest = new Request.Builder()
.url(config.getBaseUrl() + "/v1/chat/completions")
.addHeader("Authorization", "Bearer " + config.getApiKey())
.addHeader("Content-Type", "application/json")
.post(RequestBody.create(
objectMapper.writeValueAsString(requestNode),
MediaType.parse("application/json")))
.build();
httpClient.newCall(httpRequest).enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
log.error("流式请求失败", e);
onToken.accept("[错误: " + e.getMessage() + "]");
}
@Override
public void onResponse(Call call, Response response) throws IOException {
try (ResponseBody body = response.body()) {
if (!response.isSuccessful()) {
onToken.accept("[错误: HTTP " + response.code() + "]");
return;
}
// 逐行读取 SSE 数据
BufferedReader reader = new BufferedReader(
new InputStreamReader(body.byteStream()));
String line;
while ((line = reader.readLine()) != null) {
if (line.startsWith("data: ")) {
String data = line.substring(6).trim();
// 流结束标记
if ("[DONE]".equals(data)) break;
// 解析每个 token
var node = objectMapper.readTree(data);
String content = node.at("/choices/0/delta/content").asText("");
if (!content.isEmpty()) {
onToken.accept(content);
}
}
}
}
}
});
} catch (IOException e) {
log.error("构建流式请求失败", e);
onToken.accept("[错误: " + e.getMessage() + "]");
}
}
7.2 Controller 层添加 SSE 接口
// 在 AiController 中添加
import org.springframework.http.MediaType;
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
/**
* 流式对话接口(SSE)
* GET /api/ai/chat/stream?message=你好
*/
@GetMapping(value = "/chat/stream", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
public SseEmitter chatStream(@RequestParam String message) {
SseEmitter emitter = new SseEmitter(60_000L); // 60秒超时
deepseekService.chatStream(message, "你是一个有帮助的AI助手。", token -> {
try {
emitter.send(SseEmitter.event().data(token));
} catch (IOException e) {
emitter.completeWithError(e);
}
});
emitter.onCompletion(() -> log.info("SSE 连接关闭"));
emitter.onTimeout(() -> log.warn("SSE 连接超时"));
return emitter;
}
八、异常处理与超时策略
8.1 全局异常处理
package com.example.deepseek.config;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import java.util.Map;
@Slf4j
@RestControllerAdvice
public class GlobalExceptionHandler {
/** 处理所有未捕获异常 */
@ExceptionHandler(Exception.class)
public ResponseEntity<Map<String, String>> handleException(Exception e) {
log.error("系统异常", e);
return ResponseEntity
.status(HttpStatus.INTERNAL_SERVER_ERROR)
.body(Map.of("error", "系统异常,请稍后重试"));
}
/** 处理超时异常 */
@ExceptionHandler(java.net.SocketTimeoutException.class)
public ResponseEntity<Map<String, String>> handleTimeout(Exception e) {
log.warn("请求超时: {}", e.getMessage());
return ResponseEntity
.status(HttpStatus.REQUEST_TIMEOUT)
.body(Map.of("error", "AI 响应超时,请稍后重试"));
}
/** 处理参数异常 */
@ExceptionHandler(IllegalArgumentException.class)
public ResponseEntity<Map<String, String>> handleIllegalArgument(Exception e) {
return ResponseEntity
.status(HttpStatus.BAD_REQUEST)
.body(Map.of("error", e.getMessage()));
}
}
8.2 超时策略总结
┌─────────────────────────────────────────────────────┐
│ 三层超时防护 │
├──────────────┬──────────┬───────────────────────────┤
│ 层级 │ 超时时间 │ 说明 │
├──────────────┼──────────┼───────────────────────────┤
│ OkHttp 连接 │ 10秒 │ 建立TCP连接超时 │
│ OkHttp 读取 │ 30秒 │ 等待API响应超时 │
│ SSE Emitter │ 60秒 │ 流式连接保活超时 │
└──────────────┴──────────┴───────────────────────────┘
九、总结与扩展
9.1 完整接口一览
| 接口 | 方法 | 路径 | 用途 |
|---|---|---|---|
| 智能对话 | POST | /api/ai/chat |
通用对话 |
| 文本翻译 | POST | /api/ai/translate |
多语言翻译 |
| 文章摘要 | POST | /api/ai/summarize |
文本摘要 |
| 流式对话 | GET | /api/ai/chat/stream |
SSE逐字输出 |
9.2 扩展方向
- 接入数据库:存储对话历史,实现多轮对话
- 接入缓存:相同问题直接返回缓存结果,减少 API 调用
- 接入消息队列:异步处理高并发请求
- 接入 RAG:结合向量数据库,让 AI 回答业务相关问题
- 接入 Function Calling:让 AI 调用你的业务接口
🎉 总结:整个项目核心代码不到 400 行,5 分钟跑通。DeepSeek 的 OpenAI 兼容格式让 Java 接入变得极其简单,不需要学习任何新框架。
如果觉得有帮助,点赞 + 收藏支持一下!有问题欢迎评论区讨论 💬
更多推荐


所有评论(0)