\n\n\n\n Ho imparato la gestione dello stato nei sistemi AI multi-agente - AgntAI Ho imparato la gestione dello stato nei sistemi AI multi-agente - AgntAI \n

Ho imparato la gestione dello stato nei sistemi AI multi-agente

📖 13 min read2,484 wordsUpdated Apr 3, 2026

Va bene, ragazzi, Alex Petrov qui, di nuovo su agntai.net. Oggi voglio parlare di qualcosa che mi ha torturato per un po’ di tempo, qualcosa che ho affrontato e da cui ho imparato: le complessità nascoste della gestione dello stato nei sistemi AI multi-agente. Siamo tutti entusiasti degli agenti, giusto? L’idea di entità autonome che soddisfano le nostre richieste, risolvono problemi e prendono decisioni. Ma quando inizi a costruire qualcosa di più complesso di una semplice chat tra due agenti, ti scontri con un muro. Un muro grande, disordinato e impegnativo nel sincronizzare lo stato.

Ho trascorso gran parte degli ultimi sei mesi a lottare con un progetto che coinvolge un team di “agenti di ricerca” – essenzialmente, un gruppo di agenti specializzati alimentati da LLM progettati per esplorare collaborativamente un argomento specifico, sintetizzare informazioni e presentare un rapporto coerente. Sembra semplice sulla carta. L’agente A trova i dati iniziali, l’agente B incrocia le informazioni, l’agente C riassume, l’agente D fa delle critiche. Bellissimo. Nella pratica? È stata una catastrofe di credenze contrastanti, informazioni obsolete e agenti che si ritrovano a calpestarsi i piedi virtuali a vicenda.

Il mio approccio iniziale era ingenuo, per non dire altro. Ogni agente aveva il proprio “modello del mondo,” un dizionario di fatti che credeva fossero veri. Quando l’agente A trovava nuove informazioni, aggiornava il proprio modello e poi *informava* gli altri agenti. Il problema? L’agente B potrebbe essere occupato, o l’agente C potrebbe interpretare il messaggio in modo diverso, o l’agente D potrebbe aver appena aggiornato il proprio modello con informazioni contrastanti provenienti da un’altra fonte. Era come una chat di gruppo in cui tutti parlavano sopra gli altri, e nessuno era sicuro di chi avesse l’ultima versione della verità.

Questo non riguarda solo l’assicurarsi che tutti abbiano gli stessi dati. Si tratta di garantire una comprensione condivisa della *situazione attuale* e degli *obiettivi*. Senza ciò, gli agenti continuano a riesaminare, contraddire e, in ultima analisi, a non collaborare in modo efficace. È la differenza tra un’orchestra sinfonica e una dozzina di musicisti che suonano ciascuno la propria melodia, sperando che in alguna maniera si mescoli.

La Disordinata Realtà dello Stato Decentralizzato

Siamo onesti, la maggior parte delle dimostrazioni brillanti che vedi per gli agenti AI eludono questo problema. Esse coinvolgono o compiti molto semplici e sequenziali, o assumono implicitamente una sorta di condivisione delle informazioni perfetta e istantanea. Non appena introduci operazioni asincrone, più agenti con velocità di elaborazione diverse, o agenti che potrebbero essere temporaneamente offline, l’illusione si frantuma.

Pensaci: se l’agente A deve trovare i dettagli del volo di un utente e l’agente B deve prenotare un’auto basandosi su questi dettagli, cosa succede se l’agente A trova tre voli potenziali e non ha ancora chiarito con l’utente? L’agente B dovrebbe procedere con il primo? Aspettare? O l’agente A dovrebbe condividere tutti e tre, lasciando che l’agente B scelga in qualche modo? E cosa succede se l’utente cambia idea sul volo dopo che l’agente B ha già iniziato a cercare auto? Non è solo un problema di comunicazione; è una sfida architettonica fondamentale.

Il mio progetto di “agenti di ricerca” ha esposto questo brutalmente. Un agente trovava un fatto, un altro lo verificava indipendentemente usando una fonte diversa, e entrambi aggiornavano i loro modelli individuali. Poi, un terzo agente, incaricato di sintetizzare, vedeva due versioni leggermente diverse della “verità” e si bloccava. Era inefficiente, frustrante e rendeva l’intero sistema inaffidabile.

Perché la Semplice Trasmissione di Messaggi Non Basta

