Spring AI 1.0实战:构建基于DeepSeek的智能客服系统

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主要由以下几个核心组件构成:

  1. ChatClient:与LLM进行对话的主要接口
  2. Prompt Manager:管理和组织提示词模板
  3. Function Calling:函数调用机制
  4. Vector Store:向量存储抽象层
  5. 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 核心模块划分

系统包含以下核心模块:

  1. 对话管理模块:管理用户会话和对话历史
  2. 知识库模块:存储和管理企业知识文档
  3. 意图识别模块:理解用户需求并分类
  4. 消息路由模块:将用户请求分发到合适的处理单元
  5. 监控统计模块:跟踪系统性能和用户满意度

四、系统集成流程

4.1 系统交互流程

用户与智能客服系统的交互遵循一个清晰的处理流程。

交互步骤说明:

  1. 用户发起对话请求
  2. 系统验证用户身份并加载历史会话
  3. 意图识别模块分析用户输入
  4. 根据意图类型选择处理策略:
    • 简单问答:直接从知识库检索
    • 复杂问题:通过RAG增强后调用LLM
    • 特定操作:触发函数调用
  5. DeepSeek模型生成响应
  6. 系统处理并格式化响应结果
  7. 流式返回给用户
  8. 保存对话记录到数据库

4.2 数据流转

系统中的数据流转路径清晰:

  • 输入数据流:用户消息 → WebSocket → 消息处理器 → AI服务
  • 知识检索流:用户查询 → 向量化 → 向量数据库 → 相似文档检索
  • 输出数据流:LLM响应 → 格式化 → WebSocket → 用户界面

五、数据库设计

5.1 数据库表结构

合理的数据库设计是系统稳定运行的基础。

核心表说明:

  1. conversations(会话表)

    • 存储用户会话基本信息
    • 包含会话状态、创建时间等字段
    • 支持多轮对话的关联
  2. messages(消息表)

    • 记录所有对话消息
    • 区分用户消息和AI响应
    • 存储消息元数据(tokens、耗时等)
  3. knowledge_base(知识库表)

    • 存储企业知识文档
    • 包含文档分类和标签
    • 支持全文检索
  4. 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 部署架构

部署说明:

  1. 应用服务器:部署Spring Boot应用(建议使用Docker容器化)
  2. 数据库服务器:MySQL主从复制配置
  3. 缓存服务器:Redis集群部署
  4. 负载均衡: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响应质量的关键:

  1. 角色定义清晰:明确AI的定位和职责
  2. 上下文充分:提供足够的背景信息
  3. 输出格式规范:指定响应的结构和格式

9.2 性能优化

  • 缓存策略:对常见问题进行缓存
  • 批处理:合并多个请求减少API调用
  • 异步处理:使用异步非阻塞IO
  • 连接池:合理配置数据库和HTTP连接池

十、总结

本文详细介绍了如何使用Spring AI 1.0构建一个完整的智能客服系统,并通过DeepSeek大模型实现了智能对话能力。

相关推荐
蓝程序1 天前
Spring AI学习 程序接入大模型(框架接入)
人工智能·学习·spring
爱吃山竹的大肚肚1 天前
Kafka中auto-offset-reset各个选项的作用
java·spring boot·spring·spring cloud
while(1){yan}1 天前
图书管理系统(超详细版)
spring boot·spring·java-ee·tomcat·log4j·maven·mybatis
sunddy_x1 天前
Spring IOC 入门
java·spring
沉默-_-1 天前
从小程序前端到Spring后端:新手上路必须理清的核心概念图
java·前端·后端·spring·微信小程序
xrkhy1 天前
多线程,高并发、物联网以及spring架构的面试题-->周
java·spring·架构
星辰引路-Lefan1 天前
在浏览器中运行大模型:基于 WebGPU 的本地 LLM 应用深度解析
ai·ai编程·llama·gpu算力
forestsea1 天前
Springboot 4.0十字路口:虚拟线程时代,WebFlux与WebMVC的终极选择
java·后端·spring