Spring AI 作为统一的大模型接入框架,其Model API为开发者提供了多模型适配能力。无论是OpenAI、DeepSeek、Moonshot AI(月之暗面)、Perplexity AI、Google VertexAI Gemini 等若干主流云服务商模型,还是支持Ollama私有化部署的本地模型,均可通过标准化接口实现无缝集成。
本文将介绍基于Spring AI框架,分别调用云端DeepSeek API的完整对话实现方式,话不多说,搞起来。
引入依赖
第一步,先引入依赖:Springboot 3.4.5 、 Spring AI 1.0.0-M7 。因为deepseek支持open ai的标准接口,所以这里引入 open ai的依赖即可。
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.4.5</version>
<relativePath/>
</parent>
<groupId>site.qxkd</groupId>
<artifactId>chat-client</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>chat-client</name>
<description>chat-client</description>
<properties>
<java.version>17</java.version>
<spring-ai.version>1.0.0-M7</spring-ai.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-starter-model-openai</artifactId>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-bom</artifactId>
<version>${spring-ai.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
配置文件
这只是列举一些简单配置文件,实际上配置还是挺多的,感兴趣可以去官网看一下
spring.application.name=chat-client
# 大模型相关依赖
spring.ai.openai.base-url=https://api.siliconflow.cn
spring.ai.openai.api-key=sk-你的秘钥
#spring.ai.openai.chat.options.model=deepseek-ai/DeepSeek-V3
spring.ai.openai.chat.options.model=deepseek-ai/DeepSeek-R1
测试
上面一切准备好之后,写两个接口测试一下,一个是一次性输出结果的接口,一个是流式输出的接口。
RestController
@RequestMapping("/deepseek")
public class DeepseekController {
@Autowired
private OpenAiChatModel chatModel;
@GetMapping("/ai/generate")
public Map<String , String> generate(@RequestParam(value = "message") String message) {
String content = chatModel.call(message);
return Map.of("generation", content);
}
/**
* 生成流式结果
* @param message
* @return
*/
@GetMapping("/ai/generateStream")
public Flux<ChatResponse> generateStream(@RequestParam(value = "message") String message) {
Prompt prompt = new Prompt(new UserMessage(message));
return this.chatModel.stream(prompt);
}
}
先测试一次性输出结果的接口,浏览器访问http://localhost:8080/deepseek/ai/generate?message=你是谁 ,会输出如下结果:
下面再来测试一下流式输出到接口,为了实现流式输出的效果,我让deepseek给我写了一个网页,简单修改了一下,达到了如下图中的效果。
流式输出返回的一段JSON是这样的。
{
"result": {
"metadata": {
"finishReason": "",
"contentFilters": [],
"empty": true
},
"output": {
"messageType": "ASSISTANT",
"metadata": {
"refusal": "",
"finishReason": "",
"index": 0,
"id": "019684b265266dbe29ab56f75eaa75cd",
"role": "ASSISTANT",
"messageType": "ASSISTANT"
},
"toolCalls": [],
"media": [],
"text": "DeepSeek)公司开发的智能助手"
}
},
"metadata": {
"id": "019684b265266dbe29ab56f75eaa75cd",
"model": "deepseek-ai/DeepSeek-R1",
"rateLimit": {
"requestsRemaining": 0,
"requestsLimit": 0,
"tokensRemaining": 0,
"tokensReset": "PT0S",
"requestsReset": "PT0S",
"tokensLimit": 0
},
"usage": {
"promptTokens": 6,
"completionTokens": 64,
"totalTokens": 70,
"nativeUsage": {
"completion_tokens": 64,
"prompt_tokens": 6,
"total_tokens": 70,
"completion_tokens_details": {
"reasoning_tokens": 38
}
}
},
"promptMetadata": [],
"empty": false
},
"results": [{
"metadata": {
"finishReason": "",
"contentFilters": [],
"empty": true
},
"output": {
"messageType": "ASSISTANT",
"metadata": {
"refusal": "",
"finishReason": "",
"index": 0,
"id": "019684b265266dbe29ab56f75eaa75cd",
"role": "ASSISTANT",
"messageType": "ASSISTANT"
},
"toolCalls": [],
"media": [],
"text": "DeepSeek)公司开发的智能助手"
}
}]
}
至此,一个简单的Spring AI对话就完成了。细心的同学可能会发现,这也就只能单轮对话,没什么用呀,要连续对话才行。别急,下面就演示一下连续对话的demo。
连续对话
想要连续对话需要3个相关接口和API:
-
ChatMemory : 大模型(LLM)是无状态的,这意味着它们不会保留有关以前交互的信息。在多个交互中维护上下文或状态时,这就变成了一种限制。为了解决这个问题,Spring AI 提供了一个存储和检索与大模型多次对话信息的接口
ChatMemory。 -
ChatClient :
ChatClient提供了一个流式API(fluent API),用于与AI模型进行通信,它同时支持同步和流式两种编程模型。该流式API提供了一系列方法,用于逐步构建**提示词(Prompt)**的各个组成部分,这些提示词将作为输入传递给AI模型。 -
Advisors API:
Advisors API为开发者提供了一种灵活而强大的方式,用于在 Spring 应用程序中拦截、修改和增强 AI 驱动的交互。它的核心优势包括:封装常见的生成式 AI 模式,转换发送给大语言模型(LLMs)的数据及处理其返回结果,以及实现跨不同模型和用例的可移植性。
话不多说,上代码。
- 先注入
ChatClient和ChatMemory对象 本文使用InMemoryChatMemory将对话记录存放在内存中,如果想实现将对话记录存放在数据库可以考虑实现ChatMemory。
@Configuration
public class ChatConfig {
@Bean
public ChatClient chatClient(OpenAiChatModel openAiChatModel) {
ChatClient chatClient = ChatClient.builder(openAiChatModel)
.defaultAdvisors(new MessageChatMemoryAdvisor(chatMemory())) // 设置默认的MemoryAdvisor ,将对话记录存放在内存中
.build();
return chatClient;
}
@Bean
public ChatMemory chatMemory(){
return new InMemoryChatMemory();
}
}
- 测试 测试使用流式输出,调用接口时需要传一个chatId ,这样才能根据chatId到内存中查询相关对话信息。
@Autowired
private ChatClient chatClient;
@GetMapping("/ai/chatContext")
public Flux<ChatResponse> chatContext(@RequestParam(value = "message") String message , String chatId) {
Flux<ChatResponse> chatResponseFlux = chatClient.prompt()
//连续对话的key
.advisors(advisor -> advisor.param(AbstractChatMemoryAdvisor.CHAT_MEMORY_CONVERSATION_ID_KEY, chatId)
.param(AbstractChatMemoryAdvisor.CHAT_MEMORY_RETRIEVE_SIZE_KEY, 100))
.user(message).stream().chatResponse();
return chatResponseFlux;
}
修改一下之前的聊天界面代码进行测试:
至此,Spring AI 使用Deepseek大模型对话的简单示例就完成了,如果使用了Ollama私有化部署了大模型也可以使用上面的流程,或者是引入Ollama的依赖。
下一篇文章将介绍如何利用Spring AI框架使用嵌入模型和向量数据库,敬请关注。