\n\n\n\n Gestione degli errori degli agenti: Una guida pratica avanzata - AiDebug \n

Gestione degli errori degli agenti: Una guida pratica avanzata

📖 11 min read2,060 wordsUpdated Apr 4, 2026

Introduzione : La Realtà Inevitabile degli Errori degli Agenti

Nel mondo degli agenti di IA, l’esecuzione perfetta è un mito. Che il tuo agente stia navigando in un’applicazione web complessa, generando contenuti creativi o gestendo flussi di lavoro complessi, gli errori fanno parte integrante del processo. Le interruzioni di rete, i limiti di frequenza delle API, le risposte malformate, i cambiamenti inaspettati dell’interfaccia utente e anche le interpretazioni sottili delle istruzioni possono portare a fallimenti. Anche se semplici blocchi try-catch sono un buon inizio, la vera solidità nella progettazione di agenti richiede un approccio più sofisticato nella gestione degli errori. Questa guida avanzata esplorerà strategie pratiche e modelli architettonici per costruire agenti che non solo si riprendono in modo elegante, ma imparano anche e si adattano dai loro errori.

Oltre ai Ripetuti Semplici : Comprendere i Tipi di Errori e la Loro Gravità

Il primo passo verso una gestione avanzata degli errori consiste nel superare un generico “ripeti tutto”. Non tutti gli errori sono uguali. Distingere i diversi tipi di errori e la loro gravità consente di adottare strategie di recupero più intelligenti e contestualmente consapevoli.

Categorizzazione degli Errori :

  • Errori Transitori: Problemi temporanei che tendono a risolversi da soli con un breve attesa e un ripetizione (ad esempio, errori di rete, sovraccarichi temporanei delle API, blocchi del database).
  • Errori Persistenti: Problemi che probabilmente non si risolvono con un semplice ripetizione e necessitano di un approccio diverso (ad esempio, chiavi API non valide, schemi di input errati, errori logici fondamentali, accesso negato).
  • Errori Sistemici: Problemi profondi che indicano un difetto fondamentale nella progettazione, nell’addestramento o nell’ambiente dell’agente (ad esempio, allucinazioni ricorrenti, incapacità di analizzare un componente critico, fallimenti continui su un tipo di compito specifico).
  • Errori di Sistema Esterno: Errori provenienti da servizi di terze parti con cui l’agente interagisce, richiedendo spesso un trattamento specifico basato sulla documentazione del servizio esterno.

Livelli di Gravità :

  • Informativo: Problemi minori che non ostacolano il completamento del compito ma potrebbero indicare una performance subottimale.
  • Avviso: Problemi che potrebbero influenzare le prestazioni o indicare un potenziale problema, ma l’agente può comunque proseguire.
  • Errore: Un problema significativo che impedisce l’attuale fase o sotto-compito di completarsi.
  • Critico: Un fallimento catastrofico che impedisce all’intero agente di raggiungere il suo obiettivo principale.

Mecanismi di Ripetizione Avanzati con Ritardo e Jitter

Ripetizioni semplici possono spesso aggravare i problemi, soprattutto con errori transitori come i limiti di frequenza delle API. Strategie di ripetizione avanzate sono cruciali.

Ritardo Esponenziale :

Invece di ripetere immediatamente, attendi un intervallo di tempo che aumenta esponenzialmente tra le ripetizioni. Questo dà al sistema il tempo di riprendersi e impedisce di sovraccaricarlo ulteriormente.


import time
import random

def call_api_with_exponential_backoff(func, *args, max_retries=5, initial_delay=1, max_delay=60):
 for i in range(max_retries):
 try:
 return func(*args)
 except Exception as e:
 print(f"Fallimento del tentativo {i+1} : {e}")
 if i == max_retries - 1:
 raise
 delay = min(initial_delay * (2 ** i), max_delay)
 jitter = random.uniform(0, delay * 0.1) # Aggiungere un jitter fino al 10%
 print(f"Nuovo tentativo tra {delay + jitter:.2f} secondi...")
 time.sleep(delay + jitter)

