2026 年是 AI Agent 爆发的一年,越来越多的企业开始将 AI 能力集成到内部系统中。DeepSeek 作为国内领先的大模型提供商,凭借其出色的代码能力和工具调用支持,成为了企业级 AI 应用的首选之一。
本文将详细介绍如何使用 SpringBoot 3.x 快速集成 DeepSeek API,实现一个具备工具调用能力、多轮对话记忆和流式输出的企业级 AI Agent。文章包含完整的代码实现和最佳实践,你可以直接复制到项目中使用。
首先,你需要在 DeepSeek 官网注册账号并获取 API Key:
在你的 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.2.5</version>
<relativePath/>
</parent>
<groupId>com.example</groupId>
<artifactId>deepseek-agent-demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>deepseek-agent-demo</name>
<description>DeepSeek AI Agent Demo with SpringBoot</description>
<properties>
<java.version>17</java.version>
</properties>
<dependencies>
<!-- SpringBoot Web -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- OkHttp -->
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp</artifactId>
<version>4.12.0</version>
</dependency>
<!-- Jackson -->
<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>
<!-- SpringBoot Test -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>
</project>在 application.yml 中添加 DeepSeek 配置:
spring:
application:
name: deepseek-agent-demo
deepseek:
api:
key: your-api-key-here
base-url: https://api.deepseek.com
model: deepseek-chat
timeout: 60000
server:
port: 8080首先,我们创建一个 DeepSeek API 客户端,用于与 DeepSeek 服务器进行通信:
package com.example.deepseekagentdemo.client;
import com.example.deepseekagentdemo.dto.*;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.RequiredArgsConstructor;
import okhttp3.*;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import java.io.IOException;
import java.util.List;
import java.util.concurrent.TimeUnit;
@Component
@RequiredArgsConstructor
public class DeepSeekClient {
@Value("${deepseek.api.key}")
private String apiKey;
@Value("${deepseek.api.base-url}")
private String baseUrl;
@Value("${deepseek.api.model}")
private String model;
@Value("${deepseek.api.timeout}")
private int timeout;
private final ObjectMapper objectMapper;
private OkHttpClient okHttpClient;
// 初始化 OkHttpClient
@jakarta.annotation.PostConstruct
public void init() {
this.okHttpClient = new OkHttpClient.Builder()
.connectTimeout(timeout, TimeUnit.MILLISECONDS)
.readTimeout(timeout, TimeUnit.MILLISECONDS)
.writeTimeout(timeout, TimeUnit.MILLISECONDS)
.build();
}
// 发送聊天请求
public ChatResponse chat(ChatRequest request) throws IOException {
// 设置默认模型
if (request.getModel() == null) {
request.setModel(model);
}
// 构建请求体
RequestBody body = RequestBody.create(
objectMapper.writeValueAsString(request),
MediaType.parse("application/json")
);
// 构建请求
Request httpRequest = new Request.Builder()
.url(baseUrl + "/v1/chat/completions")
.header("Authorization", "Bearer " + apiKey)
.header("Content-Type", "application/json")
.post(body)
.build();
// 发送请求并获取响应
try (Response response = okHttpClient.newCall(httpRequest).execute()) {
if (!response.isSuccessful()) {
throw new IOException("DeepSeek API 请求失败: " + response.code() + " " + response.message());
}
String responseBody = response.body().string();
return objectMapper.readValue(responseBody, ChatResponse.class);
}
}
// 发送流式聊天请求
public void streamChat(ChatRequest request, StreamResponseHandler handler) throws IOException {
// 设置默认模型和流式输出
if (request.getModel() == null) {
request.setModel(model);
}
request.setStream(true);
// 构建请求体
RequestBody body = RequestBody.create(
objectMapper.writeValueAsString(request),
MediaType.parse("application/json")
);
// 构建请求
Request httpRequest = new Request.Builder()
.url(baseUrl + "/v1/chat/completions")
.header("Authorization", "Bearer " + apiKey)
.header("Content-Type", "application/json")
.post(body)
.build();
// 发送请求并处理流式响应
okHttpClient.newCall(httpRequest).enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
handler.onError(e);
}
@Override
public void onResponse(Call call, Response response) throws IOException {
if (!response.isSuccessful()) {
handler.onError(new IOException("DeepSeek API 请求失败: " + response.code() + " " + response.message()));
return;
}
try (ResponseBody responseBody = response.body()) {
if (responseBody == null) {
handler.onComplete();
return;
}
// 逐行读取响应
String line;
while ((line = responseBody.source().readUtf8Line()) != null) {
if (line.isEmpty()) {
continue;
}
if (line.startsWith("data: ")) {
String data = line.substring(6);
if (data.equals("[DONE]")) {
handler.onComplete();
break;
}
try {
StreamChatResponse streamResponse = objectMapper.readValue(data, StreamChatResponse.class);
handler.onNext(streamResponse);
} catch (Exception e) {
handler.onError(e);
}
}
}
}
}
});
}
}接下来,我们定义与 DeepSeek API 交互所需的数据传输对象:
package com.example.deepseekagentdemo.dto;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.List;
import java.util.Map;
// 聊天请求
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class ChatRequest {
private String model;
private List<Message> messages;
private List<Tool> tools;
@JsonProperty("tool_choice")
private String toolChoice;
private boolean stream;
private double temperature;
@JsonProperty("max_tokens")
private int maxTokens;
}
// 消息
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class Message {
private String role;
private String content;
private List<ToolCall> toolCalls;
@JsonProperty("tool_call_id")
private String toolCallId;
}
// 工具
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class Tool {
private String type;
private Function function;
}
// 函数
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class Function {
private String name;
private String description;
private Map<String, Object> parameters;
}
// 工具调用
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class ToolCall {
private String id;
private String type;
private FunctionCall function;
}
// 函数调用
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class FunctionCall {
private String name;
private String arguments;
}
// 聊天响应
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class ChatResponse {
private String id;
private String object;
private long created;
private String model;
private List<Choice> choices;
private Usage usage;
}
// 选择
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class Choice {
private int index;
private Message message;
@JsonProperty("finish_reason")
private String finishReason;
}
// 使用情况
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class Usage {
@JsonProperty("prompt_tokens")
private int promptTokens;
@JsonProperty("completion_tokens")
private int completionTokens;
@JsonProperty("total_tokens")
private int totalTokens;
}
// 流式聊天响应
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class StreamChatResponse {
private String id;
private String object;
private long created;
private String model;
private List<StreamChoice> choices;
}
// 流式选择
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class StreamChoice {
private int index;
private Message delta;
@JsonProperty("finish_reason")
private String finishReason;
}
// 流式响应处理器
public interface StreamResponseHandler {
void onNext(StreamChatResponse response);
void onError(Throwable e);
void onComplete();
}现在,我们实现工具调用的核心逻辑。首先定义一个工具接口:
package com.example.deepseekagentdemo.tool;
import java.util.Map;
public interface Tool {
// 获取工具名称
String getName();
// 获取工具描述
String getDescription();
// 获取工具参数定义
Map<String, Object> getParameters();
// 执行工具
String execute(Map<String, Object> arguments);
}然后,实现一个简单的天气查询工具作为示例:
package com.example.deepseekagentdemo.tool;
import org.springframework.stereotype.Component;
import java.util.HashMap;
import java.util.Map;
@Component
public class WeatherTool implements Tool {
@Override
public String getName() {
return "get_weather";
}
@Override
public String getDescription() {
return "获取指定城市的天气信息";
}
@Override
public Map<String, Object> getParameters() {
Map<String, Object> parameters = new HashMap<>();
parameters.put("type", "object");
Map<String, Object> properties = new HashMap<>();
Map<String, Object> city = new HashMap<>();
city.put("type", "string");
city.put("description", "城市名称,例如:北京、上海、深圳");
properties.put("city", city);
parameters.put("properties", properties);
parameters.put("required", new String[]{"city"});
return parameters;
}
@Override
public String execute(Map<String, Object> arguments) {
String city = (String) arguments.get("city");
// 这里模拟天气查询,实际项目中可以调用第三方天气API
Map<String, String> weatherData = new HashMap<>();
weatherData.put("北京", "晴,15-25℃,微风");
weatherData.put("上海", "多云,18-28℃,东南风3级");
weatherData.put("深圳", "雷阵雨,22-30℃,西南风2级");
weatherData.put("广州", "阴,20-29℃,东北风2级");
String weather = weatherData.getOrDefault(city, "暂无" + city + "的天气信息");
return city + "今日天气:" + weather;
}
}最后,我们实现 AI Agent 服务,整合聊天和工具调用功能:
package com.example.deepseekagentdemo.service;
import com.example.deepseekagentdemo.client.DeepSeekClient;
import com.example.deepseekagentdemo.dto.*;
import com.example.deepseekagentdemo.tool.Tool;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import java.io.IOException;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
@Service
@RequiredArgsConstructor
public class AgentService {
private final DeepSeekClient deepSeekClient;
private final List<Tool> tools;
private final ObjectMapper objectMapper;
// 会话存储,实际项目中可以使用Redis
private final Map<String, List<Message>> sessionStore = new ConcurrentHashMap<>();
// 获取工具定义列表
private List<com.example.deepseekagentdemo.dto.Tool> getToolDefinitions() {
List<com.example.deepseekagentdemo.dto.Tool> toolDefinitions = new ArrayList<>();
for (Tool tool : tools) {
com.example.deepseekagentdemo.dto.Tool dtoTool = com.example.deepseekagentdemo.dto.Tool.builder()
.type("function")
.function(Function.builder()
.name(tool.getName())
.description(tool.getDescription())
.parameters(tool.getParameters())
.build())
.build();
toolDefinitions.add(dtoTool);
}
return toolDefinitions;
}
// 执行工具调用
private List<Message> executeToolCalls(List<ToolCall> toolCalls) {
List<Message> toolResponses = new ArrayList<>();
for (ToolCall toolCall : toolCalls) {
String toolName = toolCall.getFunction().getName();
String argumentsStr = toolCall.getFunction().getArguments();
try {
// 解析参数
Map<String, Object> arguments = objectMapper.readValue(argumentsStr, new TypeReference<Map<String, Object>>() {});
// 查找对应的工具
Tool tool = tools.stream()
.filter(t -> t.getName().equals(toolName))
.findFirst()
.orElseThrow(() -> new RuntimeException("工具不存在: " + toolName));
// 执行工具
String result = tool.execute(arguments);
// 构建工具响应消息
Message toolResponse = Message.builder()
.role("tool")
.toolCallId(toolCall.getId())
.content(result)
.build();
toolResponses.add(toolResponse);
} catch (Exception e) {
// 构建错误响应
Message errorResponse = Message.builder()
.role("tool")
.toolCallId(toolCall.getId())
.content("工具执行失败: " + e.getMessage())
.build();
toolResponses.add(errorResponse);
}
}
return toolResponses;
}
// 发送消息给AI Agent
public String sendMessage(String sessionId, String userMessage) throws IOException {
// 获取或创建会话
List<Message> messages = sessionStore.computeIfAbsent(sessionId, k -> new ArrayList<>());
// 添加用户消息
messages.add(Message.builder()
.role("user")
.content(userMessage)
.build());
// 构建聊天请求
ChatRequest request = ChatRequest.builder()
.messages(new ArrayList<>(messages))
.tools(getToolDefinitions())
.temperature(0.7)
.maxTokens(2048)
.build();
// 发送请求
ChatResponse response = deepSeekClient.chat(request);
Message assistantMessage = response.getChoices().get(0).getMessage();
// 添加助手消息到会话
messages.add(assistantMessage);
// 检查是否需要调用工具
while (assistantMessage.getToolCalls() != null && !assistantMessage.getToolCalls().isEmpty()) {
// 执行工具调用
List<Message> toolResponses = executeToolCalls(assistantMessage.getToolCalls());
// 添加工具响应到会话
messages.addAll(toolResponses);
// 再次发送请求给AI
request.setMessages(new ArrayList<>(messages));
response = deepSeekClient.chat(request);
assistantMessage = response.getChoices().get(0).getMessage();
// 添加助手消息到会话
messages.add(assistantMessage);
}
// 更新会话
sessionStore.put(sessionId, messages);
return assistantMessage.getContent();
}
// 发送流式消息给AI Agent
public void sendStreamMessage(String sessionId, String userMessage, StreamResponseHandler handler) throws IOException {
// 获取或创建会话
List<Message> messages = sessionStore.computeIfAbsent(sessionId, k -> new ArrayList<>());
// 添加用户消息
messages.add(Message.builder()
.role("user")
.content(userMessage)
.build());
// 构建聊天请求
ChatRequest request = ChatRequest.builder()
.messages(new ArrayList<>(messages))
.tools(getToolDefinitions())
.temperature(0.7)
.maxTokens(2048)
.build();
// 发送流式请求
deepSeekClient.streamChat(request, new StreamResponseHandler() {
private final StringBuilder contentBuilder = new StringBuilder();
private List<ToolCall> toolCalls = new ArrayList<>();
@Override
public void onNext(StreamChatResponse response) {
if (response.getChoices() == null || response.getChoices().isEmpty()) {
return;
}
Message delta = response.getChoices().get(0).getDelta();
// 处理内容
if (delta.getContent() != null) {
contentBuilder.append(delta.getContent());
handler.onNext(response);
}
// 处理工具调用
if (delta.getToolCalls() != null) {
for (ToolCall toolCallDelta : delta.getToolCalls()) {
int index = toolCallDelta.getId() != null ?
Integer.parseInt(toolCallDelta.getId()) : toolCalls.size();
if (index >= toolCalls.size()) {
toolCalls.add(toolCallDelta);
} else {
ToolCall existingToolCall = toolCalls.get(index);
if (toolCallDelta.getFunction() != null) {
if (existingToolCall.getFunction() == null) {
existingToolCall.setFunction(toolCallDelta.getFunction());
} else {
FunctionCall existingFunction = existingToolCall.getFunction();
FunctionCall deltaFunction = toolCallDelta.getFunction();
if (deltaFunction.getName() != null) {
existingFunction.setName(deltaFunction.getName());
}
if (deltaFunction.getArguments() != null) {
existingFunction.setArguments(
(existingFunction.getArguments() == null ? "" : existingFunction.getArguments())
+ deltaFunction.getArguments()
);
}
}
}
}
}
}
}
@Override
public void onError(Throwable e) {
handler.onError(e);
}
@Override
public void onComplete() {
// 构建完整的助手消息
Message assistantMessage = Message.builder()
.role("assistant")
.content(contentBuilder.toString())
.toolCalls(toolCalls.isEmpty() ? null : toolCalls)
.build();
// 添加助手消息到会话
messages.add(assistantMessage);
// 检查是否需要调用工具
if (assistantMessage.getToolCalls() != null && !assistantMessage.getToolCalls().isEmpty()) {
try {
// 执行工具调用
List<Message> toolResponses = executeToolCalls(assistantMessage.getToolCalls());
// 添加工具响应到会话
messages.addAll(toolResponses);
// 再次发送流式请求
request.setMessages(new ArrayList<>(messages));
deepSeekClient.streamChat(request, handler);
} catch (Exception e) {
handler.onError(e);
}
} else {
// 更新会话
sessionStore.put(sessionId, messages);
handler.onComplete();
}
}
});
}
// 清除会话
public void clearSession(String sessionId) {
sessionStore.remove(sessionId);
}
}最后,我们创建一个 REST 控制器,提供 HTTP 接口:
package com.example.deepseekagentdemo.controller;
import com.example.deepseekagentdemo.dto.StreamChatResponse;
import com.example.deepseekagentdemo.dto.StreamResponseHandler;
import com.example.deepseekagentdemo.service.AgentService;
import jakarta.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
import java.io.IOException;
import java.util.UUID;
@RestController
@RequestMapping("/api/agent")
@RequiredArgsConstructor
public class AgentController {
private final AgentService agentService;
// 创建新会话
@PostMapping("/session")
public String createSession() {
return UUID.randomUUID().toString();
}
// 发送消息(非流式)
@PostMapping("/chat")
public String chat(@RequestParam String sessionId, @RequestParam String message) throws IOException {
return agentService.sendMessage(sessionId, message);
}
// 发送消息(流式)
@GetMapping(value = "/stream-chat", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
public SseEmitter streamChat(@RequestParam String sessionId, @RequestParam String message) {
SseEmitter emitter = new SseEmitter(60000L);
try {
agentService.sendStreamMessage(sessionId, message, new StreamResponseHandler() {
@Override
public void onNext(StreamChatResponse response) {
try {
emitter.send(SseEmitter.event()
.name("message")
.data(response));
} catch (Exception e) {
emitter.completeWithError(e);
}
}
@Override
public void onError(Throwable e) {
emitter.completeWithError(e);
}
@Override
public void onComplete() {
emitter.complete();
}
});
} catch (IOException e) {
emitter.completeWithError(e);
}
return emitter;
}
// 清除会话
@DeleteMapping("/session/{sessionId}")
public void clearSession(@PathVariable String sessionId) {
agentService.clearSession(sessionId);
}
}运行 SpringBoot 应用,应用将在 8080 端口启动。
发送 POST 请求到 http://localhost:8080/api/agent/session,获取会话 ID。
发送 POST 请求到 http://localhost:8080/api/agent/chat?sessionId=你的会话ID&message=你好,你将收到 AI 的回复。
发送 POST 请求到 http://localhost:8080/api/agent/chat?sessionId=你的会话ID&message=北京今天天气怎么样,AI 会自动调用天气查询工具并返回结果。
使用浏览器或 Postman 访问 http://localhost:8080/api/agent/stream-chat?sessionId=你的会话ID&message=写一篇关于SpringBoot的介绍文章,你将看到 AI 逐字逐句生成回复。
你可以将这个应用轻松部署到腾讯云 CVM 或容器服务上:
mvn clean package 命令打包应用java -jar deepseek-agent-demo-0.0.1-SNAPSHOT.jar 命令运行应用原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。