你是否也遇到过这样的场景:用Spring AI写一个智能客服,每次调用都要手动拼接提示词、注入对话历史、处理RAG检索结果,代码越写越臃肿?这就是很多开发者在使用Spring AI时的真实痛点——明明只是想做AI采购助手,却要花大量精力处理重复的“周边逻辑”。其实,Spring AI早已通过ChatClient + Advisor的架构设计,将AI应用的开发模式从“拼积木”变成了“搭流水线” 。本文将带你从零到一构建一个企业级AI采购助手,深入理解ChatClient与Advisor的关系与实现原理,并提供可运行的代码示例和高频面试要点。
一、痛点切入:为什么传统AI调用方式“又臭又长”?

先看一段不使用Advisor的“裸调用”代码:
@Servicepublic class PurchaseAssistantService { @Autowired private ChatModel chatModel; @Autowired private VectorStore vectorStore; public String askPurchase(String userQuery) { // 1. RAG检索:从向量库中获取相关采购知识 List<Document> docs = vectorStore.similaritySearch(userQuery); String context = docs.stream().map(Document::getContent).collect(Collectors.joining("\n")); // 2. 手动拼接提示词模板 String systemPrompt = "你是一个采购助手,根据以下上下文回答问题:\n" + context; String fullPrompt = systemPrompt + "\n用户问题:" + userQuery; // 3. 构造消息并调用模型 UserMessage userMsg = new UserMessage(fullPrompt); ChatResponse response = chatModel.call(new Prompt(userMsg)); // 4. 手动记录对话历史(如果需要多轮对话) // ... 大量重复代码 return response.getResult().getOutput().getContent(); } }
这段代码的痛点非常明显:
耦合度高:RAG检索、提示词拼接、模型调用全部混在一起,改一个环节就要动整个方法
扩展性差:想加对话记忆?改代码。想加日志拦截?改代码。想加安全过滤?还是改代码
代码冗余:每个AI接口方法都要重复写类似的RAG、提示词、模型调用逻辑
这就是Spring AI引入Advisor机制的设计初衷——让开发者只关心“核心业务逻辑”,把横切关注点(RAG、对话记忆、日志、过滤等)交给可插拔的Advisor处理-5。
二、核心概念讲解:ChatClient
定义
ChatClient 是Spring AI提供的面向应用层的高级Fluent API,用于与大语言模型进行通信。它不是一个新的模型抽象,而是在底层ChatModel之上的“服务层封装”,通过链式调用让开发者以更自然的方式构建Prompt、配置参数、挂载Advisor-5。
拆解关键词
Fluent(流式接口) :像
StringBuilder一样通过.链式调用,代码可读性极高Client(客户端) :它是一个“客户端”而非模型本身,类似于WebClient之于HTTP请求
Builder模式:通过Builder完成配置,支持默认参数复用
生活化类比
想象你去一家高级餐厅点餐:
ChatModel 就是厨房:你告诉厨房“做一份红烧肉”,它只关心怎么做菜
ChatClient 就是服务员:你可以通过服务员点餐,服务员会帮你记录忌口、确认口味偏好、打包带走的整个流程
ChatClient让你不用自己进厨房,只需要和服务员说话就行。
核心作用
ChatClient解决的问题是协调多个组件的复杂性。一个典型的AI应用需要提示词模板、对话记忆、RAG组件、输出解析器等多个模块协同工作,如果用原子API(ChatModel、Message等)硬编码,将产生大量样板代码。ChatClient将这些复杂性隐藏在背后,提供了一键式的调用体验-31。
三、关联概念讲解:Advisor
定义
Advisor 是Spring AI中的拦截器(Interceptor),它在ChatClient的调用链中拦截、修改和增强AI驱动的交互。Advisor处理ChatClientRequest和ChatClientResponse对象,通过getOrder()值决定执行顺序,最后一个Advisor负责真正调用LLM-2-4。
与ChatClient的关系
| 维度 | ChatClient | Advisor |
|---|---|---|
| 角色定位 | 调用方 / 客户端 | 拦截器 / 增强器 |
| 职责 | 发起请求、接收响应 | 在请求前后做额外处理 |
| 类比 | 水管总闸 | 水管上的过滤器 |
| 数量关系 | 1个ChatClient | 可挂载多个Advisor |
一句话记忆:ChatClient 是“怎么调”,Advisor 是“调之前/之后做什么”。
内置Advisor类型
Spring AI提供了多种内置Advisor实现-4:
对话记忆Advisor(
MessageChatMemoryAdvisor):自动注入历史对话上下文,实现多轮对话-22RAG Advisor:自动执行向量检索,将结果拼入Prompt
日志Advisor(
SimpleLoggerAdvisor):记录每次调用的请求和响应护栏Advisor(Guardrails):过滤敏感词、防止提示词注入
Advisor的工作原理(示意代码)
public class MyPurchaseAdvisor implements CallAdvisor { @Override public int getOrder() { return 100; } // 数字越小越先执行 @Override public ChatClientResponse adviseCall(ChatClientRequest request, CallAdvisorChain chain) { // 前置处理:修改/增强请求 System.out.println("【前置】用户问题:" + request.userText()); request = enhanceRequestWithPurchaseKnowledge(request); // 调用链中的下一个Advisor(或最终调用LLM) ChatClientResponse response = chain.nextCall(request); // 后置处理:修改/增强响应 System.out.println("【后置】AI回答:" + response.assistantResponse()); return formatResponse(response); } }
四、概念关系与区别总结
用一张表格直观对比ChatClient和Advisor:
| 对比维度 | ChatClient | Advisor |
|---|---|---|
| 英文全称 | Chat Client | Advisor |
| 本质 | Fluent API客户端 | 拦截器(Interceptor) |
| 设计思想 | 门面模式(Facade) | 责任链模式(Chain of Responsibility) |
| 控制方向 | 主动调用 | 被动拦截 |
| 是否必需 | 是,核心调用入口 | 否,可选增强 |
| 依赖关系 | 依赖ChatModel | 依赖ChatClient执行链 |
一句话概括:ChatClient是“调用AI的大门”,Advisor是“大门上的安检和装饰”,门只有一个,但可以挂多个安检模块。
五、代码示例:打造企业级AI采购助手
5.1 项目依赖(build.gradle / pom.xml)
<dependency> <groupId>org.springframework.ai</groupId> <artifactId>spring-ai-openai-spring-boot-starter</artifactId> <version>1.0.0</version> </dependency> <dependency> <groupId>org.springframework.ai</groupId> <artifactId>spring-ai-pgvector-store-spring-boot-starter</artifactId> <version>1.0.0</version> </dependency>
5.2 配置ChatClient(含默认Advisor)
@Configuration public class AIConfig { @Bean public ChatClient purchaseChatClient(ChatClient.Builder builder) { return builder // 默认系统提示词:定义AI的角色 .defaultSystem("你是一个专业的企业采购助手," + "负责回答关于采购流程、供应商管理、采购成本优化等方面的问题。" + "请基于提供的采购知识库上下文给出准确回答。") // 默认RAG Advisor:自动从向量库检索知识 .defaultAdvisors(new RAGAdvisor()) // 默认对话记忆Advisor:保持10轮对话历史 .defaultAdvisors(new MessageChatMemoryAdvisor(new InMemoryChatMemory(), 10)) // 默认日志Advisor:记录每次调用 .defaultAdvisors(new SimpleLoggerAdvisor()) .build(); } }
5.3 实现RAG Advisor(核心)
@Component public class RAGAdvisor implements CallAdvisor { @Autowired private VectorStore vectorStore; // 采购知识库向量存储 @Override public String getName() { return "RAGAdvisor"; } @Override public int getOrder() { return 10; } // 优先级较高,先做检索 @Override public ChatClientResponse adviseCall(ChatClientRequest request, CallAdvisorChain chain) { // 1. 从用户消息中提取查询内容 String userQuery = extractUserText(request); // 2. 向量检索:从采购知识库中找相关文档 List<Document> relevantDocs = vectorStore.similaritySearch( SearchRequest.builder() .query(userQuery) .topK(5) // 返回最相关的5条知识 .build() ); // 3. 构建增强后的系统提示词(注入检索到的上下文) String context = relevantDocs.stream() .map(doc -> "- " + doc.getContent()) .collect(Collectors.joining("\n")); String enhancedSystemMsg = "【采购知识库参考】\n" + context + "\n\n请基于以上信息回答用户问题。"; // 4. 修改请求:在原系统消息基础上追加上下文 ChatClientRequest enhancedRequest = request.mutate() .system(enhancedSystemMsg) .build(); // 5. 调用链中的下一个Advisor(最终会调用LLM) return chain.nextCall(enhancedRequest); } }
5.4 业务服务层调用
@Service public class PurchaseService { @Autowired private ChatClient purchaseChatClient; // 注入配置好的ChatClient // 单轮问答 public String askPurchase(String userQuery) { return purchaseChatClient.prompt() .user(userQuery) .call() .content(); } // 带用户ID的多轮对话 public String askPurchaseWithHistory(String userId, String userQuery) { return purchaseChatClient.prompt() .user(userQuery) .advisors(advisorSpec -> advisorSpec.param("chat_memory_conversation_id", userId)) .call() .content(); } // 结构化输出:让AI返回采购建议对象 public PurchaseAdvice getStructuredAdvice(String productName) { return purchaseChatClient.prompt() .user("请针对采购【" + productName + "】给出建议:包括供应商推荐、价格区间、注意事项") .call() .entity(PurchaseAdvice.class); // 自动映射为Java对象 } }
六、底层原理/技术支撑
Advisor机制能够优雅运作,底层依赖Spring的三大核心技术:
1. 责任链模式
Advisor通过CallAdvisorChain串联成一个执行链。框架按getOrder()值排序,每个Advisor执行后调用chain.nextCall()将请求传递给下一个,形成经典的“洋葱模型”-2。
2. 动态代理(AOP思想)
Spring AI在DefaultChatClient内部构建Advisor链时,本质上是用组合模式替代了传统的AOP动态代理。每个Advisor都持有对下一个的引用,最终形成递归调用链,比AOP更显式、更可控-5。
3. Builder + 不可变对象模式
ChatClientRequest和ChatClientResponse采用不可变设计,通过mutate()方法生成修改后的新副本。这种设计确保了链式调用中的线程安全,多个请求之间互不干扰。
七、高频面试题与参考答案
Q1:Spring AI的架构分层是怎样的?
踩分点:五层架构、各层职责、层间关系
参考答案:
Spring AI采用五层分层架构:①通用模型层(org.springframework.ai.model)定义最底层的Model/Request/Response抽象;②领域模型层(org.springframework.ai.chat等)为各AI能力建立领域对象如Message/Prompt;③Fluent客户端层(ChatClient)提供链式调用API;④增强层(Advisor/RAG/Memory等)提供可插拔的横切能力;⑤具体提供商适配层(openai/ollama等)通过Spring Boot自动配置接入具体厂商-5-46。
Q2:ChatModel和ChatClient有什么区别?
踩分点:层级关系、抽象程度、使用场景
参考答案:ChatModel是底层原子接口,直接与大模型API交互,需要开发者手动处理Prompt构建、消息组装等细节;ChatClient是高级Fluent封装,内部持有ChatModel对象,通过Builder模式提供了defaultSystem/defaultAdvisors等配置能力,并集成了Advisor、RAG、对话记忆等增强功能。简单说,ChatModel是发动机,ChatClient是整车--31。
Q3:Advisor的工作原理是什么?如何自定义Advisor?
踩分点:责任链、前置/后置处理、order排序
参考答案:
Advisor本质上是一个拦截器,实现CallAdvisor接口。Spring AI将多个Advisor按getOrder()值排序组成责任链,每个Advisor执行adviseCall方法,在该方法内可进行前置处理(修改request)和后置处理(修改response),最后调用chain.nextCall(request)将控制权交给下一个Advisor,最后一个Advisor负责调用LLM。自定义Advisor需要实现接口、定义order和name,并在adviseCall中编写业务逻辑-2-22。
Q4:Spring AI如何实现RAG(检索增强生成)?
踩分点:向量存储、Advisor注入、相似度检索
参考答案:
Spring AI通过VectorStore抽象统一管理向量数据库,支持PgVector、Chroma、Milvus等20+种存储后端-。在RAG实现上,通常通过自定义RAGAdvisor实现:在adviseCall前置阶段调用vectorStore.similaritySearch()检索与用户查询最相关的Top-K文档,将检索到的上下文追加到System Prompt中,再继续调用LLM。Spring AI 1.1.0-M4还引入了递归Advisor,支持多轮RAG迭代-4。
Q5:Spring AI相比LangChain的优势是什么?
踩分点:Spring生态深度集成、企业级特性
参考答案:
Spring AI的最大优势在于深度融入Spring生态:提供Spring Boot自动配置、依赖注入、统一配置管理,符合Spring开发者的使用习惯-。它解决了传统LangChain(Python生态)在Java企业应用中难以落地的问题,尤其适合已有Spring技术栈的团队-。框架演进趋势正从实验性探索走向“可运维的生产级框架”-。
八、结尾总结
回顾全文,核心知识点可以浓缩为以下脑图:
Spring AI核心知识体系 ├── ChatClient(调用入口) │ ├── Fluent链式调用 │ ├── Builder配置(defaultSystem / defaultAdvisors) │ └── 支持同步/流式/结构化输出 ├── Advisor(增强拦截器) │ ├── 责任链模式 │ ├── 前置/后置处理 │ └── 内置:RAG / 对话记忆 / 日志 / 护栏 └── 实战:AI采购助手 ├── RAG知识库检索 ├── 多轮对话记忆 └── 结构化输出映射
重点提示:面试中遇到Spring AI相关问题,核心得分点在于说清楚 “分层架构 + ChatClient vs ChatModel区别 + Advisor机制原理” 这三板斧。尤其是Advisor,把它理解为“Spring AOP在AI领域的落地”,用chain.nextCall()的责任链机制回答,会让面试官眼前一亮。
易错点提醒:不要混淆ChatModel和ChatClient的职责;不要忘记在自定义Advisor中调用chain.nextCall()(否则链会中断);RAG检索时注意控制Top-K数量,避免Prompt过长。
下篇预告:我们将深入剖析Spring AI中的递归Advisor(Recursive Advisor),看它如何实现工具调用循环、输出验证重试等复杂的Agentic工作流。敬请期待!
📌 代码仓库:本文完整示例代码已上传至GitHub,“spring-ai-purchase-assistant”即可获取。
