返回顶部
热门问答 更多热门问答
技术文章 更多技术文章

SpringAI Alibaba实战文生图、聊天记忆功能

[复制链接]
链载Ai 显示全部楼层 发表于 1 小时前 |阅读模式 打印 上一主题 下一主题

SpringAI Alibaba通过DashScope灵积平台可以实现文生图和聊天记忆等功能,而且整合在Spring AI Alibaba一套框架内,无需额外再花功夫整合。其中文生图可以基于DashScope或者OpenAI模型,聊天会话记忆分享了内存、MySQL、Redis和SQLite等记录的方法。


文生图功能实现




首先需要注册阿里云百炼平台,上一篇文章已经分享过注册方法,记住APIKEY。

文生图利用DashScope底层原理是通过调用通义千问文生图模型实现,封装了一层公共工具到Spring AI。

通义千问文生图功能模型有:

我们先来搭建文本图项目,项目名称及坐标信息:


<groupId>org.example</groupId>
<artifactId>spring-ai-image</artifactId>
<version>1.0.0</version>
<packaging>jar</packaging>
<name>spring-ai-image</name>
<description>SpringAI文生图项目</description>




集成的SpringBoot父模型是3.4.0版本:


<parent>



<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.4.0</version>
<relativePath/>
</parent>




JDK采用17版本,UTF-8编码,Maven 3.6.3配置:


<properties>



<maven.compiler.source>17</maven.compiler.source>



<maven.compiler.target>17</maven.compiler.target>



<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>



</properties>




引入SpringBoot Web模块spring-boot-starter-web,表明它是一个Web项目:


<dependency>



<groupId>org.springframework.boot</groupId>



<artifactId>spring-boot-starter-web</artifactId>



</dependency>




引入spring-ai-alibaba-starter-dashscope,即阿里巴巴灵积模型模块:


<dependency>



<groupId>com.alibaba.cloud.ai</groupId>



<artifactId>spring-ai-alibaba-starter-dashscope</artifactId>



<version>1.0.0.1</version>



</dependency>




依赖项整体如图:

引入Maven镜像仓库:

<repositories>



<repository>
<id>sonatype-snapshots</id>
<url>https://oss.sonatype.org/content/repositories/snapshots</url>
<snapshots>
<enabled>true</enabled>
</snapshots>
</repository>
<repository>
<id>spring-milestones</id>
<name>SpringMilestones</name>
<url>https://repo.spring.io/milestone</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
<repository>
<id>spring-snapshots</id>
<name>SpringSnapshots</name>
<url>https://repo.spring.io/snapshot</url>
<releases>
<enabled>false</enabled>
</releases>
</repository>
</repositories>




然后由于是SpringBoot项目,加上Maven插件:


<build>



<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>3.4.0</version>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-deploy-plugin</artifactId>
<version>3.1.1</version>
</plugin>
</plugins>
</build>




整体Maven镜像仓库如图:

插件用的3.4.0版本:

做完这一步,开始Maven打包:

之后刷新Maven环境:

项目环境就可用了。

在/src/main/resources目录下新建application.yml配置文件:


server:



port:8080

spring:
application:
name:spring-ai-image

ai:
dashscope:
api-key:"sk-DashScopeAPIKEY"



紧接着在源码目录/src/main/java下面新建一个包:com.hyxf,然后建立一个启动类DashScopeImageApplication:


packagecom.hyxf;

importorg.springframework.boot.SpringApplication;
importorg.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
publicclassDashScopeImageApplication{

publicstaticvoidmain(String[]args){

SpringApplication.run(DashScopeImageApplication.class,args);
}

}



新建一个controller层,在com.hyxf.controller层下新建DashScopeImageController类:


packagecom.hyxf.controller;

importjakarta.servlet.http.HttpServletResponse;
importorg.springframework.ai.image.*;
importorg.springframework.http.HttpStatus;
importorg.springframework.http.MediaType;
importorg.springframework.http.ResponseEntity;
importorg.springframework.web.bind.annotation.GetMapping;
importorg.springframework.web.bind.annotation.RequestMapping;
importorg.springframework.web.bind.annotation.RequestParam;
importorg.springframework.web.bind.annotation.RestController;

