Spring AI 1.0实战:构建基于DeepSeek的智能客服系统
一、引言
随着人工智能技术的飞速发展,大语言模型(LLM)正在深刻改变着我们构建应用的方式。Spring AI 1.0作为Spring生态系统中首个AI框架,为Java开发者提供了一种简洁、优雅的方式来集成AI能力到应用中。
本文将带领大家从零开始,使用Spring AI 1.0构建一个完整的智能客服系统,并对接国产优秀大模型DeepSeek。通过实际案例,你将掌握Spring AI的核心概念、配置方法以及在实际项目中的应用。

二、Spring AI 1.0概述
2.1 什么是Spring AI
Spring AI是一个为AI工程应用设计的框架,它继承了Spring生态系统的核心理念------可移植性、模块化和可扩展性。Spring AI提供了:
- 统一的API接口:支持多种AI模型提供商
- 提示词模板管理:简化提示词的构建和版本控制
- 函数调用能力:让LLM能够调用外部服务和工具
- 向量数据库集成:支持RAG(检索增强生成)架构
- 流式响应支持:提供更好的用户体验
2.2 核心组件
Spring AI主要由以下几个核心组件构成:
- ChatClient:与LLM进行对话的主要接口
- Prompt Manager:管理和组织提示词模板
- Function Calling:函数调用机制
- Vector Store:向量存储抽象层
- Embedding Model:文本向量化接口
2.3 技术栈选型
本实例采用以下技术栈:
- Spring Boot 3.2:现代化Java应用开发框架
- Spring AI 1.0:AI集成框架
- DeepSeek API:国产高性能大语言模型
- MySQL 8.0:关系型数据库
- Redis:缓存和会话管理
- WebSocket:实时通信协议
三、系统架构设计
3.1 整体架构
我们的智能客服系统采用分层架构设计,确保系统的可扩展性和可维护性。

架构说明:
- 表现层(Presentation Layer):提供Web界面和API接口
- 应用层(Application Layer):实现业务逻辑和AI对话管理
- 领域层(Domain Layer):核心业务模型和规则
- 基础设施层(Infrastructure Layer):外部服务集成和数据持久化
- AI服务层(AI Service Layer):Spring AI与DeepSeek的集成
3.2 核心模块划分
系统包含以下核心模块:
- 对话管理模块:管理用户会话和对话历史
- 知识库模块:存储和管理企业知识文档
- 意图识别模块:理解用户需求并分类
- 消息路由模块:将用户请求分发到合适的处理单元
- 监控统计模块:跟踪系统性能和用户满意度
四、系统集成流程
4.1 系统交互流程
用户与智能客服系统的交互遵循一个清晰的处理流程。

交互步骤说明:
- 用户发起对话请求
- 系统验证用户身份并加载历史会话
- 意图识别模块分析用户输入
- 根据意图类型选择处理策略:
- 简单问答:直接从知识库检索
- 复杂问题:通过RAG增强后调用LLM
- 特定操作:触发函数调用
- DeepSeek模型生成响应
- 系统处理并格式化响应结果
- 流式返回给用户
- 保存对话记录到数据库
4.2 数据流转
系统中的数据流转路径清晰:
- 输入数据流:用户消息 → WebSocket → 消息处理器 → AI服务
- 知识检索流:用户查询 → 向量化 → 向量数据库 → 相似文档检索
- 输出数据流:LLM响应 → 格式化 → WebSocket → 用户界面
五、数据库设计
5.1 数据库表结构
合理的数据库设计是系统稳定运行的基础。

