SpringBoot使用SpringAi完成简单智能助手

文章目录

SpringBoot使用SpringAi完成简单智能助手

一、Spring AI 基础认知

1.1 主流大模型开发框架对比

Java 领域实现大模型(LLM)开发的两大核心框架,核心差异如下:

表格

框架 最低JDK版本 核心优势
Spring AI 17 深度适配 SpringBoot 生态,自动装配,开发成本低
LangChain4J 8 兼容性强,支持低版本 JDK,生态插件丰富

1.2 Spring AI 核心特性

  1. 完全适配 SpringBoot 自动装配,提供各主流大模型的 starter 依赖,快速集成;
  2. 封装 ChatClient 统一对话 API,支持同步调用和流式调用两种交互方式;
  3. 基于 Advisor 切面机制实现功能增强,支持会话记忆、日志记录、RAG 等能力;
  4. 自动扫描 @Tool 注解实现工具调用,无需手动注册;
  5. 支持自定义 System 系统提示、对话上下文记忆,适配多轮对话场景。

1.3 快速开始

先带大家快速搭建一个基本功能项目,后面再依次拆分讲解
环境要求

JDK:17 及以上版本(Spring AI 强制要求);

SpringBoot:3.5.9 及以上(本文示例使用 3.5.9);

构建工具:Maven;

