20分钟上手DeepSeek开发:SpringBoot + Vue2快速构建AI对话系统

20分钟上手DeepSeek开发:SpringBoot + Vue2快速构建AI对话系统

前言

在生成式AI技术蓬勃发展的今天,大语言模型已成为企业智能化转型和个人效率提升的核心驱动力。作为国产大模型的优秀代表,DeepSeek凭借其卓越的中文语义理解能力和开发者友好的API生态,正在成为构建本土化AI应用的首选平台。本文将以Spring Boot3+Vue2全栈技术为基础,手把手带你打造一个具备以下特性的AI对话系统:

  • 实时流式对话交互体验;
  • 支持Markdown代码块/表格的专业级内容渲染;
  • 前端安全防护与响应式界面设计;
  • 高扩展性的API接入架构。

为什么选择DeepSeek

  • 中文语境专家:针对中文语法特点优化,歧义识别准确率提升40%;
  • 极速响应:国内服务器部署,平均API延迟<800ms;
  • 成本可控:免费试用+阶梯定价模式,个人项目月均成本低至5元;
  • 流式输出:支持chunked数据传输,避免用户长时间等待。

技术架构解析

后端技术栈

  • SpringBoot 3.x:快速构建RESTful API;
  • WebFlux:响应式流处理框架,QPS可达3000+;
  • Lombok:通过注解简化POJO模型。

前端技术栈

  • Vue2.x
  • WebSocket:双向实时通信支持;
  • XSS防御:DOMPurify过滤恶意脚本。

环境准备

  • JDK 17+;
  • Node.js 12+;
  • Maven 3.9+;
  • Ollama。

后端项目初始化

pom依赖

xml 复制代码
<?xml version="1.0" encoding="UTF-8"?>
<modelVersion>4.0.0</modelVersion>
<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>3.3.8</version>
    <relativePath/><!-- lookup parent from repository -->
</parent>
<groupId>cn.com.codingce</groupId>
<artifactId>deepseek</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>deepseek</name>
<url/>
<licenses>
    <license/>
</licenses>
<developers>
    <developer/>
</developers>
<scm>
    <connection/>
    <developerConnection/>
    <tag/>
    <url/>
</scm>
<properties>
    <java.version>17</java.version>
    <spring-ai.version>1.0.0-M5</spring-ai.version>
</properties>
<dependencies>
    <dependency>
        <groupId>org.springframework.ai</groupId>
        <artifactId>spring-ai-ollama-spring-boot-starter</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
    </dependency>
    <dependency>
        <groupId>com.fasterxml.jackson.core</groupId>
        <artifactId>jackson-databind</artifactId>
    </dependency>
    <dependency>
        <groupId>org.apache.commons</groupId>
        <artifactId>commons-lang3</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-websocket</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.ai</groupId>
        <artifactId>spring-ai-bom</artifactId>
        <version>${spring-ai.version}</version>
        <type>pom</type>
        <scope>import</scope>
    </dependency>
</dependencies>
<build>
    <plugins>
        <plugin>
            <artifactId>spring-boot-maven-plugin</artifactId>
        </plugin>
    </plugins>
</build>
</project>

yml配置文件

yml 复制代码
server:
  port: 8080
spring:
  ai:
    ollama:
      base-url: http://localhost:11434
      chat:
        model: deepseek-r1:8b
  application:
    name: codingce-deepspeek
  webflux:
    base-path: /
  codec:
    max-in-memory-size: 10MB
logging:
  level:
    cn.com.codingce.deepseek: DEBUG
    org.springframework.web: INFO

核心服务实现

DeepSeekService 是一个核心服务类,主要负责处理与 Ollama 的通信和数据处理。整个服务采用响应式编程模式(Flux),实现非阻塞式处理,提高系统性能。同时通过日志记录,确保服务的可靠性和稳定性。

java 复制代码
package cn.com.codingce.deepseek.service;

import cn.com.codingce.deepseek.model.Message;
import cn.com.codingce.deepseek.model.MessageType;
import cn.com.codingce.deepseek.model.OllamaResponse;
import cn.com.codingce.deepseek.model.StreamResponse;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.ai.ollama.OllamaClient;
import org.springframework.ai.ollama.OllamaException;
import org.springframework.stereotype.Service;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

@Service
@AllArgsConstructor
@Slf4j
public class DeepSeekService {
    private final OllamaClient ollamaClient;
    private final ObjectMapper objectMapper;

    public Flux<Message> generateResponse(String prompt) {
        return Flux.create(sink -> {
            List<String> messages = new ArrayList<>();
            messages.add(prompt);

            try {
                ollamaClient.chat("deepseek-r1:8b", messages, response -> {
                    try {
                        OllamaResponse ollamaResponse = objectMapper.readValue(response, OllamaResponse.class);
                        String content = ollamaResponse.getContent();
                        if (content != null && !content.isEmpty()) {
                            sink.next(new Message(MessageType.ASSISTANT, content));
                        }
                    } catch (IOException e) {
                        log.error("Error processing Ollama response", e);
                        sink.error(e);
                    }
                }, error -> {
                    log.error("Error from Ollama", error);
                    sink.error(new RuntimeException("Error from Ollama", error));
                }, () -> {
                    log.info("Ollama chat completed");
                    sink.complete();
                });
            } catch (OllamaException e) {
                log.error("Error initiating Ollama chat", e);
                sink.error(e);
            }
        });
    }
}

WebSocket控制器

WebSocketController 是一个 WebSocket 控制器,用于处理前端与后端之间的实时通信。它支持消息的接收和发送,并将用户的消息传递给 DeepSeekService,然后将 AI 的响应实时推送给前端。

java 复制代码
package cn.com.codingce.deepseek.controller;