核心表说明:
-
conversations(会话表)
- 存储用户会话基本信息
- 包含会话状态、创建时间等字段
- 支持多轮对话的关联
-
messages(消息表)
- 记录所有对话消息
- 区分用户消息和AI响应
- 存储消息元数据(tokens、耗时等)
-
knowledge_base(知识库表)
- 存储企业知识文档
- 包含文档分类和标签
- 支持全文检索
-
user_feedback(用户反馈表)
- 收集用户对AI回复的评价
- 用于持续改进系统
5.2 关键索引设计
为提升查询性能,我们在以下字段上建立索引:
- messages表的conversation_id字段
- messages表的created_at字段
- knowledge_base表的category和tags字段
- user_feedback表的rating字段
六、核心代码实现
6.1 项目初始化
首先,创建Spring Boot项目并添加必要的依赖:
xml
<dependencies>
<!-- Spring Boot Starter -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- Spring AI dependency -->
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-openai-spring-boot-starter</artifactId>
<version>1.0.0</version>
</dependency>
<!-- Database -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<!-- Redis -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!-- WebSocket -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
</dependencies>
6.2 配置DeepSeek API
在application.yml中配置DeepSeek API:
yaml
spring:
ai:
openai:
api-key: ${DEEPSEEK_API_KEY}
base-url: https://api.deepseek.com/v1
chat:
options:
model: deepseek-chat
temperature: 0.7
max-tokens: 2000
datasource:
url: jdbc:mysql://localhost:3306/customer_service
username: root
password: password
driver-class-name: com.mysql.cj.jdbc.Driver
jpa:
hibernate:
ddl-auto: update
show-sql: true
data:
redis:
host: localhost
port: 6379
6.3 创建AI服务层
实现AI对话服务:
java
@Service
@Slf4j
public class ChatService {
private final ChatClient chatClient;
private final ConversationRepository conversationRepository;
private final MessageRepository messageRepository;
private final KnowledgeBaseService knowledgeBaseService;
@Autowired
public ChatService(ChatClient.Builder chatClientBuilder,
ConversationRepository conversationRepository,
MessageRepository messageRepository,
KnowledgeBaseService knowledgeBaseService) {
this.chatClient = chatClientBuilder.build();
this.conversationRepository = conversationRepository;
this.messageRepository = messageRepository;
this.knowledgeBaseService = knowledgeBaseService;
}
/**
* 处理用户消息并返回AI响应
*/
public Flux<String> chat(String userId, String sessionId, String userMessage) {
log.info("用户 {} 在会话 {} 中发送消息: {}", userId, sessionId, userMessage);
// 保存用户消息
saveMessage(sessionId, "USER", userMessage);
// 检索相关知识
String context = knowledgeBaseService.searchRelevantContent(userMessage);
// 构建提示词
String prompt = buildPrompt(userMessage, context);
// 调用AI模型并流式返回
return chatClient.prompt()
.user(prompt)
.stream()
.content()
.doOnNext(response -> {
log.debug("AI响应片段: {}", response);
})
.doOnComplete(() -> {
log.info("会话 {} 的AI响应完成", sessionId);
})
.doOnError(error -> {
log.error("AI调用出错", error);
});
}
/**
* 构建提示词模板
*/
private String buildPrompt(String userMessage, String context) {
return String.format("""
你是一个专业的客服助手,负责回答用户的问题。
【相关知识】
%s
【用户问题】
%s
请基于上述知识回答用户问题。如果知识库中没有相关信息,请诚实地告知用户,并尽可能提供建设性的帮助。
注意事项:
1. 回答要准确、专业、友好
2. 避免提供不确定的信息
3. 如果涉及具体操作,请提供详细步骤
4. 保持对话的连贯性
""", context, userMessage);
}
/**
* 保存消息到数据库
*/
private void saveMessage(String sessionId, String role, String content) {
Message message = new Message();
message.setSessionId(sessionId);
message.setRole(role);
message.setContent(content);
message.setTimestamp(LocalDateTime.now());
messageRepository.save(message);
}
}
6.4 实现函数调用
Spring AI 1.0支持函数调用,让AI能够执行特定操作:
java
@Component
@Slf4j
public class CustomerServiceFunctions {
private final OrderRepository orderRepository;
private final UserRepository userRepository;
/**
* 查询订单状态
*/
@FunctionInfo(
description = "查询用户的订单状态",
name = "queryOrderStatus"
)
public String queryOrderStatus(@FunctionParam(description = "订单号") String orderId) {
log.info("查询订单状态: {}", orderId);
Order order = orderRepository.findById(orderId)
.orElse(null);
if (order == null) {
return "订单不存在";
}
return String.format("订单 %s 的状态是: %s,预计 %s 送达",
orderId, order.getStatus(), order.getEstimatedDelivery());
}
/**
* 查询用户余额
*/
@FunctionInfo(
description = "查询用户账户余额",
name = "queryUserBalance"
)
public String queryUserBalance(@FunctionParam(description = "用户ID") String userId) {
log.info("查询用户余额: {}", userId);
User user = userRepository.findById(userId)
.orElse(null);
if (user == null) {
return "用户不存在";
}
return String.format("您的账户余额为: %.2f 元", user.getBalance());
}
}
在ChatService中启用函数调用:
java
public Flux<String> chatWithFunctions(String userId, String sessionId, String userMessage) {
return chatClient.prompt()
.user(userMessage)
.functions("queryOrderStatus", "queryUserBalance") // 注册函数
.stream()
.content();
}
6.5 WebSocket实时通信
实现WebSocket端点:
java
@Configuration
@EnableWebSocket
public class WebSocketConfig implements WebSocketConfigurer {
@Autowired
private ChatWebSocketHandler chatWebSocketHandler;
@Override
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
registry.addHandler(chatWebSocketHandler, "/ws/chat")
.setAllowedOrigins("*");
}
}
@Component
@Slf4j
public class ChatWebSocketHandler extends TextWebSocketHandler {
@Autowired
private ChatService chatService;
@Override
protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
String payload = message.getPayload();
ChatRequest request = parseRequest(payload);
// 流式发送AI响应
chatService.chat(request.getUserId(), request.getSessionId(), request.getMessage())
.doOnNext(response -> {
try {
session.sendMessage(new TextMessage(response));
} catch (IOException e) {
log.error("发送消息失败", e);
}
})
.subscribe();
}
}
6.6 知识库向量检索
实现基于向量相似度的知识检索:
java
@Service
@Slf4j
public class KnowledgeBaseService {
private final JdbcTemplate jdbcTemplate;
private final EmbeddingModel embeddingModel;
@Value("${spring.ai.embedding.dimension}")
private int embeddingDimension;
/**
* 搜索相关知识内容
*/
public String searchRelevantContent(String query) {
// 将查询转换为向量
List<Double> queryEmbedding = embeddingModel.embed(query);
// 在数据库中搜索最相似的文档
String sql = """
SELECT content, similarity
FROM knowledge_base,
(SELECT ? AS query_vector) AS q
WHERE kb_vector IS NOT NULL
ORDER BY kb_vector <=> query_vector
LIMIT 3
""";
List<KnowledgeBase> results = jdbcTemplate.query(sql,
new Object[]{queryEmbedding},
(rs, rowNum) -> {
KnowledgeBase kb = new KnowledgeBase();
kb.setContent(rs.getString("content"));
kb.setSimilarity(rs.getDouble("similarity"));
return kb;
});
// 组合返回最相关的内容
return results.stream()
.map(KnowledgeBase::getContent)
.collect(Collectors.joining("\n\n"));
}
/**
* 添加知识到知识库
*/
public void addKnowledge(String title, String content, String category) {
// 生成向量表示
List<Double> embedding = embeddingModel.embed(content);
KnowledgeBase kb = new KnowledgeBase();
kb.setTitle(title);
kb.setContent(content);
kb.setCategory(category);
kb.setVector(embedding);
kb.setCreatedAt(LocalDateTime.now());
knowledgeBaseRepository.save(kb);
}
}
七、前端界面实现
7.1 聊天界面

