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

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

文章目录

在这里插入图片描述

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

一、Spring AI 基础认知

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

Java 领域实现大模型(LLM)开发的两大核心框架,核心差异如下:
表格
框架最低JDK版本核心优势
Spring AI17深度适配 SpringBoot 生态,自动装配,开发成本低
LangChain4J8兼容性强,支持低版本 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的版本信息:
<properties><java.version>17</java.version><spring-ai.version>1.0.0-SNAPSHOT</spring-ai.version><!-- Spring AI 版本 --></properties>
然后,添加spring-ai的依赖管理项:
<!-- 管理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 的依赖:
<dependency><groupId>org.springframework.ai</groupId><artifactId>spring-ai-starter-model-openai</artifactId><version>${spring-ai.version}</version></dependency>
为了方便后续开发,我们再手动引入一个Lombok依赖:
<dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>1.18.22</version></dependency>

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

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

<?xml version="1.0" encoding="UTF-8"?><projectxmlns="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:点击链接会默认填写推荐码,账户会自动免费充值2元的额度,供大家使用

在这里插入图片描述
无论什么大模型网站我们都需要获取两个内容

API key

在这里插入图片描述

模型请求地址

在这里插入图片描述
接下来,我们在配置文件中配置模型的参数信息。
以 openai 为例,我们将application.properties修改为application.yaml,然后添加下面的内容:
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工具类
importjakarta.annotation.Resource;importorg.springframework.ai.chat.client.ChatClient;importorg.springframework.ai.openai.OpenAiChatModel;importorg.springframework.context.annotation.Bean;importorg.springframework.context.annotation.Configuration;@ConfigurationpublicclassAiChatConfig{@Resource//自动装配OpenAiChatModel:由spring-ai-starter-model-openai自动配置OpenAiChatModel openAiChatModel;/** * 配置 ChatClient - OpenAI兼容的聊天客户端 * @return ChatClient 实例 */@Bean("open-ai")publicChatClientopenAIChatClient(){returnChatClient.builder(openAiChatModel).build();}}
⑤创建AiChatController控制类
importlombok.RequiredArgsConstructor;importorg.springframework.ai.chat.client.ChatClient;importorg.springframework.web.bind.annotation.RequestMapping;importorg.springframework.web.bind.annotation.RequestParam;importorg.springframework.web.bind.annotation.RestController;@RequiredArgsConstructor@RestController@RequestMapping("/ai")publicclassAiChatController{privatefinalChatClient chatClient;// 请求方式和路径不要改动,将来要与前端联调@RequestMapping("/chat")publicStringchat(@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所属包核心作用
ChatClientorg.springframework.ai.chat.client大模型对话统一入口,封装同步 / 流式调用
ChatClient.Builderorg.springframework.ai.chat.client构建 ChatClient 实例,配置系统提示、增强器
OpenAiChatModelorg.springframework.ai.openaiOpenAI 兼容的模型实现,由 Spring 自动装配
ChatMemoryorg.springframework.ai.chat.memory对话记忆接口,存储多轮对话上下文
MessageWindowChatMemoryorg.springframework.ai.chat.memoryChatMemory 的实现类,基于消息窗口保留上下文
MessageChatMemoryAdvisororg.springframework.ai.chat.client.advisor会话记忆增强器,实现多轮对话上下文关联
SimpleLoggerAdvisororg.springframework.ai.chat.client.advisor日志增强器,打印 AI 交互全流程日志
Fluxreactor.core.publisher流式返回结果类型,实现前端实时接收数据

1.5 流式结果

同步调用是指等待大模型完整返回结果后,再将数据返回给前端,适用于短文本问答场景,
核心API 为String ChatClient.prompt().call().content()
快速开始中就是使用同步调用
流式调用是指大模型逐字 / 逐段返回结果,前端实时接收并展示,解决同步调用 “等待时间长、用户体验差” 的问题,核心基于WebFlux实现
核心 API 为Flux<String> ChatClient.prompt().stream().content()

编写流式对话接口

在ChatController中添加流式调用接口chat2:
/** * 流式对话接口 * @param prompt 用户提问的提示词,默认值为“介绍一下你自己” * @return Flux<String> 流式结果,前端实时接收 */@RequestMapping(value ="/chat2", produces ="text/html;charset=UTF-8")publicFlux<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系统设置管理类

/** * AI服务System模板管理 * 职责:统一管理所有AI服务使用的System模板 */publicclassSystemManage{//提示词DemopublicstaticfinalStringDEMO_SYSTEM=""" 你是一个专业的AI智能助手,你的名字叫小艾同学,请以友好、乐于助人和愉快的方式解答各种问题。 重要:当用户询问具体信息时,不要编造不存在的数据。 """;}

修改AiChatConfig类

importjakarta.annotation.Resource;importorg.springframework.ai.chat.client.ChatClient;importorg.springframework.ai.openai.OpenAiChatModel;importorg.springframework.context.annotation.Bean;importorg.springframework.context.annotation.Configuration;@ConfigurationpublicclassAiChatConfig{@Resource//自动装配OpenAiChatModel:由spring-ai-starter-model-openai自动配置OpenAiChatModel openAiChatModel;/** * 配置 ChatClient - OpenAI兼容的聊天客户端 * @return ChatClient 实例 */@Bean("open-ai")publicChatClientopenAIChatClient(){returnChatClient.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 切面机制实现的功能增强接口,用于在大模型对话的请求前、响应后进行无侵入式处理,核心执行流程:

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

Advisor API

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

修改AiChatConfig类

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

测试多轮对话

  • 第一次访问:http://localhost:8080/ai/chat?prompt=12个苹果分给2个人,每人分几个?
    返回:6 个;
  • 第二次访问:http://localhost:8080/ai/chat?prompt=分给3个人呢?
    返回:4 个(成功识别上下文 “12 个苹果”)。
在这里插入图片描述

1.8 日志集成

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

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

在这里插入图片描述

Advisor API

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

修改AiChatConfig类

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

修改日志级别

application.yaml中添加日志配置,更新日志级别:
位置要顶格写,不要写在 spring 标签的下面

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

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

在这里插入图片描述

1.9 工具调用

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

在这里插入图片描述


工具调用常用注解

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

定义可被 AI 调用的工具类

importorg.springframework.ai.tool.annotation.Tool;importorg.springframework.ai.tool.annotation.ToolParam;importorg.springframework.stereotype.Component;/** * 这里两个示例工具方法就直接返回字符串,实际项目中可以注入mapper实现数据库查询 * 工具1:数学计算工具 * 工具2:天气查询工具 */@ComponentpublicclassMyTool{@Tool( name ="calculator_tool", description ="执行数学计算,参数:expression(数学表达式,如 10+20*3)", returnDirect =true)publicStringcalculator_tool(@ToolParam(description ="执行数学计算,如10+20*3等")String expression){System.out.println("------------------------------------------数学计算-----------------------------------------");// 简单计算(实际可使用安全的表达式解析库,如 JEP)return"自己拿计算器算去";}@Tool( name ="weather_tool", description ="查询指定城市的实时天气信息,入参:city(城市名称,如北京、上海)", returnDirect =true)publicStringweather_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类

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

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

//提示词DemopublicstaticfinalStringTEST_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 包中添加一个类:
importorg.springframework.context.annotation.Configuration;importorg.springframework.web.servlet.config.annotation.CorsRegistry;importorg.springframework.web.servlet.config.annotation.WebMvcConfigurer;@ConfigurationpublicclassMvcConfigurationimplementsWebMvcConfigurer{@OverridepublicvoidaddCorsMappings(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 对应方法

/** * 流式对话接口 * @param prompt 用户提问的提示词,默认值为“介绍一下你自己” * @return Flux<String> 流式结果,前端实时接收 */@RequestMapping(value ="/chat2", produces ="text/html;charset=UTF-8")publicFlux<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类,保存对话信息

importlombok.AllArgsConstructor;importlombok.Builder;importlombok.Data;importlombok.NoArgsConstructor;importjava.time.LocalDateTime;/** * AI聊天消息实体类 * @author system */@Data@Builder@NoArgsConstructor@AllArgsConstructor//AI聊天消息实体类publicclassAiChatMessage{//消息IDprivateLong id;//会话IDprivateString sessionId;//角色:user-用户,assistant-AI助手privateString role;//消息内容")privateString content;//创建时间privateLocalDateTime createTime;}
数据实际应该存储到数据库,本文使用自定义数据类模拟

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

importjava.util.ArrayList;//保存对话信息工具类,模拟数据库存储publicclassMessageData{publicstaticArrayList<AiChatMessage> messages=newArrayList<>();publicstaticvoidaddMessage(AiChatMessage message){ messages.add(message);}}

修改ChatController类内容

/** * 流式对话接口 * @param prompt 用户提问的提示词,默认值为“介绍一下你自己” * @return Flux<String> 流式结果,前端实时接收 */@RequestMapping(value ="/chat2", produces ="text/html;charset=UTF-8")publicFlux<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 =newStringBuilder();return content.doOnNext(fullResponse::append)//返回结束时执行.doOnComplete(()->{//获取会话结果存储MessageData.addMessage(AiChatMessage.builder().role(MessageType.ASSISTANT.getValue()).content(fullResponse.toString()).sessionId(chatId).build());});}@GetMapping("/history/chat/{chatId}")publicList<AiChatMessage>history(@PathVariableString chatId){//获取指定会话的历史信息并返回returnMessageData.messages.stream().filter(msg->msg.getSessionId().equals(chatId)).toList();}

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

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

修改ChatController类内容

/** * 流式对话接口 * @param prompt 用户提问的提示词,默认值为“介绍一下你自己” * @return Flux<String> 流式结果,前端实时接收 */@RequestMapping(value ="/chat", produces ="text/html;charset=UTF-8")publicFlux<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 =newStringBuilder();return content.doOnNext(fullResponse::append)//返回结束时执行.doOnComplete(()->{//获取会话结果存储MessageData.addMessage(AiChatMessage.builder().role(MessageType.ASSISTANT.getValue()).content(fullResponse.toString()).sessionId(chatId).build());});}@GetMapping("/history/chat/{chatId}")publicList<AiChatMessage>history(@PathVariableString chatId){returnMessageData.messages.stream().filter(msg->msg.getSessionId().equals(chatId)).toList();}/** * 获取历史会话列表方法 * @param session 当前会话对象 自动注入 * @return HashSet<String> 存储ChatId的集合 */@GetMapping("/history/chat")publicHashSet<String>history1(HttpSession session){System.out.println("----------------------------------------------");HashSet<String> sessionIds=(HashSet<String>) session.getAttribute("sessionIds");if(sessionIds==null){ sessionIds=newHashSet<String>();//加几个模拟数据 要不需要手动点击 sessionIds.add("1773648154863"); sessionIds.add("1773648154864"); sessionIds.add("1773648154865");}return sessionIds;}

Read more

无线蜂窝网络:编织世界的无形之网

无线蜂窝网络:编织世界的无形之网

🔥作者简介: 一个平凡而乐于分享的小比特,中南民族大学通信工程专业研究生,研究方向无线联邦学习 🎬擅长领域:驱动开发,嵌入式软件开发,BSP开发 ❄️作者主页:一个平凡而乐于分享的小比特的个人主页 ✨收录专栏:无线通信技术,本专栏介绍无线通信相关技术 欢迎大家点赞 👍 收藏 ⭐ 加关注哦!💖💖 无线蜂窝网络:编织世界的无形之网 无线蜂窝网络是世界通信的基石,它通过“蜂窝”般的小区划分,让几十亿人能够随时随地无线通话、上网。我将从核心原理、工作流程、代际演进以及与Wi-Fi的对比等几个维度,为你展开这幅无线世界的全景图。 一、 什么是蜂窝网络?—— 从一个比喻开始 想象一下,你要在一个巨大的操场上举办一场派对,需要让所有人都能听到音乐。 * 方案A(大广播): 在操场中央放一个超级大喇叭。 * 问题: 离得近的人震耳欲聋,离得远的人听不清;而且大家不能同时点歌(信道有限)。 * 方案B(蜂窝派对): 把操场分成许多小格子,每个格子里放一个小音箱。每个音箱只负责覆盖自己的小格子。 * 好处: 每个人都能听清;相邻的格子可以播放不同的音乐(

By Ne0inhk
构建基于 Rust 与 GLM-5 的高性能 AI 翻译 CLI 工具:从环境搭建到核心实现全解析

构建基于 Rust 与 GLM-5 的高性能 AI 翻译 CLI 工具:从环境搭建到核心实现全解析

前言 随着大语言模型(LLM)能力的飞速提升,将 AI 能力集成到终端命令行工具(CLI)中已成为提升开发效率的重要手段。Rust 语言凭借其内存安全、零成本抽象以及极其高效的异步运行时,成为构建此类高性能网络 IO 密集型应用的首选。本文将深度剖析如何使用 Rust 语言,结合智谱 AI 的 GLM-5 模型,从零构建一个支持流式输出、多语言切换及文件批处理的 AI 翻译引擎。 本文将涵盖环境配置、依赖管理、异步网络编程、流式数据处理(SSE)、命令行参数解析以及最终的二进制发布优化。 第一部分:Rust 开发环境的系统级构建 在涉足 Rust 编程之前,必须确保底层操作系统具备必要的构建工具链。Rust 虽然拥有独立的包管理器,但在链接阶段依赖于系统的 C 语言编译器和链接器,尤其是在涉及网络库(如 reqwest 依赖的 OpenSSL)

By Ne0inhk
RUST异步微服务架构的最佳实践与常见反模式

RUST异步微服务架构的最佳实践与常见反模式

RUST异步微服务架构的最佳实践与常见反模式 一、项目优化前的问题分析 1.1 任务调度不合理 💡在第21篇项目中,用户同步服务的任务调度使用了Cron调度器,但Cron调度器的精度有限,可能导致任务执行延迟。此外,任务的并发度没有配置,可能导致任务积压。 1.2 I/O资源限制不足 订单处理服务的TCP连接队列大小没有配置,可能导致连接失败。数据库连接池的大小没有配置,可能导致数据库连接耗尽。 1.3 同步原语使用不当 实时监控服务中,Redis连接没有使用连接池,可能导致连接开销过大。任务结果的处理没有使用批量操作,可能导致上下文切换过多。 1.4 错误处理不完善 任务失败的处理逻辑不够完善,没有进行任务重试和错误统计。服务之间的通信没有进行超时管理和错误处理。 二、异步架构设计模式的应用 2.1 命令查询分离(CQS) CQS是一种架构设计模式,将系统的操作分为命令和查询两种类型。命令用于修改系统状态,查询用于获取系统状态,两者互不干扰。 在项目中,我们可以将用户同步任务视为命令操作,将系统状态查询视为查询操作: // 用户同步任务(

By Ne0inhk
Flutter 组件 test_track 适配鸿蒙 HarmonyOS 实战:全链路追踪与灰度治理,构建全场景 A/B 测试与特性分发架构

Flutter 组件 test_track 适配鸿蒙 HarmonyOS 实战:全链路追踪与灰度治理,构建全场景 A/B 测试与特性分发架构

欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.ZEEKLOG.net Flutter 组件 test_track 适配鸿蒙 HarmonyOS 实战:全链路追踪与灰度治理,构建全场景 A/B 测试与特性分发架构 前言 在鸿蒙(OpenHarmony)生态迈向精细化运营、涉及多端设备同步实验、大规模特性灰度发布及实时埋点分析的背景下,如何实现高可靠的“特性开关(Feature Flags)”与“用户行为追踪”,已成为决定应用迭代效率与商业决策准确性的“神经中枢”。在鸿蒙设备这类强调分布式协同与离线可用性的场景下,如果 A/B 测试逻辑依然采用简单的在线同步参数,由于由于网络波动或设备流转时的身份不一致,极易由于由于配置缺失导致应用进入不可预知的逻辑分支。 我们需要一种能够实现配置本地快照、支持访客(Visitor)身份关联且具备高可靠异步追踪记录能力的实验治理框架。 test_track 为 Flutter 开发者引入了工业级的分布式实验分发方案。它不仅支持基于标识符的恒定分流,更内置了健壮的离线追踪队列。在适配到鸿蒙

By Ne0inhk