Cambia tema

State machine per Agent IA: perché un workflow complesso non può dipendere solo dal prompt

Easton editorial illustration: large Agent state recorder, coral failure beacon, checkpoint rewind handle, recovery status strip
8
Campi di stato centrali
state, event, guard, action, checkpoint, retry, compensation, terminal.
4
Oggetti di record
state snapshot, event log, trace, audit log.
3
Action di recovery
resume, retry, compensate.
数据来源: Questa checklist di engineering si basa sulla documentazione ufficiale di LangGraph, Temporal, OpenAI Agents SDK, AWS Step Functions e Stately. Nomi API e comportamenti di prodotto vanno comunque verificati sulle fonti ufficiali dopo la pubblicazione.

"La documentazione LangGraph Persistence descrive i checkpoint come graph state snapshot con scope di thread e spiega che supportano conversation continuity, human-in-the-loop, time travel e fault tolerance."

Un Agent di reportistica è fallito poco prima di inviare l’e-mail al passo 5. Il team operations ha rilanciato il task. L’Agent è ripartito dal passo 1, ha generato un nuovo report e ha sovrascritto la versione già approvata. Lo stato di approvazione è andato perso. Il record firmato dall’approvatore è stato sostituito dal nuovo risultato, e nessun log poteva più dimostrare che la prima versione del report fosse stata approvata.

Non era un problema di rollback del database e nemmeno un semplice retry di coda. Nel prompt restava solo la frase “continua l’elaborazione”. Il modello ha dedotto di nuovo l’intero flusso, senza sapere che i passi 1-4 avevano già prodotto effetti esterni: chiamata all’API di approval, generazione del report, scrittura di un file temporaneo. Il punto di errore era il passo 5, ma gli effetti erano iniziati dal passo 2.

Il problema vero non era la capacità del modello. Il progresso del task era nascosto nel linguaggio naturale del prompt, senza uno state snapshot recuperabile. I messages portati dal prompt sono contesto del modello, non fatti di esecuzione.

Per correggere un incidente del genere non basta aggiungere al prompt una frase come “controlla il progresso prima di continuare”. La scelta più solida è scrivere nodo corrente, effetti già prodotti, action successiva e compensation dell’errore in una tabella di stato recuperabile.

Punti chiave dell’incidente

Flusso di esecuzione dell’Agent di reportistica:

PassoOperazioneEffetto esternoIdempotenza
Passo 1Query datiChiama il database e legge dati utenteIdempotente (operazione di lettura)
Passo 2Generazione reportChiama lo strumento di reportistica e genera un PDFNon idempotente (sovrascrive un file)
Passo 3Attesa approvalInvia una richiesta di approvazione e attende un umanoIdempotente (API supportata)
Passo 4Approval accettatoRiceve l’event approveIdempotente (query di stato)
Passo 5Invio e-mailChiama l’API e-mail e invia il reportFallito (timeout)

Causa dell’errore: l’invio e-mail al passo 5 è andato in timeout per rate limiting dell’API esterna, e il task è stato marcato come FAILED.

Logica di rerun: leggere il “progresso attuale” dal prompt. Il prompt diceva solo “approvato, continua”. Esecuzione reale: ripartire dal passo 1 -> rigenerare il report al passo 2 (sovrascrivendo la versione approvata) -> richiedere di nuovo approval al passo 3 -> inviare con successo al passo 5.

Impatto business: il report approvato è stato sostituito, i record di approval non corrispondevano più al report consegnato, l’utente ha segnalato che il report approvato non era quello ricevuto, e il flusso di approvazione è stato sprecato: due versioni approvate, una sola inviata.

Tabella per riconoscere gli anti-pattern

Controlla se il tuo Agent rientra in questi anti-pattern:

Anti-patternCome si presentaRischio nascostoCorrezione
Progresso scritto nel PromptRiassunto in linguaggio naturale, tipo “siamo al passo 3”Perso dopo restart, non recuperabileRegistrare il nodo corrente in un campo State
Trace trattato come StateUna trace completa viene scambiata per statoTrace non decide il prossimo passoState registra cosa deve succedere dopo
Retry senza controllo di idempotenzaIn caso di errore si riparte dall’inizioGli effetti esterni si ripetonoIdempotency key + controllo già eseguito
Resume dopo approval senza verificaSi continua direttamenteNon si torna al punto correttocheckpoint + thread_id