html
<!DOCTYPE html>
<html>
<head>
<title>智能客服系统</title>
<style>
.chat-container {
max-width: 800px;
margin: 0 auto;
height: 600px;
border: 1px solid #ddd;
display: flex;
flex-direction: column;
}
.chat-messages {
flex: 1;
overflow-y: auto;
padding: 20px;
}
.message {
margin-bottom: 15px;
padding: 10px;
border-radius: 8px;
}
.user-message {
background-color: #e3f2fd;
text-align: right;
}
.ai-message {
background-color: #f5f5f5;
}
.chat-input {
display: flex;
padding: 20px;
border-top: 1px solid #ddd;
}
.chat-input input {
flex: 1;
padding: 10px;
font-size: 16px;
border: 1px solid #ddd;
border-radius: 4px;
}
.chat-input button {
margin-left: 10px;
padding: 10px 20px;
background-color: #2196F3;
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
}
</style>
</head>
<body>
<div class="chat-container">
<div class="chat-messages" id="messages"></div>
<div class="chat-input">
<input type="text" id="userInput" placeholder="请输入您的问题...">
<button onclick="sendMessage()">发送</button>
</div>
</div>
<script>
const ws = new WebSocket('ws://localhost:8080/ws/chat');
const messagesDiv = document.getElementById('messages');
const userInput = document.getElementById('userInput');
ws.onmessage = function(event) {
addMessage('AI', event.data);
};
function sendMessage() {
const message = userInput.value.trim();
if (!message) return;
addMessage('USER', message);
ws.send(JSON.stringify({
userId: 'user123',
sessionId: 'session456',
message: message
}));
userInput.value = '';
}
function addMessage(role, content) {
const messageDiv = document.createElement('div');
messageDiv.className = `message ${role.toLowerCase()}-message`;
messageDiv.textContent = content;
messagesDiv.appendChild(messageDiv);
messagesDiv.scrollTop = messagesDiv.scrollHeight;
}
userInput.addEventListener('keypress', function(e) {
if (e.key === 'Enter') sendMessage();
});
</script>
</body>
</html>
八、系统部署与监控
8.1 部署架构

