SpringAI-Advisors API

官网地址:https://docs.spring.io/spring-ai/reference/api/advisors.html

1、描述

作用:拦截、修改和增强Spring应用中的AI驱动交互,建议使用defaultAdvisors方法注册Advisor

2、核心组件

该API分为非流式CallAdvisor和流CallAdvisorChain,以及流式StreamAdvisor和StreamAdvisorChain,
包含未封装的Prompt请求的ChatClientRequest,以及用于聊天完成响应的ChatClientResponse。
image

方法:
advisorCall()和advisorStream()是关键的Advisor方法,通常执行检查未封装的Prompt数据、自定义和增强Prompt数据、调用Advisor链中的下一个实体、可选地阻止请求、检查聊天完成响应以及抛出异常等操作
getOrder()方法确定Advisor在链中的执行顺序,值越低执行越早,顺序值相同,执行顺序不确定,自动添加的最后一个Advisor将请求发送LLM
getName()提供唯一的Advisor名称。
image

代码示例(注册了jdbcChatMemoryRepository,用于将连天记忆持久化到数据库;注册了milvusVectorStore,集成向量数据库,实现简单问答)

 @Bean
    public ChatClient chatClient(OllamaChatModel ollamaChatModel) {
        MessageWindowChatMemory messageWindowChatMemory = MessageWindowChatMemory.builder()
                .chatMemoryRepository(jdbcChatMemoryRepository).maxMessages(10).build();
        return ChatClient.builder(ollamaChatModel)
                .defaultAdvisors(MessageChatMemoryAdvisor.builder(messageWindowChatMemory).build(),
                        QuestionAnswerAdvisor.builder(milvusVectorStore).build(), new SimpleLoggerAdvisor())
                .build();
    }

3、日志Advisor

SimpleLoggerAdvisor,它在调用链中下一个Advisor之前记录ChatClientRequest,并在之后记录ChatClientResponse。
只观察请求和响应,不修改
注意:需要把日志级别设置为DEBUG

logging.level.org.springframework.ai.chat.client.advisor=DEBUG
    @Bean
    public ChatClient chatClient(OllamaChatModel ollamaChatModel) {
        return ChatClient.builder(ollamaChatModel)
                .defaultAdvisors(new SimpleLoggerAdvisor())
                .build();
    }

执行日志,可以看到,打印了request和response
image

4、SpringAI内置的Advisor

4.1、聊天记忆Advisor

  • MessageChatMemoryAdvisor,检索记忆并将其作为消息集合添加到Prompt中,此方法维护对话历史的结构,并非所有AI模型都支持此方法
  • PromptChatMemoryAdvisor,检索记忆并将其合并到Prompt的系统文本中
  • VectorStoreChatMemoryAdvisor,从vectorStore检索记忆并将其添加到Prompt的系统文本中。

三者区别(来自deekseek回答):

特征纬度 MessageChatMemoryAdvisor PromptChatMemoryAdvisor VectorStoreChatMemoryAdvisor
记忆模式 固定窗口 (最近N条) 完整会话压缩 语义检索 (动态相关)
核心技术 结构化消息列表 文本拼接与压缩 向量嵌入与相似度搜索
数据形态 保留角色的消息对象 纯文本历史段落 文本的向量嵌入
历史组织方式 按时间顺序,先进先出 按时间顺序,整体压缩 按语义相关性动态检索
主要优势 简单可靠,保留对话结构 实现简单,兼容性好 如破上下文长度限制,关联长期记忆
潜在局限 长对话会丢失早期信息 压缩可能导致信息丢失 依赖向量化质量,检索可能不准确
典型使用场景 简单多轮对话,需精确角色管理 基础对话模型,模型输入格式受限 知识库问答、长文档分析、复杂客服

代码实现:

    @Bean
    public ChatMemory chatMemory() {
        return MessageWindowChatMemory.builder()
                .chatMemoryRepository(jdbcChatMemoryRepository).maxMessages(10).build();
    }

    @Bean
    public ChatClient chatClient(OllamaChatModel ollamaChatModel) {
        return ChatClient.builder(ollamaChatModel)
//                .defaultAdvisors(MessageChatMemoryAdvisor.builder(chatMemory()).build())  //使用MessageChatMemoryAdvisor
                .defaultAdvisors(PromptChatMemoryAdvisor.builder(chatMemory()).build())       //使用PromptChatMemoryAdvisor
                .build();
    }

