
LangGraph con approvazione umana: senza checkpoint l’agente non riparte

Per gestire l’approvazione umana in un agente LangGraph, configura una policy che interrompa la chiamata allo strumento prima dell’azione rischiosa, associa l’esecuzione a un thread e riprendila con una decisione strutturata. La guida di LangChain al controllo umano prevede approve, edit, reject e respond e richiede un checkpointer per conservare lo stato durante l’interruzione.
Il pulsante «Approva» raccoglie soltanto la scelta del revisore. L’applicazione deve poi ritrovare l’esecuzione sospesa tramite lo stesso thread_id e passarle la decisione con Command(resume=...). Se avvia un nuovo thread, quella decisione non riprende la chiamata in attesa.
Interrompi solo le chiamate che richiedono revisione
Considera due strumenti in un esempio ipotetico: execute_sql, che può modificare un database, e send_message, che invia un contenuto all’esterno. Con HumanInTheLoopMiddleware, la mappa interrupt_on associa ciascun nome alle decisioni consentite. Per execute_sql puoi ammettere approve e reject; per send_message puoi aggiungere edit, così il revisore corregge destinatario o testo prima dell’invio. Una lettura autorizzata può proseguire senza interrompere l’agente.
Se lo stesso strumento esegue sia letture sia scritture, la policy può usare when: il predicato riceve la richiesta dello strumento e restituisce True quando occorre fermarla. Nell’esempio SQL, is_write_query esamina l’argomento query e manda in revisione le operazioni di modifica. Un controllo che considera sicura qualunque stringa inizi con SELECT è solo una dimostrazione del meccanismo: una query può avere effetti o rischi che quel prefisso non rivela. Per un database reale, lascia passare automaticamente soltanto le operazioni classificate in modo affidabile e limita comunque i permessi dell’account usato dallo strumento.
La decisione di interrompere va presa prima che lo strumento produca l’effetto. Se un invio parte già durante la preparazione della proposta, la successiva richiesta di approvazione arriva troppo tardi. Tieni quindi separati la costruzione degli argomenti da mostrare al revisore e il codice che esegue davvero la query o l’invio.
Conserva il checkpoint e l’identità del thread
I checkpointer di LangGraph salvano lo stato del grafo in checkpoint organizzati per thread. Per un servizio che deve sopravvivere al riavvio del processo, scegli un backend persistente: PostgresSaver e AsyncPostgresSaver sono opzioni documentate per la produzione. InMemorySaver è adatto a prove e prototipi, ma il suo stato resta nella memoria del processo.
Nel percorso Python dell’esempio, prepara il checkpointer Postgres, inizializzane lo schema con setup() e passalo come checkpointer a create_agent insieme agli strumenti e al middleware. Prima della prima invoke, assegna alla richiesta un identificativo stabile e usa config={"configurable": {"thread_id": "id-stabile"}}. Conserva nell’applicazione l’associazione fra quell’identificativo e la revisione in corso: servirà quando il revisore risponderà, anche se nel frattempo il processo applicativo è ripartito.
Il checkpoint conserva lo stato dell’esecuzione; non sostituisce il registro delle autorizzazioni dell’applicazione. Registra separatamente chi può decidere, quale proposta gli è stata mostrata e se la sua risposta è già stata elaborata. In questo modo puoi verificare che una richiesta di ripresa riguardi proprio la chiamata sospesa, anziché affidarti al solo possesso di un thread_id.
Presenta la proposta e invia la decisione
Invoca l’agente con la richiesta iniziale, il config del thread e version="v2". Se la policy interrompe una chiamata, il risultato espone interrupts: action_requests contiene il nome dello strumento e gli argomenti proposti, mentre review_configs indica le decisioni ammesse. Per una scrittura SQL, mostra la query effettiva; per un invio, mostra destinatario e contenuto. Il revisore deve decidere sull’azione concreta che l’agente sta per eseguire.
Quando arriva la risposta, invoca di nuovo lo stesso agente con il medesimo config e Command(resume={"decisions": [{"type": "approve"}]}). Approve esegue la chiamata con gli argomenti proposti. Reject salta l’esecuzione e restituisce un feedback all’agente; un messaggio di rifiuto esplicito può indicargli se abbandonare l’azione o chiedere chiarimenti.
Con edit, la decisione include edited_action, composto dal nome dello strumento e dagli argomenti aggiornati. Prima di inoltrare una modifica, convalida di nuovo destinatario, query e altri valori rispetto alle regole dell’applicazione: la correzione umana cambia l’azione che sarà eseguita. Respond serve invece agli strumenti che chiedono una risposta a una persona; il messaggio umano diventa il risultato dello strumento. Per negare una scrittura o un invio usa reject, perché respond viene trattato dall’agente come un risultato riuscito.
Se l’interruzione raccoglie più chiamate, prepara una decisione per ciascuna nello stesso ordine delle action_requests. Il revisore può così approvare una proposta e rifiutarne un’altra. Dopo la ripresa, l’agente può formulare nuove chiamate: ciascuna attraversa di nuovo la policy prevista per il relativo strumento.
Proteggi gli effetti esterni dalla ripetizione
La guida alle interruzioni di LangGraph precisa che, dopo il resume, il nodo interrotto riparte dall’inizio. Il codice eseguito prima di interrupt può quindi essere eseguito di nuovo. Colloca gli effetti esterni dopo l’interruzione oppure in un nodo distinto; se un’operazione deve precederla, rendila idempotente.
Esiste anche un rischio successivo all’approvazione: una query o un invio possono riuscire, mentre la risposta si perde prima che l’applicazione registri il completamento. Per una modifica al database, una chiave univoca dell’operazione e una registrazione nella stessa transazione possono impedire di applicarla due volte. Per un servizio di invio, usa una chiave di idempotenza se è supportata; altrimenti verifica l’esito presso il sistema di destinazione prima di ritentare. Il checkpoint dell’agente non può, da solo, stabilire se quel sistema abbia già prodotto l’effetto.
Prima di mettere il flusso in servizio, verifica l’intero ciclo:
- La policy ferma le chiamate con effetti esterni prima della loro esecuzione e presenta al revisore gli argomenti effettivi.
- Il checkpointer conserva lo stato oltre un riavvio e la invoke iniziale e quella con Command usano lo stesso thread_id.
- Ogni decisione è autorizzata, corrisponde alla proposta sospesa ed è elaborata una sola volta.
- Gli argomenti modificati vengono convalidati e il sistema di destinazione dispone di una protezione contro gli effetti duplicati.
- Una prova di riavvio durante l’attesa e una di perdita della risposta dopo l’effetto esterno chiariscono che cosa viene recuperato e quando occorre verificare l’esito prima di riprovare.
Articoli correlati


Prompt injection negli agenti IA: il filtro da solo non basta

Notion o Obsidian: collaborazione cloud contro file davvero tuoi

Un RAG sui documenti non basta: senza citazioni gli errori restano invisibili

Il backup 3-2-1 non basta se non provi davvero il ripristino

Il G7 crea un gruppo sulla sicurezza IA: gli standard restano da scrivere
Iscriviti alla nostra newsletter
Ricevi le ultime notizie su Web3, IA e cripto direttamente nella tua casella di posta.