# Esempio d'uso :
def problematic_api_call():
 if random.random() < 0.7: # 70% di probabilità di fallimento
 raise ConnectionError("Problema di rete simulato")
 return "Successo!"

try:
 result = call_api_with_exponential_backoff(problematic_api_call)
 print(result)
except Exception as e:
 print(f"Fallimento finale dopo vari tentativi : {e}")

Jitter :

Aggiungere un lieve ritardo casuale (jitter) al periodo di attesa impedisce un problema di “stormo tonante” in cui numerosi agenti ripetono a intervalli esponenziali precisi, il che potrebbe sovraccaricare un servizio ripristinato simultaneamente.

Modello di Interruttore : Prevenire i Fallimenti in Cascata

Sebbene le ripetizioni siano utili per i problemi transitori, ripetere continuamente di fronte a un servizio in fallimento persistente è frustrante e può portare a fallimenti in cascata. Il modello di interruttore è progettato per questo scenario.

Come Funziona :

  1. Stato Chiuso: Il circuito è normale. Le chiamate al servizio continuano. Se si verifica un certo numero di fallimenti all'interno di una soglia, il circuito passa a Apri.
  2. Stato Aperto: Le chiamate al servizio falliscono immediatamente senza tentare di accedere al servizio reale. Dopo un ritardo configurabile, il circuito passa a Mezzo-Aperto.
  3. Stato Mezzo-Aperto: Un numero limitato di chiamate è autorizzato a passare al servizio per testare se si è ripreso. Se queste chiamate di test hanno successo, il circuito torna a Chiuso. Se falliscono, torna a Aperto.

import time

class CircuitBreaker:
 def __init__(self, failure_threshold=3, recovery_timeout=10, half_open_test_count=1):
 self.failure_threshold = failure_threshold
 self.recovery_timeout = recovery_timeout
 self.half_open_test_count = half_open_test_count

 self.failures = 0
 self.last_failure_time = None
 self.state = "CLOSED" # CHIUSO, APERTO, MEZZO-APERTO
 self.successes_in_half_open = 0

 def __call__(self, func, *args, **kwargs):
 if self.state == "OPEN":
 if time.time() - self.last_failure_time > self.recovery_timeout:
 self.state = "HALF_OPEN"
 self.successes_in_half_open = 0
 print("Interruttore : APERTO -> MEZZO-APERTO")
 else:
 raise CircuitBreakerOpenError("Il circuito è aperto, non si è tentato alcun richiamo.")

 try:
 result = func(*args, **kwargs)
 self._on_success()
 return result
 except Exception as e:
 self._on_failure(e)
 raise

 def _on_success(self):
 if self.state == "CLOSED":
 self.failures = 0
 elif self.state == "HALF_OPEN":
 self.successes_in_half_open += 1
 if self.successes_in_half_open >= self.half_open_test_count:
 self.state = "CLOSED"
 self.failures = 0
 print("Interruttore : MEZZO-APERTO -> CHIUSO")

 def _on_failure(self, error):
 if self.state == "CLOSED":
 self.failures += 1
 self.last_failure_time = time.time()
 if self.failures >= self.failure_threshold:
 self.state = "OPEN"
 print(f"Interruttore : CHIUSO -> APERTO (fallimenti : {self.failures})")
 elif self.state == "HALF_OPEN":
 self.state = "OPEN"
 self.last_failure_time = time.time()
 print("Interruttore : MEZZO-APERTO -> APERTO (test fallito)")

class CircuitBreakerOpenError(Exception):
 pass

# Esempio d'uso :
breaker = CircuitBreaker(failure_threshold=2, recovery_timeout=5)

def flaky_service():
 if random.random() < 0.8: # 80% di probabilità di fallimento
 raise ValueError("Errore del servizio non funzionante")
 return "Servizio operativo!"

for i in range(10):
 try:
 print(f"Tentativo {i+1} :")
 result = breaker(flaky_service)
 print(f" {result}")
 except (ValueError, CircuitBreakerOpenError) as e:
 print(f" Errore : {e}")
 time.sleep(0.5)

Gestione Semantica degli Errori e Recupero Contestuale

