ELAI S.r.l.

Gli agenti lavorano in parallelo: perché il compito non finisce prima?

Un flusso a sei compiti mostra dipendenze, cammino critico e limiti del parallelismo: calcolo riproducibile, senza benchmark inventati sugli agenti.

Gli agenti lavorano in parallelo: perché il compito non finisce prima?

Più esecutori non cancellano ciò che deve venire prima

Un sistema di agenti AI prepara una risposta a partire da un documento, un catalogo e alcune regole. Ogni agente sembra veloce e diversi passaggi possono lavorare contemporaneamente; aggiungere un terzo esecutore però non riduce il tempo finale. Per capire perché non basta sommare o dividere le durate. Dobbiamo sapere quali risultati servano prima di avviare ogni passaggio. Costruiamo un flusso piccolo, dichiariamo tutte le dipendenze e troviamo sia un limite inferiore sia un piano che lo raggiunge. La domanda è sul coordinamento del lavoro, non sulla precisione delle singole risposte.

Abstract. Sei compiti sintetici richiedono 13 s di lavoro totale. Le dipendenze impongono il cammino A→B→D→F, lungo 10 s. Con un solo lavoratore il compito termina in 13 s; con due ne bastano 10, e il terzo non migliora il risultato. Il programma considera 720 permutazioni, ne conserva cinque compatibili con il grafo e costruisce piani non preemptive a durate intere. Il piano migliore raggiunge il limite del cammino critico, dimostrando ottimalità per questa istanza. Le durate sono scelte, non misure di LLM, servizi o prodotti EL-AI.

Un grafo descrive vincoli, non una conversazione

Usiamo un grafo diretto aciclico, abbreviato DAG. Ogni nodo è un compito; una freccia da A a B significa che B richiede il risultato completo di A. Aciclico significa che non esiste un percorso di dipendenze che torna al punto iniziale. Non modelliamo dialoghi iterativi, retry o decisioni che cambiano il grafo durante l’esecuzione. Un eventuale ciclo richiederebbe una descrizione diversa oppure lo sviluppo esplicito di un numero finito di iterazioni. Qui ogni compito si esegue una volta, senza effetti esterni e senza interruzioni.

A rappresenta una preparazione del documento(2 s); B una ricerca nel catalogo(4 s); C una lettura delle regole(1 s); D una combinazione dei risultati(3 s); E un controllo separato sulle regole(2 s); F la finalizzazione(1 s). Sono nomi per leggere l’esempio, non moduli disponibili o protocolli reali. B e C dipendono da A; D da B e C; E soltanto da C; F da D e E. In particolare E può iniziare senza aspettare B: questa indipendenza, dichiarata nel modello, rende possibile sovrapporre lavoro utile.

CompitoDurata(s)Predecessori
A2—
B4A
C1A
D3B, C
E2C
F1D, E

Il limite che nessun numero di lavoratori supera

Se ogni compito potesse partire appena pronti i predecessori, il suo termine più precoce sarebbe la propria durata più il massimo dei termini dei predecessori. Usiamo il massimo perché devono essere tutti pronti: non basta che sia finito il più veloce. Per un nodo senza predecessori il massimo vuoto è zero. Lavoriamo in ordine topologico, un ordine che colloca ogni predecessore prima del successore; così i termini necessari sono già noti. Questo calcolo assume lavoratori illimitati e fornisce un limite inferiore, non ancora un piano per due risorse.

EF_i=d_i+max(EF_j : j in Pred(i)) EF_A=2; EF_B=6; EF_C=3; EF_D=9; EF_E=5; EF_F=10

Il massimo finale 10 s deriva da A→B→D→F, con 2+4+3+1=10 s. È un cammino critico: i compiti su quella sequenza non possono sovrapporsi. Anche mille lavoratori non possono avviare F prima che D abbia ricevuto e combinato il risultato di B. Il ramo A→C→E→F è lungo 6 s e non determina il limite in questa istanza. Questo non rende E inutile: F ne ha comunque bisogno. Significa che alcuni suoi tempi possono essere assorbiti dall’attesa di un altro ramo.

Esiste anche un limite di capacità: con W=13 s di lavoro e P lavoratori identici, almeno W/P secondi sono necessari, se nessun lavoro si duplica. Insieme otteniamo T≥max(10,13/P). Con due lavoratori il vincolo 10 domina 6,5. Non è un’affermazione generale che basti conoscere i due numeri per trovare un piano: dipendenze e risorse possono creare ulteriori attese. Ma se troviamo un piano valido di 10 s, l’uguaglianza con il limite prova che non possiamo fare meglio sotto queste ipotesi.

Costruire e controllare un piano che raggiunge il limite

Il piano a due lavoratori esegue A da 0 a 2 s. Poi B occupa un lavoratore da 2 a 6 s, mentre C usa l’altro da 2 a 3 s. Quando C termina, E può usare quella risorsa da 3 a 5 s. A 6 s B e C sono entrambi conclusi, quindi D lavora fino a 9 s. E è già terminato e F può chiudere da 9 a 10 s. In nessun istante sono attivi più di due compiti e nessuno parte prima dei risultati necessari. La figura mostra intervalli di compiti, non misure di utilizzo di CPU o GPU.

LavoratoriDurata totale(s)Lavoro totale(s)
11313
21013
31013

Il lavoro complessivo resta 13 s; la durata finale scende da 13 a 10 s perché alcune parti si sovrappongono. Il fattore di accelerazione è 13/10=1,3, non 2. Il terzo lavoratore non può rendere paralleli i compiti del cammino critico, perciò non offre un vantaggio nel modello. Questa è una spiegazione più informativa del generico consiglio di aggiungere agenti: indica esattamente dove si trova il vincolo. Non dimostra però che un terzo servizio non aiuti una produzione con molte richieste contemporanee: qui studiamo il completamento di un singolo flusso.