importjava.io.IOException;
importjava.io.InputStream;
importjava.net.URI;
importjava.net.URL;
importjava.time.LocalDateTime;
importjava.util.Collection;
importjava.util.Map;
importjava.util.Set;
importjava.util.stream.Collectors;

@RestController
@RequestMapping("/ai")
publicclassDashScopeImageController{

privatefinalImageModelimageModel;

privatestaticfinalStringDEFAULT_PROMPT="为人工智能生成一张富有科技感的图片!";

publicDashScopeImageController(ImageModelimageModel){
this.imageModel=imageModel;
}

@GetMapping("/image")
publicvoidimage(HttpServletResponseresponse){

ImageResponseimageResponse=imageModel.call(newImagePrompt(DEFAULT_PROMPT));
StringimageUrl=imageResponse.getResult().getOutput().getUrl();

try{
URLurl=URI.create(imageUrl).toURL();
InputStreamin=url.openStream();

response.setHeader("Content-Type",MediaType.IMAGE_PNG_VALUE);
response.getOutputStream().write(in.readAllBytes());
response.getOutputStream().flush();
}catch(IOExceptione){
response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
}
}

/**
* Generates multiple images from single prompt.
*/
@GetMapping("/image/multiPrompt")
publicResponseEntity<Collection<String>>generateImageWithMultiPrompt(
@RequestParam(value="prompt",defaultValue="一只会编程的猫")Stringprompt,
@RequestParam(defaultValue="2")intcount){

ImageOptionsoptions=ImageOptionsBuilder.builder()
.N(count)
.build();
ImageResponseresponse=imageModel.call(newImagePrompt(prompt,options));
Set<String>imageSet=response.getResults().stream().map(result->result.getOutput().getUrl()).collect(Collectors.toSet());
returnResponseEntity.ok(imageSet);
}

/**
* multi condition and safe to generation image
*/
@GetMapping("/image/multipleConditions")
publicResponseEntity<?>multipleConditions(
@RequestParam(value="subject",defaultValue="一只会编程的猫")Stringsubject,
@RequestParam(value="environment",defaultValue="办公室")Stringenvironment,
@RequestParam(value="height",defaultValue="1024")Integerheight,
@RequestParam(value="width",defaultValue="1024")Integerwidth,
@RequestParam(value="style",defaultValue="生动")Stringstyle){

Stringprompt=String.format(
"一个%s,置身于%s的环境中,使用%s的艺术风格,高清4K画质,细节精致",
subject,environment,style
);

ImageOptionsoptions=ImageOptionsBuilder.builder()
.height(height)
.width(width)
.build();

try{
ImageResponseresponse=imageModel.call(newImagePrompt(prompt,options));
returnResponseEntity.ok(response.getResult().getOutput().getUrl());
}catch(Exceptione){
returnResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
.body(Map.of(
"error","图像生成失败",
"message",e.getMessage(),
"timestamp",LocalDateTime.now()
));
}
}

}



如图:

其中


privatefinalImageModelimageModel;




使用的是

importorg.springframework.ai.image.*;




依赖,Spring AI已经整合好ImageModel够大家使用。

ImageModel也需要注入Controller:


publicDashScopeImageController(ImageModelimageModel){



this.imageModel=imageModel;



}




调用图片模型,获取返回的response数据,并显示图片:


@GetMapping("/image")
publicvoidimage(HttpServletResponseresponse){

ImageResponseimageResponse=imageModel.call(newImagePrompt(DEFAULT_PROMPT));
StringimageUrl=imageResponse.getResult().getOutput().getUrl();

try{
URLurl=URI.create(imageUrl).toURL();
InputStreamin=url.openStream();

response.setHeader("Content-Type",MediaType.IMAGE_PNG_VALUE);
response.getOutputStream().write(in.readAllBytes());
response.getOutputStream().flush();
}catch(IOExceptione){
response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
}
}




启动项目DashScopeImageApplication类,查看运行:

在浏览器输入:http://localhost:8080/ai/image

生成了一张科技感的图片:

你还可以修改指令:


privatestaticfinalStringDEFAULT_PROMPT="为人工智能生成一张富有科技感的图片!";