Il primo istinto per molti, incluso il mio passato io, è di fare affidamento puramente sulla trasmissione di messaggi. L’agente A invia un messaggio all’agente B dicendo “Ehi, ho trovato X!” L’agente B lo elabora, magari invia un messaggio all’agente C. Questo funziona per semplici schemi di richiesta-risposta. Ma per uno stato condiviso complesso e in evoluzione, diventa un incubo di:

  • Informazioni non sincronizzate: I messaggi possono essere ritardati, persi o elaborati in un ordine imprevisto.
  • Aggiornamenti in conflitto: Due agenti potrebbero tentare di aggiornare lo stesso pezzo di informazione basandosi sulle loro percezioni, portando a divergenza.
  • Interrogare lo stato “ultimo”: Come può un agente sapere quale messaggio contiene le informazioni più aggiornate senza sondare costantemente o mantenere timestamp complessi?
  • Comprendere il contesto: Un messaggio come “L’utente vuole caffè” va bene. Ma “L’utente vuole caffè, *ma solo se è equosolidale, e ha cambiato idea sull’espresso dopo aver visto il menu dei latte*” richiede un contesto più ricco e persistente.

Ho imparato questo a mie spese quando il mio agente riassuntore continuava a produrre rapporti basati su una versione precedente della ricerca, mentre l’agente di verifica dei fatti stava già lavorando su nuovi dati. I “messaggi” non erano sufficienti per comunicare lo stato in evoluzione dell’argomento di ricerca.

Verso un Repository di Stato Centralizzato, Ma Flessibile

Dopo molte riflessioni, sessioni al tavolo bianco e qualche tazza di caffè freddo di troppo, ho iniziato a gravitare verso un repository di stato più centralizzato, ma comunque accessibile agli agenti. La chiave non era forzare tutti gli agenti a operare su un singolo oggetto monolitico, ma fornire un meccanismo per loro per *leggere da e scrivere a una fonte condivisa di verità* in modo strutturato.

Questo non riguarda la creazione di un collo di bottiglia, ma la creazione di un punto di riferimento canonico. Pensalo meno come un dittatore e più come una biblioteca ben mantenuta. Gli agenti possono prendere in prestito libri, fare appunti e persino contribuire con nuovi, ma c’è un sistema chiaro per ciò che è considerato ufficiale e aggiornato.

La Mia Iterazione: Il “Knowledge Graph” come Stato Condiviso

Per i miei agenti di ricerca, ho implementato un grafo della conoscenza semplificato come stato condiviso. Ogni nodo rappresentava un’entità (ad esempio, un concetto, una persona, un evento), e i bordi rappresentavano relazioni. Questo ha permesso agli agenti di contribuire fatti (nuovi nodi o bordi) e interrogare informazioni esistenti. La parte critica era definire un protocollo chiaro per aggiornamenti e risoluzione dei conflitti.

Ecco un esempio semplificato in Python di come potrebbe apparire. Immagina un grafo in memoria di base, dove gli agenti possono aggiungere fatti:


import networkx as nx
import threading
import time

class SharedKnowledgeGraph:
 def __init__(self):
 self.graph = nx.DiGraph()
 self.lock = threading.Lock()
 self.updates = [] # Per una trail audit rudimentale

 def add_fact(self, source_agent_id: str, subject: str, predicate: str, obj: str, timestamp: float = None):
 with self.lock:
 if not timestamp:
 timestamp = time.time()
 
 # Semplice risoluzione dei conflitti: l'ultimo scrittore vince per fatti diretti,
 # ma è possibile costruire logica più complessa (ad esempio, versioning, voting)
 if self.graph.has_edge(subject, obj) and self.graph[subject][obj]['predicate'] == predicate:
 # Aggiorna il fatto esistente se è lo stesso predicato, altrimenti aggiungi nuovo
 self.graph[subject][obj]['timestamp'] = timestamp
 self.graph[subject][obj]['source_agent'] = source_agent_id
 else:
 self.graph.add_edge(subject, obj, predicate=predicate, timestamp=timestamp, source_agent=source_agent_id)
 
 self.updates.append({"agent": source_agent_id, "action": "add_fact", "s": subject, "p": predicate, "o": obj, "time": timestamp})
 print(f"[{source_agent_id}] Aggiunto fatto: {subject} - {predicate} -> {obj}")

 def query_facts(self, subject: str = None, predicate: str = None, obj: str = None):
 with self.lock:
 results = []
 for s, o, data in self.graph.edges(data=True):
 match_s = (subject is None or s == subject)
 match_p = (predicate is None or data.get('predicate') == predicate)
 match_o = (obj is None or o == obj)
 
 if match_s and match_p and match_o:
 results.append({"subject": s, "predicate": data.get('predicate'), "object": o, "source": data.get('source_agent'), "timestamp": data.get('timestamp')})
 return results

 def get_audit_trail(self):
 with self.lock:
 return list(self.updates)

# Esempio di utilizzo:
knowledge_base = SharedKnowledgeGraph()

