先看效果
项目搭建
Spring AI 是 Spring 推出的一个项目,目标是提供统一的API抽象层,屏蔽不同AI模型和服务的底层差异,实现跨平台兼容性。
演示使用的模型是阿里的 qwq-32b。
环境要求:
JDK :17以上(包括17)
Spring Boot 版本:目前支持 3.4.X,3.5.X 发布后也会同步支持。
主要的 maven 依赖:
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-openai-spring-boot-starter</artifactId>
<version>1.0.0-M6</version>
</dependency>
配置文件:
qwq-32b的接口类似于openai ,所以直接使用 openai 的配置即可,其他类 openai 的模型也是类似。
spring:
ai:
openai:
api-key: #申请的 key
base-url: https://dashscope.aliyuncs.com/compatible-mode #api地址
chat:
options:
model: qwq-32b # 模型名称
编写接口
创建 ChatClient。ChatClient
提供了与 AI 模型通信的 Fluent API,它支持同步和反应式(Reactive)编程模型。
this.chatClient = ChatClient.builder(chatModel)
.defaultSystem(DEFAULT_PROMPT)
.defaultAdvisors(new MessageChatMemoryAdvisor(new InMemoryChatMemory()))
.defaultAdvisors(new SimpleLoggerAdvisor())
.defaultOptions(OpenAiChatOptions.builder().temperature(0.7d).build())
.build();
创建接口,使用 SSE 响应结果,SSE 是一个单向的、从服务端向客户端推送数据的技术。使用SSE可以实时的将大模型的结果推送到前端。
@GetMapping
public SseEmitter chat(String message) {
SseEmitter emitter = new SseEmitter();
// 先把结果返回,后续逐渐响应结果
CompletableFuture.runAsync(() -> {
chatClient.prompt(message).stream()
.content()
.doOnComplete(emitter::complete)
.subscribe(result -> {
try {
emitter.send(result);
} catch (IOException e) {
throw new RuntimeException(e);
}
});
});
return emitter;
}
完整的接口代码如下:
package cn.salim.ai.controller;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.chat.client.advisor.MessageChatMemoryAdvisor;
import org.springframework.ai.chat.client.advisor.SimpleLoggerAdvisor;
import org.springframework.ai.chat.memory.InMemoryChatMemory;
import org.springframework.ai.openai.OpenAiChatModel;
import org.springframework.ai.openai.OpenAiChatOptions;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
import java.io.IOException;
import java.util.concurrent.CompletableFuture;
@RestController
@RequestMapping("ai")
public class AiController {
private static final String DEFAULT_PROMPT = "你是一个资深Java程序员,你熟悉各种JAVA框架,包括SpringBoot、Mybatis等等";
private final ChatClient chatClient;
public AiController(OpenAiChatModel chatModel) {
this.chatClient = ChatClient.builder(chatModel)
.defaultSystem(DEFAULT_PROMPT)
.defaultAdvisors(new MessageChatMemoryAdvisor(new InMemoryChatMemory()))
.defaultAdvisors(new SimpleLoggerAdvisor())
.defaultOptions(OpenAiChatOptions.builder().temperature(0.7d).build())
.build();
}
@GetMapping
public SseEmitter chat(String message) {
SseEmitter emitter = new SseEmitter();
CompletableFuture.runAsync(() -> {
chatClient.prompt(message).stream()
.content()
.doOnComplete(emitter::complete)
.subscribe(result -> {
try {
emitter.send(result);
} catch (IOException e) {
throw new RuntimeException(e);
}
});
});
return emitter;
}
}