来生成各式各样的图片,根据指令提示词。

生成多张图片,根据指令和图片生成数量,修改ImageModel参数,来生成要求的图片:


@GetMapping("/image/multiPrompt")
publicResponseEntity<Collection<String>>generateImageWithMultiPrompt(
@RequestParam(value="prompt",defaultValue="一只会编程的猫")Stringprompt,
@RequestParam(defaultValue="2")intcount){

ImageOptionsoptions=ImageOptionsBuilder.builder()
.N(count)
.build();
ImageResponseresponse=imageModel.call(newImagePrompt(prompt,options));
Set<String>imageSet=response.getResults().stream().map(result->result.getOutput().getUrl()).collect(Collectors.toSet());
returnResponseEntity.ok(imageSet);
}




其中ImageOptions设置了张数,根据指令并入ImageModel参数,来获取结果,我们打开浏览器:

http://localhost:8080/ai/image/multiPrompt?prompt=一只机械狗&count=3

运行查看结果,出来三张图片url路径:

我们将路径复制到浏览器查看,下载到本地,打开看图片:

帮我们生成了机械狗照片。

手动设置指令,动态传入参数示例:


@GetMapping("/image/multipleConditions")
publicResponseEntity<?>multipleConditions(
@RequestParam(value="subject",defaultValue="一只会编程的猫")Stringsubject,
@RequestParam(value="environment",defaultValue="办公室")Stringenvironment,
@RequestParam(value="height",defaultValue="1024")Integerheight,
@RequestParam(value="width",defaultValue="1024")Integerwidth,
@RequestParam(value="style",defaultValue="生动")Stringstyle){

Stringprompt=String.format(
"一个%s,置身于%s的环境中,使用%s的艺术风格,高清4K画质,细节精致",
subject,environment,style
);

ImageOptionsoptions=ImageOptionsBuilder.builder()
.height(height)
.width(width)
.build();

try{
ImageResponseresponse=imageModel.call(newImagePrompt(prompt,options));
returnResponseEntity.ok(response.getResult().getOutput().getUrl());
}catch(Exceptione){
returnResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
.body(Map.of(
"error","图像生成失败",
"message",e.getMessage(),
"timestamp",LocalDateTime.now()
));
}
}




可以调整宽高和指令,动态控制,我们打开浏览器输入:http://localhost:8080/ai/image/multipleConditions

将路径拷贝至浏览器,下载查看:

生成了一只编程猫,1024*1024像素。

这些是文生图功能,接下来进入聊天记忆功能。


模型聊天会话记忆功能




大家在使用大模型聊天过程中,常常需要上下文功能,来补足对话,如果不能记得上下文,大模型可能会出现幻觉等状况,胡说八道。

这个时候就需要模型记忆功能了。

模型记忆的核心在于Spring AI提供的三个Memory模块:

内存记忆模块:


<dependency>



<groupId>com.alibaba.cloud.ai</groupId>



<artifactId>spring-ai-alibaba-starter-memory</artifactId>



<version>1.0.0.1</version>



</dependency>




JDBC记忆模块:


<dependency>



<groupId>com.alibaba.cloud.ai</groupId>



<artifactId>spring-ai-alibaba-starter-memory-jdbc</artifactId>



<version>1.0.0.1</version>



</dependency>




Redis记忆模块:


<dependency>



<groupId>com.alibaba.cloud.ai</groupId>



<artifactId>spring-ai-alibaba-starter-memory-redis</artifactId>



<version>1.0.0.1</version>



</dependency>




此外还需要引入Redis、MySQL驱动包:


<dependency>



<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>5.2.0</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.32</version>
</dependency>




如果要用到SQLite,还需SQLite驱动:


<dependency>



<groupId>org.xerial</groupId>



<artifactId>sqlite-jdbc</artifactId>



<version>3.49.1.0</version>



</dependency>




引入向量数据库和ES作为知识库底蕴:


<dependency>



<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-advisors-vector-store</artifactId>
<version>1.0.0</version>
</dependency>
<dependency>
<groupId>co.elastic.clients</groupId>
<artifactId>elasticsearch-java</artifactId>
<version>8.15.5</version>
</dependency>