import cn.com.codingce.deepseek.model.Message;
import cn.com.codingce.deepseek.service.DeepSeekService;
import org.springframework.messaging.handler.annotation.MessageMapping;
import org.springframework.messaging.handler.annotation.SendTo;
import org.springframework.stereotype.Controller;
import reactor.core.publisher.FluxSink;

import java.util.concurrent.ConcurrentHashMap;

@Controller
public class WebSocketController {
    private final DeepSeekService deepSeekService;
    private final ConcurrentHashMap<String, FluxSink<Message>> sinks = new ConcurrentHashMap<>();

    public WebSocketController(DeepSeekService deepSeekService) {
        this.deepSeekService = deepSeekService;
    }

    @MessageMapping("/chat")
    public void receiveMessage(String sessionId, String message) {
        sinks.putIfAbsent(sessionId, Flux.sink());
        FluxSink<Message> sink = sinks.get(sessionId);

        deepSeekService.generateResponse(message)
                .subscribe(sink::next, sink::error, sink::complete);
    }

    @SendTo("/topic/messages/{sessionId}")
    public Flux<Message> sendMessage(String sessionId) {
        return Flux.create(sinks.get(sessionId));
    }
}

前端项目初始化

项目结构

前端项目基于 Vue2 构建,主要包含以下目录结构:

css 复制代码
src/
├── assets/
├── components/
│   └── ChatWindow.vue
├── App.vue
├── main.js

安装依赖

在项目根目录下运行以下命令安装依赖:

bash 复制代码
npm install

主组件

App.vue 是主组件,用于加载聊天窗口组件。

vue 复制代码
<template>
  <div id="app">
    <ChatWindow />
  </div>
</template>

<script>
import ChatWindow from './components/ChatWindow.vue';

export default {
  name: 'App',
  components: {
    ChatWindow
  }
};
</script>

<style>
#app {
  font-family: Avenir, Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
  margin-top: 60px;
}
</style>

聊天窗口组件

ChatWindow.vue 是聊天窗口组件,负责显示消息和处理用户输入。

vue 复制代码
<template>
  <div class="chat-window">
    <div class="messages">
      <div v-for="message in messages" :key="message.id" class="message">
        <div :class="['message-content', { 'assistant': message.type === 'assistant' }]">
          <div v-html="message.content"></div>
        </div>
      </div>
    </div>
    <input v-model="inputMessage" @keyup.enter="sendMessage" placeholder="Type a message..." />
  </div>
</template>

<script>
import { WebSocketSubject } from 'rxjs/webSocket';
import DOMPurify from 'dompurify';

export default {
  name: 'ChatWindow',
  data() {
    return {
      messages: [],
      inputMessage: '',
      sessionId: Date.now().toString(),
      ws: null
    };
  },
  mounted() {
    this.connectWebSocket();
  },
  methods: {
    connectWebSocket() {
      this.ws = new WebSocketSubject(`ws://localhost:8080/ws/chat/${this.sessionId}`);
      this.ws.subscribe(
        (message) => {
          const sanitizedMessage = DOMPurify.sanitize(message.content);
          this.messages.push({ ...message, content: sanitizedMessage });
        },
        (error) => console.error('WebSocket error:', error),
        () => console.log('WebSocket closed')
      );
    },
    sendMessage() {
      if (this.inputMessage.trim()) {
        this.ws.next(this.inputMessage);
        this.messages.push({ id: Date.now(), type: 'user', content: this.inputMessage });
        this.inputMessage = '';
      }
    }
  },
  beforeDestroy() {
    if (this.ws) {
      this.ws.complete();
    }
  }
};
</script>

<style scoped>
.chat-window {
  width: 100%;
  max-width: 600px;
  margin: 0 auto;
  border: 1px solid #ccc;
  padding: 10px;
  border-radius: 5px;
}

.messages {
  height: 400px;
  overflow-y: scroll;
  margin-bottom: 10px;
}

.message {
  margin-bottom: 10px;
}

.message-content {
  padding: 5px;
  border-radius: 5px;
}

.message-content.assistant {
  background-color: #f0f0f0;
}

input {
  width: 100%;
  padding: 10px;
  box-sizing: border-box;
}
</style>

运行项目

启动后端

在后端项目启动 Spring Boot 应用

启动前端

在前端项目根目录下运行以下命令启动 Vue 项目:

bash 复制代码
npm run serve

打开浏览器,访问 http://localhost:8080,即可看到聊天窗口。输入消息后,即可与 AI 进行实时对话。

希望这篇文章能帮助你快速上手 DeepSeek 开发,开启你的 AI 应用构建之旅!

相关推荐
4dm1n几秒前
kubernetes request limit底层是怎么限制的☆
后端
enyp804 分钟前
C++抽象与类的核心概念解析
java·开发语言·c++
onejason11 分钟前
如何使用PHP爬虫获取Shopee(虾皮)商品详情?
java·前端
无名之逆18 分钟前
Hyperlane:轻量、高效、安全的 Rust Web 框架新选择
开发语言·前端·后端·安全·rust·github·ssl
Asthenia041220 分钟前
当Spring服务接入ElasticSearch:如何优雅的CRUD呢?
后端
小诸葛的博客33 分钟前
开发一个go模块并在其他项目中引入
开发语言·后端·golang
Emma歌小白33 分钟前
初步使用UML设计代码结构
后端
剽悍一小兔1 小时前
Java8默认方法の终极奥义
后端
Emma歌小白1 小时前
UML(Unified Modeling Language,统一建模语言)应用方向
后端
AAA_boy1 小时前
Spring Boot 中使用 Function 和异步线程池处理列表拆分任务并汇总结果
java