反物质维度
69.50M · 2026-03-22
大家好,我是野人。作为一名AI新手,当你第一次接触Spring AI时,可能会被各种概念弄晕:什么是ChatClient?什么是Advisor?怎么让AI记住我之前说的话?
别担心,本文将通过一个生动的 “恋爱助手” 案例,带你一步步梳理这些核心概念,并最终实现一个支持多轮对话的AI应用。
在Spring AI的世界里,ChatClient是你与大模型对话的主要入口。你可以把它想象成一个智能电话,你对着它说话,它帮你接通并转告给真正的大模型(如通义千问、ChatGPT)。
那么,如何获得这个“电话”呢?主要有两种方式:
这种方式代码清晰,便于测试和维护。就像你去营业厅,明确告诉工作人员你需要什么配置的电话。
这种方式比较直接,通过@Autowired拿到模型,然后手动用模型去创建电话
新手提示: 推荐使用第一种方式(构造器注入),因为它更符合Spring的规范,并且在你后续需要添加更多功能(比如拦截器)时会更加灵活。
光有电话还不够,我们有时想在打电话前先检查一下信号(检查提示词),或者在挂电话后记录一下通话内容(记录日志)。Spring AI 的 Advisors(顾问) 就是用来做这个的。
你可以把 Advisor 想象成一个个 “拦截器” ,它们像洋葱一样层层包裹住真正的大模型。你的话(Prompt)要先经过这些顾问才能传给模型,模型的回答也要经过它们才能返回来。
执行流程拆解:
AdvisedRequest。AroundAdvisor 链。每个顾问都可以查看或修改你的问题。ChatModel(大模型)。AdvisedResponse,再次逆序经过顾问链。顾问们可以查看或修改这个结果。默认情况下,大模型是没有记忆的。你问“你好”,它回答“你好”;你接着问“我刚才说了什么?”,它就忘了。为了让AI能记住上下文(实现多轮对话),我们就需要用到 ChatMemoryAdvisor。
Spring AI 提供了几种把“记忆”塞给AI的方式:
顾问本身不负责存数据,它只是负责“取”和“放”。真正存数据的是 ChatMemory。
Spring AI 提供了多种存储方案:
InMemoryChatMemory:存在内存里(程序重启就没了,适合测试)。JdbcChatMemory:存在数据库里(永久保存)。现在,我们把上面的知识都串起来,写一个真正的 LoveApp。这个助手不仅能以恋爱专家的身份回答你,还能记住你上一轮说了什么(多轮对话)。
项目需求:
chatId区分不同用户的对话历史。完整代码实现:
package com.swl.baoaiagent.app;
import lombok.extern.slf4j.Slf4j;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.chat.client.advisor.MessageChatMemoryAdvisor;
import org.springframework.ai.chat.memory.ChatMemory;
import org.springframework.ai.chat.memory.InMemoryChatMemory;
import org.springframework.ai.chat.model.ChatModel;
import org.springframework.ai.chat.model.ChatResponse;
import org.springframework.stereotype.Component;
import static org.springframework.ai.chat.client.advisor.AbstractChatMemoryAdvisor.CHAT_MEMORY_CONVERSATION_ID_KEY;
import static org.springframework.ai.chat.client.advisor.AbstractChatMemoryAdvisor.CHAT_MEMORY_RETRIEVE_SIZE_KEY;
@Component
@Slf4j
public class LoveApp {
// 对话客户端
private ChatClient chatClient;
// 系统预设:告诉AI它该扮演什么角色
private static final String SYSTEM_PROMPT = "扮演深耕恋爱心理领域的专家。开场向用户表明身份,告知用户可倾诉恋爱难题。围绕单身、恋爱、已婚三种状态提问:单身状态询问社交圈拓展及追求心仪对象的困扰;恋爱状态询问沟通、习惯差异引发的矛盾;已婚状态询问家庭责任与亲属关系处理的问题。引导用户详述事情经过、对方反应及自身想法,以便给出专属解决方案。";
/**
* 构造函数:初始化AI助手
* @param dashscopeChatModel Spring注入的通义千问模型
*/
public LoveApp(ChatModel dashscopeChatModel) {
// 1. 创建记忆存储器(这里先用内存存储,方便测试)
ChatMemory chatMemory = new InMemoryChatMemory();
// 2. 构建ChatClient,并装配上“记忆顾问”
this.chatClient = ChatClient.builder(dashscopeChatModel)
.defaultSystem(SYSTEM_PROMPT) // 设置角色
.defaultAdvisors(
// 使用链式构造器创建记忆顾问
MessageChatMemoryAdvisor.builder(chatMemory).build()
)
.build();
}
/**
* AI 基础对话方法(支持多轮对话)
* @param message 用户输入的消息
* @param chatId 会话ID(用于区分不同用户的对话)
* @return AI 的回复内容
*/
public String doChat(String message, String chatId){
// 发起对话
ChatResponse chatResponse = chatClient.prompt()
.user(message) // 用户说:我最近和女朋友吵架了
.advisors(spec -> spec
// 告诉顾问:这是谁的对话(张三还是李四)
.param(CHAT_MEMORY_CONVERSATION_ID_KEY, chatId)
// 告诉顾问:取最近几条历史记录?(这里取最近10条,后进先出)
.param(CHAT_MEMORY_RETRIEVE_SIZE_KEY, 10))
.call() // 拨打电话
.chatResponse(); // 等待回复
// 解析回复
String content = chatResponse.getResult().getOutput().getText();
log.info("AI回复: {}", content);
return content;
}
}
构造函数:
ChatModel(大模型)。InMemoryChatMemory 作为临时记忆仓库。ChatClient.builder(...) 进行链式配置:设置系统提示词 (SYSTEM_PROMPT),并装配默认顾问 (MessageChatMemoryAdvisor)。doChat 方法:
关键点1:chatId:这是一个非常重要的参数。它就像一个文件夹标签,告诉程序这个对话是属于“用户A”还是“用户B”。如果没有它,所有人的对话就会混在一起。
关键点2:advisors 配置:我们在调用prompt()时,通过advisors动态指定了两个参数:
CHAT_MEMORY_CONVERSATION_ID_KEY:指定本次对话属于哪个会话ID。CHAT_MEMORY_RETRIEVE_SIZE_KEY:指定从记忆中取回多少条最近的对话。这里设置为10,意味着AI会看到最近10轮(用户和AI一来一回算一轮)的聊天记录。通过这个简单的恋爱助手例子,你应该对Spring AI有了一个初步的认识:
ChatClient 是你的AI应用的核心API。Advisors 是强大的拦截器机制,用于横切关注点(如记忆、审核、日志)。ChatMemoryAdvisor + ChatMemory 是实现多轮对话记忆的黄金搭档。Advisor负责处理逻辑,ChatMemory负责存储数据。现在,你可以试着运行这个程序,连续问它几个关于恋爱的问题,比如“我喜欢一个女孩但不敢表白怎么办?”,然后接着问“你刚才建议我第一步做什么?”,你会发现,AI已经记住了你们的对话内容。
开源文档:mubaodian/bao-ai-agent: AI超级智能体