大模型 URL&API:可通过硅基流动(https://www.siliconflow.cn/) 获取(支持 DeepSeek、OpenAI 等多模型,需实名认证并获取 API-Key)。

①创建SpringBoot项目
②引入依赖

首先,在项目pom.xml中添加spring-ai的版本信息:

xml 复制代码
    <properties>
        <java.version>17</java.version>
        <spring-ai.version>1.0.0-SNAPSHOT</spring-ai.version> <!-- Spring AI 版本 -->
    </properties>

然后,添加spring-ai的依赖管理项:

xml 复制代码
    <!-- 管理Spring AI 所有依赖版本,避免版本冲突 -->
    <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-ai-openai 的依赖:

xml 复制代码
		<dependency>
            <groupId>org.springframework.ai</groupId>
            <artifactId>spring-ai-starter-model-openai</artifactId>
            <version>${spring-ai.version}</version>
        </dependency>

为了方便后续开发,我们再手动引入一个Lombok依赖:

xml 复制代码
<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <version>1.18.22</version>
</dependency>

注意: 千万不要用start.spring.io提供的lombok,有bug!!

完整依赖(复制注意修改项目信息)

xml 复制代码
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>3.5.9</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.ai</groupId>
    <artifactId>SpringAi</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>SpringAi</name>
    <description>SpringAi</description>

    <properties>
        <java.version>17</java.version>
        <spring-ai.version>1.0.0-SNAPSHOT</spring-ai.version>
    </properties>
    <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>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.ai</groupId>
            <artifactId>spring-ai-starter-model-openai</artifactId>
            <version>${spring-ai.version}</version>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.22</version>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>
③配置模型信息

首先需要使用Ai的对应key

介绍一个网站,叫做硅基流动 https://www.siliconflow.cn/,可以从这获取,当然后面也会介绍其他的模型获取网站ps:点击链接会默认填写推荐码,谢谢大家

无论什么大模型网站我们都需要获取两个内容

  1. 模型请求地址

  2. API key

接下来,我们在配置文件中配置模型的参数信息。

以 openai 为例,我们将application.properties修改为application.yaml,然后添加下面的内容:

yml 复制代码
spring:
  # Spring AI 核心配置
  ai:
    openai:
      api-key: fghjklfghjklsahdjksadasdsadasd # 硅基流动/OpenAI的API-Key(我瞎写的改成你自己的)
      base-url: https://api.siliconflow.cn # 大模型接口地址(硅基流动/OpenAI官方地址)
      chat:
        options:
          model: deepseek-ai/DeepSeek-V3 # 模型名称(硅基流动/OpenAI模型名,你选择模型的名字)
          temperature: 0.7 # 随机性(0-1,值越大回答越灵活)
      completions-path: /v1/chat/completions # 对话接口路径(上面截图API地址)

配置项说明:

  • api-key:大模型平台的访问密钥,需从硅基流动 / OpenAI 等平台获取;
  • base-url:大模型的接口根地址,硅基流动为https://api.siliconflow.cn,OpenAI 官方为-https://api.openai.com/v1;
  • model:指定调用的大模型名称,需与平台提供的模型名完全一致;
  • temperature:回答的随机性,0 为完全固定回答,1 为最大随机性,推荐 0.5-0.7;
  • completions-path:对话接口的固定路径,主流大模型均为/v1/chat/completions。
④创建AiChatConfig工具类
java 复制代码
import jakarta.annotation.Resource;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.openai.OpenAiChatModel;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class AiChatConfig {
	
    @Resource
    //自动装配OpenAiChatModel:由spring-ai-starter-model-openai自动配置
    OpenAiChatModel openAiChatModel;

    /**
     * 配置 ChatClient - OpenAI兼容的聊天客户端
     * @return ChatClient 实例
     */
    @Bean("open-ai")
    public ChatClient openAIChatClient() {
        return ChatClient.builder(openAiChatModel)
                .build();
    }

}
⑤创建AiChatController控制类
java 复制代码
import lombok.RequiredArgsConstructor;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@RequiredArgsConstructor
@RestController
@RequestMapping("/ai")
public class AiChatController{
    private final ChatClient chatClient;
    // 请求方式和路径不要改动,将来要与前端联调
    @RequestMapping("/chat")
    public String chat(@RequestParam(defaultValue = "介绍一下你自己") String prompt) {
        return chatClient
                .prompt(prompt) // 传入用户提示词
                .call() // 同步请求,会等待AI全部输出完才返回结果
                .content(); //返回响应内容
    }
}
⑥测试

请求地址:http://localhost:8080/ai/chat

1.4 Spring AI 核心 API

Spring AI 围绕ChatClient构建统一对话入口,核心相关 API 及作用如下:

核心 API 所属包 核心作用
ChatClient org.springframework.ai.chat.client 大模型对话统一入口,封装同步 / 流式调用
ChatClient.Builder org.springframework.ai.chat.client 构建 ChatClient 实例,配置系统提示、增强器
OpenAiChatModel org.springframework.ai.openai OpenAI 兼容的模型实现,由 Spring 自动装配
ChatMemory org.springframework.ai.chat.memory 对话记忆接口,存储多轮对话上下文
MessageWindowChatMemory org.springframework.ai.chat.memory ChatMemory 的实现类,基于消息窗口保留上下文
MessageChatMemoryAdvisor org.springframework.ai.chat.client.advisor 会话记忆增强器,实现多轮对话上下文关联
SimpleLoggerAdvisor org.springframework.ai.chat.client.advisor 日志增强器,打印 AI 交互全流程日志
Flux reactor.core.publisher 流式返回结果类型,实现前端实时接收数据

1.5 流式结果

同步调用是指等待大模型完整返回结果后,再将数据返回给前端,适用于短文本问答场景,

核心API 为String ChatClient.prompt().call().content()

快速开始中就是使用同步调用
流式调用是指大模型逐字 / 逐段返回结果,前端实时接收并展示,解决同步调用 "等待时间长、用户体验差" 的问题,核心基于WebFlux实现

核心 API 为Flux<String> ChatClient.prompt().stream().content()

编写流式对话接口

在ChatController中添加流式调用接口chat2:

java 复制代码
/**
 * 流式对话接口
 * @param prompt 用户提问的提示词,默认值为"介绍一下你自己"
 * @return Flux<String> 流式结果,前端实时接收
 */
@RequestMapping(value = "/chat2", produces = "text/html;charset=UTF-8")
public Flux<String> chat2(@RequestParam(defaultValue = "介绍一下你自己") String prompt) {
    // 流式调用核心API链
    return chatClient
            .prompt(prompt) // 传入用户提示词
            .stream()       // 流式调用:非阻塞,逐段返回结果
            .content();     // 提取流式的纯文本内容
}

重启测试,再次访问,会一点点生成数据展示在页面上。

1.6 系统(角色)设置

可以发现,当我们询问AI你是谁的时候,它回答自己是DeepSeek-R1,这是大模型底层的设定。如果我们希望AI按照新的设定工作,就需要给它设置System背景信息。
在SpringAI中,设置System信息非常方便,不需要在每次发送时封装到Message,而是创建ChatClient时指定即可。

用于定义 AI 的角色、回答风格、业务规则,无需在每次调用时重复传递,由 ChatClient 自动附加到 Prompt 中,不同的项目可能需要设置不同的System信息,所以一般会定义对应的类保存。

创建SystemManage系统设置管理类

java 复制代码
/**
 * AI服务System模板管理
 * 职责:统一管理所有AI服务使用的System模板
 */
public class SystemManage {

   //提示词Demo
   public static final String DEMO_SYSTEM= """
            你是一个专业的AI智能助手,你的名字叫小艾同学,请以友好、乐于助人和愉快的方式解答各种问题。
            重要:当用户询问具体信息时,不要编造不存在的数据。    
            """;
}

修改AiChatConfig类

java 复制代码
import jakarta.annotation.Resource;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.openai.OpenAiChatModel;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class AiChatConfig {
	
    @Resource
    //自动装配OpenAiChatModel:由spring-ai-starter-model-openai自动配置
    OpenAiChatModel openAiChatModel;

    /**
     * 配置 ChatClient - OpenAI兼容的聊天客户端
     * @return ChatClient 实例
     */
    @Bean("open-ai")
    public ChatClient openAIChatClient() {
        return ChatClient.builder(openAiChatModel)
        		// 配置系统提示:定义AI的角色、回答风格
        		.defaultSystem(SystemManage.DEMO_SYSTEM)
                .build();
    }
}

重启测试,再次访问,会按照定义的内容生成。

1.7 多轮对话上下文

多轮对话的核心是上下文关联,即 AI 能识别上一轮的提问和回答,例如:

用户:12 个苹果分给 2 个人,每人分几个?

AI:6 个;

用户:分给 3 个人呢?

AI:4 个(需识别 "12 个苹果" 的上下文)。

核心原理

  1. MessageChatMemoryAdvisor会在每次调用大模型时,自动从 ChatMemory 中读取历史对话消息,并附加到当前 Prompt 中;
  2. 大模型基于历史消息 + 当前提问生成回答,实现上下文关联;
  3. 回答生成后,MessageChatMemoryAdvisor会自动将当前用户消息和 AI 回答存入 ChatMemory,更新上下文。

Spring AI 通过ChatMemory + MessageChatMemoryAdvisor实现该能力,无需额外编写业务代码,只需在配置类中完成相关 Bean 配置。

Advisor 核心概念

Advisor 是 Spring AI 基于AOP 切面机制实现的功能增强接口,用于在大模型对话的请求前、响应后进行无侵入式处理,核心执行流程:

java 复制代码
用户请求 → AdvisedRequest(增强前请求)→ Advisor增强(如添加上下文、记录日志)→ Prompt(最终请求)→ 大模型 → ChatResponse(模型响应)→ Advisor增强(如存储上下文)→ AdvisedResponse(增强后响应)→ 返回给用户

Advisor API

Advisor 类名 核心作用 配置方式
MessageChatMemoryAdvisor 实现多轮对话上下文关联,自动读写 ChatMemory MessageChatMemoryAdvisor.builder(chatMemory).build()

修改AiChatConfig类

java 复制代码
import jakarta.annotation.Resource;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.openai.OpenAiChatModel;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class AiChatConfig {
	
    @Resource
    //自动装配OpenAiChatModel:由spring-ai-starter-model-openai自动配置
    OpenAiChatModel openAiChatModel;
	 /**
     * 配置 ChatMemory - 内存存储的会话记忆
     *
     * @return ChatMemory 内存存储的会话记忆实例
     */
    @Bean
    public ChatMemory chatMemory() {
        return MessageWindowChatMemory.builder()
                .maxMessages(30) // 窗口最大消息数目,保留最近30条消息
                .build();
    }
    /**
     * 配置 ChatClient - OpenAI兼容的聊天客户端
     * @return ChatClient 实例
     */
    @Bean("open-ai")
    public ChatClient openAIChatClient() {
        return ChatClient.builder(openAiChatModel)
        		// 配置系统提示:定义AI的角色、回答风格
        		.defaultSystem(SystemManage.DEMO_SYSTEM)
        		// 配置增强器:会话记忆(多轮对话)
                .defaultAdvisors(
                	//会话记忆增强器,实现多轮对话上下文关联
                    MessageChatMemoryAdvisor.builder(chatMemory).build(), // 会话记忆增强器
                )
                .build();
    }
}

测试多轮对话

1.8 日志集成

默认情况下,应用于AI的交互时不记录日志的,我们无法得知SpringAI组织的提示词到底长什么样,有没有问题。这样不方便我们调试。

SpringAI基于AOP机制实现与大模型对话过程的增强、拦截、修改等功能。所有的增强通知都需要实现Advisor接口。

Advisor API

Advisor 类名 核心作用 配置方式
SimpleLoggerAdvisor 记录 AI 交互全流程日志(Prompt、响应、Token 等) new SimpleLoggerAdvisor()

修改AiChatConfig类

java 复制代码
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.ChatMemory;
import org.springframework.ai.chat.memory.MessageWindowChatMemory;
import org.springframework.ai.openai.OpenAiChatModel;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class AiChatConfig {
	
    @Resource
    //自动装配OpenAiChatModel:由spring-ai-starter-model-openai自动配置
    OpenAiChatModel openAiChatModel;
	 /**
     * 配置 ChatMemory - 内存存储的会话记忆
     *
     * @return ChatMemory 内存存储的会话记忆实例
     */
    @Bean
    public ChatMemory chatMemory() {
        return MessageWindowChatMemory.builder()
                .maxMessages(30) // 窗口最大消息数目,保留最近30条消息
                .build();
    }
    /**
     * 配置 ChatClient - OpenAI兼容的聊天客户端
     * @return ChatClient 实例
     */
    @Bean("open-ai")
    public ChatClient openAIChatClient() {
        return ChatClient.builder(openAiChatModel)
        		// 配置系统提示:定义AI的角色、回答风格
        		.defaultSystem(SystemManage.DEMO_SYSTEM)
                 // 配置增强器:会话记忆(多轮对话)+ 日志记录(调试)
                .defaultAdvisors(
                        MessageChatMemoryAdvisor.builder(chatMemory).build(), // 会话记忆增强器
                        new SimpleLoggerAdvisor() // 日志增强器
                )
                .build();
    }
}

修改日志级别

application.yaml中添加日志配置,更新日志级别:

位置要顶格写,不要写在 spring 标签的下面

yml 复制代码
logging:
  level:
    org.springframework.ai: debug # AI对话的日志级别
    com.ruangong.springai: debug # 本项目的日志级别

重启项目,再次聊天就能看到AI对话的日志信息了~

1.9 工具调用

工具调用是 Spring AI 核心扩展能力之一,允许大模型根据用户提问自动判断并调用自定义工具(如天气查询、数据库操作、计算器等),而非仅依赖模型自身知识回答问题,核心解决 "大模型知识时效性差、无法执行实时 / 计算类操作" 的问题。
工具调用流程

工具调用常用注解

核心组件 所属包 注解位置 作用
@Tool org.springframework.ai.annotation 方法 标记方法为可被 AI 调用的工具
@ToolParam org.springframework.ai.annotation 参数 标记被 AI 调用的工具方法参数

定义可被 AI 调用的工具类

java 复制代码
import org.springframework.ai.tool.annotation.Tool;
import org.springframework.ai.tool.annotation.ToolParam;
import org.springframework.stereotype.Component;

/**
 * 这里两个示例工具方法就直接返回字符串,实际项目中可以注入mapper实现数据库查询	
 * 工具1:数学计算工具
 * 工具2:天气查询工具
 */
@Component
public class MyTool {
	
    @Tool(
            name = "calculator_tool",
            description = "执行数学计算,参数:expression(数学表达式,如 10+20*3)",
            returnDirect = true
    )
    public String calculator_tool(@ToolParam(description = "执行数学计算,如10+20*3等") String expression) {
        System.out.println("------------------------------------------数学计算-----------------------------------------");
        // 简单计算(实际可使用安全的表达式解析库,如 JEP)
        return "自己拿计算器算去";
    }
    @Tool(
            name = "weather_tool",
            description = "查询指定城市的实时天气信息,入参:city(城市名称,如北京、上海)",
            returnDirect = true
    )
    public String weather_tool(@ToolParam(description = "搜索关键词,如'北京'、'上海'等") String city) {
        System.out.println("------------------------------------------天气查询-----------------------------------------");
        String weatherInfo = switch (city) {
            case "北京" -> "晴,气温 18~28℃,西南风 2级";
            case "上海" -> "多云,气温 22~30℃,东南风 3级";
            case "广州" -> "小雨,气温 25~32℃,东北风 1级";
            default -> "暂未查询到「" + city + "」的天气信息,请确认城市名称";
        };
        return weatherInfo;
    }
}

修改AiChatConfig类

java 复制代码
import jakarta.annotation.Resource;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.openai.OpenAiChatModel;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class AiChatConfig {
	
    @Resource
    //自动装配OpenAiChatModel:由spring-ai-starter-model-openai自动配置
    OpenAiChatModel openAiChatModel;
	@Resource
	//注入工具函数所在工具类
    MyTool myTool;
	 /**
     * 配置 ChatMemory - 内存存储的会话记忆
     *
     * @return ChatMemory 内存存储的会话记忆实例
     */
    @Bean
    public ChatMemory chatMemory() {
        return MessageWindowChatMemory.builder()
                .maxMessages(30) // 窗口最大消息数目,保留最近30条消息
                .build();
    }
    /**
     * 配置 ChatClient - OpenAI兼容的聊天客户端
     * @return ChatClient 实例
     */
    @Bean("open-ai")
    public ChatClient openAIChatClient() {
        return ChatClient.builder(openAiChatModel)
        		// 配置系统提示:定义AI的角色、回答风格
        		.defaultSystem(SystemManage.DEMO_SYSTEM)
        		// 配置增强器:会话记忆(多轮对话)
                .defaultAdvisors(
                	//会话记忆增强器,实现多轮对话上下文关联
                    MessageChatMemoryAdvisor.builder(chatMemory).build(), // 会话记忆增强器
                )
                // 配置自定义调用工具
                .defaultTools(myTool)
                .build();
    }
}

这样就可以实现工具调用了,由大模型自动识别调用,当然为了提高工具调用的命中率可以修改系统设置

java 复制代码
   //提示词Demo
   public static final String TEST_SYSTEM= """
            你是一个专业的AI智能助手,你的名字叫小艾同学,请以友好、乐于助人和愉快的方式解答各种问题。

            ## 可用工具函数:
            当用户询问具体信息时,你应该**优先使用工具函数**查询数据库中的实际数据,而不是凭空回答:

            1. **calculator_tool(expression)** - 执行数学计算
                - 用途:当用户询问'帮我算'、'帮我计算',如帮我算10+20*3等
                - 示例:calculator_tool("10+20*3")
            2. **weather_tool(city)** - 查询指定城市的实时天气信息
                - 用途:当用户询问'今天北京天气怎么样'、'广州天气'等
                - 示例:weather_tool("北京")

            **重要**:当用户询问具体信息时,必须先调用相应工具查询,然后基于查询结果进行回答。不要编造不存在的数据。    
            """;

1.10 前端集成

在浏览器通过地址访问,非常麻烦,也不够优雅。如果能有一个优美的前端页面就好了。

别着急,我提前给大家准备了一个前端页面。已经进行了资源绑定


前端启动流程

解决CORS问题

前后端在不同域名,存在跨域问题,因此我们需要在服务端解决cors问题。在 config 包中添加一个类:

java 复制代码
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
public class MvcConfiguration implements WebMvcConfigurer {
    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**")
                .allowedOrigins("*")
                .allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS")
                .allowedHeaders("*")
                .exposedHeaders("Content-Disposition");
    }
}