# L'agente 1 scopre un fatto
knowledge_base.add_fact("Agent_A", "PyTorch", "is_a", "ML_Framework")
knowledge_base.add_fact("Agent_A", "TensorFlow", "is_a", "ML_Framework")

# L'agente 2 trova ulteriori dettagli
knowledge_base.add_fact("Agent_B", "PyTorch", "developed_by", "Facebook")

# L'agente 3 interroga
print("\nAgent_C interroga i framework ML:")
frameworks = knowledge_base.query_facts(predicate="is_a", obj="ML_Framework")
for fact in frameworks:
 print(f" - {fact['subject']} {fact['predicate']} {fact['object']} (da {fact['source']})")

# L'agente 1 aggiorna o aggiunge un fatto (ad esempio, un nuovo framework)
knowledge_base.add_fact("Agent_A", "JAX", "is_a", "ML_Framework")

# L'agente 3 interroga di nuovo
print("\nAgent_C interroga di nuovo i framework ML:")
frameworks_updated = knowledge_base.query_facts(predicate="is_a", obj="ML_Framework")
for fact in frameworks_updated:
 print(f" - {fact['subject']} {fact['predicate']} {fact['object']} (da {fact['source']})")

Questo semplice grafo della conoscenza, anche nella sua forma più elementare, fornisce un luogo centralizzato per gli agenti per inserire e ottenere informazioni. Il `threading.Lock` è cruciale qui per prevenire condizioni di corsa durante le scritture concorrenti. In uno scenario reale, utilizzeresti un database adeguato (come Neo4j per un vero DB grafico, o anche un DB relazionale con un attento design dello schema) e controlli di concorrenza robusti.

Oltre i Fatti Semplici: Obiettivi e Progressi Condivisi

Il repository di stato non riguarda solo fatti sul mondo. È anche fondamentale per gestire obiettivi e progressi condivisi. I miei agenti di ricerca avevano bisogno di sapere:

  • Qual è la domanda di ricerca principale?
  • A chi sono state assegnate le sotto-domande?
  • Qual è lo stato attuale di ciascuna sotto-domanda (ad esempio, “in corso”, “necessita verifica”, “completato”)?
  • Ci sono risultati contrastanti che devono essere risolti?

Questo aspetto della “task board” o “project tracker” dello stato condiviso è tanto importante quanto la conoscenza fattuale. Aiuta gli agenti a coordinare le loro azioni e a evitare lavoro ridondante. Per questo, ho introdotto un oggetto separato chiamato “TaskState” all’interno del repository condiviso, che consente agli agenti di rivendicare compiti, contrassegnarli come completati o segnalare problemi.


class TaskState:
 def __init__(self):
 self.tasks = {} # task_id -> {"description": str, "status": str, "assigned_to": str, "results": list}
 self.lock = threading.Lock()

 def add_task(self, task_id: str, description: str):
 with self.lock:
 if task_id not in self.tasks:
 self.tasks[task_id] = {"description": description, "status": "pending", "assigned_to": None, "results": []}
 print(f"[Task Manager] Aggiunto nuovo compito: {task_id} - {description}")
 return True
 return False

 def assign_task(self, task_id: str, agent_id: str):
 with self.lock:
 if task_id in self.tasks and self.tasks[task_id]["status"] == "pending":
 self.tasks[task_id]["assigned_to"] = agent_id
 self.tasks[task_id]["status"] = "in_progress"
 print(f"[{agent_id}] Compito assegnato {task_id}")
 return True
 return False

 def update_task_status(self, task_id: str, agent_id: str, status: str, result_data: any = None):
 with self.lock:
 if task_id in self.tasks and self.tasks[task_id]["assigned_to"] == agent_id:
 self.tasks[task_id]["status"] = status
 if result_data:
 self.tasks[task_id]["results"].append({"agent": agent_id, "data": result_data, "timestamp": time.time()})
 print(f"[{agent_id}] Aggiornato il compito {task_id} a stato: {status}")
 return True
 return False
 
 def get_task(self, task_id: str):
 with self.lock:
 return self.tasks.get(task_id)

 def get_pending_tasks(self):
 with self.lock:
 return {tid: task for tid, task in self.tasks.items() if task["status"] == "pending"}

# Integra con il nostro esempio precedente:
task_manager = TaskState()
task_manager.add_task("T1", "Ricerca sulla storia dei trasformatori")
task_manager.add_task("T2", "Trovare gli ultimi benchmark per LLM")

# L'agente A vuole assegnarsi un compito
if task_manager.assign_task("T1", "Agent_A"):
 # L'agente A svolge il lavoro
 time.sleep(1) # Simula lavoro
 task_manager.update_task_status("T1", "Agent_A", "completato", {"summary": "Trasformatori sviluppati da Google Brain nel 2017..."})