Sinistra: intervalli del piano con due lavoratori astratti e durate sintetiche; righeA–F non rappresentano processori. Destra: completamento con1,2,3 lavoratori e linea del limite10s. Il lavoro totale è13s in tutti i casi; nessun tempo di un LLM è stato misurato.
Sinistra: intervalli del piano con due lavoratori astratti e durate sintetiche; righe A–F non rappresentano processori. Destra: completamento con 1,2,3 lavoratori e linea del limite 10 s. Il lavoro totale è13 s in tutti i casi; nessun tempo di un LLM è stato misurato.

Accelerare il nodo giusto

Il programma esegue due variazioni separate. Ridurre E da 2 a 1 s lascia il completamento minimo a 10 s: il ramo di E era già pronto prima del ramo critico. Ridurre invece B da 4 a 2 s permette 8 s con due lavoratori. Non sommiamo i due interventi né assumiamo un’accelerazione gratuita: cambiamo una durata per volta e ricalcoliamo i piani. Il risultato non significa che migliorare E non abbia valore in assoluto; libera lavoro e può aiutare altri obiettivi. Dimostra soltanto che ridurre una durata non riduce necessariamente il tempo finale del compito studiato.

VariazioneDurata finale(s)
E:2→110
B:4→28

Un ordine topologico non è ancora un piano temporale

La documentazione Python 3.14 di graphlib descrive TopologicalSorter: riceve per ogni nodo i predecessori e rende disponibili i nodi i cui predecessori risultano completati. Abbiamo letto anche get_ready e done. L’ordine statico è una sequenza valida, ma non assegna da solo durate o lavoratori. Segnalare done significa che il risultato necessario è effettivamente pronto: marcarlo quando la richiesta è soltanto partita renderebbe falsa la dipendenza. Non stiamo collaudando un framework di agenti; usiamo questi concetti per esplicitare che cosa una libreria può garantire e che cosa appartenga al coordinatore.

Nel nostro codice enumeriamo le 720 permutazioni dei sei nodi e ne conserviamo cinque che rispettano tutte le frecce. Per ogni ordine prioritario inseriamo un compito nel primo intervallo libero dopo la fine dei predecessori, senza superare la capacità P. Gli inizi sono interi perché le durate dichiarate sono intere; gli intervalli sono non interrompibili. Non affermiamo che questa enumerazione di priorità descriva ogni possibile pianificazione in generale. In questa istanza basta che trovi un piano 10 s e che il limite indipendente sia 10 s: la prova di ottimalità viene dall’incontro fra costruzione e limite.

Le asserzioni controllano che ogni predecessore finisca prima dell’inizio del successore e che il numero di compiti attivi non superi P. La ricerca fattoriale è didattica, non una strategia scalabile per centinaia di agenti. Il solo calcolo dei termini precoci in ordine topologico richiede invece O(V+E) con V nodi ed E frecce, una volta note le durate. Queste complessità riguardano l’algoritmo astratto: non sono secondi misurati su una piattaforma. Il codice e i risultati JSON permettono di verificare ogni intervallo mostrato nella figura.

Dove il modello finisce e il servizio comincia

Un agente reale può avere durata variabile, attese di rete, limiti di richieste e consumo di memoria non uniforme. Due chiamate possono contendersi la stessa GPU pur essendo compiti logicamente indipendenti. Il nostro lavoratore è invece una risorsa astratta identica e ogni compito ne occupa uno per tutta la sua durata. Non abbiamo simulato queste contese. Usare durate medie come se fossero limiti certi non garantisce una scadenza: il ramo più lento può cambiare fra esecuzioni. Il grafo rende leggibili le dipendenze, ma non sostituisce la misura delle distribuzioni dei tempi.

In un confronto operativo servirebbe registrare sia quando un passaggio viene avviato sia quando rende disponibile il risultato richiesto dai successori, distinguendo tempo di esecuzione da tempo di attesa. Questo è un protocollo proposto, non un esperimento effettuato su EL-AI. Non misuriamo qualità, costo in token o affidabilità degli agenti: migliorare il tempo di completamento non dimostra che la risposta sia corretta. Le due domande vanno valutate con evidenze diverse. Qui l’unica conclusione quantitativa riguarda il piano deterministico dichiarato.

La risposta iniziale è quindi che il parallelismo aiuta solo il lavoro che può realmente sovrapporsi. Nel nostro flusso due lavoratori bastano a raggiungere il limite 10 s; il terzo resta senza possibilità di accorciare il cammino critico. Accelerare B cambia quel limite, accelerare E no nella variante eseguita. Abbiamo trasformato un’impressione generica su agenti veloci in una spiegazione verificabile: quale risultato deve aspettare quale altro, quali attese sono inevitabili e quali dipendono invece dalla disponibilità delle risorse.

Python 3.14 documentation: graphlib. TopologicalSorter, predecessors, get_ready, done, cycles. Read 17 October 2026. Own deterministic scheduling calculation; no agent-runtime benchmark..

from experiment import D,PRE,schedule
print(schedule(tuple(D),2))

Codice, dati e istruzioni · JSON. Calcoli didattici eseguiti con Python 3.14.0; figure con Matplotlib 3.11.2. Analisi con assistenza AI, senza dichiarare peer review o revisione umana. Copertina originale ImageGen, illustrativa: non documenta persone, sedi o installazioni EL-AI. Fonti consultate il 17 ottobre 2026.