重启服务,如果你的服务端接口正确,那么应该就可以聊天了。

注意: 前端访问服务端的默认路径是:http://localhost:8080

聊天对话的接口是:POST /ai/chat 如果想实现流式对话将后台请求路径修改

请确保你的服务端接口也是这样。

恭喜您,你的第一个AI对话机器人就简单完成了。

1.11 会话隔离

在实际项目中,不同用户会在不同会话进行提问,在上文的多轮对话上下文中,使用MessageChatMemoryAdvisor仅能实现上下文,无法实现会话隔离。

因为所有的请求都使用默认的记忆,所以要实现会话级别的记忆那么久需要为每一个会话都创建一个专属于会话的"记忆",例如前台案例请求携带的chatId,就是会话的标识

修改ChatController 对应方法

java 复制代码
/**
 * 流式对话接口
 * @param prompt 用户提问的提示词,默认值为"介绍一下你自己"
 * @return Flux<String> 流式结果,前端实时接收
 */
@RequestMapping(value = "/chat2", produces = "text/html;charset=UTF-8")
public Flux<String> chat2(@RequestParam(defaultValue = "介绍一下你自己") String prompt,String chatId) {
    // 流式调用核心API链
    return chatClient
            .prompt(prompt) // 传入用户提示词
            //为当前请求设置对话记忆(使用默认的会话id标识与前台生成的chatId)
            .advisors(advisorSpec -> advisorSpec.param(ChatMemory.CONVERSATION_ID, chatId))
            .stream()       // 流式调用:非阻塞,逐段返回结果
            .content();     // 提取流式的纯文本内容
}