1. Fondamenti di state machine: State, Event, Transition, Guard, Action

Una state machine non è necessaria per ogni Agent. Un semplice Q&A di supporto può funzionare con un array di messages. Ma un task complesso, con più passi, approval, chiamate a sistemi esterni e recovery dopo errore, deve rendere esplicito il progresso.

1.1 Tabella dei termini centrali

La terminologia di base viene dalla documentazione Stately:

TermineDefinizioneEsempio AgentFonte
StateModalità in cui si trova la macchina, con un’intenzione semantica unicaINIT, PLAN_READY, TOOL_RUNNING, APPROVAL_PENDING, FAILED, COMPLETEDStately state machines
EventSegnale esterno che innesca un cambio di statotimeout, approve, reject, retry, resume, task_receivedStately state machines
TransitionPercorso consentito tra stati, come mapping deterministicoINIT -> PLAN_READY (event: task_received)Stately state machines
Guard/ConditionPrecondizione per entrare in uno statoEntrare in TOOL_RUNNING solo se il budget è sufficienteStately state machines
ActionOperazione eseguita durante una transitionChiamare uno strumento entrando in TOOL_RUNNINGStately state machines
CheckpointState snapshot usato per il recoveryLangGraph checkpointer salva graph stateLangGraph Persistence

Principio di determinismo: la stessa combinazione State + Event dovrebbe puntare a un solo next state, evitando ambiguità. Insieme finito di stati: una state machine non è un flowchart infinito, ma un insieme finito di stati raggiungibili più regole di transition esplicite.

1.2 Confronto Trace vs State vs Audit

Trace, Audit Log e State Snapshot risolvono tre problemi diversi:

ConcettoProblema risoltoÈ stato di business?Decide il prossimo passo?Esempio Agent
TraceOsservabilità e diagnosiNoNoOpenAI Agents SDK trace (workflow_name, trace_id)
Audit LogRegistro di compliance e audit trailNoNoCampi audit del modello permessi (actor, traceId, action, result)
State SnapshotStato corrente che decide il prossimo passoLangGraph checkpoint (nodo corrente, passi completati, prossima action)

La distinzione è cruciale: una trace aiuta a osservare cosa è successo, ma non è lo stato di business. Un audit log registra la storia per responsabilità e compliance. Uno state snapshot decide cosa deve succedere dopo, ed è il cuore del recovery. Non sono intercambiabili: avere trace non significa avere state; avere audit non significa poter recuperare.

2. Come LangGraph gestisce la persistenza dello stato

Un checkpoint non è un riassunto in linguaggio naturale nel prompt. È uno state snapshot recuperabile, ispezionabile e replayable. La documentazione LangGraph persistence definisce il checkpoint come graph state snapshot con stato completo e prossimi nodi da eseguire.

2.1 Checkpointer e Thread State

Meccanismi centrali (documentazione LangGraph Persistence):

  • Checkpointer: salva snapshot di stato con scope di thread (graph state snapshot)
  • Store: salva dati a lungo termine tra thread (application-defined store)
  • Thread_id: punto di ingresso unico per recuperare lo stato di uno specifico thread
  • Quattro usi: conversation continuity, human-in-the-loop, time travel, fault tolerance

LangGraph persistence mette lo stato breve con scope di thread nei checkpointers e i dati a lungo termine tra thread negli stores. Un checkpoint include state snapshot e application-defined store. Thread_id è l’ingresso del recovery: con la stessa thread_id puoi continuare dal punto di pausa.

Un checkpoint LangGraph contiene graph state, lista dei prossimi nodi da eseguire, checkpoint_id, timestamp e versione. I dati sensibili non devono entrare nel checkpoint senza controllo: alcuni campi del graph state possono contenere informazioni sensibili e vanno esclusi dalla persistenza con configurazione esplicita.

2.2 Interrupts e meccanismo di recovery

Meccanismi centrali (documentazione LangGraph Interrupts):

  • interrupt(): mette in pausa dinamicamente l’esecuzione dentro un nodo del grafo, salva graph state e attende input esterno
  • Metodo di recovery: usare la stessa thread_id e Command(resume=…)
  • Pattern comuni: approval, review/edit, tool call review, human input validation
  • Avviso sugli effetti idempotenti: gli effetti prima di interrupt devono essere idempotenti, perché al resume il nodo riparte dall’inizio del nodo che ha chiamato interrupt