其中SpringBoot父模块还是3.4.0:


<parent>



<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.4.0</version>
<relativePath/>
</parent>




JDK依然是17,UTF-8编码:


<properties>



<maven.compiler.source>17</maven.compiler.source>



<maven.compiler.target>17</maven.compiler.target>



<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>



</properties>




引入Spring Boot Web和DashScope模型:


<dependency>



<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud.ai</groupId>
<artifactId>spring-ai-alibaba-starter-dashscope</artifactId>
<version>1.0.0.1</version>
</dependency>




Maven私服镜像不要忘了:

Maven打包插件神器:

右边Maven Install之后记得刷新Maven环境:

之后将chat-memory.db SQLite数据库文件放入/src/main/resources目录下,下载方式:

下载下来拷贝到/src/main/resources目录下:

在你的电脑环境中确保Redis和MySQL已安装,没有安装的话去查看相关Redis和MySQL安装方式。

然后在/src/main/resources目录下新建application.yml文件,内容如下:


server:



port:8080

spring:
ai:
dashscope:
api-key:"sk-DashScopeAPIKEY"
memory:
redis:
host:localhost
port:6379
password:
timeout:5000
chat:
memory:
repository:
jdbc:
mysql:
jdbc-url:jdbc:mysql://localhost:3306/spring_ai_alibaba_mysql?useUnicode=true&characterEncoding=utf-8&useSSL=false&allowPublicKeyRetrieval=true&zeroDateTimeBehavior=convertToNull&transformedBitIsBoolean=true&allowMultiQueries=true&tinyInt1isBit=false&allowLoadLocalInfile=true&allowLocalInfile=true&allowUrl
username:root
password:123456
driver-class-name:com.mysql.cj.jdbc.Driver
enabled:true



其中spring.ai.memory.redis配置Redis连接存储地址,请配置为你环境中的Redis。

spring.ai.chat.memory.repository.jdbc设置JDBC连接存储地址,配置为你电脑环境中的Redis。

如图:

新建com.hyxf包,包中新建启动类:


packagecom.hyxf;

importorg.springframework.boot.SpringApplication;
importorg.springframework.boot.autoconfigure.SpringBootApplication;
importorg.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;

@SpringBootApplication(exclude={DataSourceAutoConfiguration.class})
publicclassChatMemoryApplication{

publicstaticvoidmain(String[]args){

SpringApplication.run(ChatMemoryApplication.class,args);
}

}



此外,还需要Spring AI Memory配置文件,我们新建com.hyxf.config包,在包下新建MemoryConfig文件:


packagecom.hyxf.config;

importcom.alibaba.cloud.ai.memory.jdbc.MysqlChatMemoryRepository;
importcom.alibaba.cloud.ai.memory.jdbc.SQLiteChatMemoryRepository;
importcom.alibaba.cloud.ai.memory.redis.RedisChatMemoryRepository;
importorg.springframework.beans.factory.annotation.Value;
importorg.springframework.context.annotation.Bean;
importorg.springframework.context.annotation.Configuration;
importorg.springframework.jdbc.core.JdbcTemplate;
importorg.springframework.jdbc.datasource.DriverManagerDataSource;