Per gli agenti di IA, gli errori non sono spesso solo eccezioni tecniche; possono essere interpretazioni semantiche errate o fallimenti nel raggiungere un obiettivo desiderato. Una gestione avanzata degli errori implica comprendere il significato dell'errore nel contesto operativo dell'agente.

Esempio : Agente di Web Scraping

Considera un agente progettato per estrarre i prezzi dei prodotti da un sito di e-commerce.

  • Errore Tecnico: requests.exceptions.ConnectionError (transitorio, ripetere con ritardo).
  • Errore Semantico 1: XPath per il prezzo non trovato. Non è un errore tecnico; la pagina si è caricata, ma l'elemento atteso non è presente.
    • Strategia di Recupero: Provare XPaths alternativi, utilizzare l'OCR su uno screenshot, segnalare per esame umano, o annotare che il prezzo è indisponibile.
  • Errore Semantico 2: Il prezzo estratto è "Esaurito" o "N/D". L'estrazione ha funzionato, ma il valore non è un prezzo valido.
    • Strategia di Recupero: Contrassegnare come indisponibile, cercare di trovare una data di riassortimento, notificare che il prodotto è esaurito.
  • Errore Semantico 3: L'agente viene reindirizzato a una pagina di login invece della pagina del prodotto.
    • Strategia di Recupero: Tentare di accedere (se le credenziali sono disponibili), o segnalare come impossibile da elaborare a causa di un requisito di autenticazione.

Implementazione della Gestione Semantica degli Errori :