Una pausa di approval deve essere uno stato di pausa nella state machine, non una speranza che il modello “si ricordi di aspettare l’approvazione”. Il recovery richiede lo stesso thread cursor.

Il recovery usa la stessa thread_id e Command(resume=…). Gli effetti idempotenti sono una precondizione. Se prima dell’approvazione esiste un effetto esterno, come una chiamata API, deve essere idempotente; altrimenti il nodo ripreso chiamerà di nuovo l’API.

3. Analogia ingegneristica: Temporal Durable Execution

L’affidabilità dei task lunghi non è un problema nuovo. Temporal durable execution offre un riferimento maturo.

3.1 Definizione di Durable Execution

Concetti centrali (documentazione Temporal Durable Execution):

  • Durable Execution: workflow execution conserva state/progress durante errori, crash o interruzioni di servizio
  • Event History: registra lo stato di ogni passo, così dopo un errore si può recuperare dall’ultimo evento registrato
  • Tre proprietà: Resumable, Recoverable, Reactive

L’affidabilità dei task lunghi nasce da event history ed esecuzione recuperabile, non dalla memoria di un singolo processo o dal contesto del prompt. Una state machine per Agent richiede un meccanismo simile: checkpoint/event log + stato di business, non solo nuova inferenza del modello.

Event History di Temporal e checkpoint di LangGraph sono concettualmente simili: registrano la storia di esecuzione e supportano il recovery dal punto di errore. La differenza è che Temporal è un workflow engine completo, mentre LangGraph è un framework di gestione dello stato per Agent. La lezione è chiara: durable execution richiede storia strutturata dello stato, non memoria di processo o contesto del modello.

4. Template di tabella di stato: una Agent State Table riutilizzabile

I concetti di state machine sono astratti. Per renderli utili serve un modello di stato concreto. Qui trovi tre template: tabella di stato, tabella degli eventi ed esempio guidato dall’incidente.

4.1 Template di tabella di stato (blocco eseguibile)

Struttura del template:

StateEventGuardAction obbligatoriaNext
INITtask_receivedNessunoInizializzare il contesto e registrare l’ora di inizioPLAN_READY
PLAN_READYplan_generatedplan_validGenerare il piano di esecuzione e registrare la sequenza strumentiTOOL_RUNNING
TOOL_RUNNINGtool_completedbudget_sufficientChiamare lo strumento, registrare il risultato e aggiornare il budgetAPPROVAL_PENDING o COMPLETED
APPROVAL_PENDINGapproveapproval_requiredInviare richiesta di approval e registrare l’approvatoreCOMPLETED
APPROVAL_PENDINGrejectNessunoRegistrare motivo del rifiuto e notificare l’utenteFAILED
FAILEDretryretry_count < maxVerificare idempotenza e tornare al checkpoint precedenteTOOL_RUNNING o APPROVAL_PENDING
COMPLETEDNessunoNessunoRegistrare ora di completamento e ripulire risorseTerminal

Note: la colonna State definisce tutti gli stati raggiungibili (INIT, PLAN_READY, TOOL_RUNNING, APPROVAL_PENDING, FAILED, COMPLETED). Event definisce gli eventi che innescano transition (task_received, approve, reject, retry). Guard definisce le precondizioni (budget_sufficient, retry_count < max). Action definisce l’operazione obbligatoria durante la transition. Next definisce il prossimo stato in modo deterministico.

4.2 Template di tabella eventi (complemento della tabella di stato)

Struttura del template:

EventCondizione di triggerStato precedente richiestoStato successivoProduce effetti esterni?
task_receivedL’utente invia un taskINITPLAN_READYNo
plan_generatedL’LLM genera un piano di esecuzionePLAN_READYTOOL_RUNNINGNo
tool_completedLo strumento termina l’esecuzioneTOOL_RUNNINGAPPROVAL_PENDING o COMPLETEDSì (chiamata API esterna)
approveL’approvatore accettaAPPROVAL_PENDINGCOMPLETEDSì (invia e-mail, scala budget)
rejectL’approvatore rifiutaAPPROVAL_PENDINGFAILEDNo
retryRichiesta di retry dopo erroreFAILEDTOOL_RUNNING o APPROVAL_PENDINGRichiede controllo di idempotenza
timeoutTimeout di esecuzioneTOOL_RUNNINGFAILEDNo