@Configuration
publicclassMemoryConfig{

@Value("${spring.ai.memory.redis.host}")
privateStringredisHost;
@Value("${spring.ai.memory.redis.port}")
privateintredisPort;
@Value("${spring.ai.memory.redis.password}")
privateStringredisPassword;
@Value("${spring.ai.memory.redis.timeout}")
privateintredisTimeout;

@Value("${spring.ai.chat.memory.repository.jdbc.mysql.jdbc-url}")
privateStringmysqlJdbcUrl;
@Value("${spring.ai.chat.memory.repository.jdbc.mysql.username}")
privateStringmysqlUsername;
@Value("${spring.ai.chat.memory.repository.jdbc.mysql.password}")
privateStringmysqlPassword;
@Value("${spring.ai.chat.memory.repository.jdbc.mysql.driver-class-name}")
privateStringmysqlDriverClassName;

@Bean
publicSQLiteChatMemoryRepositorysqliteChatMemoryRepository(){
DriverManagerDataSourcedataSource=newDriverManagerDataSource();
dataSource.setDriverClassName("org.sqlite.JDBC");
dataSource.setUrl("jdbc:sqlite:spring-ai-dashscope-memory/src/main/resources/chat-memory.db");
JdbcTemplatejdbcTemplate=newJdbcTemplate(dataSource);
returnSQLiteChatMemoryRepository.sqliteBuilder()
.jdbcTemplate(jdbcTemplate)
.build();
}

@Bean
publicMysqlChatMemoryRepositorymysqlChatMemoryRepository(){
DriverManagerDataSourcedataSource=newDriverManagerDataSource();
dataSource.setDriverClassName(mysqlDriverClassName);
dataSource.setUrl(mysqlJdbcUrl);
dataSource.setUsername(mysqlUsername);
dataSource.setPassword(mysqlPassword);
JdbcTemplatejdbcTemplate=newJdbcTemplate(dataSource);
returnMysqlChatMemoryRepository.mysqlBuilder()
.jdbcTemplate(jdbcTemplate)
.build();
}

@Bean
publicRedisChatMemoryRepositoryredisChatMemoryRepository(){
returnRedisChatMemoryRepository.builder()
.host(redisHost)
.port(redisPort)
// 若没有设置密码则注释该项
// .password(redisPassword)
.timeout(redisTimeout)
.build();
}
}



注入ChatMemory地址,其中SQLite这个项目名称需要替换为你的实际项目名称:

然后可以开始写controller接口层了,新建InMemoryController类,注入聊天客户端:


privatefinalChatClientchatClient;




导入的功能包如下,其中CONVERSATION_ID表示聊天记录会话id:


importorg.springframework.ai.chat.client.ChatClient;
importorg.springframework.ai.chat.client.advisor.MessageChatMemoryAdvisor;
importorg.springframework.ai.chat.memory.InMemoryChatMemoryRepository;
importorg.springframework.ai.chat.memory.MessageWindowChatMemory;
importorg.springframework.ai.chat.messages.Message;
importstaticorg.springframework.ai.chat.memory.ChatMemory.CONVERSATION_ID;




内存存储聊天记录,并设置最大消息条数:


privatefinalInMemoryChatMemoryRepositorychatMemoryRepository=newInMemoryChatMemoryRepository();
privatefinalintMAX_MESSAGES=100;
privatefinalMessageWindowChatMemorymessageWindowChatMemory=MessageWindowChatMemory.builder()
.chatMemoryRepository(chatMemoryRepository)
.maxMessages(MAX_MESSAGES)
.build();




Controller设置聊天工具:


publicInMemoryController(ChatClient.Builderbuilder){
this.chatClient=builder
.defaultAdvisors(
MessageChatMemoryAdvisor.builder(messageWindowChatMemory)
.build()
)
.build();
}




调用聊天信息,并存储记录:


@GetMapping("/call")
publicStringcall(@RequestParam(value="query",defaultValue="你好,我的外号是阿紫,请记住呀")Stringquery,
@RequestParam(value="conversation_id",defaultValue="azi")StringconversationId
){
returnchatClient.prompt(query)
.advisors(
a->a.param(CONVERSATION_ID,conversationId)
)
.call().content();
}




如图:

启动项目,打开PostMan,输入url:

http://localhost:8080/advisor/memory/in/call

设置记忆参数,取外号:

记住了我的外号,再输入新的聊天指令:

这些聊天记录已被存储到内存中,再看看获取聊天记录的接口:


@GetMapping("/messages")
publicList<Message>messages(@RequestParam(value="conversation_id",defaultValue="azi")StringconversationId){
returnmessageWindowChatMemory.get(conversationId);
}




POSTMAN调用:http://localhost:8080/advisor/memory/in/messages?conversation_id=azi

存储了历史记录信息:

接下来我们来试试MySQL存储历史记录的功能,新建Controller:


packagecom.hyxf.controller;

importcom.alibaba.cloud.ai.memory.jdbc.MysqlChatMemoryRepository;
importorg.springframework.ai.chat.client.ChatClient;
importorg.springframework.ai.chat.client.advisor.MessageChatMemoryAdvisor;
importorg.springframework.ai.chat.memory.MessageWindowChatMemory;
importorg.springframework.ai.chat.messages.Message;
importorg.springframework.web.bind.annotation.GetMapping;
importorg.springframework.web.bind.annotation.RequestMapping;
importorg.springframework.web.bind.annotation.RequestParam;
importorg.springframework.web.bind.annotation.RestController;

