递归顾问
什么是递归顾问?
递归顾问是一类特殊的顾问,能够多次循环遍历下游的顾问链。当你需要重复调用大语言模型(LLM)直至满足特定条件时,这种模式非常实用,典型场景包括:
- 循环执行工具调用,直到无需再调用任何工具
- 校验结构化输出,若校验失败则重新尝试
- 实现附带请求修改的评估逻辑
- 实现附带请求修改的重试逻辑
CallAdvisorChain.copy(CallAdvisor after) 方法是实现递归顾问模式的核心工具。它会创建一个新的顾问链,该子链仅包含原链中指定顾问之后的所有顾问,并允许递归顾问根据需要调用这个子链。这种方案能够保证:
- 递归顾问可以循环遍历链中剩余的顾问
- 链中的其他顾问能够监听并拦截每一次循环迭代
- 顾问链保持正确的执行顺序和可观测性
- 递归顾问不会重新执行其自身之前的顾问
内置递归顾问
Spring AI 提供了两个内置的递归顾问,用于演示该模式:
ToolCallAdvisor(工具调用顾问)
ToolCallAdvisor 将工具调用循环作为顾问链的一部分实现,而非依赖模型内部的工具执行能力。这使得链中的其他顾问可以拦截并监听工具调用的全过程。
核心特性:
- 通过设置
setInternalToolExecutionEnabled(false)禁用模型内部的工具执行 - 循环遍历顾问链,直到不存在待执行的工具调用
- 支持“直接返回”功能——当工具执行配置
returnDirect=true时,会中断工具调用循环,并将工具执行结果直接返回给客户端应用,而非回传给大语言模型 - 使用
callAdvisorChain.copy(this)创建子链以实现递归调用 - 包含空值安全校验,处理聊天响应可能为空的场景
- 支持通过
conversationHistoryEnabled配置会话历史管理
使用示例:
var toolCallAdvisor = ToolCallAdvisor.builder()
.toolCallingManager(toolCallingManager)
.advisorOrder(BaseAdvisor.HIGHEST_PRECEDENCE + 300)
.build();
var chatClient = ChatClient.builder(chatModel)
.defaultAdvisors(toolCallAdvisor)
.build();
会话历史管理
ToolCallAdvisor 包含一个配置选项,用于控制工具调用迭代过程中会话历史的管理方式。
默认情况下(conversationHistoryEnabled=true),该顾问会在工具调用迭代期间内部维护完整的会话历史。这意味着工具调用循环中每一次后续的大语言模型调用,都会包含所有历史消息(用户消息、助手响应、工具响应)。
可通过 .disableMemory() 方法禁用内部会话历史管理。禁用后,仅会将最后一条工具响应消息传递给下一次迭代。适用于以下场景:
- 你已在顾问链中注册了聊天内存顾问,由其负责管理会话历史
- 你希望避免重复管理历史,减少令牌消耗
- 你需要与外部会话内存系统集成
禁用会话历史的示例:
var toolCallAdvisor = ToolCallAdvisor.builder()
.toolCallingManager(toolCallingManager)
.disableMemory() // 禁用内部历史管理 - 交由 ChatMemory 处理
.advisorOrder(BaseAdvisor.HIGHEST_PRECEDENCE + 300)
.build();
var chatMemoryAdvisor = MessageChatMemoryAdvisor.builder(chatMemory)
.advisorOrder(BaseAdvisor.HIGHEST_PRECEDENCE + 200) // 优先级高于 ToolCallAdvisor
.build();
var chatClient = ChatClient.builder(chatModel)
.defaultAdvisors(chatMemoryAdvisor, toolCallAdvisor)
.build();
直接返回功能
“直接返回”特性允许工具绕过大语言模型,将结果直接返回给客户端应用。适用于以下场景:
- 工具输出即为最终答案,无需大语言模型处理
- 你希望避免额外的大语言模型调用,降低延迟
- 工具结果需要原样返回,无需二次解析
当工具执行配置 returnDirect=true 时,ToolCallAdvisor 会执行以下逻辑:
- 正常执行工具调用
- 在
ToolExecutionResult中检测到returnDirect标记 - 跳出工具调用循环
- 将工具执行结果直接以
ChatResponse形式返回给客户端应用,工具输出作为生成内容
StructuredOutputValidationAdvisor(结构化输出校验顾问)
StructuredOutputValidationAdvisor 会根据生成的 JSON 模式校验大语言模型输出的结构化 JSON 数据,若校验失败则重新调用模型,最多重试指定次数。
核心特性:
- 根据预期输出类型自动生成 JSON 模式
- 基于 JSON 模式校验大语言模型的响应
- 校验失败时重新调用模型,支持配置最大重试次数
- 重试时将校验错误信息追加到提示词中,帮助大语言模型修正输出
- 使用
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();