\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,079 wordsUpdated Apr 4, 2026

Introduzione : La Realtà Ineludibile degli Errori dell’Agente

Nel mondo degli agenti IA, l’esecuzione perfetta è un mito. Che il tuo agente navighi in un’applicazione web complessa, generi contenuti creativi o gestisca flussi di lavoro complicati, gli errori sono inevitabilmente parte del processo. I guasti di rete, i limiti di frequenza delle API, le risposte mal formattate, modifiche inattese dell’interfaccia utente e persino interpretazioni sottili delle istruzioni possono tutti portare a fallimenti. Sebbene blocchi try-catch di base siano un buon inizio, una vera solidità nella progettazione degli agenti richiede un approccio più sofisticato per la gestione degli errori. Questa guida avanzata esplorerà strategie pratiche e modelli architetturali per costruire agenti che non solo si riprendono con grazia, ma imparano e si adattano anche ai loro errori.

Oltre ai Nuovi Tentativi di Base : Comprendere i Tipi e la Gravità degli Errori

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

Categorizzazione degli Errori :

  • Errori Temporanei : Problemi temporanei che si risolvono probabilmente da soli dopo un breve intervallo e un nuovo tentativo (ad esempio, problemi di rete, sovraccarichi temporanei delle API, deadlock nei database).
  • Errori Persistenti : Problemi che non si risolvono con un semplice tentativo e richiedono un approccio diverso (ad esempio, chiavi API non valide, schemi di input errati, errori logici fondamentali, permesso 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 continuativi su un tipo specifico di compito).
  • Errori di Sistema Esterno : Errori provenienti da servizi di terzi con cui l’agente interagisce, richiedendo spesso un trattamento specifico basato sulla documentazione del servizio esterno.

Livelli di Gravità :

  • Informativo : Problemi minori che non impediscono il completamento del compito ma possono indicare una performance subottimale.
  • Avvertimento : Problemi che potrebbero impattare la performance o indicare un problema potenziale, ma che l’agente può comunque affrontare.
  • Errore : Un problema significativo che impedisce il completamento della fase attuale o della sottoattività.
  • Critico : Un fallimento catastrofico che impedisce all’intero agente di raggiungere il suo obiettivo principale.

Mecanismi di Nuovi Tentativi Avanzati con Backoff e Jitter

I semplici ripetizioni possono spesso aggravare i problemi, specialmente con errori temporanei come i limiti di frequenza delle API. Strategie avanzate di nuovo tentativo sono cruciali.

Backoff Esponenziale :

Invece di riprovare immediatamente, attendi un tempo crescente in modo esponenziale tra i tentativi. 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"Tentativo {i+1} fallito : {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"Nuovo tentativo in {delay + jitter:.2f} secondi...")
 time.sleep(delay + jitter)

# Esempio d'uso :
def problematic_api_call():
 if random.random() < 0.7: # 70% di probabilità di fallire
 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 nuovi tentativi : {e}")

Jitter :

Aggiungere un breve ritardo casuale (jitter) al periodo di backoff evita un problema di "corsa al carico" in cui molti agenti riprovano a intervalli esponenziali fissi, il che potrebbe sommemente sovraccaricare un servizio recuperato.

Modello di Interruttore : Prevenire i Fallimenti a Catena

Sebbene i tentativi siano efficaci per problemi temporanei, tentare continuamente di accedere a un servizio che fallisce in modo persistente è inefficace e può portare a fallimenti a catena. Il modello di interruttore è progettato per questo scenario.