importjava.util.List;

importstaticorg.springframework.ai.chat.memory.ChatMemory.CONVERSATION_ID;

@RestController
@RequestMapping("/advisor/memory/mysql")
publicclassMysqlMemoryController{

privatefinalChatClientchatClient;
privatefinalintMAX_MESSAGES=100;
privatefinalMessageWindowChatMemorymessageWindowChatMemory;

publicMysqlMemoryController(ChatClient.Builderbuilder,MysqlChatMemoryRepositorymysqlChatMemoryRepository){
this.messageWindowChatMemory=MessageWindowChatMemory.builder()
.chatMemoryRepository(mysqlChatMemoryRepository)
.maxMessages(MAX_MESSAGES)
.build();

this.chatClient=builder
.defaultAdvisors(
MessageChatMemoryAdvisor.builder(messageWindowChatMemory)
.build()
)
.build();
}

@GetMapping("/call")
publicStringcall(@RequestParam(value="query",defaultValue="你好,我的外号是阿紫,请记住呀")Stringquery,
@RequestParam(value="conversation_id",defaultValue="azi")StringconversationId
){
returnchatClient.prompt(query)
.advisors(
a->a.param(CONVERSATION_ID,conversationId)
)
.call().content();
}

@GetMapping("/messages")
publicList<Message>messages(@RequestParam(value="conversation_id",defaultValue="azi")StringconversationId){
returnmessageWindowChatMemory.get(conversationId);
}
}




具体存储信息采用的是

MysqlChatMemoryRepository




来存储历史记录,会自动创建表存储历史信息。

将新建的ai_chat_memory表执行以下命令,修改字符集:


--修改数据库字符集
ALTER DATABASE your_database CHARACTER SET utf8mb4COLLATEutf8mb4_unicode_ci;

--修改数据表字符集
ALTER TABLE ai_chat_memoryCONVERT TO CHARACTER SET utf8mb4COLLATEutf8mb4_unicode_ci;

--单独修改某一列(如 content)
ALTER TABLE ai_chat_memoryMOdify content TEXT CHARACTER SET utf8mb4COLLATEutf8mb4_unicode_ci;



打开POSTMAN运行:

http://localhost:8080/advisor/memory/mysql/call

然后再问一个问题:

我们查看ai_chat_memory,表中已经有了历史记录:

我们运行查看历史记录url的接口:

http://localhost:8080/advisor/memory/mysql/messages?conversation_id=azi

接下来我们来测试Redis历史记录的功能,新建Controller接口:


packagecom.hyxf.controller;

importcom.alibaba.cloud.ai.memory.redis.RedisChatMemoryRepository;
importorg.springframework.ai.chat.client.ChatClient;
importorg.springframework.ai.chat.client.advisor.MessageChatMemoryAdvisor;
importorg.springframework.ai.chat.memory.MessageWindowChatMemory;
importorg.springframework.ai.chat.messages.Message;
importorg.springframework.web.bind.annotation.GetMapping;
importorg.springframework.web.bind.annotation.RequestMapping;
importorg.springframework.web.bind.annotation.RequestParam;
importorg.springframework.web.bind.annotation.RestController;

importjava.util.List;

importstaticorg.springframework.ai.chat.memory.ChatMemory.CONVERSATION_ID;

