\n\n\n\n Gestione degli Errori dell'Agente: Una Guida Pratica Avanzata - AiDebug \n

Gestione degli Errori dell’Agente: Una Guida Pratica Avanzata

📖 11 min read2,056 wordsUpdated Apr 4, 2026

Introduzione: La Realtà Ineludibile degli Errori degli Agenti

Nel mondo degli agenti AI, l’esecuzione perfetta è un mito. Che il tuo agente stia navigando in una complessa applicazione web, generando contenuti creativi o gestendo flussi di lavoro intricati, gli errori sono una parte inevitabile del processo. Interruzioni di rete, limiti di frequenza API, risposte malformate, cambiamenti imprevisti dell’interfaccia utente e persino sottili malintesi nelle istruzioni possono tutti portare a fallimenti. Mentre i base try-catch sono un buon punto di partenza, una vera solidità nel design dell’agente richiede un approccio più sofisticato nella gestione degli errori. Questa guida avanzata esplorerà strategie pratiche e modelli architettonici per costruire agenti che non solo recuperano con grazia, ma apprendono e si adattano dai propri errori.

Oltre ai Riprovi di Base: Comprendere i Tipi di Errori e la Loro Gravità

Il primo passo verso una gestione avanzata degli errori è muoversi oltre un generico “ritenta tutto”. Non tutti gli errori sono creati uguali. Distinguere tra i diversi tipi di errori e la loro gravità consente strategie di recupero più intelligenti e consapevoli del contesto.

Catalogazione degli Errori:

  • Errori Transitori: Problemi temporanei che probabilmente si risolveranno da soli con un breve ritardo e un nuovo tentativo (ad esempio, glitch di rete, sovraccarichi temporanei dell’API, deadlock nel database).
  • Errori Persistenti: Problemi che è improbabile si risolvano con un semplice tentativo e richiedono un approccio diverso (ad esempio, chiavi API inválide, schemi di input errati, errori logici fondamentali, permesso negato).
  • Errori Sistemici: Problemi radicati che indicano un difetto fondamentale nel design dell’agente, nella formazione o nell’ambiente (ad esempio, allucinazioni ricorrenti, incapacità di analizzare un componente critico, fallimenti continui su un tipo di attività specifico).
  • Errori di Sistema Esterno: Errori che provengono da servizi di terze parti con cui l’agente interagisce, richiedendo spesso una gestione specifica in base alla documentazione del servizio esterno.

Livelli di Gravità:

  • Informativo: Problemi minori che non impediscono il completamento del compito ma potrebbero indicare un rendimento subottimale.
  • Avviso: Problemi che potrebbero impattare sulle performance o indicare un potenziale problema, ma l’agente può comunque procedere.
  • Errore: Un problema significativo che impedisce il completamento del passo o del sotto-compito attuale.
  • Critico: Un fallimento catastrofico che impedisce all’intero agente di raggiungere il proprio obiettivo primario.

Meccanismi di Riprova Avanzati con Backoff e Jitter

I semplici riprovi possono spesso esacerbare i problemi, specialmente con errori transitori come i limiti di frequenza dell’API. Le strategie di riprova avanzate sono cruciali.

Backoff Esponenziale:

Invece di riprovare immediatamente, attendi un tempo crescente esponenzialmente tra i tentativi. Questo dà al sistema il tempo di recuperare e previene un ulteriore sovraccarico.


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"Attempt {i+1} failed: {e}")
 if i == max_retries - 1:
 raise
 delay = min(initial_delay * (2 ** i), max_delay)
 jitter = random.uniform(0, delay * 0.1) # Aggiungi fino al 10% di jitter
 print(f"Retrying in {delay + jitter:.2f} seconds...")
 time.sleep(delay + jitter)

# Esempio di utilizzo:
def problematic_api_call():
 if random.random() < 0.7: # 70% di possibilità 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 diversi tentativi: {e}")

Jitter:

Aggiungere un piccolo ritardo casuale (jitter) al periodo di backoff previene un problema di "mandria in tempesta" in cui molti agenti riprovano simultaneamente a intervalli esponenziali, potenzialmente sovraccaricando un servizio recuperato.

Schema del Circuit Breaker: Prevenire i Fallimenti a Cascata

Mentre i riprovi sono utili per problemi transitori, riprovare continuamente contro un servizio che fallisce persistentemente è uno spreco e può portare a fallimenti a cascata. Il pattern Circuit Breaker è progettato per questo scenario.

Come Funziona:

  1. Stato Chiuso: Il circuito è normale. Le chiamate al servizio proseguono. Se si verifica un certo numero di fallimenti all'interno di una soglia, il circuito scatta su APERTO.
  2. Stato Aperto: Le chiamate al servizio sono immediatamente segnalate come fallite senza tentare di raggiungere effettivamente il servizio. Dopo un timeout configurabile, il circuito passa a Mezzo-Aperto.
  3. Stato Mezzo-Aperto: Un numero limitato di chiamate è autorizzato a passare al servizio per testare se questo si è ripreso. Se queste chiamate di prova 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("Circuit Breaker: APERTO -> MEZZO-APERTO")
 else:
 raise CircuitBreakerOpenError("Il circuito è aperto, non si sta tentando la chiamata.")

 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("Circuit Breaker: 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"Circuit Breaker: CHIUSO -> APERTO (fallimenti: {self.failures})")
 elif self.state == "HALF_OPEN":
 self.state = "OPEN"
 self.last_failure_time = time.time()
 print("Circuit Breaker: MEZZO-APERTO -> APERTO (test fallito)")

class CircuitBreakerOpenError(Exception):
 pass

# Esempio di utilizzo:
breaker = CircuitBreaker(failure_threshold=2, recovery_timeout=5)

def flaky_service():
 if random.random() < 0.8: # 80% di possibilità di fallimento
 raise ValueError("Errore del servizio instabile")
 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 AI, gli errori non sono spesso solo eccezioni tecniche; possono essere malintesi semantici o fallimenti nel raggiungere un obiettivo previsto. La 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, riprova con backoff).
  • Errore Semantico 1: XPath per il prezzo non trovato. Questo non è un errore tecnico; la pagina è stata caricata, ma l'elemento atteso non è presente.
    • Strategia di Recupero: Prova percorsi XPath alternativi, usa OCR su uno screenshot, segnala per revisione umana o annota che il prezzo non è disponibile.
  • Errore Semantico 2: Il prezzo estratto è "Esaurito" o "N/D". L'estrazione ha funzionato, ma il valore non è un prezzo valido.
    • Strategia di Recupero: Segna come non disponibile, prova a trovare la data di ristock, notifica che il prodotto è esaurito.
  • Errore Semantico 3: L'agente viene reindirizzato a una pagina di login invece che alla pagina del prodotto.
    • Strategia di Recupero: Prova a effettuare il login (se le credenziali sono disponibili), oppure segnala come non elaborabile a causa del requisito di autenticazione.

Implementare la Gestione degli Errori Semantici:

Questo implica spesso un sistema di gestione degli errori gerarchico:

  1. Gestori a Basso Livello (Tecnici): Cattura eccezioni specifiche (ad esempio, requests.exceptions, errori di parsing JSON) e applica riprovi, backoff o circuit breaker.
  2. Gestori a Medio Livello (Specifici per il Componente): All'interno di un componente specifico (ad esempio, una classe `Scraper`, un modulo `APICaller`), gestisci errori rilevanti per l'operazione di quel componente. Questo potrebbe implicare l'analisi dei codici di errore delle risposte API (ad esempio, HTTP 404, 429) e la loro traduzione in tipi di errore interni più significativi.
  3. Gestori ad Alto Livello (Obiettivo dell'Agente): Livello di orchestrazione dell'agente, valuta se l'obiettivo complessivo è stato raggiunto. In caso contrario, analizza gli errori accumulati e decidi su una strategia di recupero olistica (ad esempio, prova a utilizzare uno strumento diverso, riformula il prompt, richiedi chiarimenti, escalda a un umano).

Autocorrezione e Apprendimento dagli Errori

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

Regolazioni Dinamiche del Prompt:

Se un agente alimentato da LLM non riesce costantemente a raggiungere un sotto-obiettivo a causa di un'interpretazione errata, modifica il prompt in modo dinamico. Ad esempio, se tenta frequentemente di accedere a strumenti inesistenti:

  • Prompt Originale: "Usa gli strumenti disponibili per rispondere alla query dell'utente."
  • Dopo Errore (ToolNotFound): "Hai accesso ai seguenti strumenti: [elenco degli strumenti effettivamente disponibili]. Usa solo questi strumenti per rispondere alla query dell'utente."
  • Dopo Errore (IncorrectToolParameters): "Quando usi 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 di sistema esterno persistente (ad es., un sito web specifico restituisce sempre un 403), registra questo in una base di conoscenza persistente. Gli agenti futuri 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, segnalalo 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"Attenzione: {endpoint_url} sembra non affidabile. Considera alternative.")

 def is_endpoint_unreliable(self, endpoint_url, recent_threshold=3600):
 # Controlla se un endpoint ha avuto recenti ripetuti fallimenti
 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 d'esempio

# Utilizzo in un agente:
kb = ErrorKnowledgeBase()

def make_api_call(url):
 if kb.is_endpoint_unreliable(url):
 print(f"Salto {url} a causa di una nota inaffidabilità.")
 raise Exception("Endpoint considerato inaffidabile.")
 try:
 # ... chiamata API effettiva ...
 if random.random() < 0.6: # Simula un errore
 raise requests.exceptions.HTTPError(f"403 Forbidden da {url}")
 return "Dati da " + 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)

Feedback con Human-in-the-Loop:

Per errori critici o irreversibili, passare a un umano è spesso la strategia migliore. L'agente dovrebbe fornire tutto il contesto rilevante:

  • Cosa stava cercando di fare l'agente?
  • Quale passo è fallito?
  • Quale era il messaggio di errore/stack trace esatto?
  • Quali tentativi di recupero sono stati effettuati?
  • Quali dati hanno portato all'errore?

La soluzione dell'umano (ad es., fornire un input corretto, aggiornare uno strumento, modificare la logica dell'agente) può poi essere reinserita nella base di conoscenza o nel codice dell'agente per future iterazioni.

Osservabilità e Monitoraggio per la Gestione degli Errori

Anche la migliore gestione degli errori è inutile se non sai che sta funzionando (o fallendo). Un'osservabilità solida è fondamentale.

  • Logging Strutturato: Registra gli errori con formati coerenti (JSON è eccellente). Includi timestamp, ID agente, ID attività, tipo di errore, gravità, stack trace e variabili di contesto rilevanti.
  • Metrica e Avvisi: Monitora la frequenza dei vari tipi di errore. Imposta avvisi per errori critici, alti tassi di errore, o periodi prolungati di attivazione del circuito di interruzione.
  • Tracing: Per agenti complessi e multi-passaggio, il tracing distribuito può aiutare a visualizzare il flusso e identificare dove si verificano i fallimenti tra i diversi componenti o servizi.
  • Dashboards: Crea dashboard per visualizzare le tendenze degli errori, i tassi di recupero e la salute generale 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 errore, implementando modelli sofisticati di ripetizione e interruzione del circuito, adottando una gestione semantica degli errori e costruendo meccanismi per l'autocorrezione e l'apprendimento, possiamo creare agenti che navigano con grazia le complessità del mondo reale. Questo approccio proattivo non solo migliora l'affidabilità dei tuoi sistemi AI, ma riduce anche i costi operativi e migliora l'esperienza complessiva dell'utente, aprendo la strada a un'AI 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