Note: lo stato precedente richiesto rende esplicito in quali stati un event può essere ricevuto. La colonna sugli effetti esterni segnala quali event richiedono idempotenza o compensation.

4.3 Esempio di tabella di stato guidata dall’incidente di report sovrascritto

Esempio completo: state table dell’Agent di reportistica derivata dall’incidente iniziale

StateEventGuardActionNextControllo idempotenza/compensation
INITtask_receivedNessunoInizializzare thread_id e registrare ora di inizioQUERY_RUNNINGNon serve
QUERY_RUNNINGquery_completedNessunoInterrogare dati e salvare risultato in stateREPORT_GENERATINGNon serve
REPORT_GENERATINGreport_generatedNessunoGenerare report e salvare report ID in stateAPPROVAL_PENDINGControllo idempotenza: se il report esiste già, saltare generazione
APPROVAL_PENDINGapproveNessunoRegistrare approvatore e ora approvalEMAIL_SENDINGNon serve
APPROVAL_PENDINGrejectNessunoRegistrare motivo del rifiutoFAILEDNon serve
EMAIL_SENDINGemail_sentNessunoInviare e-mail e registrare email IDCOMPLETEDControllo idempotenza: se l’e-mail è già stata inviata, saltare
EMAIL_SENDINGtimeoutretry_count < 3Registrare errore e verificare idempotenzaEMAIL_SENDING (retry) o FAILEDIdempotency key: email_id + thread_id
FAILEDretryretry_count < maxVerificare idempotenza e recuperare dal checkpoint precedenteQUERY_RUNNING o REPORT_GENERATING o EMAIL_SENDINGDecidere il punto di recovery in base al checkpoint
COMPLETEDNessunoNessunoRegistrare ora di completamento e ripulire risorseTerminalNon serve

Correzione dell’incidente: se il passo 5 fallisce (EMAIL_SENDING -> timeout), il recovery deve riprendere da EMAIL_SENDING, non da QUERY_RUNNING. Il checkpoint deve registrare il nodo corrente (EMAIL_SENDING), i passi completati (QUERY, REPORT_GENERATED, APPROVAL_APPROVED) e cosa fare dopo (EMAIL_SENDING). Generazione report e invio e-mail richiedono idempotency key per evitare duplicati.

5. Idempotenza e compensation: recovery non significa solo checkpoint

Avere un checkpoint non significa poter recuperare in sicurezza tutti gli effetti esterni. Il recovery richiede anche idempotenza, transazioni, compensation e controlli sullo stato del sistema esterno.

5.1 Concetti di idempotenza e compensation

Definizioni:

  • Idempotente: più esecuzioni producono lo stesso risultato e non creano effetti esterni duplicati
  • Compensation: annullare un effetto esterno già avvenuto e ripristinare consistenza
  • Rollback transazionale: operazione atomica che si annulla automaticamente in caso di errore
  • Controllo dello stato esterno: verificare il sistema esterno prima del recovery per evitare operazioni duplicate

Tre pilastri della consistenza dello stato: identità di idempotenza (action_id + schema_hash), catena di state snapshot (snapshot + prev_hash + delta) e compensation action registrata (undo_op).

5.2 Checklist idempotenza e compensation

Come decidere quali operazioni richiedono idempotenza e quali richiedono compensation:

Tipo di operazioneRichiede idempotenza?Richiede compensation?Design idempotency keyPiano di compensation
Query dati (senza effetti esterni)NoNo--
Generazione report (sovrascrive file)report_id + thread_idEliminare il nuovo report e ripristinare la versione approvata
Invio e-mail (API esterna)Difficileemail_id + thread_idInviare e-mail di correzione o annullamento in alcuni scenari
Decurtazione inventario (database)inventory_id + order_idAggiungere di nuovo inventario
Creazione ticket (sistema esterno)ticket_id + thread_idChiudere il ticket
Decurtazione budget (stato interno)budget_id + thread_idAggiungere di nuovo budget
Invio richiesta approval (senza effetto duraturo)NoNo--

