【2026年4月9日】Spring AI采购助手:基于ChatClient与Advisor的RAG企业级实战

小编头像

小编

管理员

发布于:2026年04月29日

2 阅读 · 0 评论

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

一、痛点切入:为什么传统AI调用方式“又臭又长”?

先看一段不使用Advisor的“裸调用”代码:

java
复制
下载
@Service

public 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处理ChatClientRequestChatClientResponse对象,通过getOrder()值决定执行顺序,最后一个Advisor负责真正调用LLM-2-4

与ChatClient的关系

维度ChatClientAdvisor
角色定位调用方 / 客户端拦截器 / 增强器
职责发起请求、接收响应在请求前后做额外处理
类比水管总闸水管上的过滤器
数量关系1个ChatClient可挂载多个Advisor

一句话记忆ChatClient 是“怎么调”,Advisor 是“调之前/之后做什么”。

内置Advisor类型

Spring AI提供了多种内置Advisor实现-4

  • 对话记忆AdvisorMessageChatMemoryAdvisor):自动注入历史对话上下文,实现多轮对话-22

  • RAG Advisor:自动执行向量检索,将结果拼入Prompt

  • 日志AdvisorSimpleLoggerAdvisor):记录每次调用的请求和响应

  • 护栏Advisor(Guardrails):过滤敏感词、防止提示词注入

Advisor的工作原理(示意代码)

java
复制
下载
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:

对比维度ChatClientAdvisor
英文全称Chat ClientAdvisor
本质Fluent API客户端拦截器(Interceptor)
设计思想门面模式(Facade)责任链模式(Chain of Responsibility)
控制方向主动调用被动拦截
是否必需是,核心调用入口否,可选增强
依赖关系依赖ChatModel依赖ChatClient执行链

一句话概括:ChatClient是“调用AI的大门”,Advisor是“大门上的安检和装饰”,门只有一个,但可以挂多个安检模块。

五、代码示例:打造企业级AI采购助手

5.1 项目依赖(build.gradle / pom.xml)

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)

java
复制
下载
@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(核心)

java
复制
下载
@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 业务服务层调用

java
复制
下载
@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 + 不可变对象模式

ChatClientRequestChatClientResponse采用不可变设计,通过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技术栈的团队-。框架演进趋势正从实验性探索走向“可运维的生产级框架”-

八、结尾总结

回顾全文,核心知识点可以浓缩为以下脑图:

text
复制
下载
Spring AI核心知识体系
├── ChatClient(调用入口)
│   ├── Fluent链式调用
│   ├── Builder配置(defaultSystem / defaultAdvisors)
│   └── 支持同步/流式/结构化输出
├── Advisor(增强拦截器)
│   ├── 责任链模式
│   ├── 前置/后置处理
│   └── 内置:RAG / 对话记忆 / 日志 / 护栏
└── 实战:AI采购助手
    ├── RAG知识库检索
    ├── 多轮对话记忆
    └── 结构化输出映射

重点提示:面试中遇到Spring AI相关问题,核心得分点在于说清楚 “分层架构 + ChatClient vs ChatModel区别 + Advisor机制原理” 这三板斧。尤其是Advisor,把它理解为“Spring AOP在AI领域的落地”,用chain.nextCall()的责任链机制回答,会让面试官眼前一亮。

易错点提醒:不要混淆ChatModelChatClient的职责;不要忘记在自定义Advisor中调用chain.nextCall()(否则链会中断);RAG检索时注意控制Top-K数量,避免Prompt过长。

下篇预告:我们将深入剖析Spring AI中的递归Advisor(Recursive Advisor),看它如何实现工具调用循环、输出验证重试等复杂的Agentic工作流。敬请期待!

📌 代码仓库:本文完整示例代码已上传至GitHub,“spring-ai-purchase-assistant”即可获取。

标签:

相关阅读