Spring AI 2.0终于来了!以前想在Java里接入大模型,要么手写一堆HTTP调用和JSON解析,要么东拼西凑各种第三方库。现在有了Spring AI,加个Starter、配个Bean、注入ChatClient,三步就能让AI在项目里跑起来。这篇文章就带你从零搭建一个带对话记忆的聊天服务,看看它到底有多香。
Spring AI是Spring生态面向人工智能领域的官方扩展,旨在让Java开发者无需深入机器学习底层,就能像使用Spring MVC、Spring Data一样自然地构建AI应用。
Spring AI的核心功能如下:
call和流式
stream两种调用方式。@Tool注解注册Java方法,让模型调用你的API执行真实操作。第一步,把Spring AI集成到项目中去。
pom.xml中添加Spring AI的依赖管理,用于统一管理Spring AI版本,这里使用的是2.0.0版本;
<
dependencyManagement
<
dependencies
<
dependency
<
groupIdorg.springframework.ai
</
groupId
<
artifactIdspring-ai-bom
</
artifactId
<
version${spring-ai.version}
</
version
<
typepom
</
type
<
scopeimport
</
scope
</
dependency
</
dependencies
</
dependencyManagement
<!-- Spring AI OpenAI Starter -->
<
dependency
<
groupIdorg.springframework.ai
</
groupId
<
artifactIdspring-ai-starter-model-openai
</
artifactId
</
dependency
<!-- SpringBoot WebFlux依赖模块(提供Flux/Mono响应式类型) -->
<
dependency
<
groupIdorg.springframework.boot
</
groupId
<
artifactIdspring-boot-starter-webflux
</
artifactId
</
dependency
application.yaml中添加模型调用相关配置,包含base-url、api-key、chat.model,这里使用的是deepseek-v4-pro模型;
spring:
ai:
openai:
# 通过OpenAI兼容接口访问DeepSeek服务
base-url:
# 对应API_KEY
api-key:
${DEEPSEEK_API_KEY}
chat:
# 要使用的模型ID,支持deepseek-v4-flash、deepseek-v4-pro
model:
deepseek-v4-pro
/**
* Spring AI配置类
*
@author macrozheng
*
@since 2026/6/29
*
@see <a href="https://github.com/macrozheng">GitHub</a>
*/
@Configuration
public
class
SpringAIConfig {
@Bean
public ChatClient
chatClient
(ChatClient.Builder builder) {
return builder.build;
}
}
Spring AI集成完毕,开发一个对话功能来试试效果。
TEXT_EVENT_STREAM_VALUE;
/**
* 对话功能相关接口
*
@author macrozheng
*
@since 2026/6/29
*
@see <a href="https://github.com/macrozheng">GitHub</a>
*/
@RequiredArgsConstructor
@RestController
@RequestMapping(
"/chat")
@Tag(name =
"ChatController",description =
"对话功能相关接口")
public
class
ChatController {
private
final ChatClient chatClient;
@Operation(summary =
"同步调用大模型")
@PostMapping(
"/call")
public String
call
(@RequestParam String question, @RequestParam String conversationId) {
return
this.chatClient.prompt
.user(question)
.call
.content;
}
@Operation(summary =
"流式调用大模型")
@PostMapping(value =
"/stream", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
public Flux<ChatEventDto>
stream
(@RequestParam String question, @RequestParam String conversationId) {
return
this.chatClient.prompt
.user(question)
.stream
.content
// 对于流式输出中的每条消息,转化为ChatEventDto对象
.map(content -> ChatEventDto.builder
.eventType(ChatEventType.DATA.getValue)
.eventData(content)
.build)
// 在流式输出结束后追加一条代表STOP的消息
.concatWith(Flux.just(ChatEventDto.builder
.eventType(ChatEventType.STOP.getValue)
.build));
}
}
/**
* Sse会话事件返回结果
*
@author macrozheng
*
@since 2026/7/1
*
@see <a href="https://github.com/macrozheng">GitHub</a>
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@Schema(title =
"ChatEventDto",description =
"Sse会话事件返回结果")
public
class
ChatEventDto {
@Schema(description =
"事件类型,1001-数据事件,1002-停止事件,1003-参数事件")
private Integer eventType;
@Schema(description =
"消息内容")
private Object eventData;
}
那么如何实现对话记忆功能呢,Spring AI支持多种类型的记忆存储,以适应不同的使用场景,例如内存、JDBC、Neo4j、MongoDB、Redis等。这里就以Redis为例,介绍下如何实现对话记忆功能。
docker run --name redis-stack \
-p 6379:6379 \
-p 8001:8001 \
-d redis/redis-stack:7.4.0-v8
pom.xml中添加Redis对话记忆对应的Starter;
<!-- Spring AI Redis Chat Memory Repository -->
<
dependency
<
groupIdorg.springframework.ai
</
groupId
<
artifactIdspring-ai-starter-model-chat-memory-repository-redis
</
artifactId
</
dependency
application.yaml中添加Redis的连接配置;
spring:
ai:
chat:
memory:
redis:
host:
192.168
.3
.101
port:
6379
time-to-live:
24h
key-prefix:
spring-chat
/**
* Spring AI配置类
*
@author macrozheng
*
@since 2026/6/29
*
@see <a href="https://github.com/macrozheng">GitHub</a>
*/
@Configuration
public
class
SpringAIConfig {
@Value(
"${spring.ai.chat.memory.redis.host}")
private String redisHost;
@Value(
"${spring.ai.chat.memory.redis.port}")
private
int redisPort;
@Bean
public RedisChatMemoryRepository
redisChatMemoryRepository
{
RedisClient redisClient = RedisClient.builder
.hostAndPort(redisHost, redisPort)
.build;
return RedisChatMemoryRepository.builder
.jedisClient(redisClient)
.build;
}
@Bean
public ChatMemory
chatMemory
(RedisChatMemoryRepository repository) {
return MessageWindowChatMemory.builder
.chatMemoryRepository(repository)
.maxMessages(
100)
.build;
}
}
/**
* 对话功能相关接口
*
@author macrozheng
*
@since 2026/6/29
*
@see <a href="https://github.com/macrozheng">GitHub</a>
*/
@RequiredArgsConstructor
@RestController
@RequestMapping(
"/chat")
@Tag(name =
"ChatController",description =
"对话功能相关接口")
public
class
ChatController {
private
final ChatClient chatClient;
private
final ChatMemory chatMemory;
@Operation(summary =
"同步调用大模型")
@PostMapping(
"/call")
public String
call
(@RequestParam String question, @RequestParam String conversationId) {
// 获取历史消息作为上下文
List<Message> historyMessages = chatMemory.get(conversationId);
// 手动保存用户消息
chatMemory.add(conversationId, List.of(
new UserMessage(question)));
// 调用大模型
String response =
this.chatClient.prompt
.messages(historyMessages)
.user(question)
.call
.content;
// 手动保存助手回复
chatMemory.add(conversationId, List.of(
new AssistantMessage(response)));
return response;
}
@Operation(summary =
"流式调用大模型")
@PostMapping(value =
"/stream", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
public Flux<ChatEventDto>
stream
(@RequestParam String question, @RequestParam String conversationId) {
// 获取历史消息作为上下文
List<Message> historyMessages = chatMemory.get(conversationId);
// 手动保存用户消息
chatMemory.add(conversationId, List.of(
new UserMessage(question)));
// 用于收集完整的助手回复
StringBuilder fullResponse =
new StringBuilder;
return
this.chatClient.prompt
.messages(historyMessages)
.user(question)
.stream
.content
// 对于流式输出中的每条消息,转化为ChatEventDto对象
.map(content -> {
fullResponse.append(content);
return ChatEventDto.builder
.eventType(ChatEventType.DATA.getValue)
.eventData(content)
.build;
})
// 在流式输出结束后追加一条代表STOP的消息
.concatWith(Flux.just(ChatEventDto.builder
.eventType(ChatEventType.STOP.getValue)
.build))
.doOnComplete( -> {
// 流完成后手动保存助手回复
if (!fullResponse.isEmpty) {
chatMemory.add(conversationId, List.of(
new AssistantMessage(fullResponse.toString)));
}
});
}
@Operation(summary =
"获取对话历史记录")
@GetMapping(
"/history")
public CommonResult<List<Map<String, Object>>> history(
@RequestParam String conversationId) {
var result = chatMemory.get(conversationId).stream
.map(msg -> Map.<String, Object>of(
"role", msg.getMessageType.name,
"content", msg.getText
))
.collect(Collectors.toList);
return CommonResult.success(result);
}
@Operation(summary =
"清除对话历史记录")
@PostMapping(
"/clearHistory")
public CommonResult<Void>
clearHistory
(@RequestParam String conversationId) {
chatMemory.clear(conversationId);
return CommonResult.success(
null);
}
}
我这里用TDesign中的Chatbot组件做了个聊天界面,让我们一起来看下效果。
之前问了什么问题,是第几次对话了,大模型正确回答了,说明已经实现了对话记忆;
获取对话历史记录的接口,刷新下页面,就会根据该接口获取历史记录了。
本文带你从零开始,用Spring AI 2.0搭建了一个具备对话记忆功能的AI对话服务。核心步骤就三步: 引入Starter依赖、配置模型参数、注入ChatClient调用,几行代码即可实现同步对话和SSE流式输出。
在此基础上,通过引入ChatMemory并对接Redis,轻松实现了多轮对话记忆,彻底解决了大模型"每次都是第一次聊天"的问题。
Spring AI让你用最熟悉的Spring方式,以最少的代码,将AI能力集成到项目中去,感兴趣的小伙伴可以尝试下!
https://github.com/macrozheng/spring-ai-examples
来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/31545808/viewspace-3176029/ ,如需转载,请注明出处,否则将追究法律责任。