引言
之前刚上大学的时候,看到网上有各种gpt套壳会觉得很厉害,但是随着认识的加深发现实际上并不难,特别是现在的Cursor的辅助之下,个人开发者会变得愈发强大,做这种东西很简单,但是我还是希望刚上手的小伙伴们能把知识内化成自己的并做出拓展,所以想要写一篇实现过程给大家,让大家更加了解这个过程。下面且听我娓娓道来。
准备
首先,我们需要一个api-key,咱们去deepseek官网(DeepSeek | 深度求索),点击右上角的API开放平台
点击左边的API keys
点击创建API key,输入一个你喜欢的名称,然后点击创建
看到出现sk-xxxxxxxxx的标识就是我们的apikey啦,点击复制,出于保护的目的,这个 apikey是无法第二次查看的,所以咱们把他保留下来。
但是咱们的apikey是需要花钱才可以正常使用的,所以我们可以在这里充值1块钱进行使用
项目使用
在application.yml文件里面,配置上咱们的apikey和其他的默认配置
下面以一个调用接口“/api/deepseek/chat”为例,来说明调用过程:
前端访问这个接口的时候,就会调用下面这个chat方法,这里的DeepSeekResponseDTO和DeepSeekRequestDTO都是两个请求结构体类,前端发来的json必须符合 DeepSeekRequestDTO类型,后端返回的响应体是DeepSeekResponseDTO类型。接着就调用Service层里面的chat方法。
我们直接来看Service层的实现类代码:
这里我们设置请求头、创建请求实体和发送请求就是为了我们能通过之前的apikey来和官网的deepseek模型进行交互。
public Resp<DeepSeekResponseDTO> chat(DeepSeekRequestDTO request) {
try {
log.info("发送 DeepSeek 聊天请求,模型:{}", request.getModel());
// 设置请求头
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
headers.set("Authorization", "Bearer " + deepSeekConfig.getApiKey());
// 创建请求实体
HttpEntity<DeepSeekRequestDTO> entity = new HttpEntity<>(request, headers);
// 发送请求
ResponseEntity<String> response = restTemplate.exchange(
deepSeekConfig.getApiUrl(),
HttpMethod.POST,
entity,
String.class
);
if (response.getStatusCode().value() == HttpStatus.OK.getCode()) {
DeepSeekResponseDTO responseDTO = JSON.parseObject(response.getBody(), DeepSeekResponseDTO.class);
log.info("DeepSeek 响应成功,token使用:{}", responseDTO.getUsage().getTotalTokens());
return Resp.success(responseDTO);
} else {
log.error("DeepSeek API 请求失败,状态码:{}", response.getStatusCode());
return Resp.error(HttpStatus.INTERNAL_ERROR, "AI服务请求失败");
}
} catch (Exception e) {
log.error("DeepSeek API 调用异常:", e);
return Resp.error(HttpStatus.INTERNAL_ERROR, "AI服务调用异常:" + e.getMessage());
}
}
到这里其实就已经结束了,但是套壳套壳,这显然只是调用对不对,所以再来说说另一个接口
“/api/deepseek/chat”的simpleChat方法
转到对应的service层的实现类里面,我们可以看到这里加入了一个系统身份提示,现在无论用户怎么问“你是谁?你叫什么名字?”,他都会以“小易机器人”的身份和你交流,这样用户们就无法判断这到底是谁了,因为谁来了都是小易机器人,这就实现了套壳的核心目标了。
下面这两个接口的方法这里 就不再赘述了,相信小伙伴们已经知道是怎么回事了。
好了,到这里就是真的结束了,如果伙伴们觉得这篇文章对大家有帮助的话,欢迎各位小伙伴们点赞和收藏这篇文章方便下次查阅和转发给其他伙伴们,有问题欢迎评论区留言,下次见!
具体代码
DeepSeekController.java:
package com.example.ezs.controller;
import com.example.ezs.pojo.dto.DeepSeekRequestDTO;
import com.example.ezs.pojo.dto.DeepSeekResponseDTO;
import com.example.ezs.service.DeepSeekService;
import com.example.ezs.variable.Resp;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.*;
import java.util.List;
/**
* DeepSeek AI 测试控制器
* @author loself
* @date 2025-1-27
*/
@Slf4j
@RestController
@RequestMapping("/api/deepseek")
@Tag(name = "DeepSeek AI 接口", description = "DeepSeek AI 相关接口")
@RequiredArgsConstructor
public class DeepSeekController {
private final DeepSeekService deepSeekService;
@PostMapping("/chat")
@Operation(summary = "AI 聊天", description = "与 DeepSeek AI 进行对话")
public Resp<DeepSeekResponseDTO> chat(@RequestBody DeepSeekRequestDTO request) {
return deepSeekService.chat(request);
}
@PostMapping("/simple-chat")
@Operation(summary = "简单问答", description = "简单的 AI 问答")
public Resp<String> simpleChat(
@Parameter(description = "问题内容") @RequestParam String question) {
return deepSeekService.simpleChat(question);
}
@PostMapping("/context-chat")
@Operation(summary = "上下文聊天", description = "带上下文的 AI 对话")
public Resp<String> contextChat(
@Parameter(description = "消息历史") @RequestBody List<DeepSeekRequestDTO.Message> messages) {
return deepSeekService.chatWithContext(messages);
}
@GetMapping("/test")
@Operation(summary = "测试连接", description = "测试 DeepSeek API 连接")
public Resp<String> testConnection() {
return deepSeekService.simpleChat("你好,请简单介绍一下你自己。");
}
}
DeepSeekService.java:
package com.example.ezs.service;
import com.example.ezs.pojo.dto.DeepSeekRequestDTO;
import com.example.ezs.pojo.dto.DeepSeekResponseDTO;
import com.example.ezs.variable.Resp;
/**
* DeepSeek AI 服务接口
* @author loself
* @date 2025-1-27
*/
public interface DeepSeekService {
/**
* 发送聊天请求
* @param request 请求参数
* @return AI响应
*/
Resp<DeepSeekResponseDTO> chat(DeepSeekRequestDTO request);
/**
* 简单问答
* @param question 问题
* @return AI回答
*/
Resp<String> simpleChat(String question);
/**
* 带上下文的聊天
* @param messages 消息历史
* @return AI回答
*/
Resp<String> chatWithContext(java.util.List<DeepSeekRequestDTO.Message> messages);
}
DeepSeekServiceImpl.java:
package com.example.ezs.service.impl;
import com.alibaba.fastjson.JSON;
import com.example.ezs.config.DeepSeekConfig;
import com.example.ezs.pojo.dto.DeepSeekRequestDTO;
import com.example.ezs.pojo.dto.DeepSeekResponseDTO;
import com.example.ezs.service.DeepSeekService;
import com.example.ezs.variable.HttpStatus;
import com.example.ezs.variable.Resp;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.*;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
import java.util.ArrayList;
import java.util.List;
/**
* DeepSeek AI 服务实现类
* @author loself
* @date 2025-1-27
*/
@Slf4j
@Service
public class DeepSeekServiceImpl implements DeepSeekService {
private final DeepSeekConfig deepSeekConfig;
private final RestTemplate restTemplate;
@Autowired
public DeepSeekServiceImpl(DeepSeekConfig deepSeekConfig, RestTemplate restTemplate) {
this.deepSeekConfig = deepSeekConfig;
this.restTemplate = restTemplate;
}
@Override
public Resp<DeepSeekResponseDTO> chat(DeepSeekRequestDTO request) {
try {
log.info("发送 DeepSeek 聊天请求,模型:{}", request.getModel());
// 设置请求头
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
headers.set("Authorization", "Bearer " + deepSeekConfig.getApiKey());
// 创建请求实体
HttpEntity<DeepSeekRequestDTO> entity = new HttpEntity<>(request, headers);
// 发送请求
ResponseEntity<String> response = restTemplate.exchange(
deepSeekConfig.getApiUrl(),
HttpMethod.POST,
entity,
String.class
);
if (response.getStatusCode().value() == HttpStatus.OK.getCode()) {
DeepSeekResponseDTO responseDTO = JSON.parseObject(response.getBody(), DeepSeekResponseDTO.class);
log.info("DeepSeek 响应成功,token使用:{}", responseDTO.getUsage().getTotalTokens());
return Resp.success(responseDTO);
} else {
log.error("DeepSeek API 请求失败,状态码:{}", response.getStatusCode());
return Resp.error(HttpStatus.INTERNAL_ERROR, "AI服务请求失败");
}
} catch (Exception e) {
log.error("DeepSeek API 调用异常:", e);
return Resp.error(HttpStatus.INTERNAL_ERROR, "AI服务调用异常:" + e.getMessage());
}
}
@Override
public Resp<String> simpleChat(String question) {
try {
log.info("简单聊天,问题:{}", question);
// 构建请求
DeepSeekRequestDTO request = new DeepSeekRequestDTO();
request.setModel(deepSeekConfig.getModel());
request.setMaxTokens(deepSeekConfig.getMaxTokens());
request.setTemperature(deepSeekConfig.getTemperature());
request.setStream(false);
// 设置消息,添加身份提示
List<DeepSeekRequestDTO.Message> messages = new ArrayList<>();
// 添加系统身份提示
DeepSeekRequestDTO.Message systemMessage = new DeepSeekRequestDTO.Message();
systemMessage.setRole("system");
systemMessage.setContent("你是小易机器人,一个专业的智能客服助手。请以友好、专业的态度回答用户问题,始终以'小易机器人'的身份进行交流。");
messages.add(systemMessage);
// 添加用户问题
DeepSeekRequestDTO.Message userMessage = new DeepSeekRequestDTO.Message();
userMessage.setRole("user");
userMessage.setContent(question);
messages.add(userMessage);
request.setMessages(messages);
// 发送请求
Resp<DeepSeekResponseDTO> response = chat(request);
if (response.isSuccess() && response.getData() != null) {
DeepSeekResponseDTO responseDTO = response.getData();
if (responseDTO.getChoices() != null && !responseDTO.getChoices().isEmpty()) {
String answer = responseDTO.getChoices().get(0).getMessage().getContent();
return Resp.success(answer);
}
}
return Resp.error(HttpStatus.INTERNAL_ERROR, "AI回答生成失败");
} catch (Exception e) {
log.error("简单聊天异常:", e);
return Resp.error(HttpStatus.INTERNAL_ERROR, "AI服务异常:" + e.getMessage());
}
}
@Override
public Resp<String> chatWithContext(List<DeepSeekRequestDTO.Message> messages) {
try {
log.info("上下文聊天,消息数量:{}", messages.size());
// 构建请求
DeepSeekRequestDTO request = new DeepSeekRequestDTO();
request.setModel(deepSeekConfig.getModel());
request.setMaxTokens(deepSeekConfig.getMaxTokens());
request.setTemperature(deepSeekConfig.getTemperature());
request.setStream(false);
request.setMessages(messages);
// 发送请求
Resp<DeepSeekResponseDTO> response = chat(request);
if (response.isSuccess() && response.getData() != null) {
DeepSeekResponseDTO responseDTO = response.getData();
if (responseDTO.getChoices() != null && !responseDTO.getChoices().isEmpty()) {
String answer = responseDTO.getChoices().get(0).getMessage().getContent();
return Resp.success(answer);
}
}
return Resp.error(HttpStatus.INTERNAL_ERROR, "AI回答生成失败");
} catch (Exception e) {
log.error("上下文聊天异常:", e);
return Resp.error(HttpStatus.INTERNAL_ERROR, "AI服务异常:" + e.getMessage());
}
}
}
DeepSeekRequestDTO.java:
package com.example.ezs.pojo.dto;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;
import java.util.List;
/**
* DeepSeek API 请求 DTO
* @author loself
* @date 2025-1-27
*/
@Data
public class DeepSeekRequestDTO {
/**
* 模型名称
*/
private String model;
/**
* 消息列表
*/
private List<Message> messages;
/**
* 最大token数
*/
@JsonProperty("max_tokens")
private Integer maxTokens;
/**
* 温度参数
*/
private Double temperature;
/**
* 是否流式响应
*/
private Boolean stream;
/**
* 消息类
*/
@Data
public static class Message {
/**
* 角色:system, user, assistant
*/
private String role;
/**
* 消息内容
*/
private String content;
}
}
DeepSeekResponseDTO.java:
package com.example.ezs.pojo.dto;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;
import java.util.List;
/**
* DeepSeek API 响应 DTO
* @author loself
* @date 2025-1-27
*/
@Data
public class DeepSeekResponseDTO {
/**
* 响应ID
*/
private String id;
/**
* 对象类型
*/
private String object;
/**
* 创建时间
*/
private Long created;
/**
* 模型名称
*/
private String model;
/**
* 选择列表
*/
private List<Choice> choices;
/**
* 使用情况
*/
private Usage usage;
/**
* 选择类
*/
@Data
public static class Choice {
/**
* 索引
*/
private Integer index;
/**
* 消息
*/
private Message message;
/**
* 完成原因
*/
@JsonProperty("finish_reason")
private String finishReason;
}
/**
* 消息类
*/
@Data
public static class Message {
/**
* 角色
*/
private String role;
/**
* 内容
*/
private String content;
}
/**
* 使用情况类
*/
@Data
public static class Usage {
/**
* 提示token数
*/
@JsonProperty("prompt_tokens")
private Integer promptTokens;
/**
* 完成token数
*/
@JsonProperty("completion_tokens")
private Integer completionTokens;
/**
* 总token数
*/
@JsonProperty("total_tokens")
private Integer totalTokens;
}
}