部署说明:
- 应用服务器:部署Spring Boot应用(建议使用Docker容器化)
- 数据库服务器:MySQL主从复制配置
- 缓存服务器:Redis集群部署
- 负载均衡:Nginx反向代理和负载均衡
8.2 Docker部署配置
dockerfile
FROM openjdk:17-jdk-slim
WORKDIR /app
COPY target/customer-service-1.0.jar app.jar
EXPOSE 8080
ENTRYPOINT ["java", "-jar", "app.jar"]
yaml
version: '3.8'
services:
app:
build: .
ports:
- "8080:8080"
environment:
- SPRING_DATASOURCE_URL=jdbc:mysql://db:3306/customer_service
- SPRING_REDIS_HOST=redis
depends_on:
- db
- redis
db:
image: mysql:8.0
environment:
- MYSQL_ROOT_PASSWORD=password
- MYSQL_DATABASE=customer_service
volumes:
- mysql-data:/var/lib/mysql
redis:
image: redis:7-alpine
volumes:
- redis-data:/data
8.3 监控指标
系统需要监控以下关键指标:
- 响应时间:AI响应的平均延迟
- 并发数:同时在线的会话数量
- 准确率:用户满意度评分
- Token消耗:API调用的成本控制
- 错误率:系统异常和失败率
九、最佳实践
9.1 提示词工程
良好的提示词设计是提升AI响应质量的关键:
- 角色定义清晰:明确AI的定位和职责
- 上下文充分:提供足够的背景信息
- 输出格式规范:指定响应的结构和格式
9.2 性能优化
- 缓存策略:对常见问题进行缓存
- 批处理:合并多个请求减少API调用
- 异步处理:使用异步非阻塞IO
- 连接池:合理配置数据库和HTTP连接池
十、总结
本文详细介绍了如何使用Spring AI 1.0构建一个完整的智能客服系统,并通过DeepSeek大模型实现了智能对话能力。