@RestController
@RequestMapping("/advisor/memory/redis")
publicclassRedisMemoryController{

privatefinalChatClientchatClient;
privatefinalintMAX_MESSAGES=100;
privatefinalMessageWindowChatMemorymessageWindowChatMemory;

publicRedisMemoryController(ChatClient.Builderbuilder,RedisChatMemoryRepositoryredisChatMemoryRepository){
this.messageWindowChatMemory=MessageWindowChatMemory.builder()
.chatMemoryRepository(redisChatMemoryRepository)
.maxMessages(MAX_MESSAGES)
.build();

this.chatClient=builder
.defaultAdvisors(
MessageChatMemoryAdvisor.builder(messageWindowChatMemory)
.build()
)
.build();
}

@GetMapping("/call")
publicStringcall(@RequestParam(value="query",defaultValue="你好,我的外号是阿紫,请记住呀")Stringquery,
@RequestParam(value="conversation_id",defaultValue="azi")StringconversationId
){
returnchatClient.prompt(query)
.advisors(
a->a.param(CONVERSATION_ID,conversationId)
)
.call().content();
}

@GetMapping("/messages")
publicList<Message>messages(@RequestParam(value="conversation_id",defaultValue="azi")StringconversationId){
returnmessageWindowChatMemory.get(conversationId);
}
}




其中使用了RedisChatMemoryRepository作为存储历史记录数据库。

打开PostMan运行:

http://localhost:8080/advisor/memory/redis/call

再问一个问题

我们调用查看及历史记录接口:

http://localhost:8080/advisor/memory/redis/messages?conversation_id=azi

最后来测试下SQLite功能,新建SQLite历史记录接口:


packagecom.hyxf.controller;

importcom.alibaba.cloud.ai.memory.jdbc.SQLiteChatMemoryRepository;
importorg.springframework.ai.chat.client.ChatClient;
importorg.springframework.ai.chat.client.advisor.MessageChatMemoryAdvisor;
importorg.springframework.ai.chat.memory.MessageWindowChatMemory;
importorg.springframework.ai.chat.messages.Message;
importorg.springframework.web.bind.annotation.GetMapping;
importorg.springframework.web.bind.annotation.RequestMapping;
importorg.springframework.web.bind.annotation.RequestParam;
importorg.springframework.web.bind.annotation.RestController;

importjava.util.List;

importstaticorg.springframework.ai.chat.memory.ChatMemory.CONVERSATION_ID;

@RestController
@RequestMapping("/advisor/memory/sqlite")
publicclassSqliteMemoryController{

privatefinalChatClientchatClient;
privatefinalintMAX_MESSAGES=100;
privatefinalMessageWindowChatMemorymessageWindowChatMemory;

publicSqliteMemoryController(ChatClient.Builderbuilder,SQLiteChatMemoryRepositorysqliteChatMemoryRepository){
this.messageWindowChatMemory=MessageWindowChatMemory.builder()
.chatMemoryRepository(sqliteChatMemoryRepository)
.maxMessages(MAX_MESSAGES)
.build();

this.chatClient=builder
.defaultAdvisors(
MessageChatMemoryAdvisor.builder(messageWindowChatMemory)
.build()
)
.build();
}

@GetMapping("/call")
publicStringcall(@RequestParam(value="query",defaultValue="你好,我的外号是阿紫,请记住呀")Stringquery,
@RequestParam(value="conversation_id",defaultValue="azi")StringconversationId
){
returnchatClient.prompt(query)
.advisors(
a->a.param(CONVERSATION_ID,conversationId)
)
.call().content();
}

@GetMapping("/messages")
publicList<Message>messages(@RequestParam(value="conversation_id",defaultValue="azi")StringconversationId){
returnmessageWindowChatMemory.get(conversationId);
}
}



打开PostMan发送消息给SQLite:

http://localhost:8080/advisor/memory/sqlite/call

再问个问题

查看SQLite历史记录:

http://localhost:8080/advisor/memory/sqlite/messages?conversation_id=azi

如果大家想新设置会话窗口,只需要传入新的conversation_id即可。

在实际AI应用中,会话聊天记忆功能非常重要,介绍了内存、MySQL、Redis、SQLite分别存储历史记录的方法,可灵活应用。

回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

链载AI是专业的生成式人工智能教程平台。提供Stable Diffusion、Midjourney AI绘画教程,Suno AI音乐生成指南,以及Runway、Pika等AI视频制作与动画生成实战案例。从提示词编写到参数调整,手把手助您从入门到精通。
  • 官方手机版

  • 微信公众号

  • 商务合作

  • Powered by Discuz! X3.5 | Copyright © 2025-2025. | 链载Ai
  • 桂ICP备2024021734号 | 营业执照 | |广西笔趣文化传媒有限公司|| QQ