当前位置: 首页 > news >正文

如何实现大模型 “边生成边显示“

今天要实现大模型 “边生成边显示” 的效果。并介绍如何Java接入DeepSeek接口。

Java 可以通过SSE(Server-Sent Events,服务器发送事件) 技术实现。SSE 是一种基于 HTTP 的单向通信协议,适合服务器持续向客户端推送数据流(如大模型的流式输出),非常符合 “边吐内容边显示” 的场景。

准备工作

进入deepseek官网 https://www.deepseek.com/

创建key,API key 仅在创建时可见可复制,请妥善保存。

创建一个Java springboot工程。

导入依赖

必要依赖

okhttp

<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
<dependency><groupId>com.squareup.okhttp3</groupId><artifactId>okhttp</artifactId><version>4.9.3</version>
</dependency>

控制层

@Slf4j
@RestController
@RequestMapping("/model/v2")
public class SSEv2Controller {// 线程池:用于异步处理大模型生成(避免阻塞主线程)private final ExecutorService executor = Executors.newCachedThreadPool();// DeepSeek客户端实例private final ModelSseClient modelSseClient = new ModelSseClient();/*** 处理前端的SSE请求,返回模型流式响应** @param prompt 用户输入的提示词* @return SseEmitter(用于向前端推送流式数据)*/@GetMapping(value = "/stream", produces = MediaType.TEXT_EVENT_STREAM_VALUE)public SseEmitter streamResponse(@RequestParam String prompt) {// 创建SSE发射器(30分钟超时)SseEmitter emitter = new SseEmitter(30 * 60 * 1000L);// 异步调用DeepSeek模型(避免阻塞控制器线程)executor.submit(() -> {// 通过回调处理模型返回的流式数据modelSseClient.streamChat(prompt, new StreamCallback() {@Overridepublic void onChunk(String chunk) {try {// 将模型返回的内容块推送给前端emitter.send(SseEmitter.event().data(chunk));} catch (Exception e) {// 推送失败时关闭连接emitter.completeWithError(e);}}@Overridepublic void onComplete() {try {// 模型响应结束,发送结束信号并关闭连接emitter.send(SseEmitter.event().data("[DONE]"));emitter.complete();} catch (Exception e) {emitter.completeWithError(e);}}@Overridepublic void onError(Throwable throwable) {// 模型调用出错时,通知前端并关闭连接emitter.completeWithError(throwable);}});});// 当连接关闭时清理资源emitter.onCompletion(() -> System.out.println("SSE连接已完成"));emitter.onError(e -> System.err.println("SSE连接错误: " + e.getMessage()));emitter.onTimeout(() -> emitter.completeWithError(new RuntimeException("SSE连接超时")));return emitter;}
}

模型流式数据回调接口

// 模型流式数据回调接口
public interface StreamCallback {// 接收模型返回的内容块void onChunk(String chunk);// 流式响应结束void onComplete();// 发生错误时调用void onError(Throwable throwable);
}

模型客户端

