Il cliente dice al telefono: «Sì, martedì alle due va bene.» L’agente invia la prenotazione al calendario. La risposta non arriva prima del timeout.
La prenotazione è stata creata oppure no?
L’agente non può saperlo e riprova. Questa volta riceve successo. Più tardi compaiono due appuntamenti perché anche il primo request era arrivato a destinazione; si era persa soltanto la risposta.
Il modello aveva capito tutto. L’orario era giusto. Anche il retry aveva senso. Il risultato business è comunque sbagliato.
L’idempotenza permette di ripetere la stessa operazione prevista senza produrre più volte l’effetto.
L’idempotenza negli agenti IA parte dall’operazione business
I sistemi tecnici vedono request. Il cliente vede una prenotazione.
«Prenota cliente 4711 il 17 agosto alle 14 per cambio gomme» è una sola operazione. Tre tentativi di rete non dovrebbero diventare tre appuntamenti.
Stripe documenta le idempotency key proprio per rendere sicuri i retry: una chiave stabile identifica l’operazione e impedisce che una nuova richiesta equivalente crei un secondo risultato. Anche la guida AWS sui Saga pattern sottolinea l’importanza di operazioni idempotenti quando gli step possono essere ripetuti dopo un errore.
Fatto confermato: idempotency key e operazioni idempotenti sono pattern consolidati per gestire retry.
Raccomandazione: date un’identità all’azione business, non soltanto a ogni chiamata API.
Da dove arrivano i duplicati
Timeout, certo. Ma anche doppio clic, webhook consegnato due volte, worker che scrive e poi crasha prima di salvare lo stato, job manualmente risolto e successivamente rieseguito dalla queue.
Con gli agenti c’è inoltre la lingua. «Prendi martedì alle due» e «sì, confermo martedì» possono rappresentare la stessa intenzione. Non devono generare due azioni perché sono due turni conversazionali.
Una UUID casuale nuova a ogni tentativo non aiuta. Se il retry cambia chiave, il sistema target vede una nuova operazione.
La chiave deve rimanere legata a qualcosa di stabile: case ID + azione, cliente + slot + richiesta, fattura + step pagamento, ticket + transizione.
Un flusso di idempotenza piccolo ma corretto
- Definite l’operazione che può avvenire una volta.
- Create una operation key stabile che resta uguale attraverso retry del modello, trasporto e queue.
- Controllate lo stato prima del write. Esiste già
processing,successo l’oggetto nel target? - Salvate il risultato collegando ID e stato all’operazione originale.
- Trattate il timeout come “sconosciuto”, non automaticamente come fallimento.
- Mandate i casi ambigui in exception queue invece di rieseguire alla cieca.
Se l’API target supporta nativamente idempotency key, è la posizione migliore per il controllo. Altrimenti l’orchestrazione deve gestire persistenza e concorrenza.
Tra telefono e WhatsApp la deduplica diventa semantica
Il cliente chiama, non riceve subito la conferma e scrive su WhatsApp. Due canali, due sessioni, probabilmente una sola richiesta.
Qui serve una regola business oltre alla chiave API. Customer ID, servizio, sede, slot e breve finestra temporale possono indicare un duplicato.
Ma evitare falsi positivi è altrettanto importante. Una persona può prenotare due auto o due camere.
Esempio, non standard: due richieste identiche dallo stesso cliente entro tre minuti possono essere marcate come possibile duplicato, collegate e sospese per verifica. Non cancellate la seconda in modo invisibile.
L’handover umano è la scelta corretta quando il sistema non può distinguere un retry da una vera seconda intenzione.
Il pilota minimo deve simulare i casi brutti
Fate riuscire il primo write e perdete la risposta. Inviate due volte il webhook. Avviate due worker con lo stesso job. Completate manualmente un elemento prima del replay.
Misurate duplicati per 1.000 operazioni, retry che mantengono la key originale, operazioni con commit incerto, tempo di risoluzione delle eccezioni, false deduplication e azioni esterne con result ID collegato al caso originario.
Zero duplicati è un buon obiettivo operativo, non la garanzia che non esista alcuna race condition.
gli agenti IA hanno bisogno di idempotenza perché il mondo tecnico ripete le cose. Reti, utenti, code e canali non sono perfetti. Se una singola intenzione deve creare un solo effetto, quell’intenzione deve avere una identità stabile fino alla fine.
Conviene mantenere un registro dell’intenzione business distinto dal semplice log delle chiamate API. La stessa intenzione collega key, tentativi e result ID del sistema target. Dopo un timeout l’agente può così verificare se l’effetto esiste già prima di creare qualcosa di nuovo.
Per un appuntamento il risultato è l’ID della prenotazione; per una mail è il message ID; per un record CRM è l’ID dell’oggetto e, quando disponibile, la sua versione. Questo collegamento è prezioso anche per l’operatore umano: vede cosa è già successo e non deve “provare di nuovo” alla cieca.
Anche la durata della key va scelta sul processo reale. Se una queue può essere ripresa il giorno dopo, una deduplication window di pochi minuti non protegge abbastanza. Al contrario, una finestra troppo lunga può bloccare una seconda richiesta autentica. Stabilite la durata in base a quanto a lungo un retry della stessa intenzione può realisticamente ricomparire.
Per gli effetti non facilmente reversibili — mail al cliente, ordine, fattura, prenotazione — il controllo prima del retry dovrebbe leggere il sistema che fa fede. Se lo stato è incerto, fermate l’esecuzione e create un’eccezione invece di indovinare.
La modalità degradata richiede questa protezione. La riconciliazione confronta poi origine e destinazione.
Fonti
FAQ
L’idempotenza serve solo per i pagamenti?
No. Appuntamenti, ordini, messaggi, CRM e ticket possono essere duplicati.
Una UUID per request è sufficiente?
Non se cambia a ogni retry. La stessa operazione logica deve conservare la stessa chiave.
Se l’API non supporta idempotenza?
Un layer di orchestrazione o database può bloccare la seconda esecuzione, con attenzione a concorrenza e crash.
Si possono unire automaticamente i duplicati tra canali?
Solo in parte. Due richieste simili possono essere legittimamente distinte; l’ambiguità va revisionata.
Timeout significa fallimento?
No. Spesso significa stato sconosciuto. Prima di riprovare bisogna verificare se il primo commit è avvenuto.