Java快速接入DeepSeek实现流式、联网、知识库以及多轮问答
本文将详细的阐明,如何使用Java、JDK8快速接入deepseek的聊天服务,包含官方的API服务,以及本地Ollama的服务。并搭建一个简朴的前端界面,用于流式输出、多轮问答、联网、知识库问答的结果展示。
1. 创建spring boot应用
2. 引入pom
引入ai4j库的依赖。
AI4J是一款JavaSDK用于快速接入AI大模子应用,整合多平台大模子,如OpenAi、Ollama、智谱Zhipu(ChatGLM)、深度求索DeepSeek、月之暗面Moonshot(Kimi)、腾讯混元Hunyuan、零一万物(01)等等,提供统一的输入输出(对齐OpenAi)消除差别化,优化函数调用(Tool Call),优化RAG调用、支持向量数据库(Pinecone),并且支持JDK1.8,为用户提供快速整合AI的能力。
AI4J-GitHub
- <dependency>
- <groupId>io.github.lnyo-cly</groupId>
- <artifactId>ai4j-spring-boot-starter</artifactId>
- <version>1.3.0</version>
- </dependency>
复制代码 3. 设置application.yml
在deepseek官网,创建API-KEY,然后在application.yml中设置
DeepSeek-APIKEY
- ai:
- deepseek:
- api-key: "sk-123456789"
复制代码 4. 创建聊天服务Controller
接下来实现流式输出:
- @RestController
- public class OpenAiController {
- // 注入Ai服务
- @Autowired
- private AiService aiService;
-
- @GetMapping("/chatStream")
- public SseEmitter getChatMessageStream(@RequestParam String question) {
- SseEmitter emitter = new SseEmitter();
- // 获取DEEPSEEK的聊天服务
- IChatService chatService = aiService.getChatService(PlatformType.DEEPSEEK);
- // 创建请求参数
- ChatCompletion chatCompletion = ChatCompletion.builder()
- .model("deepseek-chat")
- .message(ChatMessage.withUser(question))
- .build();
- Executors.newSingleThreadExecutor().submit(() -> {
- try {
- SseListener sseListener = new SseListener() {
- @Override
- protected void send() {
- try {
- emitter.send(this.getCurrData());
- System.out.println(this.getCurrData()); // 打印当前发送的内容
- } catch (IOException e) {
- emitter.completeWithError(e);
- }
- }
- };
- emitter.onCompletion(() -> {
- System.out.println("完成");
- sseListener.getEventSource().cancel();
- });
- // 发送流式数据
- chatService.chatCompletionStream(chatCompletion, sseListener);
- // 完成后关闭连接
- emitter.complete();
- } catch (Exception e) {
- emitter.completeWithError(e);
- }
- });
- return emitter;
- }
- }
复制代码 或者
- @GetMapping("/chatStream")
- public SseEmitter getChatMessageStream(@RequestParam String question) throws Exception {
- SseEmitter emitter = new SseEmitter();
- // 获取OLLAMA的聊天服务
- IChatService chatService = aiService.getChatService(PlatformType.DEEPSEEK);
- // 创建请求参数
- ChatCompletion chatCompletion = ChatCompletion.builder()
- .model("deepseek-chat")
- .message(ChatMessage.withUser(question))
- .build();
- SseListener sseListener = new SseListener() {
- @Override
- protected void send() {
- try {
- emitter.send(this.getCurrData());
- System.out.println(this.getCurrData()); // 打印当前发送的内容
- if ("[DONE]".equals(this.getCurrData())) {
- emitter.complete();
- }
- } catch (IOException e) {
- emitter.completeWithError(e);
- }
- }
- };
- emitter.onCompletion(() -> {
- System.out.println("完成");
- sseListener.getEventSource().cancel();
- });
- // 发送流式数据
- sseListener.getCountDownLatch().countDown(); // 取消同步阻塞
- chatService.chatCompletionStream(chatCompletion, sseListener);
- return emitter;
- }
复制代码 测试流式接口如下:
5. 修改为ollama调用
- @GetMapping("/chatStream")
- public SseEmitter getChatMessageStream(@RequestParam String question) {
- SseEmitter emitter = new SseEmitter(-1L);
- // 获取OLLAMA的聊天服务
- IChatService chatService = aiService.getChatService(PlatformType.OLLAMA);
- // 创建请求参数
- ChatCompletion chatCompletion = ChatCompletion.builder()
- .model("deepseek-r1:1.5b")
- .message(ChatMessage.withUser(question))
- .build();
- Executors.newSingleThreadExecutor().submit(() -> {
- try {
- SseListener sseListener = new SseListener() {
- @Override
- protected void send() {
- try {
- emitter.send(this.getCurrData());
- System.out.println(this.getCurrData()); // 打印当前发送的内容
- } catch (IOException e) {
- emitter.completeWithError(e);
- }
- }
- };
- emitter.onCompletion(() -> {
- System.out.println("完成");
- sseListener.getEventSource().cancel();
- });
- // 发送流式数据
- chatService.chatCompletionStream(chatCompletion, sseListener);
- // 完成后关闭连接
- emitter.complete();
- } catch (Exception e) {
- emitter.completeWithError(e);
- }
- });
- return emitter;
- }
复制代码 修改两处即可:
- 修改PlatformType为OLLAMA
- 修改model为deepseek-r1:1.5b
6. 搭建前端界面
注意:此前端界面由AI天生,并未颠末严格测试,仅供参考。
- <!DOCTYPE html>
- <html lang="zh-CN">
- <head>
- <meta charset="UTF-8">
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
- <title>AI聊天助手</title>
- <!-- Font Awesome CDN -->
- <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
- <style>
- :root {
- --primary-color: #6366f1;
- --primary-light: #818cf8;
- --primary-dark: #4f46e5;
- --text-light: #ffffff;
- --text-dark: #1e293b;
- --bg-light: #f8fafc;
- --bg-dark: #0f172a;
- --message-user: #6366f1;
- --message-bot: #f1f5f9;
- --border-color: #e2e8f0;
- }
- * {
- margin: 0;
- padding: 0;
- box-sizing: border-box;
- font-family: 'Inter', 'Arial', sans-serif;
- }
- body {
- background-color: var(--bg-light);
- color: var(--text-dark);
- display: flex;
- justify-content: center;
- align-items: center;
- min-height: 100vh;
- padding: 20px;
- }
- .chat-container {
- width: 100%;
- max-width: 900px;
- background: white;
- border-radius: 16px;
- box-shadow: 0 10px 25px rgba(0, 0, 0, 0.05);
- overflow: hidden;
- display: flex;
- flex-direction: column;
- height: 85vh;
- position: relative;
- border: 1px solid var(--border-color);
- }
- .chat-header {
- background: var(--primary-color);
- color: var(--text-light);
- padding: 18px 24px;
- display: flex;
- align-items: center;
- gap: 12px;
- box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
- z-index: 10;
- }
- .chat-header i {
- font-size: 1.5rem;
- }
- .chat-header h1 {
- font-size: 1.3rem;
- font-weight: 600;
- }
- .chat-messages {
- flex: 1;
- overflow-y: auto;
- padding: 24px;
- display: flex;
- flex-direction: column;
- gap: 20px;
- scroll-behavior: smooth;
- }
- .message-container {
- display: flex;
- gap: 12px;
- max-width: 85%;
- }
- .user-container {
- align-self: flex-end;
- flex-direction: row-reverse;
- }
- .bot-container {
- align-self: flex-start;
- }
- .avatar {
- width: 38px;
- height: 38px;
- border-radius: 50%;
- display: flex;
- justify-content: center;
- align-items: center;
- font-size: 1.2rem;
- flex-shrink: 0;
- }
- .user-avatar {
- background: var(--primary-light);
- color: var(--text-light);
- }
- .bot-avatar {
- background: var(--primary-dark);
- color: var(--text-light);
- }
- .message {
- padding: 14px 20px;
- border-radius: 18px;
- font-size: 1rem;
- line-height: 1.6;
- position: relative;
- max-width: 100%;
- }
- .user-message {
- background: var(--message-user);
- color: var(--text-light);
- border-top-right-radius: 4px;
- }
- .bot-message {
- background: var(--message-bot);
- color: var(--text-dark);
- border-top-left-radius: 4px;
- }
- .message-time {
- font-size: 0.7rem;
- opacity: 0.7;
- margin-top: 6px;
- text-align: right;
- }
- .user-message .message-time {
- color: rgba(255, 255, 255, 0.9);
- }
- .bot-message .message-time {
- color: rgba(0, 0, 0, 0.6);
- }
- .chat-input-container {
- padding: 16px 24px;
- background: white;
- border-top: 1px solid var(--border-color);
- display: flex;
- align-items: center;
- gap: 14px;
- z-index: 10;
- }
- .chat-input {
- flex: 1;
- padding: 14px 20px;
- border: 1px solid var(--border-color);
- border-radius: 30px;
- font-size: 1rem;
- outline: none;
- transition: all 0.3s;
- background: var(--bg-light);
- }
- .chat-input:focus {
- border-color: var(--primary-color);
- box-shadow: 0 0 0 2px rgba(99, 102, 241, 0.2);
- }
- .send-button {
- width: 50px;
- height: 50px;
- border: none;
- background: var(--primary-color);
- color: var(--text-light);
- border-radius: 50%;
- cursor: pointer;
- transition: all 0.3s;
- display: flex;
- justify-content: center;
- align-items: center;
- box-shadow: 0 2px 10px rgba(99, 102, 241, 0.3);
- }
- .send-button:hover {
- background: var(--primary-dark);
- transform: translateY(-2px);
- box-shadow: 0 4px 12px rgba(99, 102, 241, 0.4);
- }
- .send-button:active {
- transform: translateY(0);
- }
- .send-button i {
- font-size: 1.2rem;
- }
- /* 滚动条样式 */
- .chat-messages::-webkit-scrollbar {
- width: 6px;
- }
- .chat-messages::-webkit-scrollbar-track {
- background: transparent;
- }
- .chat-messages::-webkit-scrollbar-thumb {
- background: #d1d5db;
- border-radius: 10px;
- }
- .chat-messages::-webkit-scrollbar-thumb:hover {
- background: #9ca3af;
- }
- /* 打字机效果 */
- .typing {
- display: flex;
- align-items: center;
- gap: 4px;
- padding: 8px 12px;
- border-radius: 18px;
- background: var(--message-bot);
- width: fit-content;
- }
- .typing-dot {
- width: 8px;
- height: 8px;
- background: var(--primary-color);
- border-radius: 50%;
- animation: typing-animation 1.4s infinite both;
- }
- .typing-dot:nth-child(2) {
- animation-delay: 0.2s;
- }
- .typing-dot:nth-child(3) {
- animation-delay: 0.4s;
- }
- @keyframes typing-animation {
- 0%, 100% {
- opacity: 0.3;
- transform: scale(0.8);
- }
- 50% {
- opacity: 1;
- transform: scale(1);
- }
- }
- /* 消息进入动画 */
- @keyframes message-in {
- from {
- opacity: 0;
- transform: translateY(20px);
- }
- to {
- opacity: 1;
- transform: translateY(0);
- }
- }
- .message-container {
- animation: message-in 0.3s ease-out forwards;
- }
- /* 响应式调整 */
- @media (max-width: 768px) {
- .chat-container {
- height: 90vh;
- border-radius: 12px;
- }
- .message-container {
- max-width: 90%;
- }
- .chat-header h1 {
- font-size: 1.1rem;
- }
- }
- @media (max-width: 480px) {
- .chat-container {
- height: 92vh;
- border-radius: 8px;
- }
- .message {
- padding: 12px 16px;
- }
- .avatar {
- width: 32px;
- height: 32px;
- font-size: 1rem;
- }
- .chat-input {
- padding: 12px 16px;
- }
- .send-button {
- width: 45px;
- height: 45px;
- }
- .chat-header {
- padding: 14px 20px;
- }
- .chat-messages {
- padding: 20px;
- }
- }
- </style>
- </head>
- <body>
- <div class="chat-container">
- <div class="chat-header">
- <i class="fas fa-robot"></i>
- <h1>AI聊天助手</h1>
- </div>
- <div class="chat-messages" id="chat-messages">
- <div class="message-container bot-container">
- <div class="avatar bot-avatar">
- <i class="fas fa-robot"></i>
- </div>
- <div class="message-content">
- <div class="message bot-message">
- 您好!我是AI助手,很高兴为您服务。请问有什么我可以帮助您的吗?
- </div>
- <div class="message-time">
- 刚刚
- </div>
- </div>
- </div>
- </div>
- <div class="chat-input-container">
- <input type="text" class="chat-input" id="user-input" placeholder="输入您的问题..." autofocus>
- <button class="send-button" id="send-button">
- <i class="fas fa-paper-plane"></i>
- </button>
- </div>
- </div>
- <script>
- document.addEventListener('DOMContentLoaded', function() {
- const chatMessages = document.getElementById('chat-messages');
- const userInput = document.getElementById('user-input');
- const sendButton = document.getElementById('send-button');
- let eventSource = null;
- // 获取当前时间
- function getCurrentTime() {
- const now = new Date();
- let hours = now.getHours();
- let minutes = now.getMinutes();
- // 确保分钟为两位数
- minutes = minutes < 10 ? '0' + minutes : minutes;
- return `${hours}:${minutes}`;
- }
- // 添加用户消息
- function addUserMessage(message, time) {
- const messageContainer = document.createElement('div');
- messageContainer.className = 'message-container user-container';
- const avatarDiv = document.createElement('div');
- avatarDiv.className = 'avatar user-avatar';
- avatarDiv.innerHTML = '<i class="fas fa-user"></i>';
- const messageContentDiv = document.createElement('div');
- messageContentDiv.className = 'message-content';
- const messageDiv = document.createElement('div');
- messageDiv.className = 'message user-message';
- messageDiv.textContent = message;
- const timeDiv = document.createElement('div');
- timeDiv.className = 'message-time';
- timeDiv.textContent = time;
- messageContentDiv.appendChild(messageDiv);
- messageContentDiv.appendChild(timeDiv);
- messageContainer.appendChild(avatarDiv);
- messageContainer.appendChild(messageContentDiv);
- chatMessages.appendChild(messageContainer);
- chatMessages.scrollTop = chatMessages.scrollHeight;
- }
- // 发送消息函数
- function sendMessage() {
- const message = userInput.value.trim();
- if (!message) return;
- // 添加用户消息到聊天区域
- const time = getCurrentTime();
- addUserMessage(message, time);
- // 清空输入框
- userInput.value = '';
- // 添加机器人正在输入的指示
- const typingContainer = document.createElement('div');
- typingContainer.className = 'message-container bot-container';
- typingContainer.id = 'bot-typing';
- const avatarDiv = document.createElement('div');
- avatarDiv.className = 'avatar bot-avatar';
- avatarDiv.innerHTML = '<i class="fas fa-robot"></i>';
- const typingDiv = document.createElement('div');
- typingDiv.className = 'typing';
- typingDiv.innerHTML = '<span class="typing-dot"></span><span class="typing-dot"></span><span class="typing-dot"></span>';
- typingContainer.appendChild(avatarDiv);
- typingContainer.appendChild(typingDiv);
- chatMessages.appendChild(typingContainer);
- chatMessages.scrollTop = chatMessages.scrollHeight;
- // 更改按钮为暂停
- sendButton.innerHTML = '<i class="fas fa-pause"></i>';
- sendButton.onclick = stopStream;
- // 创建EventSource连接
- const url = `http://127.0.0.1:8080/chatStream?question=${encodeURIComponent(message)}`;
- eventSource = new EventSource(url);
- let botResponse = '';
- let responseContainer = null;
- eventSource.onmessage = function(event) {
- // 如果这是第一条消息,创建回复容器
- if (!responseContainer) {
- // 移除打字指示器
- const typingIndicator = document.getElementById('bot-typing');
- if (typingIndicator) {
- typingIndicator.remove();
- }
- // 创建回复容器
- responseContainer = document.createElement('div');
- responseContainer.className = 'message-container bot-container';
- responseContainer.id = 'current-bot-response';
- const avatarDiv = document.createElement('div');
- avatarDiv.className = 'avatar bot-avatar';
- avatarDiv.innerHTML = '<i class="fas fa-robot"></i>';
- const messageContentDiv = document.createElement('div');
- messageContentDiv.className = 'message-content';
- const messageDiv = document.createElement('div');
- messageDiv.className = 'message bot-message';
- messageDiv.id = 'current-bot-message';
- const timeDiv = document.createElement('div');
- timeDiv.className = 'message-time';
- timeDiv.textContent = getCurrentTime();
- messageContentDiv.appendChild(messageDiv);
- messageContentDiv.appendChild(timeDiv);
- responseContainer.appendChild(avatarDiv);
- responseContainer.appendChild(messageContentDiv);
- chatMessages.appendChild(responseContainer);
- }
- // 更新回复内容
- botResponse += event.data;
- const messageDiv = document.getElementById('current-bot-message');
- if (messageDiv) {
- messageDiv.textContent = botResponse;
- }
- // 自动滚动到底部
- chatMessages.scrollTop = chatMessages.scrollHeight;
- };
- eventSource.onerror = function() {
- // 处理完成或错误时
- completeResponse();
- };
- }
- // 停止流式响应
- function stopStream() {
- if (eventSource) {
- eventSource.close();
- completeResponse();
- }
- }
- // 完成响应处理
- function completeResponse() {
- // 关闭连接
- if (eventSource) {
- eventSource.close();
- eventSource = null;
- }
- // 移除打字指示器
- const typingIndicator = document.getElementById('bot-typing');
- if (typingIndicator) {
- typingIndicator.remove();
- }
- // 恢复发送按钮
- sendButton.innerHTML = '<i class="fas fa-paper-plane"></i>';
- sendButton.onclick = sendMessage;
- // 移除id,以便下次使用
- const currentBotResponse = document.getElementById('current-bot-response');
- if (currentBotResponse) {
- currentBotResponse.removeAttribute('id');
- }
- const currentBotMessage = document.getElementById('current-bot-message');
- if (currentBotMessage) {
- currentBotMessage.removeAttribute('id');
- }
- }
- // 设置事件监听器
- sendButton.addEventListener('click', sendMessage);
- userInput.addEventListener('keydown', function(e) {
- if (e.key === 'Enter') {
- sendMessage();
- }
- });
- // 自动聚焦到输入框
- userInput.focus();
- });
- </script>
- </body>
- </html>
复制代码
7. 多轮对话
只必要简朴修改,即可携带汗青上下文举行对话:
- private List<ChatMessage> history = new ArrayList<>(); // 1. 创建历史消息列表
- @GetMapping("/chatStream")
- public SseEmitter getChatMessageStream(@RequestParam String question) {
- // ......
- history.add(ChatMessage.withUser(question)); // 2. 向历史中添加用户输入
- // 创建请求参数
- ChatCompletion chatCompletion = ChatCompletion.builder()
- .model("deepseek-chat")
- .messages(history) // 3. 添加完整历史消息
- .build();
- // ......
- Executors.newSingleThreadExecutor().submit(() -> {
- try {
- // ......
- emitter.onCompletion(() -> {
- System.out.println("完成");
- history.add(ChatMessage.withAssistant(sseListener.getOutput().toString())); // 4. 向历史中添加AI回复
- sseListener.getEventSource().cancel();
- });
- // ......
- } catch (Exception e) {
- emitter.completeWithError(e);
- }
- });
- // ......
- }
复制代码
8. 联网对话
- 设置application.yml中的searxng,将此中的url更换为你已经摆设的searxng服务的地点。
- ai:
- websearch:
- searxng:
- url: "http://127.0.0.1:29080/search"
- nums: 10
复制代码- @GetMapping("/chatStream")
- public SseEmitter getChatMessageStream(@RequestParam String question) {
- // ......
- // 获取DEEPSEEK的聊天服务
- IChatService chatService = aiService.webSearchEnhance(aiService.getChatService(PlatformType.DEEPSEEK)); // 1. 使用webSearchEnhance对原本chat服务增加联网功能,该联网服务使用的为searxng
- // ......
- // ......
- }
复制代码
9. 搭建知识库
本文使用的向量数据库为Pinecone
9.1 创建Pinecone
各人可以进入Pinecone官网举行注册和登录,至于注册账号,这里不在演示,信赖各人都会。
选择Database->Indexes->Create Index来创建索引
在这里可以输入你的维度,或者点击Setup by model,根据模子来选择向量维度。这里我以text-embedding-3-large模子为例子
创建完成后,记载自己的Host,我们后面要用到
创建自己的API Key
9.2 设置application.yml
请将上文得到的Host和API Key填入application.yml中
- ai:
- vector:
- pinecone:
- host: "https://XXXXXXX-XXXXXXXXX.io"
- key: "XXXXXX"
复制代码 9.3 构建RAG知识库文档
既然要创建RAG应用,那肯定少不了知识库。
本文搭建的是一个简朴的法律AI助手,以是我们必要一个法律知识库。
接下来我以刑法知识库为例为各人讲解
可以将所必要的知识库,存入一个文本文档当中:
注意:如果有现成的文档,你也可以忽略这一步,比方你已经有了txt、word、pdf等文件的知识库文档。
9.4 存储至Pinecone向量数据库中
- @SpringBootTest
- public class RagTest {
- // 1. 注入Pinecone服务
- @Autowired
- private PineconeService pineconeService;
- // 2. 注入AI服务
- @Autowired
- private AiService aiService;
- @Test
- public void test_rag_store() throws Exception {
- // 3. 获取Embedding服务
- IEmbeddingService embeddingService = aiService.getEmbeddingService(PlatformType.OPENAI);
- // 4. Tika读取file文件内容
- String fileContent = TikaUtil.parseFile(new File("D:\\data\\test.txt"));
- System.out.println(fileContent);
- // 5. 分割文本内容
- RecursiveCharacterTextSplitter recursiveCharacterTextSplitter = new RecursiveCharacterTextSplitter(1000, 200);
- List<String> contentList = recursiveCharacterTextSplitter.splitText(fileContent);
- System.out.println(contentList.size());
- // 6. 转为向量
- Embedding build = Embedding.builder()
- .input(contentList)
- .model("text-embedding-3-large")
- .build();
- EmbeddingResponse embedding = embeddingService.embedding(build);
- List<List<Float>> vectors = embedding.getData().stream().map(EmbeddingObject::getEmbedding).collect(Collectors.toList());
- VertorDataEntity vertorDataEntity = new VertorDataEntity();
- vertorDataEntity.setVector(vectors);
- vertorDataEntity.setContent(contentList);
- System.out.println(vertorDataEntity);
- // 7. 向量存储至pinecone
- Integer count = pineconeService.insert(vertorDataEntity, "abc-123-abc");
- System.out.println(count > 0 ? "存储成功" : "存储失败");
- }
- }
复制代码 下图是插入成功的数据

