提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
文章目录
- 前言
- 一、必要信息准备
- 二、HTTP问答接入
- 1.配置文件
- 2.创建实例类
- 3.创建调用外部API接口
- 4.创建调用服务service
- 5.业务层service选择模型,并调用刚刚的服务
- 三、WSS流式调用
- 1.先写一个处理流式响应的方法
- 2.业务层service调用
- 3.WebSocket调用
- 总结
前言
硅基流动推出了功能完备的DeepSeek满血版,然而众多用户在尝试接入大型模型时仍面临诸多挑战,特别是在流式接入方面。今天,我将引领大家通过Java实现双模式接入DeepSeek满血版,这涵盖了利用HTTP协议实现的问答模式,以及借助WSS协议实现的流式问答功能。话不多说,我们直接开始。
一、必要信息准备
接入满血版DeepSeek,肯定要有个硅基流动账号和秘钥啦,搜索一下硅基流动官网,打开硅基流动首页,注册账号,别忘了填邀请码wkzJFskh,注册后可以获取14元的赠送额度,嫌麻烦的同学可以直接复制https://cloud.siliconflow.cn/i/wkzJFskh,可以直接跳转到官网。
注册完成后,左侧菜单栏点击API秘钥,然后选择右上角的创建秘钥,输入必要信息后,秘钥创建完成,鼠标点击刚刚创建的秘钥,单击复制,这一步可以先把秘钥用个记事本记录一下,等会代码里会用到。
点击左侧模型广场,选取DeepSeekR1满血版模型,可以看到,广场里面有很多小模型是免费的,大家有空可以都尝试玩一下。
复制一下模型名称,写在记事本里,等会会用到。点击API文档,进入官方接入指南。
记住这边的路径,请求以及响应,下面要开始代码部分啦。
二、HTTP问答接入
我们先进行HTTP问答接入,这种接入方式需要等大模型完全回答完问题,将答案生成好之后,全部返回,这种方式的优点是前后端交互方便,缺点是在用户看来等待好长时间才返回答案。下面开始上代码
1.配置文件
代码如下(示例):
sili:
apiKey: sk-xxxxxxxxx-your-api-key
baseUrl: https://api.siliconflow.cn/v1/
2.创建实例类
会看第一节的官方API指南,根据官方的请求体和响应,构造实体类,我这边不展开篇幅
3.创建调用外部API接口
这里将普通调用和流模式均展示在了下面,流式调用需要用@Streaming注解。这里不使用openFeign是因为openFeign不支持流式响应的接收。
package com.example.awesome.feign.siliconflow;
import com.example.awesome.feign.siliconflow.req.ChatCompletionReq;
import com.example.awesome.feign.siliconflow.res.ChatCompletionRes;
import okhttp3.ResponseBody;
import retrofit2.Call;
import retrofit2.http.Body;
import retrofit2.http.HeaderMap;
import retrofit2.http.POST;
import retrofit2.http.Streaming;
import java.util.Map;
/**
* 定义与 SiliconFlow API 交互的 Retrofit 接口。
*/
public interface SiliconFlowApiService {
/**
* 发起同步的聊天完成请求。
*
* @param chatCompletionReq 请求体,包含聊天完成所需的参数。
* @param headers HTTP 请求头,包括授权信息等。
* @return 返回一个 {@link Call} 对象,用于执行HTTP请求并获取 {@link ChatCompletionRes} 响应。
*/
@POST("/chat/completions")
Call<ChatCompletionRes> getChatCompletions(
@Body ChatCompletionReq chatCompletionReq,
@HeaderMap Map<String, String> headers
);
/**
* 发起流式的聊天完成请求。
*
* @param chatCompletionReq 请求体,包含聊天完成所需的参数。
* @param headers HTTP 请求头,包括授权信息等。
* @return 返回一个 {@link Call} 对象,用于执行HTTP请求并获取 {@link ResponseBody} 流式响应。
* @see Streaming 表示该请求是流式的,不会将整个响应体加载到内存中。
*/
@POST("/chat/completions")
@Streaming
Call<ResponseBody> getChatCompletionsStream(
@Body ChatCompletionReq chatCompletionReq,
@HeaderMap Map<String, String> headers
);
}
4.创建调用服务service
package com.example.awesome.feign.siliconflow;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.example.awesome.feign.siliconflow.req.ChatCompletionReq;
import com.example.awesome.feign.siliconflow.res.ChatCompletionRes;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.PropertyNamingStrategy;
import com.volcengine.ark.runtime.model.completion.chat.ChatCompletionResult;
import com.volcengine.ark.runtime.utils.ResponseBodyCallback;
import com.volcengine.ark.runtime.utils.SSE;
import io.reactivex.BackpressureStrategy;
import io.reactivex.Flowable;
import lombok.extern.slf4j.Slf4j;
import okhttp3.OkHttpClient;
import okhttp3.ResponseBody;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import retrofit2.Call;
import retrofit2.Retrofit;
import retrofit2.adapter.rxjava3.RxJava3CallAdapterFactory;
import retrofit2.converter.gson.GsonConverterFactory;
import javax.annotation.PostConstruct;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;
/**
* 实现与 SiliconFlow API 交互的服务类。
*/
@Service
@Slf4j
public class SiliconFlowApiServiceImpl {
@Value("${sili.baseUrl}")
private String SILI_API_URL;
@Value("${sili.apiKey}")
private String apiKey;
private Retrofit retrofit;
private SiliconFlowApiService apiService;
/**
* 初始化 Retrofit 客户端和 API 服务。
*/
@PostConstruct
public void init() {
log.info("SiLiApiService init");
retrofit = new Retrofit.Builder()
.baseUrl(SILI_API_URL)
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJava3CallAdapterFactory.create())
.build();
this.apiService = retrofit.create(SiliconFlowApiService.class);
}
/**
* 发起同步的聊天完成请求,返回非流式的响应。
*
* @param req 请求体,包含聊天完成所需的参数。
* @return 返回 {@link ChatCompletionRes} 对象,表示API的响应结果。
*/
public ChatCompletionRes getChatCompletions(ChatCompletionReq req) {
Map<String, String> headers = new HashMap<>();
headers.put("Authorization", "Bearer " + apiKey);
headers.put("Content-Type", "application/json");
try {
// 执行HTTP请求并获取响应
Call<ChatCompletionRes> call = this.apiService.getChatCompletions(req, headers);
return call.execute().body();
} catch (Exception e) {
// 记录错误日志并抛出运行时异常
log.error("SiLiApiService error: {}", e.getMessage(), e);
throw new RuntimeException("SiLiApiService error: " + e.getMessage(), e);
}
}
}
5.业务层service选择模型,并调用刚刚的服务
package com.example.awesome.service;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.example.awesome.feign.siliconflow.SiliconFlowApiServiceImpl;
import com.example.awesome.feign.siliconflow.req.ChatCompletionReq;
import com.example.awesome.feign.siliconflow.req.Message;
import com.example.awesome.feign.siliconflow.res.ChatCompletionRes;
import com.volcengine.ark.runtime.model.completion.chat.ChatCompletionResult;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import javax.websocket.Session;
import java.util.ArrayList;
import java.util.List;
/**
* 提供与 SiliconFlow API 交互的服务类。
*/
@Service
@Slf4j
public class SiliconFlowService {
@Resource
private SiliconFlowApiServiceImpl siliconFlowApiServiceImpl;
/**
* 发起同步的聊天完成请求,返回用户的回答内容。
*
* @param question 用户提出的聊天问题。
* @return 返回用户的回答内容。
* @throws RuntimeException 如果请求过程中发生异常,抛出运行时异常。
*/
public String getChatCompletions(String question) {
// 创建 ChatCompletionReq 对象
ChatCompletionReq req = new ChatCompletionReq();
// 设置模型名称
req.setModel("deepseek-ai/DeepSeek-R1");
// 创建消息列表
List<Message> messages = new ArrayList<>();
// 添加用户消息
messages.add(Message.builder().role("user").content(question).build());
// 设置请求的消息列表
req.setMessages(messages);
try {
// 发起同步请求并获取响应
ChatCompletionRes chatCompletions = siliconFlowApiServiceImpl.getChatCompletions(req);
// 返回第一个选择的回答内容
return chatCompletions.getChoices().get(0).getMessage().getContent();
} catch (Exception e) {
// 记录错误日志并抛出运行时异常
log.error("siliconflow answer error: {}", e.getMessage(), e);
throw new RuntimeException("网络异常请重试", e);
}
}
}
三、WSS流式调用
1.先写一个处理流式响应的方法
在官方指南中可以看到,流式调用需要将入参的stream设置为true
package com.example.awesome.feign.siliconflow;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.example.awesome.feign.siliconflow.req.ChatCompletionReq;
import com.example.awesome.feign.siliconflow.res.ChatCompletionRes;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.PropertyNamingStrategy;
import com.volcengine.ark.runtime.model.completion.chat.ChatCompletionResult;
import com.volcengine.ark.runtime.utils.ResponseBodyCallback;
import com.volcengine.ark.runtime.utils.SSE;
import io.reactivex.BackpressureStrategy;
import io.reactivex.Flowable;
import lombok.extern.slf4j.Slf4j;
import okhttp3.OkHttpClient;
import okhttp3.ResponseBody;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import retrofit2.Call;
import retrofit2.Retrofit;
import retrofit2.adapter.rxjava3.RxJava3CallAdapterFactory;
import retrofit2.converter.gson.GsonConverterFactory;
import javax.annotation.PostConstruct;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;
/**
* 实现与 SiliconFlow API 交互的服务类。
*/
@Service
@Slf4j
public class SiliconFlowApiServiceImpl {
@Value("${sili.baseUrl}")
private String SILI_API_URL;
@Value("${sili.apiKey}")
private String apiKey;
private Retrofit retrofit;
private SiliconFlowApiService apiService;
private static final ObjectMapper mapper = defaultObjectMapper();
/**
* 创建并配置 ObjectMapper 实例。
*
* @return 配置好的 ObjectMapper 实例。
*/
public static ObjectMapper defaultObjectMapper() {
ObjectMapper mapper = new ObjectMapper();
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
mapper.setPropertyNamingStrategy(PropertyNamingStrategy.SNAKE_CASE);
return mapper;
}
/**
* 初始化 Retrofit 客户端和 API 服务。
*/
@PostConstruct
public void init() {
log.info("SiLiApiService init");
retrofit = new Retrofit.Builder()
.baseUrl(SILI_API_URL)
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJava3CallAdapterFactory.create())
.build();
this.apiService = retrofit.create(SiliconFlowApiService.class);
}
/**
* 将 Call<ResponseBody> 转换为 Flowable<T>,并进行数据映射。
*
* @param apiCall API 调用对象。
* @param cl 目标类类型。
* @param <T> 泛型类型。
* @return Flowable<T> 对象。
*/
public static <T> Flowable<T> stream(Call<ResponseBody> apiCall, Class<T> cl) {
return stream(apiCall).map((sse) -> {
// log.info("SiLiApiService stream: {}", sse.getData());
return mapper.readValue(sse.getData(), cl);
});
}
/**
* 将 Call<ResponseBody> 转换为 Flowable<SSE>,并处理响应。
*
* @param apiCall API 调用对象。
* @param emitDone 是否在流结束时发送完成信号。
* @return Flowable<SSE> 对象。
*/
public static Flowable<SSE> stream(Call<ResponseBody> apiCall, boolean emitDone) {
return Flowable.create((emitter) -> {
apiCall.enqueue(new ResponseBodyCallback(emitter, emitDone));
}, BackpressureStrategy.BUFFER);
}
/**
* 将 Call<ResponseBody> 转换为 Flowable<SSE>,默认不发送完成信号。
*
* @param apiCall API 调用对象。
* @return Flowable<SSE> 对象。
*/
public static Flowable<SSE> stream(Call<ResponseBody> apiCall) {
return stream(apiCall, false);
}
/**
* 发起流式的聊天完成请求,返回流式的响应。
*
* @param request 请求体,包含聊天完成所需的参数。
* @return 返回 {@link Flowable<ChatCompletionResult>} 对象,表示流式的API响应结果。
*/
public Flowable<ChatCompletionResult> streamChatCompletion(ChatCompletionReq request) {
Map<String, String> headers = new HashMap<>();
headers.put("Authorization", "Bearer " + apiKey);
headers.put("Content-Type", "application/json");
request.setStream(Boolean.TRUE);
return stream(this.apiService.getChatCompletionsStream(request, headers), ChatCompletionResult.class);
}
}
2.业务层service调用
package com.example.awesome.service;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.example.awesome.feign.siliconflow.SiliconFlowApiServiceImpl;
import com.example.awesome.feign.siliconflow.req.ChatCompletionReq;
import com.example.awesome.feign.siliconflow.req.Message;
import com.example.awesome.feign.siliconflow.res.ChatCompletionRes;
import com.volcengine.ark.runtime.model.completion.chat.ChatCompletionResult;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import javax.websocket.Session;
import java.util.ArrayList;
import java.util.List;
/**
* 提供与 SiliconFlow API 交互的服务类。
*/
@Service
@Slf4j
public class SiliconFlowService {
@Resource
private SiliconFlowApiServiceImpl siliconFlowApiServiceImpl;
/**
* 发起流式的聊天完成请求,并将结果通过 WebSocket 会话发送给客户端。
*
* @param question 用户提出的聊天问题。
* @param session WebSocket 会话对象。
* @throws RuntimeException 如果请求过程中发生异常,抛出运行时异常。
*/
public void getChatCompletionsStream(String question, Session session) {
// 创建 ChatCompletionReq 对象
ChatCompletionReq req = new ChatCompletionReq();
// 设置模型名称
req.setModel("deepseek-ai/DeepSeek-R1");
// 创建消息列表
List<Message> messages = new ArrayList<>();
// 添加用户消息
messages.add(Message.builder().role("user").content(question).build());
// 设置请求的消息列表
req.setMessages(messages);
try {
// 发起流式请求并处理响应
siliconFlowApiServiceImpl.streamChatCompletion(req)
.doOnError(e -> log.error("Error in streamChatCompletion: ", e))
.blockingForEach(chunk -> {
if (!chunk.getChoices().isEmpty()) {
chunk.getChoices().forEach(choice -> {
// 如果完成原因为空或不是 "stop",则继续处理
if (StrUtil.isNotEmpty(choice.getFinishReason()) && StrUtil.equals(choice.getFinishReason(), "stop")) {
// 发送 "answer-stop" 信号
session.getAsyncRemote().sendText("answer-stop");
return;
}
// 如果消息内容为空,则跳过
if (ObjectUtil.isEmpty(choice.getMessage().getContent())) {
return;
}
// 同步发送消息内容
synchronized (session) {
try {
session.getBasicRemote().sendText(choice.getMessage().getContent());
} catch (Exception e) {
// 记录错误日志并抛出运行时异常
log.error("answerByStream error: {}", e.getMessage(), e);
throw new RuntimeException(e);
}
}
});
}
});
} catch (Exception e) {
// 记录错误日志并抛出运行时异常
log.error("siliconflow answer error: {}", e.getMessage(), e);
throw new RuntimeException("网络异常请重试", e);
}
}
}
3.WebSocket调用
在onMessage方法中,在session中写入流式调用的响应,即可实现wss流式接入,输出就类似于官方的一字一字输出。在用户看来减少了等待时间,十分友好。
package com.example.awesome.controller.webSocket;
import cn.hutool.core.util.ObjectUtil;
import com.example.awesome.service.SiliconFlowService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.websocket.*;
import javax.websocket.server.ServerEndpoint;
/**
* WebSocket 服务器端点,处理与客户端的 WebSocket 连接。
*/
@Slf4j
@ServerEndpoint(value = "/websocket/test")
@Component
public class TestSocketServer {
private static SiliconFlowService siliconFlowService;
/**
* 注入 SiliconFlowService 实例。
*
* @param siliconFlowService SiliconFlowService 实例。
*/
@Autowired
public void setSiliconFlowService(SiliconFlowService siliconFlowService) {
this.siliconFlowService = siliconFlowService;
}
/**
* 处理 WebSocket 连接打开事件。
*
* @param session 当前 WebSocket 会话。
*/
@OnOpen
public void onOpen(Session session) {
log.info("新连接: {}", session.getId());
}
/**
* 处理接收到的 WebSocket 消息。
*
* @param message 接收到的消息内容。
* @param session 当前 WebSocket 会话。
*/
@OnMessage
public void onMessage(String message, Session session) {
// 调用 SiliconFlowService 处理流式聊天完成请求
siliconFlowService.getChatCompletionsStream(message, session);
}
/**
* 处理 WebSocket 连接关闭事件。
*
* @param session 当前 WebSocket 会话。
*/
@OnClose
public void onClose(Session session) {
log.info("连接关闭: {}", session.getId());
}
/**
* 处理 WebSocket 连接中的错误事件。
*
* @param session 当前 WebSocket 会话。
* @param throwable 发生的异常。
*/
@OnError
public void onError(Session session, Throwable throwable) {
log.error("Error on session: {}", session.getId(), throwable);
}
}
总结
上面就是双模式的接入全过程啦!~~~~~~