Questo implica spesso un sistema di gestione degli errori gerarchico :

  1. Gestori di Basso Livello (Tecnici) : Catturare eccezioni specifiche (ad esempio, requests.exceptions, errori di parsing JSON) e applicare retry, timeout o circuit breaker.
  2. Gestori di Mezzo Livello (Specifici per Componenti) : In un componente specifico (ad esempio, una classe `Scraper`, un modulo `APICaller`), gestire gli errori rilevanti per l'operazione di quel componente. Ciò può comportare il parsing dei codici di errore delle risposte API (ad esempio, HTTP 404, 429) e la loro traduzione in tipi di errori interni più significativi.
  3. Gestori di Alto Livello (Obiettivo dell'Agente) : A livello di orchestrazione dell'agente, valutare se l'obiettivo complessivo è stato raggiunto. In caso contrario, analizzare gli errori accumulati e decidere una strategia di recupero olistica (ad esempio, provare un altro strumento, riformulare il prompt, richiedere chiarimenti, escalare a un umano).

Auto-Correzione e Apprendimento dagli Errori

Gli agenti più avanzati non si limitano a gestire gli errori; apprendono da essi.

Aggiustamenti Dinamici dei Prompt :

Se un agente alimentato da un LLM continua a non raggiungere un sotto-obiettivo a causa di una cattiva interpretazione, modificare il prompt in modo dinamico. Ad esempio, se prova frequentemente ad accedere a strumenti non esistenti :

  • Prompt Originale : "Usa gli strumenti disponibili per rispondere alla richiesta dell'utente."
  • Dopo Errore (ToolNotFound) : "Hai accesso ai seguenti strumenti: [lista degli strumenti effettivamente disponibili]. Utilizza solo questi strumenti per rispondere alla richiesta dell'utente."
  • Dopo Errore (IncorrectToolParameters) : "Quando si utilizza lo strumento 'search', ricorda che il parametro 'query' è obbligatorio e deve essere una stringa."

Aggiornamenti della Base di Conoscenza :

Quando un agente incontra un errore persistente di un sistema esterno (ad esempio, un sito web specifico restituisce sempre un 403), registrarlo in una base di conoscenza persistente. I futuri agenti possono interrogare questa base di conoscenza prima di tentare la stessa azione.


class ErrorKnowledgeBase:
 def __init__(self):
 self.problematic_endpoints = {}

 def record_failure(self, endpoint_url, error_type, timestamp, message):
 if endpoint_url not in self.problematic_endpoints:
 self.problematic_endpoints[endpoint_url] = []
 self.problematic_endpoints[endpoint_url].append({
 "error_type": error_type,
 "timestamp": timestamp,
 "message": message
 })
 # Logica semplice : Se un endpoint fallisce ripetutamente, segnarlo come 'non affidabile'
 if len(self.problematic_endpoints[endpoint_url]) > 5 and \
 all(time.time() - f["timestamp"] < 3600 for f in self.problematic_endpoints[endpoint_url][-5:]):
 print(f"Avviso : {endpoint_url} sembra non affidabile. Considerare alternative.")

 def is_endpoint_unreliable(self, endpoint_url, recent_threshold=3600):
 # Controlla se un endpoint ha avuto fallimenti ripetuti recenti
 failures = self.problematic_endpoints.get(endpoint_url, [])
 recent_failures = [f for f in failures if time.time() - f["timestamp"] < recent_threshold]
 return len(recent_failures) > 5 # Soglia di esempio

# Utilizzo in un agente :
kb = ErrorKnowledgeBase()

def make_api_call(url):
 if kb.is_endpoint_unreliable(url):
 print(f"Ricerca {url} a causa di una non affidabilità conosciuta.")
 raise Exception("Endpoint ritenuto non affidabile.")
 try:
 # ... chiamata API reale ...
 if random.random() < 0.6: # Simula un fallimento
 raise requests.exceptions.HTTPError(f"403 Vietato da {url}")
 return "Dati di " + url
 except Exception as e:
 kb.record_failure(url, type(e).__name__, time.time(), str(e))
 raise

import requests

for _ in range(10):
 try:
 print(make_api_call("http://example.com/sensitive_api"))
 except Exception as e:
 print(f"Errore catturato : {e}")
 time.sleep(0.1)

Ritorno di Informazioni Umano :

Per gli errori critici o irrimediabili, escalare a un umano è spesso la migliore strategia. L'agente deve fornire tutto il contesto pertinente :

  • Cosa stava cercando di fare l'agente ?
  • Quale fase è fallita ?
  • Qual era il messaggio di errore esatto/traccia dello stack ?
  • Quali tentativi di recupero sono stati fatti ?
  • Quali dati hanno portato all'errore ?

La risoluzione da parte dell'umano (ad esempio, fornire un'input corretta, aggiornare uno strumento, modificare la logica dell'agente) può quindi essere integrata nella base di conoscenza o nel codice dell'agente per le prossime iterazioni.

Osservabilità e Monitoraggio per la Gestione degli Errori

Anche la migliore gestione degli errori è inutile se non sai se funziona (o fallisce). Una solida osservabilità è essenziale.

  • Registrazione Strutturata : Registra gli errori con formati coerenti (JSON è ottimo). Includi timestamp, ID dell'agente, ID del task, tipo di errore, gravità, traccia dello stack e variabili di contesto pertinenti.
  • Metrica e Allerta : Monitora la frequenza dei diversi tipi di errori. Imposta avvisi per errori critici, tassi di errore elevati o periodi prolungati di attivazione del circuit breaker.
  • Tracciamento : Per agenti complessi e a più fasi, il tracciamento distribuito può aiutare a visualizzare il flusso e localizzare i fallimenti attraverso diversi componenti o servizi.
  • Dashboard : Crea dashboard per visualizzare le tendenze degli errori, i tassi di recupero e la salute complessiva dei tuoi agenti.

Conclusione : Costruire Agenti Resilienti e Intelligenti

Una gestione avanzata degli errori trasforma un agente da uno script fragile a un'entità resiliente e intelligente. Comprendendo i tipi di errori, implementando schemi di retry e circuit breaker sofisticati, adottando una gestione semantica degli errori e costruendo meccanismi di auto-correzione e apprendimento, possiamo creare agenti che navigano con grazia nelle complessità del mondo reale. Questo approccio proattivo migliora non solo l'affidabilità dei tuoi sistemi di IA, ma riduce anche i costi operativi e migliora l'esperienza complessiva degli utenti, aprendo la strada a un'IA veramente autonoma e affidabile.

🕒 Published:

✍️
Written by Jake Chen

AI technology writer and researcher.

Learn more →
Browse Topics: ci-cd | debugging | error-handling | qa | testing
Scroll to Top