9.5 知识库查询
下面代码只多了对embedding的处理,chat部门基本稳定。
- @Autowired
- private AiService aiService;
- @Autowired
- private PineconeService pineconeService;
- private List<ChatMessage> history = new ArrayList<>();
- @GetMapping("/chatStream")
- public SseEmitter getChatMessageStream(@RequestParam String question) throws Exception {
- SseEmitter emitter = new SseEmitter(-1L);
- // 获取Embedding服务
- IEmbeddingService embeddingService = aiService.getEmbeddingService(PlatformType.OPENAI);
- // 构建要查询的问题,转为向量
- Embedding build = Embedding.builder()
- .input(question)
- .model("text-embedding-3-large")
- .build();
- EmbeddingResponse embedding = embeddingService.embedding(build);
- List<Float> questionEmbedding = embedding.getData().get(0).getEmbedding();
- // 构建向量数据库的查询对象
- PineconeQuery pineconeQueryReq = PineconeQuery.builder()
- .namespace("abc-123-abc")
- .topK(5)
- .vector(questionEmbedding)
- .build();
- // 查询
- // PineconeQueryResponse queryResponse = pineconeService.query(pineconeQueryReq);
- // delimiter为想用什么字符拼接查询出来的内容
- String retrievalContent = pineconeService.query(pineconeQueryReq, " ");
- String contentFormat = "你是一个善于回答中华人民共和国刑法相关问题的助手。请使用以下提供的检索内容和自身知识来回答问题。如果你不知道答案,请直接说不知道,不要杜撰答案。请用三句话以内回答,保持简洁。\n" +
- "\n" +
- "问题:%s\n" +
- "\n" +
- "检索内容:%s";
- String content = String.format(contentFormat, question, retrievalContent);
- // 获取DEEPSEEK的聊天服务
- IChatService chatService = aiService.getChatService(PlatformType.DEEPSEEK);
- history.add(ChatMessage.withUser(content)); // 向历史中添加用户输入
- // 创建请求参数
- ChatCompletion chatCompletion = ChatCompletion.builder()
- .model("deepseek-chat")
- .messages(history) // 添加完整历史消息
- .build();
- Executors.newSingleThreadExecutor().submit(() -> {
- try {
- SseListener sseListener = new SseListener() {
- @Override
- protected void send() {
- try {
- emitter.send(this.getCurrStr());
- System.out.println(this.getCurrData()); // 打印当前发送的内容
- } catch (IOException e) {
- emitter.completeWithError(e);
- }
- }
- };
- emitter.onCompletion(() -> {
- System.out.println("完成");
- history.add(ChatMessage.withAssistant(sseListener.getOutput().toString())); // 向历史中添加AI回复
- sseListener.getEventSource().cancel();
- });
- // 发送流式数据
- chatService.chatCompletionStream(chatCompletion, sseListener);
- // 完成后关闭连接
- emitter.complete();
- } catch (Exception e) {
- emitter.completeWithError(e);
- }
- });
- return emitter;
- }
复制代码
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |