几行代码给项目集成AI功能,Spring AI 2.0太香了!

Spring AI 2.0终于来了!以前想在Java里接入大模型,要么手写一堆HTTP调用和JSON解析,要么东拼西凑各种第三方库。现在有了Spring AI,加个Starter、配个Bean、注入ChatClient,三步就能让AI在项目里跑起来。这篇文章就带你从零搭建一个带对话记忆的聊天服务,看看它到底有多香。

Spring AI简介

Spring AI是Spring生态面向人工智能领域的官方扩展,旨在让Java开发者无需深入机器学习底层,就能像使用Spring MVC、Spring Data一样自然地构建AI应用。

Spring AI的核心功能如下:

  • 多模型多供应商支持:一套代码适配OpenAI、Deepseek、Anthropic、Ollama等主流模型,覆盖对话、文生图、语音转文字等多种场景。
  • ChatClient 流式 API :与WebClient风格一致的对话客户端,支持同步call()和流式stream()两种调用方式。
  • Advisors API:将RAG、对话记忆、安全过滤等AI模式封装为可复用的拦截器链,跨模型、跨场景移植。
  • 对话记忆(Chat Memory):内置内存、Redis、JDBC等多种存储后端,自动管理多轮对话历史上下文。
  • RAG检索增强生成:内置ETL流水线将文档切分向量化写入向量库,一行代码即可让大模型"读懂"你的文档。
  • 工具调用(Tool Calling) :用@Tool注解注册Java方法,让模型调用你的API执行真实操作。

项目集成Spring AI

第一步,把Spring AI集成到项目中去。

添加依赖

  • 首先在pom.xml中添加Spring AI的依赖管理,用于统一管理Spring AI版本,这里使用的是2.0.0版本;
xml 复制代码
<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>
  • 由于很多模型都兼容OpenAI的API,我们这里使用OpenAI模型的Starter,之后我们需要实现SSE的流式输出,还需添加WebFlux的Starter。
xml 复制代码
<!-- Spring AI OpenAI Starter -->
<dependency>
    <groupId>org.springframework.ai</groupId>
    <artifactId>spring-ai-starter-model-openai</artifactId>
</dependency>
<!-- SpringBoot WebFlux依赖模块(提供Flux/Mono响应式类型) -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-webflux</artifactId>
</dependency>

添加配置

  • 接下来在application.yaml中添加模型调用相关配置,包含base-url、api-key、chat.model,这里使用的是deepseek-v4-pro模型;
yaml 复制代码
spring:
  ai:
    openai:
      # 通过OpenAI兼容接口访问DeepSeek服务
      base-url: https://api.deepseek.com
      # 对应API_KEY
      api-key: ${DEEPSEEK_API_KEY}
      chat:
        # 要使用的模型ID,支持deepseek-v4-flash、deepseek-v4-pro
        model: deepseek-v4-pro
  • 最后添加Java配置类,配置一个ChatClient的Bean即可,ChatClient类封装了与AI模型通信的全部细节,你只需要调用它的方法,无需关心底层HTTP请求、流式处理等。
