在这里插入图片描述

Pre

大模型开发 - 01 Spring AI 核心特性一览

大模型开发 - 02 Spring AI Concepts

大模型开发 - 03 QuickStart_借助DeepSeekChatModel实现Spring AI 集成 DeepSeek

大模型开发 - 04 QuickStart_DeepSeek 模型调用流程源码解析:从 Prompt 到远程请求

大模型开发 - 05 QuickStart_接入阿里百炼平台:Spring AI Alibaba 与 DashScope SDK

大模型开发 - 06 QuickStart_本地大模型私有化部署实战:Ollama + Spring AI 全栈指南

大模型开发 - 07 ChatClient:构建统一、优雅的大模型交互接口

大模型开发 - 08 ChatClient:构建智能对话应用的流畅 API

大模型开发 - 09 ChatClient:基于 Spring AI 的多平台多模型动态切换实战


概述

在构建企业级 AI 应用时,我们常常面临这样的挑战:

  • 如何在不修改核心逻辑的前提下,为对话系统添加记忆能力
  • 如何无缝集成RAG(检索增强生成) 实现知识库问答?
  • 如何统一记录所有 AI 调用日志、监控性能、防止有害输出?
  • 如何让同一套代码适配 DeepSeek、Ollama、OpenAI 等不同模型?

Spring AI 的 Advisors API 正是为解决这些问题而生。它借鉴了 Spring AOP 的思想,提供了一套可插拔、可组合、可观察的 AI 增强机制,让你像搭积木一样构建复杂的 AI 应用。

本文将深入剖析 Advisors API 的设计哲学、核心组件、执行流程,并通过 日志记录、Re2 推理增强、RAG 集成 三大实战案例,带你掌握这一强大工具。


一、什么是 Advisors API?

Spring AI Advisors API 提供了一种灵活而强大的方式来拦截、修改和增强 Spring 应用程序中的 AI 驱动交互。通过利用 Advisors API,开发人员可以创建更复杂、可重用和可维护的 AI 组件

Advisors 是 Spring AI 中用于拦截、修改、增强 AI 请求与响应的中间件组件。它们以责任链(Chain of Responsibility) 的形式串联执行,形成一个可扩展的处理管道。

能力 说明
解耦 将通用逻辑(如记忆、检索、安全)从业务代码中剥离
复用 一个 Advisor 可被多个 ChatClient 共享
组合 多个 Advisor 可自由组合,形成复杂行为
可观测 自动集成 Micrometer,支持指标与链路追踪
模型无关 同一套 Advisor 适用于 DeepSeek、Ollama、OpenAI 等

可以使用 ChatClient API 配置现有顾问,如以下示例所示:

ChatMemory chatMemory = ... // Initialize your chat memory store
VectorStore vectorStore = ... // Initialize your vector store

var chatClient = ChatClient.builder(chatModel)
    .defaultAdvisors(
        MessageChatMemoryAdvisor.builder(chatMemory).build(), // chat-memory advisor
        QuestionAnswerAdvisor.builder(vectorStore).build()    // RAG advisor
    )
    .build();

var conversationId = "678";

String response = this.chatClient.prompt()
    // Set advisor parameters at runtime
    .advisors(advisor -> advisor.param(ChatMemory.CONVERSATION_ID, conversationId))
    .user(userText)
    .call()
	.content();

建议在构建时使用 builder 的 defaultAdvisors() 方法注册advisor。


二、核心组件与执行流程

2.1 关键接口

在这里插入图片描述

所有 Advisor 都实现 org.springframework.ai.chat.client.advisor.api.Advisor 接口:

public interface Advisor extends Ordered {
    String getName();   // 唯一标识
    int getOrder();     // 执行顺序(越小越早)
}

根据是否支持流式响应,分为两类:

类型 接口 方法
非流式 CallAdvisor ChatClientResponse adviseCall(ChatClientRequest, CallAdvisorChain)
流式 StreamAdvisor Flux<ChatClientResponse> adviseStream(ChatClientRequest, StreamAdvisorChain)

2.2 执行流程(责任链)

在这里插入图片描述

执行流程(责任链模式):

请求阶段(→):
用户 Prompt 
  → Advisor 1 (order=1) 
  → Advisor 2 (order=2) 
  → ... 
  → Framework 内置 Advisor(发送到 LLM)

响应阶段(←):
LLM Response 
  ← ... 
  ← Advisor 2 
  ← Advisor 1 
  ← 返回最终响应