Logica di decisione: il fatto che un’operazione produca effetti esterni determina il bisogno di idempotenza. Le operazioni reversibili richiedono compensation. Nelle chiamate tra sistemi, l’idempotency key dovrebbe includere un identificatore del sistema esterno. Le operazioni atomiche possono usare rollback transazionale.

Recovery non è solo checkpoint. Richiede idempotenza, transazioni, compensation e controlli sullo stato esterno. Dire che un checkpoint recupera in sicurezza tutti gli effetti esterni non è corretto.

6. Checklist degli stati del task Agent: recuperabile vs non recuperabile

Non tutti i checkpoint consentono recovery. Terminal state è lo stato finale di una workflow execution: completato, fallito, timeout o cancelled. Un terminal state non può essere ripreso; può solo essere rieseguito o compensato.

6.1 Tabella di classificazione degli stati

Tipo di statoRecuperabile?Condizione di recoveryMetodo di recoveryEsempio
Failedretry_count < maxRecuperare dal checkpoint precedenteTimeout di tool call
RetryControllo idempotenza superatoRieseguire dal nodo fallitoInvio e-mail fallito
CompensationParzialmenteEsiste un piano di compensationEseguire undo_opDecurtazione inventario fallita
Approval Pauseevent approve/rejectCommand(resume=…)Attesa approval
TerminalNoNessunaNessun percorso di recoveryCOMPLETED, FAILED (retry_count = max)

Note: uno stato Failed può recuperare con retry se retry_count < max. Uno stato Retry richiede controllo di idempotenza e riesegue dal nodo fallito. Uno stato Compensation è parzialmente recuperabile se esiste un piano. Approval Pause recupera con event approve/reject. Terminal State non è recuperabile, per esempio COMPLETED o FAILED dopo il massimo numero di retry.

7. Letture successive

Il design della state machine è solo il punto di partenza. Il modello di stato deve aderire allo scenario di business; task diversi richiedono granularità dello stato e strategie di recovery diverse.

ArticoloRelazioneLink
Human-in-the-loop Agent: quali passi richiedono approvazione umanaDettagli della pausa di approval/blog/it/posts/ai/20260707-human-in-the-loop-agent-approval-design/
Controllo costi Agent: model routing, budget strumenti e retry degli erroriStrategia budget e retry/blog/it/posts/ai/20260707-agent-cost-control-model-routing-tool-budget-cache-retry/
Gestione dello stato LangGraph in pratica: best practice di architettura Agent 2026Gestione stato LangGraph/blog/it/posts/ai/20260424-langgraph-agent-architecture/
Monitoraggio, alert e recovery degli errori per AI Agent: dai log alle state machineMonitoraggio e recovery/blog/it/posts/ai/20260527-ai-agent-monitoring-recovery/
LangGraph vs AutoGen State TrackingConfronto framework/blog/it/posts/ai/20260526-langgraph-autogen-state-tracking/
Dataset di valutazione Agent e test di regressione: evitare che una modifica rompa tuttoValutazione e test di regressioneAnteprima, prossimo articolo della serie

Riferimenti esterni

Fonti ad alta affidabilità:

FonteAffidabilitàTemaLink
Documentazione LangGraph PersistencehighCheckpointer, Store, Thread State, Checkpointhttps://docs.langchain.com/oss/python/langgraph/persistence
Documentazione LangGraph Interruptshighinterrupt(), Command(resume=…), thread_idhttps://docs.langchain.com/oss/python/langgraph/interrupts
Documentazione Temporal Durable ExecutionhighEvent History, Durable Execution, Resumable/Recoverablehttps://docs.temporal.io/temporal
Documentazione OpenAI Agents SDK TracinghighTrace, Span, workflow_name, trace_idhttps://openai.github.io/openai-agents-python/tracing/
Documentazione AWS Step Functions State MachineshighState Machine, Flow State, Task State, StartAt, Nexthttps://docs.aws.amazon.com/step-functions/latest/dg/concepts-statemachines.html
Stately: State machines and statechartsmediumState, Event, Transition, Guard, Action, Hierarchyhttps://stately.ai/docs/state-machines-and-statecharts

