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大模型实现了智能对话能力。

相关推荐
二哈赛车手4 小时前
新人笔记---ApiFox的一些常见使用出错
java·笔记·spring
counterxing4 小时前
Agent 跑起来之后,难的是复用、观测和评测
node.js·agent·ai编程
uccs4 小时前
大模型底层机制与Agent开发
agent·ai编程·claude
counterxing5 小时前
我把 Codex 里的 Skills 做成了一个 MCP,还支持分享
前端·agent·ai编程
夜雪闻竹5 小时前
vectra 向量索引文件损坏怎么办
ai编程·向量·vectra
ZzT5 小时前
Harness 到底指什么
openai·ai编程·claude
宅小年6 小时前
AI 创业最危险的地方:太容易做出来
openai·ai编程·claude
麦客奥德彪6 小时前
Android Skills
架构·ai编程
言萧凡_CookieBoty7 小时前
一文讲清 RAG:让 AI 读懂业务知识库的核心方法
ai编程
阿维的博客日记7 小时前
Nacos 为什么能让配置动态生效?(涉及 @RefreshScope 注解)
java·spring