这里只讲发一次消息和多轮对话,其余的拓展欢迎去官方文档参考进行实验

首次调用 API | DeepSeek API DocsDeepSeek API 使用与 OpenAI 兼容的 API 格式,通过修改配置,您可以使用 OpenAI SDK 来访问 DeepSeek API,或使用与 OpenAI API 兼容的软件。https://api-docs.deepseek.com/zh-cn/

一、去官网申请API key

DeepSeekJoin DeepSeek API platform to access our AI models, developer resources and API documentation.https://platform.deepseek.com/api_keys

然后进行充值,不然是使用不了key的

二、准备Java项目

1、完整代码

https://gitcode.com/bluefoxyu/deepseek-chat-demo

2、项目讲解

代码结构

接口

这里主要实现了单次对话和多轮对话:

import com.bluefoxyu.domain.Result;
import com.bluefoxyu.service.DeepSeekService;
import jakarta.annotation.Resource;
import org.springframework.web.bind.annotation.*;
import java.io.IOException;

@RestController
@RequestMapping("/api/chat")
public class ChatController {

    @Resource
    private DeepSeekService deepSeekService;

    @PostMapping("/one")
    public String chat(@RequestBody String message) {
        try {
            return Result.success(deepSeekService.sendMessage(message)).toJson();
        } catch (IOException e) {
            throw new RuntimeException("调用DeepSeek API失败: " + e.getMessage(), e);
        }
    }

    // 多轮对话
    // 目前还没做用户区分,不过数据表里面做了这个字段,到时候查询再加一层即可
    @PostMapping("/completion")
    public String chatCompletion(@RequestBody String param) {
        try {
            return Result.success(deepSeekService.chatCompletion(param)).toJson();
        } catch (IOException e) {
            throw new RuntimeException("调用DeepSeek API失败: " + e.getMessage(), e);
        }
    }
}
接口的实现

其实逻辑就那么几点:处理用户请求的数据,构建发送deepseek的http请求,解析deepseek返回的结构进行解析取出deepseek的回答(有用的数据),封装结构返回

这个是单次问答的大致逻辑,如果是多次的话还会多一些和数据库的操作,和一些保证。

多轮对话,这里我主要设计的是:

使用一个conversation_id进行隔离不同对话,使用数据库进行对话的记忆,参考官方的流程:

主要的报文格式是:

其实这样子也很容易理解

下面是我的代码的大致实现:

可能还有很多完善的点,还有完善的功能,比如多用户隔离,这样子需要数据库新增字段

完整代码示例如下:

import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.bluefoxyu.domain.ChatCompletionResponse;
import com.bluefoxyu.domain.CompletionChatParam;
import com.bluefoxyu.domain.DeepSeekRequest;
import com.bluefoxyu.domain.Message;
import com.bluefoxyu.mapper.MessageMapper;
import jakarta.annotation.Resource;
import okhttp3.*;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

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

@Service
public class DeepSeekService {

    @Resource
    private OkHttpClient client;
    @Value("${bluefox.deepseek.base_url}")
    private String baseUrl;
    @Value("${bluefox.deepseek.api_key}")
    private String apiKey;

    @Resource
    private MessageMapper messageMapper;

    /**
    * <p>
    * description: 发送用户消息到DeepSeek API。
    * </p>
    *
    * @param userMessage 用户输入的消息字符串
    * @return: java.lang.String API响应的字符串表示形式
    * @author: bluefoxyu
    * @date: 2025-06-25 17:15:21
    */
    public String sendMessage(String userMessage) throws IOException {
        return sendChatCompletion(createDefaultRequest(userMessage));
    }

    /** 
    * <p>
    * description: 创建默认的聊天请求对象,包含系统提示和用户消息。
    * </p>
    *
    * @param userMessage 用户输入的消息字符串
    * @return: com.bluefoxyu.domain.DeepSeekRequest 默认的DeepSeek请求对象
    * @author: bluefoxyu 
    * @date: 2025-06-25 17:18:54 
    */ 
    private DeepSeekRequest createDefaultRequest(String userMessage) {
        DeepSeekRequest request = new DeepSeekRequest();
        request.setMessages(List.of(
                new DeepSeekRequest.Message("assistant", "You are a helpful assistant"),
                new DeepSeekRequest.Message("user", userMessage)
        ));
        return request;
    }

    /** 
    * <p>
    * description: 发送聊天完成请求到DeepSeek API
    * </p>
    *
    * @param request 包含请求数据的对象
    * @return: java.lang.String API响应的字符串表示形式
    * @author: bluefoxyu 
    * @date: 2025-06-25 17:18:26 
    */
    public String sendChatCompletion(DeepSeekRequest request) throws IOException {
        String jsonBody = JSONUtil.toJsonStr(request);
        Request httpRequest = buildRequest(jsonBody);

        try (Response response = client.newCall(httpRequest).execute()) {
            if (!response.isSuccessful()) {
                throw new IOException(buildErrorMessage(response));
            }
            // 解析响应体
            String responseBody = Objects.requireNonNull(response.body()).string();
            ChatCompletionResponse chatCompletionResponse = JSONUtil.toBean(responseBody, ChatCompletionResponse.class);

            // 提取第一个choice的消息内容
            if (chatCompletionResponse.getChoices() != null && !chatCompletionResponse.getChoices().isEmpty()) {
                return chatCompletionResponse.getChoices().get(0).getMessage().getContent();
            } else {
                throw new RuntimeException("No valid response from DeepSeek API.");
            }
        }
    }

