Recursive Advisors

What is a Recursive Advisor?

Advisors Recursive Recursive advisors are a special type of advisor that can loop through the downstream advisor chain multiple times. This pattern is useful when you need to repeatedly call the LLM until a certain condition is met, such as:spring-doc.cn

  • Executing tool calls in a loop until no more tools need to be calledspring-doc.cn

  • Validating structured output and retrying if validation failsspring-doc.cn

  • Implementing Evaluation logic with modifications to the requestspring-doc.cn

  • Implementing retry logic with modifications to the requestspring-doc.cn

The CallAdvisorChain.copy(CallAdvisor after) method is the key utility that enables recursive advisor patterns. It creates a new advisor chain that contains only the advisors that come after the specified advisor in the original chain and allows the recursive advisor to call this sub-chain as needed. This approach ensures that:spring-doc.cn

  • The recursive advisor can loop through the remaining advisors in the chainspring-doc.cn

  • Other advisors in the chain can observe and intercept each iterationspring-doc.cn

  • The advisor chain maintains proper ordering and observabilityspring-doc.cn

  • The recursive advisor doesn’t re-execute advisors that came before itspring-doc.cn

Built-in Recursive Advisors

Spring AI provides two built-in recursive advisors that demonstrate this pattern:spring-doc.cn

ToolCallAdvisor

The ToolCallAdvisor implements the tool calling loop as part of the advisor chain, rather than relying on the model’s internal tool execution. This enables other advisors in the chain to intercept and observe the tool calling process.spring-doc.cn

Key features:spring-doc.cn

  • Disables the model’s internal tool execution by setting setInternalToolExecutionEnabled(false)spring-doc.cn

  • Loops through the advisor chain until no more tool calls are presentspring-doc.cn

  • Supports "return direct" functionality - when a tool execution has returnDirect=true, it interrupts the tool calling loop and returns the tool execution result directly to the client application instead of sending it back to the LLMspring-doc.cn

  • Uses callAdvisorChain.copy(this) to create a sub-chain for recursive callsspring-doc.cn

  • Includes null safety checks to handle cases where the chat response might be nullspring-doc.cn

Example usage:spring-doc.cn

var toolCallAdvisor = ToolCallAdvisor.builder()
    .toolCallingManager(toolCallingManager)
    .advisorOrder(BaseAdvisor.HIGHEST_PRECEDENCE + 300)
    .build();

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

Return Direct Functionality

The "return direct" feature allows tools to bypass the LLM and return their results directly to the client application. This is useful when:spring-doc.cn

  • The tool’s output is the final answer and doesn’t need LLM processingspring-doc.cn

  • You want to reduce latency by avoiding an additional LLM callspring-doc.cn

  • The tool result should be returned as-is without interpretationspring-doc.cn

When a tool execution has returnDirect=true, the ToolCallAdvisor will:spring-doc.cn

  1. Execute the tool call as normalspring-doc.cn

  2. Detect the returnDirect flag in the ToolExecutionResultspring-doc.cn

  3. Break out of the tool calling loopspring-doc.cn

  4. Return the tool execution result directly to the client application as a ChatResponse with the tool’s output as the generation contentspring-doc.cn

StructuredOutputValidationAdvisor

The StructuredOutputValidationAdvisor validates the structured JSON output against a generated JSON schema and retries the call if validation fails, up to a specified number of attempts.spring-doc.cn

Key features:spring-doc.cn

  • Automatically generates a JSON schema from the expected output typespring-doc.cn

  • Validates the LLM response against the schemaspring-doc.cn

  • Retries the call if validation fails, up to a configurable number of attemptsspring-doc.cn

  • Augments the prompt with validation error messages on retry attempts to help the LLM correct its outputspring-doc.cn

  • Uses callAdvisorChain.copy(this) to create a sub-chain for recursive callsspring-doc.cn

  • Optionally supports a custom ObjectMapper for JSON processingspring-doc.cn

Example usage:spring-doc.cn

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

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