使用VectorStoreChatMemoryAdvisor

    @Autowired
    private MilvusVectorStore milvusVectorStore;

    @Bean
    public ChatClient chatClient(OllamaChatModel ollamaChatModel) {
        return ChatClient.builder(ollamaChatModel)
                .defaultAdvisors(VectorStoreChatMemoryAdvisor.builder(milvusVectorStore).build())
                .build();
    }

4.2、问答Advisor

  • QuestionAnswerAdvisor,使用向量存储提供问答功能,实现Naive RAG(检索增强生成)模式
  • RetrievalAugmentationAdvisor,待研究

5、递归Advisor

5.1、描述

可以多次循环执行下游Advisor,当需要重复调用LLM直到满足某个条件时,这个模式非常有用,例如:

  • 循环执行工具调用直到不再需要调用工具
  • 验证结构化输出并在验证失败时重试
  • 使用对请求的修改来实现评估逻辑
  • 使用对请求的修改来实现重试逻辑

CallAdvisorChain.copy(CallAdvisor after)方法是实现递归Advisor的关键方法,创建一个新的Advisor链,其中包括原始链中指定Advisor之后的Advisor,并允许递归Advisor根据需要调用此子链,此方法确保了:

  • 递归Advisor可以循环执行链中剩余的Advisor
  • 链中的其他Advisor可以观察和拦截每次迭代
  • Advisor链保持正确的顺序和可观察性
  • 递归Advisor不会重新执行在其之前执行过的Advisor

5.2、内置递归Advisor

5.2.1、ToolCallAdvisor

将工具调用循环作为Advisor链的一部分实现,而不是依赖模型的内部工具执行,这使得链中的其他Advisor能够拦截和观察工具调用过程
主要功能:

  • 通过设置setInternalToolExecutionEnable(false)禁用模型的内部工具执行
  • 循环执行Advisor链,直到不再存在工具调用
  • 支持“直接返回”功能,当工具执行具有returnDirect=true时,它会中断工具调用循环并将工具执行结果直接返回给客户端应用程序,而不是将其发送回LLM
  • 使用callAdvisorChain.copy(this)创建子链以进行递归用
  • 包含空安全检查,以处理聊天响应可能为空的情况
    示例用法:
var toolCallAdvisor = ToolCallAdvisor.builder()
    .toolCallingManager(toolCallingManager)
    .advisorOrder(BaseAdvisor.HIGHEST_PRECEDENCE + 300)
    .build();

var chatClient = ChatClient.builder(chatModel)
    .defaultAdvisors(toolCallAdvisor)
    .build();

直接返回功能:
“直接返回”功能允许工具绕过 LLM,将其结果直接返回给客户端应用程序。这在以下情况下很有用:

  • 工具的输出是最终答案,不需要 LLM 处理
  • 希望通过避免额外的 LLM 调用来减少延迟
  • 工具结果应按原样返回,无需解释

当工具执行具有 returnDirect=true 时,ToolCallAdvisor 将:

  • 正常执行工具调用
  • 在 ToolExecutionResult 中检测 returnDirect 标志
  • 跳出工具调用循环
  • 将工具执行结果作为 ChatResponse 直接返回给客户端应用程序,其中工具的输出作为生成内容

5.2.2、StructuredOutputValidationAdvisor

根据生成的 JSON Schema 验证结构化 JSON 输出,并在验证失败时重试调用,最多重试指定次数。
主要功能:

  • 从预期输出类型自动生成 JSON Schema
  • 根据 Schema 验证 LLM 响应
  • 如果验证失败,重试调用,最多可配置次数
  • 在重试尝试时通过验证错误消息增强提示,以帮助 LLM 纠正其输出
  • 使用 callAdvisorChain.copy(this) 创建子链以进行递归调用
  • 可选支持自定义 ObjectMapper 用于 JSON 处理

示例用法:

var validationAdvisor = StructuredOutputValidationAdvisor.builder()
    .outputType(MyResponseType.class)
    .maxRepeatAttempts(3)
    .advisorOrder(BaseAdvisor.HIGHEST_PRECEDENCE + 1000)
    .build();

var chatClient = ChatClient.builder(chatModel)
    .defaultAdvisors(validationAdvisor)
    .build();
posted @ 2025-12-16 15:26  0xCAFEBABE_001  阅读(5)  评论(0)    收藏  举报