    /** 
    * <p>
    * description: 根据提供的JSON请求体构建HTTP
    * </p>
    *
    * @param jsonBody JSON格式的请求体字符串
    * @return: okhttp3.Request 构建好的HTTP请求对象
    * @author: bluefoxyu 
    * @date: 2025-06-25 17:19:33 
    */ 
    private Request buildRequest(String jsonBody) {
        MediaType mediaType = MediaType.parse("application/json");
        RequestBody body = RequestBody.create(mediaType, jsonBody);

        return new Request.Builder()
                .url(baseUrl)
                .post(body)
                .addHeader("Content-Type", "application/json")
                .addHeader("Accept", "application/json")
                .addHeader("Authorization", "Bearer " + apiKey)
                .build();
    }

    /** 
    * <p>
    * description: 构建错误信息字符串,包含HTTP状态码和响应体内容。
    * </p>
    *
    * @param response HTTP响应对象
    * @return: java.lang.String 错误信息字符串
    * @author: bluefoxyu 
    * @date: 2025-06-25 17:17:40 
    */ 
    private String buildErrorMessage(Response response) throws IOException {
        return String.format("API请求失败: %d - %s",
                response.code(),
                response.body() != null ? response.body().string() : "无响应内容");
    }

    public String chatCompletion(String param) throws IOException {
        // 将传入的参数字符串转换为CompletionChatParam对象
        CompletionChatParam bean = JSONUtil.toBean(param, CompletionChatParam.class);
        String conversationId = bean.getConversation_id();
        String userMessage = bean.getMessage();

        // 查询数据库中的历史消息
        List<Message> historyMessages = messageMapper.selectList(
                Wrappers.<Message>lambdaQuery()
                        .eq(Message::getConversationId, conversationId)
                        .orderByAsc(Message::getId) // 确保按时间顺序排列
        );

        // 构建请求消息列表
        List<DeepSeekRequest.Message> messages = new ArrayList<>();
        for (Message msg : historyMessages) {
            messages.add(new DeepSeekRequest.Message(msg.getUserRole(), msg.getUserContent()));
            messages.add(new DeepSeekRequest.Message(msg.getAssistantRole(), msg.getAssistantContent()));
        }

        // 添加当前用户的提问
        messages.add(new DeepSeekRequest.Message("user", userMessage));

        // 创建请求并发送
        DeepSeekRequest request = new DeepSeekRequest();
        request.setMessages(messages);

        // 发送聊天完成请求到DeepSeek API
        String responseMessage = sendChatCompletion(request);

        // 保存助手的回复到数据库
        Message assistantReply = new Message();
        assistantReply.setUserRole("user");
        assistantReply.setAssistantRole("assistant");
        assistantReply.setUserContent(userMessage); // 用户输入的内容
        assistantReply.setAssistantContent(responseMessage); // 助手的回复内容
        assistantReply.setConversationId(Integer.valueOf(conversationId));
        messageMapper.insert(assistantReply);

        return responseMessage;
    }
}
数据库
create table message
(
    id                bigint auto_increment comment '主键ID,唯一标识每条对话记录'
        primary key,
    user_role         varchar(255) not null comment '用户角色(例如:user)',
    assistant_role    varchar(255) not null comment '助手角色(例如:assistant)',
    user_content      text         not null comment '用户输入的内容',
    assistant_content text         not null comment '助手回复的内容',
    conversation_id   int          null comment '对话会话ID,用于关联同一轮对话的多条消息'
)
    comment '存储多轮对话记录的表,包含用户与助手之间的交互内容';

配置

详细的信息通过bean来获取

3、接口测试

http://localhost:8081/api/chat/one
"Hello, how are you?,用中文回答"

 

http://localhost:8081/api/chat/completion
{
  "message": "我刚刚问了你啥问题",
  "conversation_id": "3"
}

其实这里的解析式有些问题的,有很多的换行的符号,可能大家觉得有问题,不过由于是json数据才会这样子,这些换行符方便后续使用的时候,解析json,内容就是正常的了。

 完美实现!

Logo

火山引擎开发者社区是火山引擎打造的AI技术生态平台,聚焦Agent与大模型开发,提供豆包系列模型(图像/视频/视觉)、智能分析与会话工具,并配套评测集、动手实验室及行业案例库。社区通过技术沙龙、挑战赛等活动促进开发者成长,新用户可领50万Tokens权益,助力构建智能应用。

更多推荐