Réessayer et réfléchir

La crate adk-retry-reflect fournit un plugin qui intercepte les échecs des outils, injecte des invites de réflexion dans le contexte LLM et réessaie avec une temporisation exponentielle. Cela permet aux agents de s’auto-corriger après des erreurs transitoires ou des appels d’outils mal formés.

Vue d’ensemble

Lorsqu’un appel d’outil échoue, le comportement par défaut consiste à renvoyer l’erreur à LLM et à le laisser décider de la marche à suivre. Le plugin Retry & Reflect ajoute une récupération structurée :

  1. Intercepte l’échec de l’outil avant qu’il n’atteigne LLM
  2. Injecte une invite de réflexion demandant au modèle d’analyser ce qui s’est mal passé
  3. Réessaie l’appel de l’outil avec des arguments corrigés
  4. Applique une temporisation exponentielle si les échecs persistent
  5. Déclenche l’ouverture du circuit après des échecs répétés afin d’éviter les boucles infinies

Installation

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

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

Démarrage rapide

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()?;

Configuration

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();

Référence de configuration

ParamètrePar défautDescription
max_retries3Nombre maximal de tentatives par appel d’outil
initial_backoff_ms500Délai avant la première nouvelle tentative (millisecondes)
backoff_multiplier2.0Multiplier le délai par ce facteur à chaque tentative
max_backoff_ms30,000Délai maximal (millisecondes)
circuit_breaker_threshold5Nombre d’échecs consécutifs avant l’ouverture du circuit
circuit_breaker_reset_ms60,000Délai avant la réinitialisation du circuit à l’état fermé
reflection_prompt(intégré)Modèle pour l’injection de réflexion
include_toolstousRéessayer uniquement ces outils (vide = tous)
exclude_toolsaucunNe jamais réessayer ces outils

Disjoncteur

Le disjoncteur empêche les boucles de nouvelle tentative infinies lorsqu’un outil échoue de manière persistante :

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

Lorsque le circuit est ouvert :

  • Les appels d’outils échouent immédiatement avec une erreur de disjoncteur
  • Aucune nouvelle tentative n’est effectuée
  • Après circuit_breaker_reset_ms, l’appel suivant est autorisé (semi-ouvert)
  • S’il réussit, le circuit se ferme ; s’il échoue, le circuit reste ouvert

Fonctionnement de la réflexion

Lorsqu’un appel d’outil échoue, le plugin injecte une invite de réflexion dans la conversation :

[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"}

L’invite de réflexion fournit à LLM un contexte explicite sur l’échec afin qu’il puisse se corriger lui-même plutôt que de répéter la même erreur.

Quand l’utiliser

Bon choix :

  • Outils qui appellent des APIs externes avec des échecs transitoires
  • Outils pour lesquels LLM peut fournir des arguments légèrement mal formés
  • Requêtes de base de données pouvant échouer en raison de problèmes de connexion
  • Opérations sur des fichiers stockés sur un réseau

Moins adapté :

  • Outils défaillants de manière déterministe (corrigez plutôt l’outil)
  • Outils à longue durée d’exécution pour lesquels les nouvelles tentatives sont coûteuses
  • Outils ayant des effets secondaires qui ne sont pas idempotents (par exemple, l’envoi d’e-mails)
  • Outils de contrôle du flux tels que exit_loop

Combinaison avec d’autres plugins

Retry & Reflect respecte l’ordre de priorité des 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()?;

Observabilité

Le plugin émet des spans de traçage pour les tentatives :

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

Précédent : ← ACP Tools | Suivant : Nœuds d’action →