deepseek封装结合websocket实现与ai对话
项目概述与设计思路
在现代Web应用中,集成AI对话能力可以显著提升用户体验。本项目采用分层架构设计,将WebSocket实时通信与DeepSeek AI服务解耦,实现了可维护、可扩展的智能对话系统。
核心设计理念
- 接口隔离原则:通过接口定义服务契约,便于后续实现替换
- 单一职责原则:每个类只负责特定功能模块
- 实时通信:利用WebSocket实现低延迟的双向数据交换
详细代码解析
1. 服务层接口设计 - 定义AI服务契约
package com.qcby.websocket.service;import java.io.IOException;public interface DeepSeekService {// 核心方法:向DeepSeek API发送问题并获取响应String getDeepSeekResult(String question) throws IOException;
}设计意图:
- 定义标准的AI服务接口,为后续可能的服务替换(如切换为其他AI提供商)提供便利
throws IOException明确声明可能出现的网络异常,强制调用方处理
2. 服务层实现 - DeepSeek API集成
package com.qcby.websocket.service.Impl;import com.qcby.websocket.service.DeepSeekService;
import okhttp3.*;
import org.springframework.stereotype.Service;import java.io.IOException;@Service // Spring注解,将该类声明为服务层组件
public class DeepSeekServiceImpl implements DeepSeekService {@Overridepublic String getDeepSeekResult(String question) throws IOException {// 1. 创建HTTP客户端实例OkHttpClient client = new OkHttpClient().newBuilder().build();// 2. 设置请求内容类型为JSONMediaType mediaType = MediaType.parse("application/json");// 3. 构造符合DeepSeek API要求的请求体String jsonBody = String.format("{\n"+ " \"model\": \"deepseek-chat\",\n" // 指定使用的模型+ " \"messages\": [\n" // 对话消息数组+ " {\"role\": \"user\", \"content\": \"%s\"}\n" // 用户消息+ " ],\n"+ " \"temperature\": 0.7,\n" // 控制回复随机性(0-1)+ " \"top_p\": 0.8\n" // 核采样参数,控制词汇选择范围+ "}", question);// 4. 创建请求体对象RequestBody body = RequestBody.create(mediaType, jsonBody);// 5. 构建完整的HTTP请求Request request = new Request.Builder().url("https://api.deepseek.com/chat/completions") // API端点.method("POST", body) // POST请求.addHeader("Content-Type", "application/json") // 请求头.addHeader("Accept", "application/json").addHeader("Authorization", "Bearer yourToken") // 认证令牌.build();// 6. 执行请求并获取响应Response response = client.newCall(request).execute();// 7. 返回响应体内容return response.body().string();}
}关键技术点详解:
请求参数说明:
temperature:值越大回复越随机有创意,值越小回复越确定保守top_p:累计概率阈值,影响词汇选择的多样性
HTTP客户端选择:
- 使用OkHttp而非Spring的RestTemplate,因为OkHttp在处理大量并发请求时性能更优
- OkHttp支持连接池复用,减少TCP握手开销
3. WebSocket消息处理器 - 实时通信核心
@Component // Spring组件注解,纳入IoC容器管理
public class ChatHandler implements WebSocketHandler {@Autowired // 依赖注入,Spring自动装配DeepSeekService实例private DeepSeekService deepSeekService;/*** 用户会话管理Map* Key: session.getId() - 会话唯一标识* Value: WebSocketSession - 活跃的WebSocket会话对象* static修饰确保所有ChatHandler实例共享同一会话集合*/public static final Map<String,WebSocketSession> USERSOCKETSESSION = new HashMap<>();/*** 连接建立成功回调* 当客户端成功建立WebSocket连接时触发*/@Overridepublic void afterConnectionEstablished(WebSocketSession session) throws Exception {System.out.println("新用户连接,会话ID:" + session.getId());// 将新会话存入管理Map,便于后续消息定向发送USERSOCKETSESSION.put(session.getId(), session);}/*** 核心消息处理方法* 当客户端发送消息到服务端时触发*/@Overridepublic void handleMessage(WebSocketSession session, WebSocketMessage<?> message) throws Exception {System.out.println("接收到来自会话[" + session.getId() + "]的消息:" + message.getPayload().toString());// 步骤1:JSON反序列化 - 将客户端消息转换为Message对象Message meg = GsonUtils.fromJson(message.getPayload().toString(), Message.class);String question = meg.getMessage();// 步骤2:调用AI服务 - 将用户问题发送给DeepSeekString answer = deepSeekService.getDeepSeekResult(question);// 步骤3:解析DeepSeek API响应JSONObject jsonObject = new JSONObject(answer); // 将JSON字符串转换为对象JSONArray choices = jsonObject.getJSONArray("choices"); // 获取choices数组JSONObject choicesAnswer = choices.getJSONObject(0); // 获取第一个选择JSONObject messageAnswer = choicesAnswer.getJSONObject("message"); // 获取消息内容String content = messageAnswer.getString("content"); // 提取最终回复文本System.out.println("AI回复内容:" + content);// 步骤4:检查会话状态并返回响应if(session.isOpen()){ // 重要:发送前检查连接是否仍然有效// 构造TextMessage对象并发送给客户端session.sendMessage(new TextMessage(content));}}/*** 群发消息功能 - 向所有在线用户广播消息* 适用于公告、系统通知等场景*/public void sendMessageToAll(Message message) throws IOException {// 遍历所有活跃会话for (Map.Entry<String, WebSocketSession> entry : USERSOCKETSESSION.entrySet()){final WebSocketSession webSocketSession = entry.getValue();// 检查会话有效性后再发送if(webSocketSession.isOpen()){// 将Message对象序列化为JSON字符串webSocketSession.sendMessage(new TextMessage(GsonUtils.toJson(message)));}}}/*** 私聊功能 - 向指定用户发送消息* @param userId 目标用户的会话ID*/public void sendMessageToUser(String userId, Message message) throws IOException {// 根据用户ID从会话Map中查找对应会话WebSocketSession webSocketSession = USERSOCKETSESSION.get(userId);if(webSocketSession != null && webSocketSession.isOpen()){webSocketSession.sendMessage(new TextMessage(GsonUtils.toJson(message)));}}/*** 传输错误处理 - 网络异常、协议错误等*/@Overridepublic void handleTransportError(WebSocketSession session, Throwable exception) throws Exception {System.out.println("会话[" + session.getId() + "]连接出错:" + exception.getMessage());// 从会话管理中移除异常会话USERSOCKETSESSION.remove(session.getId());// 确保关闭异常会话,释放资源if (session.isOpen()) {session.close();}}/*** 连接关闭回调 - 客户端主动断开或超时断开*/@Overridepublic void afterConnectionClosed(WebSocketSession session, CloseStatus closeStatus) throws Exception {System.out.println("会话[" + session.getId() + "]已关闭,状态:" + closeStatus.toString());// 清理会话资源USERSOCKETSESSION.remove(session.getId());}/*** 是否支持部分消息 - 对于大文件分片传输*/@Overridepublic boolean supportsPartialMessages() {return false; // 本项目不处理大消息分片}
}核心架构优势
1. 会话管理机制
- 实时状态维护:通过HashMap实时跟踪所有在线用户
- 自动清理:连接异常或关闭时自动清理会话资源,防止内存泄漏
- 会话查找优化:O(1)时间复杂度的用户会话查找
2. 消息处理流程
客户端消息 → WebSocket接收 → JSON反序列化 → AI服务调用 → 响应解析 → WebSocket返回3. 异常处理策略
- 网络异常:IOException处理API调用失败
- 会话异常:自动移除无效会话,保持系统稳定
- JSON解析异常:通过try-catch确保格式错误的响应不会导致系统崩溃
