首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >使用Spring-AI实现完整的ChatAgent产品&SpringAI源码解读

使用Spring-AI实现完整的ChatAgent产品&SpringAI源码解读

原创
作者头像
用户12060837
发布2026-02-17 21:24:28
发布2026-02-17 21:24:28
1370
举报

第一次加载时需要拉取CDN的前端JS,尽量保持网络可以访问外网,避免显示效果不全

加载完成后形成前端缓存,后续就不用拉了

share-11.png
share-11.png

share-11.png

我们首先从一些Spring AI的基础概念开始

Advisor

Advisor在spring ai中直译为顾问,其实本质上和Spring AOP切面是一种东西,内部是责任链实现,这部分Advisor主要是对chat交互过程中进行增强

比如最简单的内置日志Advisor

org.springframework.ai.chat.client.advisor.SimpleLoggerAdvisor

share-1.png
share-1.png

share-1.png

很明显看得处理adviseStream是前后增强的模式

Advisor可以扩展的很多,比如后面实现的Memory也是通过Advisor

Transformer

transformer就是转化器的意思,一般使用在大模型api交互前,比如使用org.springframework.ai.rag.preretrieval.query.transformation.TranslationQueryTransformer

进行语言转化,比如讲用户输入的英文转化为中文

工程侧Transformer原理是什么

通常来讲,Spring AI内置的Transformer都是以定制Prompt的形式实现的,其中还需要过一遍大模型的交互,以TranslationQueryTransformer为例

share-2.png
share-2.png

share-2.png

提示词很直观,就是给定用户的提问,转化为对应的语言,如果已经是该语言,则不处理,如果不是就翻译

share-3.png
share-3.png

share-3.png

需要注意的是,目前官方实现的所有Transformer都是call()模式调用的大模型,及同步调用,这种调用在如果作为组件串联在异步流程中会报错,比如使用在后面的RAG工作流的RetrievalAugmentationAdvisor中,因为无法在完全异步流程中等待同步调用

为什么不实现Transformer的stream调用

实际上自己实现一个Stream流式类型的Transformer翻译完全只需要改动几行代码,比如我们项目中

com.demo.spring.ai.fullstack.advisor.pre.StreamTranslationQueryTransformer

share-4.png
share-4.png

share-4.png

将call同步调用变成stream流式,由于要保持格式统一,还可以block等待返回完毕了再出去

但由于改动相对简单,我们可以思考一下为什么Spring官方不实现这种模式

通过观察spring-ai及spring-ai-alibaba的issue和pr,我们可以发现的一个观点是

对于功能性确定,不需要对用户展示的转化,实现流式几乎没有意义,也就是说,作为交互的一个前置流程(比如将用户的提问翻译为特定语言,然后再提交给大模型),在翻译完成之前,让大模型就异步流式执行,是不必要的,等于翻译还没完,大模型已经开始吐字了,这种情况增加了实现难度,又让异步流变得没有意义

另外,在实际的测试过程中,虽然这种异步转同步的假异步方式Transformer实现,让后续的RAG工作流能够跑通了,但实际上耗时远远超过了纯使用call()方法同步的耗时,所以在这个项目中,stream的Transformer没有默认开启

Memory

本文采用Spring AI Alibaba Memory组件来实现记忆功能,并采用Redis记忆,具体需要引入如下两个包,且版本>=1.0.0.3

展开

代码语言:YAML

自动换行

AI代码解释

代码语言:javascript

AI代码解释

代码语言:javascript
复制
<dependency>
    <groupId>com.alibaba.cloud.ai</groupId>
    <artifactId>spring-ai-alibaba-autoconfigure-memory</artifactId>
    <version>1.0.0.3</version>
</dependency>

<dependency>
    <groupId>com.alibaba.cloud.ai</groupId>
    <artifactId>spring-ai-alibaba-starter-memory-redis</artifactId>
    <version>1.0.0.3</version>
</dependency>

配置MessageWindowChatMemory,可以设置记忆的存储最大条数

展开

代码语言:Java

自动换行

AI代码解释

代码语言:javascript

AI代码解释

代码语言:javascript
复制
@Configuration
@Slf4j
public class MemoryConfig {

    private final int MAX_MESSAGES = 100;

    @Bean("messageMemory")
    public MessageWindowChatMemory messageWindowChatMemory(RedissonChatMemoryRepository redissonChatMemoryRepository) {
        log.info("Initializing MessageWindowChatMemory with max messages: {}", MAX_MESSAGES);
        return MessageWindowChatMemory.builder()
                .chatMemoryRepository(redissonChatMemoryRepository)
                .maxMessages(MAX_MESSAGES)
                .build();
    }
}

注册该记忆到对应的ChatClient

share-5.png
share-5.png

share-5.png

使用时可自定义参数,比如指明存储的会话id

share-6.png
share-6.png

share-6.png

读取历史Memeory:https://zhuanlan.zhihu.com/p/2007202578803476328

展开

代码语言:Java

自动换行

AI代码解释

代码语言:javascript

AI代码解释

代码语言:javascript
复制
@RestController
@RequestMapping("/conversation")
@Slf4j
public class ConversationController {

    @Resource
    private MessageWindowChatMemory messageWindowChatMemory;

    @GetMapping("/messages")
    public List<Message> messages(@RequestParam(value = "sessionId") String sessionId) {
        return messageWindowChatMemory.get(sessionId);
    }
}
历史会话栏聊天记录实现思路

由于demo创建的时间关系,历史会话没有去实现,以下给出实现思路

share-7.png
share-7.png

share-7.png

share-8.png
share-8.png

share-8.png

以上图为例

当用户和大模型发生交互后,历史会话会存储在redis中

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • Advisor
  • Transformer
    • 工程侧Transformer原理是什么
    • 为什么不实现Transformer的stream调用
  • Memory
    • 读取历史Memeory:https://zhuanlan.zhihu.com/p/2007202578803476328
    • 历史会话栏聊天记录实现思路
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档