# L'agente B controlla i compiti in attesa
pending = task_manager.get_pending_tasks()
if "T2" in pending and task_manager.assign_task("T2", "Agent_B"):
 # L'agente B svolge il lavoro
 time.sleep(0.5)
 task_manager.update_task_status("T2", "Agent_B", "in_review", {"data_sources": ["arXiv:2403.01234"]})

print("\nStato finale dei compiti:")
print(task_manager.tasks)

Questo oggetto `TaskState`, combinato con il `SharedKnowledgeGraph`, offre agli agenti un quadro molto più chiaro di ciò che sta accadendo e di cosa deve essere fatto. È ancora rudimentale, ma va oltre il caos della pura trasmissione di messaggi.

Insegnamenti Praticabili per le Tue Architetture di Agenti

Se stai costruendo sistemi multi-agente, non commettere gli stessi errori che ho fatto io sottovalutando la gestione dello stato. Ecco cosa ho imparato e cosa ti consiglio di considerare:

  1. Non Fare Affidamento Solo sulla Trasmissione di Messaggi per lo Stato Condiviso: I messaggi sono ottimi per comandi e risposte immediate, ma sono terribili per mantenere una visione coerente e in evoluzione del mondo o del progresso del progetto. Hai bisogno di una fonte di verità persistente e interrogabile.

  2. Implementa un Repository di Stato Centralizzato (o Federato): Questo non significa un singolo servizio monolitico che diventa un collo di bottiglia. Significa un protocollo ben definito e un luogo per gli agenti per leggere e scrivere la versione canonica delle informazioni condivise. Questo potrebbe essere:

    • Un database dedicato (SQL, NoSQL o Graph DB).
    • Un sistema pub/sub con log di messaggi persistenti e una vista materializzata interrogabile.
    • Un archivio chiave-valore distribuito.

    La chiave è che gli agenti possono *interrogare* lo stato attuale, non solo reagire all’ultimo messaggio ricevuto.

  3. Definisci Schemi e Protocolli Chiari per gli Aggiornamenti dello Stato: Non basta gettare dati in un database. Come fanno gli agenti ad aggiungere nuovi fatti? Come modificano quelli esistenti? Cosa succede se due agenti cercano di aggiornare lo stesso fatto simultaneamente? Hai bisogno di:

    • Versionamento: Mantieni una cronologia delle modifiche.
    • Risoluzione dei Conflitti: Ultima scrittura vincolante, voto della maggioranza, arbitrato umano – scegli una strategia.
    • Operazioni Atomiche: Assicurati che gli aggiornamenti siano tutto o niente per prevenire stati corrotti.
  4. Separa la “Conoscenza del Mondo” dallo “Stato dei Compiti”: È utile avere sezioni distinte nel tuo stato condiviso. Una per fatti generali e osservazioni (il grafo conoscitivo) e un’altra per obiettivi attivi, sotto-compiti, assegnazioni e tracciamento dei progressi (il gestore dei compiti). Questo aiuta gli agenti a concentrarsi su ciò che è rilevante per il loro ruolo attuale.

  5. Fornisci Agenti con Meccanismi per “Riflettere” sullo Stato Condiviso: Gli agenti non dovrebbero semplicemente leggere e scrivere ciecamente. Devono essere in grado di comprendere le *implicazioni* dello stato attuale. Questo potrebbe comportare:

    • Attivare rivalutazioni quando specifiche parti dello stato cambiano.
    • Consentire agli agenti di interrogare per incoerenze o lacune nella conoscenza condivisa.
    • Consentire agli agenti di proporre nuovi compiti in base allo stato attuale del progetto.
  6. Considera una Tracciabilità delle Modifiche: Avere la possibilità di vedere chi ha aggiornato cosa e quando è fondamentale per il debug e per comprendere il comportamento degli agenti. La mia lista di `updates` nel `SharedKnowledgeGraph` è un esempio molto base di questo.

Costruire sistemi multi-agente efficaci è difficile. Gli LLMs potrebbero fare il ragionamento intelligente, ma *orchestrare* quel ragionamento attraverso un team di agenti richiede un’infrastruttura solida. Non permettere che la gestione dello stato sia il killer silenzioso del tuo prossimo grande progetto di agenti. Pianifica in anticipo, ripeti il tuo approccio e ti risparmierai molti mal di testa in futuro. Questo è tutto per ora, ragazzi. Fino alla prossima volta, continua a costruire, continua a imparare!

🕒 Published:

🧬
Written by Jake Chen

Deep tech researcher specializing in LLM architectures, agent reasoning, and autonomous systems. MS in Computer Science.

Learn more →
Browse Topics: AI/ML | Applications | Architecture | Machine Learning | Operations

See Also

Ai7botClawgoAgntzenAgnthq
Scroll to Top