关键特性

  • 请求阶段:从低 order 到高 order 依次处理
  • 响应阶段:从高 order 到低 order 依次处理(栈式回溯)
  • 阻断机制:任一 Advisor 可选择不调用 next(),直接返回响应

2.3 上下文共享:adviseContext

每个 ChatClientRequestChatClientResponse 都携带一个 不可变的上下文 Map,用于在 Advisor 间传递状态:

// 读取上下文
String convId = request.adviseContext().get(ChatMemory.CONVERSATION_ID);

// 更新上下文(返回新实例)
ChatClientRequest newRequest = request.updateContext(Map.of("traceId", "123"));

⚠️ 注意:上下文是不可变的updateContext() 会创建新对象。


三、内置 Advisor 一览

Spring AI 提供了丰富的开箱即用 Advisor:

类别 Advisor 功能
记忆管理 MessageChatMemoryAdvisor 将历史消息作为 Message 列表注入 Prompt
PromptChatMemoryAdvisor 将历史对话拼接为文本注入 System Prompt
VectorStoreChatMemoryAdvisor 从向量库检索相关记忆
RAG QuestionAnswerAdvisor 实现基础 RAG:检索 + 生成
RetrievalAugmentationAdvisor 支持模块化 RAG 架构
推理增强 ReReadingAdvisor 实现 Re2 技术:重复提问提升推理
安全 SafeGuardAdvisor 过滤有害/不当内容

在这里插入图片描述
在这里插入图片描述


四、实战案例 1:自定义日志 Advisor

实现一个同时支持流式与非流式的日志记录组件:

public class SimpleLoggerAdvisor implements CallAdvisor, StreamAdvisor {

    private static final Logger logger = LoggerFactory.getLogger(SimpleLoggerAdvisor.class);

    @Override
    public String getName() {
        return "SimpleLoggerAdvisor";
    }

    @Override
    public int getOrder() {
        return Ordered.LOWEST_PRECEDENCE - 100; // 靠后执行,记录最终请求
    }

    // 非流式处理
    @Override
    public ChatClientResponse adviseCall(
            ChatClientRequest request, 
            CallAdvisorChain chain) {
        
        logRequest(request);
        ChatClientResponse response = chain.nextCall(request);
        logResponse(response);
        return response;
    }

    // 流式处理
    @Override
    public Flux<ChatClientResponse> adviseStream(
            ChatClientRequest request,
            StreamAdvisorChain chain) {
        
        logRequest(request);
        Flux<ChatClientResponse> responses = chain.nextStream(request);
        
        // 使用聚合器将流式响应合并为完整响应再记录
        return new ChatClientMessageAggregator()
                .aggregateChatClientResponse(responses, this::logResponse);
    }

    private void logRequest(ChatClientRequest request) {
        logger.info(">>> AI Request: {}", 
            request.prompt().getMessages().stream()
                   .map(m -> m.getMessageType() + ": " + m.getText())
                   .collect(Collectors.joining("\n")));
    }

    private void logResponse(ChatClientResponse response) {
        logger.info("<<< AI Response: {}", response.result().getOutput().getContent());
    }
}

注册使用

@Bean
public ChatClient chatClient(ChatModel chatModel) {
    return ChatClient.builder(chatModel)
        .defaultAdvisors(new SimpleLoggerAdvisor()) // 全局生效
        .build();
}

💡 技巧:通过 Ordered.LOWEST_PRECEDENCE - 100 确保在所有业务 Advisor 之后执行,记录最终发往 LLM 的请求。


五、实战案例 2:Re2 推理增强 Advisor

根据论文《Re-Reading Improves Reasoning in LLMs》,通过重复提问可显著提升模型推理能力。

实现原理:将用户输入 Q 转换为:

Q
Read the question again: Q
public class ReReadingAdvisor implements CallAdvisor, StreamAdvisor {

    private static final String RE2_TEMPLATE = """
        {query}
        Read the question again: {query}
        """;

    @Override
    public String getName() {
        return "ReReadingAdvisor";
    }

    @Override
    public int getOrder() {
        return Ordered.HIGHEST_PRECEDENCE + 100; // 尽早执行,修改原始输入
    }