1.12 前端界面功能简单实现

多会话切换历史查询

页面在进行会话切换时,会将会话的Id发送给后台,获取信息,所以后台需要保存对话信息

创建AiChatMessage类,保存对话信息

java 复制代码
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.time.LocalDateTime;

/**
 * AI聊天消息实体类
 * @author system
 */
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
//AI聊天消息实体类
public class AiChatMessage  {
    //消息ID
    private Long id;
    //会话ID
    private String sessionId;
    //角色:user-用户,assistant-AI助手
    private String role;
    //消息内容")
    private String content;
    //创建时间
    private LocalDateTime createTime;
}

数据实际应该存储到数据库,本文使用自定义数据类模拟

创建MessageData类,模拟存储对话数据

java 复制代码
import java.util.ArrayList;
//保存对话信息工具类,模拟数据库存储
public class MessageData {
    public static ArrayList<AiChatMessage> messages=new ArrayList<>();
    public static void addMessage(AiChatMessage message){
        messages.add(message);
    }
}

修改ChatController类内容

java 复制代码
/**
 * 流式对话接口
 * @param prompt 用户提问的提示词,默认值为"介绍一下你自己"
 * @return Flux<String> 流式结果,前端实时接收
 */
@RequestMapping(value = "/chat2", produces = "text/html;charset=UTF-8")
public Flux<String> chat2(@RequestParam(defaultValue = "介绍一下你自己") String prompt,String chatId) {
    	// 流式调用核心API链 获取结果
        Flux<String> content = chatClient
                .prompt(prompt)
                .advisors(advisorSpec -> advisorSpec.param(ChatMemory.CONVERSATION_ID, chatId))
                .stream() // 流式调用
                .content();
        //将用户信息存储
        MessageData.addMessage(AiChatMessage.builder()
                .role(MessageType.USER.getValue())
                .content(prompt)
                .sessionId(chatId)
                .build());
        StringBuilder fullResponse = new StringBuilder();
        return content.doOnNext(fullResponse::append)
                //返回结束时执行
                .doOnComplete(() -> {
                    //获取会话结果存储
                    MessageData.addMessage(AiChatMessage.builder()
                            .role(MessageType.ASSISTANT.getValue())
                            .content(fullResponse.toString())
                            .sessionId(chatId)
                            .build());
                });
    }

    @GetMapping("/history/chat/{chatId}")
    public List<AiChatMessage> history(@PathVariable String chatId){
    	//获取指定会话的历史信息并返回
        return MessageData.messages.stream().filter(msg->msg.getSessionId().equals(chatId)).toList();
    }

