Java快速接入DeepSeek实现流式、联网、知识库以及多轮问答

Java快速接入DeepSeek实现流式、联网、知识库以及多轮问答

本文将详细的说明,如何使用Java、JDK8快速接入deepseek的聊天服务,包含官方的API服务,以及本地Ollama的服务。并搭建一个简单的前端界面,用于流式输出、多轮问答、联网、知识库问答的效果展示。

1. 创建spring boot应用

20240911230410
20240911230511

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;
    }

测试流式接口如下:

20250306183122

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;
    }

修改两处即可:

  • 修改PlatformTypeOLLAMA
  • 修改modeldeepseek-r1:1.5b

20250306212003

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>

20250307003331

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);
            }
        });



        // ......
    }

20250307004433

8. 联网对话

  1. 配置application.yml中的searxng,将其中的url替换为你已经部署的searxng服务的地址。
ai:
  websearch:
    searxng:
      url: "http://127.0.0.1:29080/search"
      nums: 10
  1. 修改代码,添加联网对话的功能:
    @GetMapping("/chatStream")
    public SseEmitter getChatMessageStream(@RequestParam String question) {
    
    
        // ......

        // 获取DEEPSEEK的聊天服务
        IChatService chatService = aiService.webSearchEnhance(aiService.getChatService(PlatformType.DEEPSEEK)); // 1. 使用webSearchEnhance对原本chat服务增加联网功能,该联网服务使用的为searxng

        // ......
        // ......

    }


20250307010039

9. 搭建知识库

本文使用的向量数据库为Pinecone

9.1 创建Pinecone

大家可以进入Pinecone官网进行注册和登录,至于注册账号,这里不在演示,相信大家都会。

选择Database->Indexes->Create Index来创建索引
20240926160552

在这里可以输入你的维度,或者点击Setup by model,根据模型来选择向量维度。这里我以text-embedding-3-large模型为例子
20240926160742
20240926160633

创建完成后,记录自己的Host,我们后面要用到
20240926163211

创建自己的API Key
20240926163332

9.2 配置application.yml

请将上文得到的HostAPI Key填入application.yml

ai:
  vector:
    pinecone:
      host: "https://XXXXXXX-XXXXXXXXX.io"
      key: "XXXXXX"

9.3 构建RAG知识库文档

既然要建立RAG应用,那肯定少不了知识库。

本文搭建的是一个简单的法律AI助手,所以我们需要一个法律知识库。

接下来我以刑法知识库为例为大家讲解

可以将所需要的知识库,存入一个文本文档当中:
20240926180216

注意:如果有现成的文档,你也可以忽略这一步,例如你已经有了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 ? "存储成功" : "存储失败");
    }

}

下图是插入成功的数据
20240926175841

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;
    }

20250307012623

猜你喜欢

转载自blog.csdn.net/qq_35650513/article/details/146084038
今日推荐