SpringBoot如何引入deepseek-多轮对话

直接上代码,部分主要代码

1.发送内容

@Data
@Builder
public class Message {
    private String role;
    private String content;
}

2.请求参数体

@Data
@Builder
public class ChatMessage {
    private String model;
    private List<Message> messages;
    private boolean stream;
    private float temperature;
}

3.访问层

public SseEmitter createConnect(@RequestParam(name = "prompt") String prompt, @RequestParam(name = "temperature") float temperature) throws IOException {
        log.info("prompt {}", prompt);
        log.info("temperature {}", temperature);
        SseEmitter sseEmitter = new SseEmitter(-1L); //创建sse对象 -0表示永不超时
        /**补充自己代码,业务逻辑判断等*/
        deepSeekService.sendMessage(sseEmitter, prompt, apiKey, apiPoint, deepSeekModel, temperature);
        return sseEmitter;
    }

4.业务层

public void sendMessage(SseEmitter emitter, String prompt, String apiKey, String apiHost, String deepModel, float temperature) {
        Long userId = getUserId();
        StringBuffer buffer = new StringBuffer();
        new Thread(() -> {
            OkHttpClient client = new OkHttpClient();
            // 获取或初始化用户的对话历史
            List<Message> messages = getHistory(String.format(REDIS_DEEP_SEEK_USER, userId));
            Message message = Message.builder()
                    .role("user")
                    .content(prompt).build();
            // 添加新的用户消息到对话历史
            messages.add(message);
            //创建请求参数体
            ChatMessage requestBody = ChatMessage.builder()
                    .model(deepModel)
                    .messages(messages)
                    .stream(true)
                    .temperature(temperature)
                    .build();
            // 2. 构建请求
            Request request = new Request.Builder()
                    .url(apiHost)
                    .post(RequestBody.create(JSONObject.toJSONString(requestBody), MediaType.parse("application/json; charset=utf-8")))
                    .header("Authorization", "Bearer " + apiKey)
                    .build();
            try (Response response = client.newCall(request).execute()) {
                log.info("deepSeek返回状态 {}", response.code() + "-" + DeepSeekStatusEnum.fromCode(response.code()).getDescription());
                if (!response.isSuccessful()) {
                    log.error("DeepSeek返回错误信息: {}",response.code() + "-" + DeepSeekStatusEnum.fromCode(response.code()).getDescription());
                    emitter.send(SseEmitter.event().name("error").data("DeepSeek返回错误信息:" + response.code() + "-" + DeepSeekStatusEnum.fromCode(response.code()).getDescription()));
                    emitter.complete();
                    return;
                }
                saveHistory(String.format(REDIS_DEEP_SEEK_USER, userId), messages);
                ResponseBody responseBody = response.body();
                if (responseBody != null) {
                    try (BufferedReader reader = new BufferedReader(new InputStreamReader(responseBody.byteStream()))) {
                        String line;
                        BackDataVo backDataVo = new BackDataVo();
                        while ((line = reader.readLine()) != null) {
                            if (line.startsWith("data: ")) {
                                String jsonStr = line.substring(6).trim();
                                if ("[DONE]".equals(jsonStr)) {
                                    emitter.send(SseEmitter.event()
                                            .data("[DONE]")
                                            .id(UUID.randomUUID().toString()));
                                    break;
                                }
                                JsonNode node = objectMapper.readTree(jsonStr);
                                String content = node.at("/choices/0/delta/content").asText();
                                buffer.append(content);
                                if (!content.isEmpty()) {
                                    backDataVo.setValue(content);
                                    emitter.send(SseEmitter.event()
                                            .data(backDataVo)     //直接赋值content,数据会存在丢失
                                            .id(UUID.randomUUID().toString()));
                                }
                            }
                        }
                        emitter.complete();
                    } catch (IOException e) {
                        handleException(e, emitter);
                    }
                }
            } catch (IOException e) {
                handleException(e, emitter);
            }
        }).start();
        // 异步保存响应,将历史数据保存redis,下次使用
        emitter.onCompletion(() -> {
            List<Message> newHistory = getHistory(String.format(REDIS_DEEP_SEEK_USER, userId));
            if (CollectionUtils.isEmpty(newHistory)) {
                newHistory = new ArrayList<>();
            }
            log.info("对话返回数据:{}", buffer);
            Message message = Message.builder()
                    .role("assistant")
                    .content(buffer.toString()).build();
            newHistory.add(message);
            log.info("历史对话数据:{}",  newHistory);
            saveHistory(String.format(REDIS_DEEP_SEEK_USER, userId), newHistory);
        });
    }

    // 统一异常处理
    private void handleException(Exception e, SseEmitter emitter) {
        try {
            log.error("deepSeek Unexpected error: " + e.getMessage());
            emitter.send(SseEmitter.event().name("error").data("DeepSeek返回错误信息:" + e.getMessage()));
        } catch (IOException ex) {
            log.error("Error sending unexpected error message: " + ex.getMessage());
            emitter.completeWithError(ex);
        } finally {
            emitter.complete();
        }
    }
    private List<Message> getHistory(String key) {
        Object history = redisTemplate.opsForValue().get(key);
        return history != null ? (List<Message>) history : new ArrayList<>();
    }

    private void saveHistory(String key, List<Message> history) {
        redisTemplate.opsForValue().set(key, history);
        redisTemplate.expire(key, 30, TimeUnit.MINUTES); // 每次访问续期
    }

image

 注意:deepseek多轮对话要将之前提问和返回的数据放入请求体中,因此需要保存会话期间的问题和结果

参考:https://blog.csdn.net/weiliang7/article/details/147971898

https://blog.csdn.net/m0_52025266/article/details/147501578

posted on 2025-08-05 16:44  大山008  阅读(22)  评论(0)    收藏  举报