一、SpringAI框架调用deepseek实现聊天功能

1.创建一个Springboot项目

注意:开发版本必须要JDK17以上(包含JDK17)

在进行创建springboot项目时,添加Spring Web和OpenAI两个依赖,不要添加lombok依赖,创建完项目后自己在maven中添加lombok的依赖,这是一个小小的bug,Springboot版本为3.2.x或者更高版本

手动添加下面代码到pom.xml文件中

    <repositories>
        <repository>
            <id>spring-milestones</id>
            <name>Spring Milestones</name>
            <url>https://repo.spring.io/milestone</url>
            <snapshots>
                <enabled>false</enabled>
            </snapshots>
        </repository>
        <repository>
            <id>spring-snapshots</id>
            <name>Spring Snapshots</name>
            <url>https://repo.spring.io/snapshot</url>
            <releases>
                <enabled>false</enabled>
            </releases>
        </repository>
    </repositories>

   因为 DeepSeek API 使用与 OpenAI 兼容的 API 格式,通过修改配置,我们可以使用 OpenAI SDK 来访问 DeepSeek API。所以下一步我们只需在 application.yml 中将对应的秘钥和 URL 替换为 DeepSeek 的即可。

application.yml 文件:

spring:
  ai:
    openai:
      api-key: ${DEEPSEEK_API_KEY}
      base-url: https://api.deepseek.com
      embedding:
        enabled: false
      chat:
        options:
          temperature: 0.8
          model: deepseek-chat
    这里将嵌入功能禁用,因为 DeepSeek 的 API 暂不支持此功能,虽然其提供了类似于 Open AI 类似的接口,但未实现此功能。而 Spring AI 的模块化设计会自动初始化 Open AI 的相关模块(包括嵌入模块),所以如果不禁用会报错(404  Not Found)未找到模块。

temperature:采样温度,控制 AI 输出内容的创造性,值越高越具有随机性;越低则结果越集中和确定。

model:要使用的模型名。

ChatResponse response = chatModel.call(
    new Prompt(
        message,
        OpenAiChatOptions.builder()
            .model("deepseek-chat")
            .temperature(0.4)
        .build()
    ));

当然,也可以在运行时指定对应的模型和采样温度。其中的 Prompt 是封装用户输入请求的对象,由两部分组成:

组成部分 说明
用户输入的消息内容 要发送给 AI 模型的文本(例如 "你好!你是谁?"
模型配置选项 通过 OpenAiChatOptions 定义的参数(如模型名称、温度值等)

2.测试 Spring AI 聊天模型

@RestController
public class ChatController {
 
    private final OpenAiChatModel chatModel;
 
    @Autowired
    public ChatController(OpenAiChatModel chatModel) {
        this.chatModel = chatModel;
    }
 
    @GetMapping("/ai/generate")
    public Map generate(@RequestParam(value = "message", defaultValue = "Tell me a joke") String message) {
        return Map.of("generation", this.chatModel.call(message));
    }
 
    @GetMapping("/ai/generateStream")
    public Flux<ChatResponse> generateStream(@RequestParam(value = "message", defaultValue = "Tell me a joke") String message) {
        Prompt prompt = new Prompt(new UserMessage(message));
        return this.chatModel.stream(prompt);
    }
}
同步生成接口:

流式生成接口

可以看到返回的结果是一段一段的,这就是流式响应。但这样的观赏性很差,所以我们可以将结果处理后再返回,这样就可以大大提高结果的观赏性。

 @GetMapping(value = "/ai/generateStream", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
 public Flux<String> generateStream(@RequestParam(value = "message", defaultValue = "Tell me a joke") String message) {
     return chatModel.stream(new Prompt(message))
             .map(chatResponse -> chatResponse.getResult().getOutput().getText());
 }

produces = MediaType.TEXT_EVENT_STREAM_VALUE:这个注解指定了响应的媒体类型为 text/event-stream,这是用于服务器推送事件(SSE)的标准媒体类型,适合流式输出。

二、SpringAI框架调用豆包实现聊天功能

1.引入maven依赖

     <dependency>
            <groupId>com.volcengine</groupId>
            <artifactId>volcengine-java-sdk-ark-runtime</artifactId>
            <version>LATEST</version>
        </dependency>

2.配置类

package com.hpp.common.AIChat;
​
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
​
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
​
import com.google.gson.Gson;
import com.hpp.common.redisson.RedisCache;
import com.volcengine.ark.runtime.model.completion.chat.ChatCompletionRequest;
import com.volcengine.ark.runtime.model.completion.chat.ChatMessage;
import com.volcengine.ark.runtime.model.completion.chat.ChatMessageRole;
import com.volcengine.ark.runtime.service.ArkService;
​
@Component
public class AIChatDouBao {
    private static final Logger LOGGER = LoggerFactory.getLogger(AIChatDouBao.class);
    @Autowired
    private RedisCache redisCache;
    private Gson gson = new Gson();
    private String apiKey = "xxxxxxxxxxxxxxxx";
    
    public SseEmitter conversation(String question) {
        // 创建ArkService实例
        ArkService arkService = ArkService.builder().apiKey(apiKey).build();
        // 初始化消息列表
        List<ChatMessage> chatMessages = new ArrayList<>();
        // 创建用户消息
        ChatMessage userMessage = ChatMessage.builder().role(ChatMessageRole.USER) // 设置消息角色为用户
                .content(question) // 设置消息内容
                .build();
        // 将用户消息添加到消息列表
        chatMessages.add(userMessage);
        // 创建聊天完成请求
        ChatCompletionRequest chatCompletionRequest = ChatCompletionRequest.builder().model("ep-xxxxxxxxxxxx")// 需要替换为您的推理接入点ID
                .messages(chatMessages) // 设置消息列表
                .build();
        // 发送聊天完成请求并打印响应
        // 获取响应并打印每个选择的消息内容
        SseEmitter emitter = new SseEmitter();
        try {
            new Thread(() -> {
                arkService.streamChatCompletion(chatCompletionRequest).doOnError(Throwable::printStackTrace)
                        .doFinally(() -> {
                            LOGGER.info("完成");
                            emitter.complete();
                        }).blockingForEach(choice -> {
                            if (choice.getChoices().size() > 0) {
                                ChatMessage message = choice.getChoices().get(0).getMessage();
                                // 判断是否触发深度推理,触发则打印模型输出的思维链内容
                                if (message.getReasoningContent() != null && !message.getReasoningContent().isEmpty()) {
                                    LOGGER.info(message.getReasoningContent());
                                    emitter.send(message.getReasoningContent());
                                }
                                // 打印模型输出的回答内容
                                emitter.send(message.getContent().toString());
                                LOGGER.info(message.getContent().toString());
                            }
                        });
​
            }).start();
        } catch (Exception e) {
            LOGGER.error("ai回复异常", e);
            emitter.completeWithError(e); // 发生错误时,通知客户端
        } finally {
​
        }
        return emitter;
    }
​
    public String getAccessToken() throws IOException {
        return "";
    }
​
}
​

3.controller层

@RestController
@RequestMapping(value = "chat")
public class ChatController {
    private static final Logger LOGGER = LoggerFactory.getLogger(ChatController.class);
    @Autowired
    private AIChatDouBao aiChatDouBao;
​
    @GetMapping("/event-stream")
    public SseEmitter streamEvents(HttpServletRequest req, @RequestParam String question) {
        return aiChatDouBao.conversation(question);
    }
​
}

Logo

助力广东及东莞地区开发者,代码托管、在线学习与竞赛、技术交流与分享、资源共享、职业发展,成为松山湖开发者首选的工作与学习平台

更多推荐