获取当前网页会话下的多个聊天记录

因为只是一个案例,所以使用session存储会话id,实际开发中创建会话可以存储到数据库中,然后通过数据库查询返回

修改ChatController类内容

java 复制代码
/**
 * 流式对话接口
 * @param prompt 用户提问的提示词,默认值为"介绍一下你自己"
 * @return Flux<String> 流式结果,前端实时接收
 */
    @RequestMapping(value = "/chat", produces = "text/html;charset=UTF-8")
    public Flux<String> chat2(@RequestParam(defaultValue = "介绍一下你自己") String prompt,String chatId,HttpSession session) {
    	//获取当前会话中的chatId列表
        HashSet<String> sessionIds= ( HashSet<String>) session.getAttribute("sessionIds");
        //因为是set集合所以每次请求直接添加即可
        sessionIds.add(chatId);
        //将最新的chatId列表存入sessin
        session.setAttribute("sessionIds",sessionIds);
        // 流式调用核心API链 获取结果
        Flux<String> content = chatClient
                .prompt(prompt)
                .advisors(advisorSpec -> advisorSpec.param(ChatMemory.CONVERSATION_ID, chatId))
                .stream() // 流式调用
                .content();
        //将用户信息存储
        MessageData.addMessage(AiChatMessage.builder()
                .role(MessageType.USER.getValue())
                .content(prompt)
                .sessionId(chatId)
                .build());
        StringBuilder fullResponse = new StringBuilder();
        return content.doOnNext(fullResponse::append)
                //返回结束时执行
                .doOnComplete(() -> {
                    //获取会话结果存储
                    MessageData.addMessage(AiChatMessage.builder()
                            .role(MessageType.ASSISTANT.getValue())
                            .content(fullResponse.toString())
                            .sessionId(chatId)
                            .build());
                });
    }
    @GetMapping("/history/chat/{chatId}")
    public List<AiChatMessage> history(@PathVariable String chatId){
        return MessageData.messages.stream().filter(msg->msg.getSessionId().equals(chatId)).toList();
    }

	/**
 	* 获取历史会话列表方法 
 	* @param session 当前会话对象 自动注入
 	* @return  HashSet<String> 存储ChatId的集合
 	*/
    @GetMapping("/history/chat")
    public  HashSet<String> history1(HttpSession session){
        System.out.println("----------------------------------------------");
        HashSet<String> sessionIds= (HashSet<String>) session.getAttribute("sessionIds");
        if(sessionIds==null){
            sessionIds=new  HashSet<String>();
            //加几个模拟数据 要不需要手动点击
            sessionIds.add("1773648154863");
            sessionIds.add("1773648154864");
            sessionIds.add("1773648154865");
        }
        return sessionIds;
    }
相关推荐
喵喵蒻葉睦2 小时前
力扣 hot100 和为K的子数组 哈希&前缀和
java·数据结构·算法·leetcode·前缀和·哈希算法
G探险者2 小时前
DDD开发模式说明
java·运维·数据库
lang201509282 小时前
18 Byte Buddy 进阶:揭秘方法委托中的“歧义解析”机制
java·byte buddy
海南java第二人2 小时前
Spring Boot 新接口开发:Cursor 模式与模型选择指南
spring boot·ai coding
SimonKing2 小时前
Spring Boot 动态多数据源:核心思路与关键考量
java·后端·程序员
唐叔在学习2 小时前
为了不付费,我硬生生用AI开发了一个跨平台待办应用
后端·程序员·ai编程
好家伙VCC2 小时前
**NumPy中的高效数值计算:从基础到进阶的实战指南**在现代数据科学与机器学习领域
java·python·机器学习·numpy
旷世奇才李先生2 小时前
066基于java的中医养生系统-springboot+vue
java·vue.js·spring boot
武子康2 小时前
大数据-249 离线数仓 - 电商分析 Hive 数仓实战:订单拉链表到 DWS 宽表设计与加载脚本详解
大数据·后端·apache hive