Come Funziona :

  1. Stato Chiuso : Il circuito è normale. Le chiamate al servizio continuano. Se si verificano un certo numero di fallimenti oltre una soglia definita, il circuito passa a Aperto.
  2. Stato Aperto : Le chiamate al servizio falliscono immediatamente senza tentare di raggiungere il servizio reale. Dopo un intervallo 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, chiamata non tentata.")

 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 fallire
 raise ValueError("Errore di 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 degli Errori Sementici e Recupero Contestuale

Per gli agenti IA, gli errori non sono spesso solo eccezioni tecniche; possono essere interpretazioni semantiche errate 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

Consideriamo un agente progettato per estrarre i prezzi dei prodotti da un sito di ecommerce.

  • Errore Tecnico : requests.exceptions.ConnectionError (temporaneo, riprovare con backoff).
  • Errore Semantico 1 : XPath per il prezzo non trovato. Non si tratta di un errore tecnico; la pagina è stata caricata, ma l’elemento atteso non è presente.
    • Strategia di Recupero : Provare XPaths alternativi, utilizzare l’OCR su uno screenshot, segnalare per una revisione umana, o annotare che il prezzo non è disponibile.
  • Errore Semantico 2 : Il prezzo estratto è "Esaurito" o "N/A". L’estrazione ha funzionato, ma il valore non è un prezzo valido.
    • Strategia di Recupero : Contrassegnare come non disponibile, provare a trovare una data di riapprovvigionamento, notificare che il prodotto è esaurito.
  • Errore Semantico 3 : L’agente viene reindirizzato su una pagina di login invece della pagina del prodotto.
    • Strategia di Recupero : Tentare di accedere (se le credenziali sono disponibili), o segnalare come ingestibile a causa di un requisito di autenticazione.

Implementazione della Gestione degli Errori Semantici :

Questo implica spesso un sistema gerarchico di gestione degli errori :

  1. Gestori di Basso Livello (Tecnici) : Catturare eccezioni specifiche (ad esempio, requests.exceptions, errori di parsing JSON) e applicare tentativi, backoff o disgiuntori.
  2. Gestori di Livello Intermedio (Specifici ai Componenti) : All'interno di un componente specifico (ad esempio, una classe `Scraper`, un modulo `APICaller`), gestire gli errori pertinenti all'operazione di quel componente. Ciò può comportare il parsing dei codici di errore provenienti dalle risposte API (ad esempio, HTTP 404, 429) e la loro traduzione in tipi di errore interni più significativi.
  3. Gestori di Alto Livello (Obiettivo dell'Agente) : A livello di orchestrazione dell'agente, valutare se l'obiettivo globale è stato raggiunto. In caso contrario, analizzare gli errori accumulati e decidere una strategia di recupero olistica (ad esempio, provare uno strumento diverso, riformulare la richiesta, chiedere chiarimenti, escalare a un umano).

Auto-Correzione e Apprendimento dagli Errori

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

Aggiustamenti Dinamici degli Inviti :

Se un agente alimentato da un LLM fallisce sistematicamente nel raggiungere un sotto-obiettivo a causa di un'errata interpretazione, modificare dinamicamente l'invito. Ad esempio, se tenta frequentemente di accedere a strumenti inesistenti :

  • Invito originale : "Utilizza gli strumenti disponibili per rispondere alla richiesta dell'utente."
  • Dopo un errore (ToolNotFound) : "Hai accesso ai seguenti strumenti: [lista degli strumenti effettivamente disponibili]. Utilizza solo questi strumenti per rispondere alla richiesta dell'utente."
  • Dopo un 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 persistente di un sistema esterno (ad esempio, un sito web specifico restituisce sempre un 403), registrarlo in una base di conoscenza persistente. Gli agenti futuri possono interrogare questa base di conoscenza prima di provare 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, marcarlo 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. Considera alternative.")

 def is_endpoint_unreliable(self, endpoint_url, recent_threshold=3600):
 # Controlla se un endpoint ha avuto fallimenti recenti e ripetuti
 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"Passo da {url} a causa di un'affidabilità conosciuta non soddisfacente.")
 raise Exception("Endpoint ritenuto non affidabile.")
 try:
 # ... chiamata API reale ...
 if random.random() < 0.6: # Simuliamo 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)

Feedback con un umano :

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

  • Cosa stava cercando di fare l'agente ?
  • Quale passaggio ha fallito ?
  • Qual era il messaggio d'errore esatto / la traccia dello stack ?
  • Quali tentativi di recupero sono stati fatti ?
  • Quali dati hanno portato all'errore ?

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

Osservabilità e Monitoraggio per la Gestione degli Errori

Anche il miglior trattamento degli errori è inutile se non si sa 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 compito, tipo di errore, gravità, traccia dello stack e variabili di contesto pertinenti.
  • Metrica e allerte : Monitora la frequenza dei diversi tipi di errori. Imposta allerte per errori critici, tassi di errore elevati o periodi prolungati di attivazione del disgiuntore.
  • Tracciamento : Per agenti complessi e a più fasi, il tracciamento distribuito può aiutare a visualizzare il flusso e identificare dove si verificano 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

Un avanzato trattamento degli errori trasforma un agente da uno script fragile in un'entità resiliente e intelligente. Comprendendo i tipi di errori, implementando modelli sofisticati di ripetizione e disgiuntore, adottando un trattamento semantico degli errori e costruendo meccanismi di auto-correzione e apprendimento, possiamo creare agenti che navigano con facilità nelle complessità del mondo reale. Questo approccio proattivo migliora non solo l'affidabilità dei tuoi sistemi AI, ma riduce anche i costi operativi e migliora l'esperienza utente complessiva, aprendo la strada a un'IA veramente autonoma e degna di fiducia.

🕒 Published:

✍️
Written by Jake Chen

AI technology writer and researcher.

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