java 复制代码
/**
 * 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();
    }

}

这或许是一个对你有用的开源项目,mall项目是一套基于 SpringBoot3 + Vue3 的电商系统(Github标星60K),后端支持多模块和微服务架构,采用Docker和K8S部署。包括前台商城项目和后台管理系统,能支持完整的订单流程!涵盖商品、订单、购物车、权限、优惠券、会员、支付等功能!

项目演示:

实现对话功能

Spring AI集成完毕,开发一个对话功能来试试效果。

  • 创建ChatController,实现同步调用大模型的call方法和流式调用大模型的stream方法,对于流式调用大模型的方法,输出格式我们需要配置为TEXT_EVENT_STREAM_VALUE
java 复制代码
/**
 * 对话功能相关接口
 * @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()));
    }
}
  • 其中的ChatEventDto用于封装Sse会话事件返回结果,这会让SSE对话返回json格式的数据;
java 复制代码
/**
 * 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;

}
  • 这里我们使用Postman测试下同步调用的call接口,可以发现响应比较慢,会一次性返回所有信息;
  • 再测试下异步调用的stream接口,会逐步返回JSON格式的信息;
  • 接着上面的对话询问:我刚问了什么问题,这是第几次对话,大模型会回复我们这是第一次对话,说明目前还没有对话记忆功能。

实现对话记忆

那么如何实现对话记忆功能呢,Spring AI支持多种类型的记忆存储,以适应不同的使用场景,例如内存、JDBC、Neo4j、MongoDB、Redis等。这里就以Redis为例,介绍下如何实现对话记忆功能。

  • Redis对话记忆功能需要使用redis-stack,而不是普通的redis版本,这里使用的是redis-stack的7.4.0版本,docker运行命令如下;
bash 复制代码
docker run --name redis-stack \
-p 6379:6379 \
-p 8001:8001 \
-d redis/redis-stack:7.4.0-v8
  • 然后在项目的pom.xml中添加Redis对话记忆对应的Starter;
xml 复制代码
<!-- Spring AI Redis Chat Memory Repository -->
<dependency>
    <groupId>org.springframework.ai</groupId>
    <artifactId>spring-ai-starter-model-chat-memory-repository-redis</artifactId>
</dependency>
  • application.yaml中添加Redis的连接配置;
yaml 复制代码
spring:
  ai:
    chat:
      memory:
        redis:
          host: 192.168.3.101
          port: 6379
          time-to-live: 24h
          key-prefix: spring-chat
  • 在Java配置类中创建RedisChatMemoryRepository和ChatMemory对应的Bean,通过ChatMemory我们可以让AI大模型"记住"同一会话中的历史对话内容,实现真正的多轮对话;
java 复制代码
/**
 * 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();
    }
}
  • 接下来在ChatController中注入ChatMemory,通过它的add方法添加对话记忆,get方法获取对话记忆,clear方法清空对话记忆,所有相关记忆都要绑定到对应的conversationId上。
java 复制代码
/**
 * 对话功能相关接口
 * @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组件做了个聊天界面,让我们一起来看下效果。

  • 首先我们来测试下对话记忆功能,例如我先问它一个问题,再问它之前问了什么问题,是第几次对话了,大模型正确回答了,说明已经实现了对话记忆;
  • 打开redis的管理控制台,也可以看到存储的对话记忆数据了;
  • 在Controller中我们还实现了获取对话历史记录的接口,刷新下页面,就会根据该接口获取历史记录了。

总结

本文带你从零开始,用Spring AI 2.0搭建了一个具备对话记忆功能的AI对话服务。核心步骤就三步:引入Starter依赖、配置模型参数、注入ChatClient调用,几行代码即可实现同步对话和SSE流式输出。

在此基础上,通过引入ChatMemory并对接Redis,轻松实现了多轮对话记忆,彻底解决了大模型"每次都是第一次聊天"的问题。

Spring AI让你用最熟悉的Spring方式,以最少的代码,将AI能力集成到项目中去,感兴趣的小伙伴可以尝试下!

项目源码地址

github.com/macrozheng/...

相关推荐
zed_231 小时前
给接口加把锁:Bearer Token 鉴权(附冒烟验收)
人工智能
u0103055271 小时前
昇腾Model Agent模型适配指南
人工智能
Neptune231 小时前
Agent死循环6小时:从“相信LLM判断”到“焊死硬件条件止
人工智能
用户548775431601 小时前
DeepSeek Harness 与 xAgent:两种 Agent Harness 架构路线怎么选
人工智能·deepseek
安逸sgr1 小时前
卷积神经网络 CNN 是什么?为什么适合处理图像?
人工智能·ai·大模型·agent·智能体
人工智能AI技术1 小时前
告别AI瞎编API!GitMCP实战:Web‑CAD开发准确率拉满
人工智能
元界metalite1 小时前
SpringBoot修改接口全字段更新为什么危险-MetaLite如何只更新变化字段
spring boot
用户73499134716531 小时前
为 DeepSeek V4 Flash 加上视觉:40M 参数连接器实战
人工智能
Devin~Y1 小时前
从内容社区到AI智能客服:Spring Boot + Spring Cloud + Spring AI 全栈实战面试拆解
java·spring boot·redis·elasticsearch·spring cloud·kafka·mybatis