十分钟搞定SpringAI+DeepSeek
之前通过Okhttp实现过对大模型的调用,感觉流程比较繁琐,现在一起来学习下如何通过Spring Ai的方式来实现,非常简单,只需要一个类就可以实现。
下面以调用DeepSeek模型为例!
先看效果,然后拆解步骤~
发起问答:

日志打印:

代码实现
PS:代码相关解释都放在代码段注释里~
1. 环境
JDK 17
SpringBoot 3.x.x 以上
SpringAI 版本 1.0.0-M6
2. 配置
引入SpringAI依赖
<dependencies>
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-openai-spring-boot-starter</artifactId>
<version>1.0.0-M6</version>
</dependency>
</dependencies>
<!-- 如果下载不了 再引入下面的配置 -->
<repositories>
<repository>
<id>spring-milestones</id>
<name>Spring Milestones</name>
<url>https://repo.spring.io/milestone</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
</repositories>
springboot配置
server:
port: 9093
spring:
application:
name: mdx-ai
# spring ai
ai:
openai:
base-url: https://api.deepseek.com # deepseek base-url
api-key: your-aip-key # 你的 deepseek api-key
chat:
options:
model: deepseek-chat # 模型选择 deepseek-chat为通用模型
temperature: 0.7 # 温度 介于 0 和 2 之间 值越高输出越随机
3. 实现
package com.mdx.mdxai.controller;
import com.mdx.mdxai.dto.ChatRequestDto;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.chat.messages.Message;
import org.springframework.ai.chat.messages.UserMessage;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import reactor.core.publisher.Flux;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
/**
* @author : jiagang
* @date : Created in 2025/10/30 18:42
*/
@RestController
@RequestMapping("/chat")
public class AiChatController {
private static final Logger logger = LoggerFactory.getLogger(AiChatController.class);
private final ChatClient chatClient;
private final List<Message> conversationHistory = new CopyOnWriteArrayList<>();
public AiChatController(ChatClient.Builder chatClientBuilder) {
this.chatClient = chatClientBuilder
.defaultSystem("你是一个有用的AI助手")
.build();
}
@PostMapping(value = "/stream", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
public Flux<String> streamMessage(@RequestBody ChatRequestDto request) {
logger.info("【AI助手】开始流式对话: {}", request.getMessage());
return Flux.create(sink -> {
try {
UserMessage userMessage = new UserMessage(request.getMessage());
// 上下文信息
conversationHistory.add(userMessage);
// 使用Spring AI的流式API
Flux<String> contentStream = chatClient.prompt()
// 将上下文给到模型
.messages(conversationHistory)
.stream()
.content();
// 订阅流式内容并转发给前端
contentStream
// 接收模型的流式响应
.doOnNext(content -> {
logger.info("【AI助手】流式内容片段: {}", content);
// 发送SSE格式的数据
sink.next("data: " + content + "\n\n");
})
// 接收模型的流式完成响应
.doOnComplete(() -> {
logger.info("【AI助手】流式对话完成");
sink.next("data: [DONE]\n\n");
sink.complete();
})
// 接收模型的流式异常响应
.doOnError(error -> {
logger.error("【AI助手】流式对话错误: {}", error.getMessage());
sink.error(error);
})
// 订阅模型的sse流
.subscribe();
} catch (Exception e) {
logger.error("【AI助手】流式对话启动失败: {}", e.getMessage());
sink.error(e);
}
});
}
// 清空对话历史
@DeleteMapping("/history/clear")
public ResponseEntity<String> clearHistory() {
conversationHistory.clear();
return ResponseEntity.ok("对话历史已清空");
}
private String getFullResponseFromStream() {
// 这里需要实现从流中收集完整响应的方法
// 实际实现可能需要更复杂的逻辑来收集流数据
return "";
}
}
这就结束了,这你受得了吗,从搭建项目到接收问答20分钟就能搞定。
当然,你可能还需要了解一些其他知识,比如Flux这玩意是啥?
答:
它属于 Spring WebFlux中的知识,也就是响应式编程,是和传统的Spring Mvc的方式做对比的,一般和Flux一起出现的还有Mono。
Mono:只包含0个或者1个元素,一般用于查询单个数据,比如我们之前的单个对象。
Flux:包含0个或者N个元素,一般用于返回多个数据,比如我们之前的集合,它支持异步处理,比如说处理消息流或者是本次的SSE事件。
其实对于概念我也比较懵,总结一段话就是:
对于WebFlux这种响应式编程,不会像传统mvc模式下一个请求占用一个线程,如果线程池耗尽那新的请求就要阻塞, 而对于WebFlux这种框架它一个线程就可以处理多个请求,比如某一个线程在处理一个io的耗时操作,传统框架这个线程就会阻塞等待,而阻塞就会操作系统内核,并且导致cpu时间片和上下文切换,非常消耗性能; 而WebFlux在遇到io操作时,线程不会阻塞,它会注册一个回调函数然后去处理其他任务,当上一个io完成之后底层系统会通知这个线程继续处理。
友情链接:
deepseek开放平台: https://platform.deepseek.com/usage
更多推荐


所有评论(0)