    @Override
    public ChatClientResponse adviseCall(
            ChatClientRequest request, 
            CallAdvisorChain chain) {
        
        String originalQuery = request.prompt().getUserMessage().getText();
        String augmentedQuery = PromptTemplate.builder()
                .template(RE2_TEMPLATE)
                .variables(Map.of("query", originalQuery))
                .build()
                .render();

        // 构建新请求
        ChatClientRequest modifiedRequest = request.mutate()
                .prompt(request.prompt().augmentUserMessage(augmentedQuery))
                .build();

        return chain.nextCall(modifiedRequest);
    }

    @Override
    public Flux<ChatClientResponse> adviseStream(
            ChatClientRequest request,
            StreamAdvisorChain chain) {
        
        // 流式处理逻辑同上(略)
        // ...
    }
}

效果对比

输入 普通模型输出 Re2 增强后输出
“1 到 100 的和是多少?” “5050” “这是一个等差数列求和问题… 公式为 n(n+1)/2 … 结果是 5050”

适用场景:数学题、逻辑推理、复杂指令理解


六、实战案例 3:动态 RAG 与记忆组合

结合内置 Advisor,实现带记忆的 RAG 系统

@Configuration
public class AiAdvisorConfig {

    @Bean
    public ChatClient ragChatClient(
            ChatModel chatModel,
            VectorStore vectorStore,      // 知识库
            ChatMemory chatMemory) {      // 对话记忆

        return ChatClient.builder(chatModel)
            .defaultAdvisors(
                // 1. 先加载对话历史(高优先级)
                MessageChatMemoryAdvisor.builder(chatMemory)
                    .withOrder(Ordered.HIGHEST_PRECEDENCE + 50)
                    .build(),
                
                // 2. 再执行 RAG 检索(中等优先级)
                QuestionAnswerAdvisor.builder(vectorStore)
                    .withOrder(Ordered.HIGHEST_PRECEDENCE + 100)
                    .build(),
                
                // 3. 最后记录日志(低优先级)
                new SimpleLoggerAdvisor()
            )
            .build();
    }
}

调用时指定会话 ID

@RestController
public class AiController {

    @Autowired
    private ChatClient ragChatClient;

    @PostMapping("/chat")
    public String chat(@RequestBody ChatRequest req) {
        return ragChatClient.prompt()
            .advisors(advisor -> 
                advisor.param(ChatMemory.CONVERSATION_ID, req.getConversationId()))
            .user(req.getMessage())
            .call()
            .content();
    }
}

🌟 执行顺序

  1. MessageChatMemoryAdvisor → 注入历史对话
  2. QuestionAnswerAdvisor → 检索知识库并增强 Prompt
  3. 发送最终 Prompt 到 LLM
  4. 响应经日志 Advisor 返回

七、最佳实践与避坑指南

7.1 Advisor 顺序设计原则

场景 建议 Order
修改用户原始输入(如 Re2) HIGHEST_PRECEDENCE + N
加载上下文(记忆、用户信息) HIGHEST_PRECEDENCE + 100
RAG 检索增强 HIGHEST_PRECEDENCE + 200
安全校验(输入) HIGHEST_PRECEDENCE + 300
日志/监控 LOWEST_PRECEDENCE - 100
安全校验(输出) LOWEST_PRECEDENCE

7.2 流式处理注意事项

在这里插入图片描述

  • 使用 ChatClientMessageAggregator 聚合流式响应进行整体处理
  • 避免在流式 Advisor 中执行阻塞操作(使用 publishOn(Schedulers.boundedElastic())
  • 响应修改需通过 map() 而非直接赋值

7.3 性能与可观测性

  • 所有 Advisor 自动集成 Micrometer,可通过 /actuator/metrics 查看:
    • ai.advisor.duration
    • ai.advisor.calls
  • adviseContext 中传递 traceId 实现全链路追踪

八、版本演进与兼容性

Spring AI Advisors API 经历了快速迭代:

版本 变更
1.0 M2 RequestAdvisor + ResponseAdvisor
1.0 M3 合并为 CallAroundAdvisor / StreamAroundAdvisor
1.0.0+ 稳定版:CallAdvisor / StreamAdvisor

迁移提示

  • AdvisedRequestChatClientRequest
  • AdvisedResponseChatClientResponse
  • 上下文从独立参数变为对象内嵌

九、总结

Spring AI Advisors API 是构建企业级 AI 应用的基石:

  • 像 AOP 一样优雅:无侵入增强 AI 能力
  • 像管道一样灵活:自由组合记忆、RAG、安全、日志等模块
  • 像 Spring 一样标准:无缝集成可观测性、事务、安全等生态

在这里插入图片描述

Logo

更多推荐