SpringAI框架接入Deepseek和豆包实现智能聊天
一、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.comembedding:enabled: falsechat:options:temperature: 0.8model: 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;@Autowiredpublic 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);@Autowiredprivate 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);@Autowiredprivate AIChatDouBao aiChatDouBao; @GetMapping("/event-stream")public SseEmitter streamEvents(HttpServletRequest req, @RequestParam String question) {return aiChatDouBao.conversation(question);} }