Retentar e Refletir

O crate adk-retry-reflect fornece um plugin que intercepta falhas de Tool, injeta prompts de reflexão no contexto LLM e retenta com backoff exponencial. Isso dá aos Agents a capacidade de se autocorrigir após erros transitórios ou chamadas de Tool malformadas.

Visão Geral

Quando uma chamada de Tool falha, o comportamento padrão é retornar o erro para o LLM e deixá-lo decidir o que fazer. O plugin Retentar e Refletir adiciona recuperação estruturada:

  1. Intercepta a falha da Tool antes que ela atinja o LLM
  2. Injeta um prompt de reflexão pedindo ao model para analisar o que deu errado
  3. Retenta a chamada da Tool com argumentos corrigidos
  4. Aplica backoff exponencialmente se as falhas persistirem
  5. Quebra o circuito após falhas repetidas para evitar loops infinitos

Instalação

[dependencies]
adk-retry-reflect = "2.0.0"

# Or via umbrella crate (included in standard tier)
adk-rust = { version = "2.0.0", features = ["standard"] }

Início Rápido

use adk_retry_reflect::RetryReflectPlugin;
use adk_agent::LlmAgentBuilder;
use std::sync::Arc;

let plugin = RetryReflectPlugin::builder()
    .max_retries(3)
    .initial_backoff_ms(500)
    .backoff_multiplier(2.0)
    .build();

let agent = LlmAgentBuilder::new("resilient_agent")
    .model(model)
    .instruction("You are a helpful assistant with access to external APIs.")
    .tool(Arc::new(flaky_api_tool))
    .plugin(Arc::new(plugin))
    .build()?;

Configuração

use adk_retry_reflect::{RetryReflectPlugin, RetryReflectConfig};

let plugin = RetryReflectPlugin::builder()
    // Retry settings
    .max_retries(3)                    // Maximum retry attempts [default: 3]
    .initial_backoff_ms(500)           // First retry delay in ms [default: 500]
    .backoff_multiplier(2.0)           // Multiply delay each retry [default: 2.0]
    .max_backoff_ms(30_000)            // Cap delay at this value [default: 30000]

    // Circuit breaker
    .circuit_breaker_threshold(5)      // Open circuit after N failures [default: 5]
    .circuit_breaker_reset_ms(60_000)  // Reset circuit after this duration [default: 60000]

    // Reflection
    .reflection_prompt(                // Custom reflection prompt template
        "The tool '{tool_name}' failed with: {error}. \
         Analyze what went wrong and provide corrected arguments."
    )

    // Scope
    .include_tools(&["api_call", "db_query"])  // Only retry these tools
    .exclude_tools(&["exit_loop"])             // Never retry these tools

    .build();

Referência de Configuração

ParâmetroPadrãoDescrição
max_retries3Número máximo de tentativas de repetição por chamada de ferramenta
initial_backoff_ms500Atraso antes da primeira repetição (milissegundos)
backoff_multiplier2.0Multiplicar o atraso por este fator a cada tentativa
max_backoff_ms30,000Limite máximo de atraso (milissegundos)
circuit_breaker_threshold5Falhas consecutivas antes que o circuito se abra
circuit_breaker_reset_ms60,000Tempo antes que o circuito seja redefinido para fechado
reflection_prompt(integrado)Modelo para injeção de reflexão
include_toolstodosTentar novamente apenas estas ferramentas (vazio = todas)
exclude_toolsnenhumNunca tentar novamente estas ferramentas

Disjuntor de Circuito

O disjuntor de circuito evita loops infinitos de novas tentativas quando uma ferramenta falha persistentemente:

Closed (normal) ─── failure count >= threshold ──→ Open (all calls fail fast)
       ↑                                                    │
       └──────── reset_ms elapsed, next call succeeds ──────┘
                              (Half-Open)

Quando o circuito está aberto:

  • Chamadas de ferramenta falham imediatamente com um erro de disjuntor de circuito
  • Nenhuma nova tentativa é feita
  • Após circuit_breaker_reset_ms, a próxima chamada é permitida (semiaberto)
  • Se for bem-sucedida, o circuito fecha; se falhar, o circuito permanece aberto

Como a Reflexão Funciona

Quando uma chamada de ferramenta falha, o plugin injeta um prompt de reflexão na conversa:

[User]: What's the weather in NYC?
[Model]: *calls get_weather({"city": "nyc", "units": "kelvin"})*
[Tool Error]: Invalid units. Supported: celsius, fahrenheit
[Plugin injects]: The tool 'get_weather' failed with: "Invalid units. 
    Supported: celsius, fahrenheit". Analyze what went wrong and provide 
    corrected arguments.
[Model]: *calls get_weather({"city": "NYC", "units": "celsius"})*
[Tool Success]: {"temperature": 22, "condition": "sunny"}

O prompt de reflexão fornece ao LLM contexto explícito sobre a falha para que ele possa se autocorrigir em vez de repetir o mesmo erro.

Quando Usar

Boa adequação:

  • Ferramentas que chamam APIs externos com falhas transitórias
  • Ferramentas onde o LLM pode fornecer argumentos ligeiramente malformados
  • Consultas de banco de dados que podem falhar devido a problemas de conexão
  • Operações de arquivo em armazenamento em rede

Não é uma boa adequação:

  • Ferramentas que estão deterministicamente quebradas (corrija a ferramenta em vez disso)
  • Ferramentas de longa duração onde as novas tentativas são caras
  • Ferramentas com efeitos colaterais que não são idempotentes (por exemplo, envio de e-mails)
  • Ferramentas de controle de fluxo como exit_loop

Combinando com Outros Plugins

Retry & Reflect respeita a ordem de prioridade dos plugins:

use adk_plugin::PluginManager;

let agent = LlmAgentBuilder::new("agent")
    .model(model)
    .plugin(Arc::new(logging_plugin))         // Priority 1 (runs first)
    .plugin(Arc::new(retry_reflect_plugin))   // Priority 2
    .plugin(Arc::new(guardrail_plugin))       // Priority 3 (runs last)
    .build()?;

Observabilidade

O plugin emite spans de rastreamento para tentativas de nova execução:

WARN adk_retry_reflect: tool call failed, retrying
    tool_name=get_weather attempt=1 max=3 backoff_ms=500
    error="Invalid units"

INFO adk_retry_reflect: retry succeeded
    tool_name=get_weather attempt=2

WARN adk_retry_reflect: circuit breaker opened
    tool_name=broken_api failures=5 reset_ms=60000

Anterior: ← ACP Ferramentas | Próximo: Nós de Ação →