public class ModelSseClient {// DeepSeek API地址(请确认官方最新地址)private static final String DEEPSEEK_API_URL = "https://api.deepseek.com/v1/chat/completions";// 替换为你的DeepSeek API Keyprivate static final String API_KEY = "key";// 模型名称(根据DeepSeek官方文档填写)private static final String MODEL = "deepseek-chat";private OkHttpClient client;private ObjectMapper objectMapper;public ModelSseClient() {// 初始化OkHttp客户端(设置超时时间)this.client = new OkHttpClient.Builder().connectTimeout(30, TimeUnit.SECONDS).readTimeout(60, TimeUnit.SECONDS) // 流式响应需较长读取超时.writeTimeout(30, TimeUnit.SECONDS).build();// 初始化JSON解析器(用于构建请求体和解析响应)this.objectMapper = new ObjectMapper();}/*** 调用DeepSeek流式接口,通过回调返回实时内容** @param prompt   用户输入的提示词* @param callback 回调接口(用于传递内容块、结束信号、错误信息)*/public void streamChat(String prompt, StreamCallback callback) {try {// 构建请求体(使用Jackson生成JSON,避免字符串拼接导致的格式错误)// 1. 构建messages参数List<Message> messages = new ArrayList<>();messages.add(new Message("user", prompt));// 2. 构建完整请求对象ChatRequest request = new ChatRequest(MODEL, messages, true);// 3. 转换为JSON字符串String requestBody = objectMapper.writeValueAsString(request);// 构建请求Request httpRequest = new Request.Builder().url(DEEPSEEK_API_URL).addHeader("Content-Type", "application/json").addHeader("Authorization", "Bearer " + API_KEY).post(RequestBody.create(requestBody, MediaType.parse("application/json"))).build();// 发送异步请求client.newCall(httpRequest).enqueue(new Callback() {@Overridepublic void onFailure(Call call, IOException e) {// 调用失败时通知回调callback.onError(e);}@Overridepublic void onResponse(Call call, Response response) throws IOException {if (!response.isSuccessful()) {// 非200状态码时通知错误(如401认证失败、400参数错误)callback.onError(new RuntimeException("DeepSeek请求失败: 状态码=" + response.code() + ", 信息=" + response.message()));response.close();return;}ResponseBody body = response.body();if (body == null) {callback.onError(new RuntimeException("DeepSeek响应体为空"));response.close();return;}try (BufferedSource source = body.source()) {// 循环读取流式响应while (!source.exhausted()) {String line = source.readUtf8Line();if (line == null) break;if (line.trim().isEmpty()) continue;// 解析SSE格式数据if (line.startsWith("data: ")) {String data = line.substring("data: ".length()).trim();if (data.equals("[DONE]")) {// 流式结束,通知回调callback.onComplete();break;}// 解析JSON获取内容JsonNode jsonNode = objectMapper.readTree(data);String content = jsonNode.at("/choices/0/delta/content").asText(null);if (content != null && !content.isEmpty()) {// 将内容块通过回调传递给SSE控制器callback.onChunk(content);}}}} finally {response.close();}}});} catch (Exception e) {// 构建请求体失败时通知错误callback.onError(e);}}
}

创建两个类,用来构建请求体

class ChatRequest {private String model;private List<Message> messages;private boolean stream;
}class Message { private String role;private String content;
}
http://www.dtcms.com/a/537975.html

相关文章:

  • 网站排版教程程序员 做网站 微信公众号 赚钱
  • 无人机数据 → 三维模型与光谱指数 → 多源融合特征 → 机器学习模型与机理解释 → 生态应用案例与科研论文
  • 做性的网站有哪些内容科技股有哪些股票龙头2021
  • 深圳网站建设找智恒网络网站做竞价优化
  • 计算机视觉:基于YOLOv8/YOLOv7/YOLOv6/YOLOv5的零售柜商品检测识别系统(Python+PySide6界面+训练代码)(源码+文档)✅
  • 重庆网站设计公司推荐永久免费虚拟主机
  • 软件自学网站房地产设计公司
  • 网络科普:自治系统编号
  • 网站不显示index.html北京最大的广告制作公司
  • TCP 消息分段与粘包问题的完整解决方案
  • 网站怎么运营推广电话销售管理系统
  • 邢台公司网站建设南漳网站制作
  • 度假村网站模板关键词研究工具
  • 【算法】day13 链表
  • 可以做网站的语言济南泰安网站建设公司
  • 超级工程网站建设上海中心大厦wordpress 登陆后台
  • 淮安网站定制wordpress多用户图库
  • 顺企网萍乡网站建设网站排名优化怎么弄
  • switch宝可梦传说Z-A金手指1.0.1免通信进化和持物通信进化修改
  • 校园电子商务网站建设网站制作教程网站
  • 长沙第三方网站建设公司辽宁工程建设信息网诚信库怎么填
  • 建网站需要什么软件义乌跨境电商公司前十名
  • 网站建设费 科目百度推广怎么注册账号
  • FP8013降压恒流单芯片切五路调光调色方案
  • 知识就是力量——数据库
  • 住建设部官方网站wordpress 4.7.2 中文
  • 当神谕落入都市老城区的染缸
  • PillarsOfModernCpp 报告总结
  • 网站建设这块是怎么挣钱手机版网站做一下多少钱
  • 凡科做的网站如何绑定域名移动网站建设哪家快