Una state machine non serve a ogni Agent, ma i task complessi devono rendere esplicito il progresso. Il passo successivo non è introdurre altri framework. È progettare State, Event, Transition, Guard e Action adatti al tuo scenario di business, spostando il progresso del task dal linguaggio naturale del prompt a uno stato strutturato.

Progettare la state machine di un Agent IA complesso

Scomponi un task complesso di Agent IA in state, event, guard, action, checkpoint, retry, compensation e terminal state, evitando che il progresso resti nascosto solo nel prompt.

⏱️ Estimated time: 45 min

  1. 1

    Step 1: Elenca i punti di rischio

    Elenca gli effetti esterni del task, i punti di pausa umana, i punti di errore e le condizioni terminali.
  2. 2

    Step 2: Definisci il set minimo di stati

    Definisci il set minimo utile di state, come pending, running, waiting_approval, retrying, compensating, succeeded, failed e cancelled.
  3. 3

    Step 3: Collega event e next state

    Per ogni state, scrivi quali event può ricevere e a quale next state porta ogni event.
  4. 4

    Step 4: Aggiungi le condizioni di guard

    Aggiungi guard alle transition pericolose: permessi, budget, approval, idempotency key e stato delle risorse esterne.
  5. 5

    Step 5: Isola le action degli strumenti

    Metti le chiamate agli strumenti nel livello action e registra riepilogo input, riepilogo output, traceId e risultato dell'effetto esterno.
  6. 6

    Step 6: Definisci le policy di errore

    Definisci retry policy, terminal state e compensation policy per ogni percorso di errore.
  7. 7

    Step 7: Persisti la base di recovery

    Definisci un checkpoint o event log per il recovery e tratta il prompt come contesto temporaneo, non come unica fonte di verità.

FAQ

Se l'Agent fallisce al passo 5, devo ripartire dal passo 1 o continuare da un checkpoint?
Dipende dal fatto che gli effetti esterni siano idempotenti e dal fatto che il checkpoint sia sufficiente. Senza effetti esterni puoi ripartire dall'inizio. Con effetti idempotenti devi continuare dal checkpoint. Se gli effetti non sono idempotenti, compensa prima e poi recupera. Senza checkpoint resta solo il riavvio completo, con il rischio di duplicare gli effetti.
Lo stato del task deve stare nel prompt, in un database, in un checkpoint LangGraph o in un job di coda?
Per task semplici, il prompt può essere contesto temporaneo. I task complessi hanno bisogno di checkpoint o event log più stato di business. In produzione spesso si usa LangGraph checkpoint per il thread state e un database di business per ordini, approval, permessi e fatturazione. Un job di coda serve per l'asincrono, ma richiede comunque gestione dello stato.
Qual è la differenza tra una state machine e un diagramma di workflow?
Una state machine mette al centro stati finiti raggiungibili, transition deterministiche, guard e action. Un workflow descrive più la sequenza dei passi di esecuzione. Un Agent ha bisogno dei concetti centrali della state machine, ma non sempre di un statechart completo con gerarchia e concorrenza.
Come garantire che l'Agent torni allo stesso punto di esecuzione dopo approval?
Usa la stessa thread_id e ripristina da un checkpoint, per esempio con il pattern Command(resume=...) descritto nella documentazione LangGraph Interrupts. Il checkpoint deve registrare nodo corrente, passi completati e action successiva; gli effetti prima dell'interrupt devono essere idempotenti.
Retry e compensation vanno nel prompt o nelle regole di transition dello stato?
Vanno nelle regole di transition lato server, non solo nel prompt. retry_count, max retry, idempotency key, undo_op e terminal state devono essere testabili, auditabili e recuperabili. Il prompt può aiutare nel giudizio, ma non deve essere l'unico supporto delle regole di affidabilità.
Un semplice Agent di customer service ha bisogno di una state machine?
Un bot FAQ a turno singolo di solito non ha bisogno di una state machine pesante. Quando l'Agent consulta ordini, crea ticket, gestisce approvazioni di rimborso, pagamenti o API esterne, servono stato esplicito, checkpoint, idempotenza e compensation.

14 min di lettura · Pubblicato il: 17 set 2026

Commenti

Accedi con GitHub per lasciare un commento

Easton BlogEaston Blog