Tutti si chiedono "Ma che cavolo è un loop?" Ecco la domanda che nessuno si fa: cosa gestisce il loop?
Il dibattito sull'IA si è concentrato sui loop come elemento fondamentale dei sistemi agenziali. Matt Van Horn (@mvanhorn) ha tracciato la genealogia dei loop degli agenti, da ReAct all'uso di strumenti, ai loop di orchestrazione, fino ai loop che supervisionano altri loop. Addy Osmani (@addyosmani) ha scomposto i mattoni fondamentali all'interno dei loop: automazioni, alberi di lavoro, competenze, connettori, sub-agenti. Van Horn ha puntato sulla durabilità, sostenendo che i loop che non sopravvivono a un riavvio non sono veri loop. Il filo conduttore di Osmani era l'orchestrazione: progettare il sistema che istruisce l'agente al posto tuo.
Voglio portare oltre le loro osservazioni. La durabilità non è solo una proprietà del loop. È l'intero strato di esecuzione che lo sottende. Il punto fondamentale è che un'orchestrazione durevole è essenziale per costruire la tua architettura di loop per agenti. Analizziamo questa architettura.
Dove si rompono i loop
I pattern /loop e /goal gestiscono bene il lavoro a singolo agente e singola sessione. Un agente itera fino al completamento dell'attività. Questo copre gran parte del lavoro. Ma la fase successiva (Fase 5 secondo Van Horn) è dove il tutto crolla:
- Loop che supervisionano altri loop
- Loop che vengono eseguiti secondo pianificazioni, non solo attivati da un umano
- Loop che sopravvivono a riavvii di processo, deploy e crash
- Loop che generano sub-agenti e attendono i risultati (a volte ore dopo)
- Loop che devono essere osservabili a posteriori
Questo non è un problema di progettazione dei prompt. È un problema di infrastruttura.
Van Horn cita @runes_leo: "La cosa più costosa nella programmazione IA non è più scrivere codice, ma gestire il loop dell'agente." Un while True in un terminale non ti dà niente di tutto questo. E nemmeno un processo a lunga esecuzione su una VM o in una sandbox.
Pensa a cosa succede quando esegui un loop di un agente su un server. Il processo potrebbe morire o riavviarsi. Un deploy, un OOM, una revoca di un'istanza spot. Il loop si riavvia. Ma cosa stava facendo? A che passo era? Aveva già inviato quel messaggio su Slack? Aveva già invocato il sub-agente?
Non lo sai. Ricomincia da capo. Recupera di nuovo dati che già possedeva. Richiama l'LLM per decisioni già prese. Invia una notifica duplicata. Genera un sub-agente duplicato. Ti svegli con tre messaggi Slack identici e un team confuso.
La soluzione non è una "migliore gestione degli errori" — è un modello di esecuzione in cui ogni passo è salvato come checkpoint, ogni decisione è persistita e il recupero significa riprendere dall'ultimo passo completato con successo.
L'architettura del loop dell'agente in tre strati
Tre strati. Ognuno corrisponde a un elemento primitivo concreto.
Strato 1: Il Loop
Un loop è un cron più un decisore. Viene eseguito secondo una pianificazione (o un trigger), valuta lo stato e decide cosa fare dopo.
Questa è la definizione di Van Horn resa concreta: ciò che a cron è sempre mancato è la decisione al centro. È l'agente che decide, non tu. Il cron è il battito cardiaco. L'LLM è il decisore. I passi sono l'esecuzione durevole che salva lo stato di avanzamento.
1export const infraHealthCheck = inngest.createFunction(2 { id: "infra-health-check" },3 { cron: "*/30 * * * *" }, // Ogni 30 minuti4 async ({ step }) => {5 const metrics = await step.run("fetch-service-metrics", async () => {6 return await fetchServiceMetrics(); // tassi di errore, latenza, memoria, CPU7 });89 const assessment = await step.run("assess-health", async () => {10 return await callLLM({11 prompt: `Dati questi parametri dei servizi, classifica lo stato di salute generale del sistema12 come "normale", "degradato" o "critico". Spiega il tuo ragionamento.13 Parametri: ${JSON.stringify(metrics)}`,14 });15 });1617 if (assessment.status === "degraded" || assessment.status === "critical") {18 await step.invoke("triage-incident", {19 function: incidentTriage,20 data: { metrics, assessment, services: assessment.affectedServices },21 });22 }23 }24);
Ogni lunedì alle 9:00, il loop si attiva. Recupera i dati, chiede all'LLM se è necessario un report e, in caso affermativo, invoca una competenza. Se il processo si riavvia tra un passo e l'altro, i passi già completati non vengono rie eseguiti. Questo è il loop. Non l'LLM, ma il loop intorno all'LLM.
Strato 2: La Competenza
In questo contesto, una competenza non è un prompt. È un flusso di lavoro durevole. Multi-passo, ripetibile, componibile e distribuibile indipendentemente.
Van Horn: "Il loop è l'infrastruttura idraulica. Il vero valore è la competenza che viene chiamata." Questa è la parte che si accumula. Ogni nuova competenza appresa dal sistema rende ogni loop più capace.
1export const incidentTriage = inngest.createFunction(2 { id: "incident-triage", retries: 3 },3 { event: "infra.incident.triage" },4 async ({ event, step }) => {5 const details = await step.run("fetch-detailed-metrics", async () => {6 return await fetchDetailedMetrics({ services: event.data.services });7 });89 const deploys = await step.run("fetch-deploy-history", async () => {10 return await fetchRecentDeploys({ since: hoursAgo(2) });11 });1213 const analysis = await step.run("correlate-incident", async () => {14 return await callLLM({15 prompt: `Correla questi parametri dei servizi con i deploy recenti.16 Identifica la causa principale probabile e la gravità.17 Parametri: ${JSON.stringify(details)}18 Deploy recenti: ${JSON.stringify(deploys)}`,19 });20 });2122 await step.run("post-triage-summary", async () => {23 await slack.postMessage({24 channel: "#incidents",25 text: formatTriageSummary({26 analysis,27 affectedServices: event.data.services,28 recommendedActions: analysis.recommendations,29 }),30 });31 });3233 return analysis;34 }35);
Questa competenza recupera, classifica e inoltra. È un'unità di lavoro con tolleranza ai guasti integrata. La competenza può essere un flusso di lavoro IA con un LLM al centro o codice deterministico.
Strato 3: L'Orchestratore
L'orchestratore è il motore che gestisce tutto: pianifica i cron, esegue i passi, gestisce i tentativi, impone i limiti di concorrenza, memorizza la cronologia delle esecuzioni e distribuisce a caldo nuove funzioni/flussi di lavoro senza interrompere quelli in esecuzione.
Questo è lo strato di cui nessuno parla perché si suppone sia invisibile. Ma è fondamentale.
La maggior parte delle persone pensa agli agenti come "LLM + strumenti". L'architettura del loop dell'agente riformula questo concetto: gli agenti sono "loop + competenze + orchestrazione". LLM e strumenti sono all'interno dei loop. Possono essere scambiati o modificati mentre l'architettura rimane. L'orchestrazione rende possibile l'architettura.
Cosa succede quando le cose si rompono
Il percorso felice è facile. Ma questo è software in esecuzione in produzione: le cose vanno mai veramente secondo i piani?
La tua competenza di triage degli incidenti viene attivata e l'API delle metriche va in timeout. La lettura ha dovuto andare su disco e la cache in memoria non aveva i dati. Il passo che chiama questa API ora riprova e colpisce di nuovo l'API. I dati ora sono parzialmente in cache e l'API completa la richiesta. La competenza continua con il passo successivo come se nulla fosse successo.
A volte, non è così semplice. E se una chiave API scade, o il tuo provider di hosting è giù per 30 minuti? Tutti i tuoi tentativi sono esauriti. Cosa succede ora? Devi anche gestire i fallimenti.
1export const incidentTriage = inngest.createFunction(2 {3 id: "incident-triage",4 retries: 3,5 onFailure: async ({ error, event, step }) => {6 // La funzione ha fallito dopo aver esaurito i tentativi.7 // Abbiamo ancora i dati dell'evento originale. Niente è perduto.8 await step.run("notify-failure", async () => {9 await slack.postMessage({10 channel: "#agent-ops",11 text: `⚠️ Triage incidente fallito: ${error.message}. ` +12 `Riproverò al prossimo ciclo di health check. ` +13 `Servizi interessati: ${event.data.services.join(", ")}`,14 });15 });16 },17 },18 { event: "infra.incident.triage" },19 async ({ event, step }) => {20 /* la stessa logica della competenza qui sopra */21 }22);
Il gestore onFailure viene attivato dopo che tutti i tentativi sono esauriti. Pubblica un messaggio su un canale operativo in modo che qualcuno lo sappia. L'evento viene preservato, nulla viene perso. La successiva esecuzione pianificata riprende da dove quella fallita non aveva potuto.
Un'orchestrazione durevole deve fornire tentativi a livello di singolo passo per errori transitori e hook di gestione dei fallimenti per errori non recuperabili. Senza questo, le cose si rompono (come accade) e lo scopri ore o giorni dopo.
Gli errori transitori sono anche costosi. Se la tua competenza o agente riprova dall'inizio, stai chiamando gli LLM più volte e bruciando token inutilmente. La chiamata LLM può essere salvata come checkpoint. Ora moltiplica questo per 10, o 30, agenti in tutto il tuo sistema. È costoso.
Il checkpoint a livello di passo non è solo una funzionalità di correttezza. È un risparmio di denaro.
L'agente che costruisce le proprie competenze
È qui che le cose si fanno più interessanti. Il sistema non è statico, è progettato per evolversi ed estendersi.
L'agente non si limita a eseguire all'interno dei loop — crea nuovi loop e li registra con il motore di orchestrazione. Ogni funzione distribuita è una competenza durevole che viene eseguita in modo indipendente, attivabile da un loop o da un agente, o eseguita secondo una pianificazione, con la propria logica di ripetizione. Le competenze si accumulano.
È un agente consapevole dell'orchestrazione.
Ecco come funziona. Un agente IA ha accesso all'SDK di orchestrazione come strumento. Può scrivere nuove funzioni, registrarle con il motore e queste iniziano a essere eseguite immediatamente. Il processo dell'agente ricarica a caldo le nuove funzioni senza riavviare o interrompere le esecuzioni in corso.
Analizziamo un esempio concreto:
1. Un umano esprime un'esigenza. Un ingegnere dice: "I nostri servizi continuano ad avere picchi di latenza durante la notte e nessuno se ne accorge fino al mattino." Questo è il trigger. L'agente non deve dedurre uno schema vago da dati ambientali. Ha istruzioni chiare.
2. L'agente scrive una competenza. Due funzioni multi-passo: un loop di health check che viene eseguito ogni 30 minuti, recuperando tassi di errore, latenza e utilizzo delle risorse, con l'LLM che classifica lo stato di salute del sistema come normale, degradato o critico. E una competenza di triage degli incidenti che recupera metriche dettagliate e la cronologia dei deploy recenti, correla le cause principali con un LLM e pubblica un riepilogo del triage su Slack con azioni consigliate. Gestione degli errori: se l'API delle metriche è giù, attendi e riprova. Se l'LLM fallisce, torna a una classificazione di gravità basata su regole.
3. L'agente distribuisce la competenza. L'agente scrive il codice della funzione che viene raccolto da un processo sidecar. Le nuove funzioni vengono registrate automaticamente. Sono attive immediatamente, senza pipeline di deploy, senza PR.
4. La competenza viene eseguita in modo autonomo. Ogni 30 minuti, il motore attiva il health check. Se qualcosa non va, invoca la competenza di triage. Nessun umano nel loop. Completamente durevole.
5. L'agente itera sui segnali. Questa è la parte che molti trascurano, quindi lasciami essere specifico su cosa significa "iterare". L'agente non nota magicamente gli schemi. Ha un loop di revisione separato: una funzione attivata da cron che viene eseguita settimanalmente, legge la cronologia delle esecuzioni dall'orchestratore e valuta le prestazioni:
1export const reviewSkillPerformance = inngest.createFunction(2 { id: "review-skill-performance" },3 { cron: "0 10 * * 5" }, // Ogni venerdì alle 10:004 async ({ step }) => {5 const runs = await step.run("fetch-run-history", async () => {6 return await getInngestRuns({7 functionId: "incident-triage",8 since: daysAgo(7),9 });10 });1112 const analysis = await step.run("analyze-performance", async () => {13 const successRate = runs.filter(r => r.status === "completed").length / runs.length;14 const avgDuration = average(runs.map(r => r.duration));15 const incidents = await fetchIncidentOutcomes(); // Gli incidenti erano correlati a guasti reali?1617 return await callLLM({18 prompt: `Rivedi le prestazioni di questa competenza nell'ultima settimana.19 Tasso di successo: ${successRate}20 Durata media: ${avgDuration}ms21 Incidenti correlati a guasti reali: ${incidents.confirmed}/${incidents.total}22 Falsi positivi: ${incidents.falsePositives}23 Il team ha agito sugli avvisi: ${incidents.actedOn}/${incidents.total}2425 Dovremmo aggiustare le soglie o la classificazione? Quali modifiche specifiche?`,26 });27 });2829 if (analysis.shouldModify) {30 await step.invoke("update-skill", {31 function: coreAgent,32 data: { prompt: `Aggiorna le competenze di triage degli incidenti in base alle seguenti modifiche proposte: ${analysis.proposedChanges}` },33 });34 }35 }36);
La "revisione" è una funzione. Legge la cronologia delle esecuzioni, verifica se gli incidenti erano correlati a guasti reali e fornisce quel segnale all'LLM. Se il health check continua a segnalare un servizio come degradato ma il team lo ignora perché le soglie sono troppo sensibili, il loop di revisione lo rileva e la competenza viene aggiornata per aggiustare la classificazione. Non è magia. È un cron job con un LLM al posto del decisore.
E la convalida? L'agente che scrive codice è valido tanto quanto le protezioni che lo circondano. Il codice può essere controllato staticamente. L'agente può invocare la funzione stessa per testarla, poiché è in grado di interagire con il motore di orchestrazione stesso. Anche se non è infallibile, stai dando all'agente principale la capacità di eseguire il debug delle competenze che scrive nativamente all'interno del sistema in cui opera. Il loop di revisione rileva i problemi che non vengono individuati con il debug iniziale.
Spingendoci un po' oltre, l'agente può usare gli hook onFailure per attivarsi e valutare lui stesso un determinato fallimento. È un ciclo di feedback che continua a migliorare.
E i conflitti? I controlli di flusso, in particolare i controlli di concorrenza o i singleton, gestiscono il caso semplice (concorrenza: [{ limit: 1, key: "event.data.service" }]) il che significa che un solo triage di incidente viene eseguito alla volta per servizio. Ma la domanda più profonda è: cosa succede se due health check rilevano entrambi problemi nello stesso servizio simultaneamente? L'orchestratore li mette in coda. Il secondo triage attende che il primo sia completato. Nessun avviso duplicato, nessuna race condition. Questo non è teorico. È lo stesso primitivo di concorrenza che useresti in qualsiasi coda di job.
L'agente non si limita a eseguire compiti. Sta costruendo infrastrutture per se stesso. Ogni competenza durevole persiste oltre la conversazione che l'ha creata. Uccidi il processo dell'agente e riavvialo. Le competenze continuano a essere eseguite. Sostituisci il modello sottostante. Le competenze continuano a essere eseguite. L'agente è effimero — il suo output è durevole.

Panoramica del sistema di architettura del loop dell'agente
Il punto di vista dello sviluppatore
Questo è importante perché se lo sviluppatore non può vedere cosa ha distribuito l'agente, eseguire il debug di ciò che si è rotto e controllare cosa è stato eseguito alle 3 del mattino, l'intera architettura è una grossa responsabilità.
Il motore di orchestrazione memorizza ogni esecuzione, ogni passo, ogni input, ogni output, ogni tentativo. Una competenza distribuita dall'agente martedì scorso che è fallita alle 4 del mattino? Puoi vedere esattamente quale passo è fallito, qual era l'input, quale errore ha generato e quante volte ha ritentato prima di arrendersi. Tracce complete fino al livello del passo sono l'output del motore di orchestrazione stesso.
Questa non è una dashboard aggiunta dopo. È inerente all'esecuzione durevole. Ogni step.run() è un checkpoint. Ogni checkpoint è osservabile. Quando la cosa che ha scritto il codice non è un umano, l'osservabilità non è un optional: è il livello di fiducia.
Nel lavoro quotidiano, il flusso di lavoro dello sviluppatore è questo: controlla la dashboard delle esecuzioni la mattina. Vedi quali competenze sono state eseguite durante la notte, quali hanno avuto successo, quali sono fallite. Se una competenza scritta dall'agente si comporta male, puoi leggere il codice direttamente, modificarlo, eliminarlo o dire all'agente di risolverlo. L'agente l'ha creata, ma tu la possiedi. L'agente e le sue competenze sono pur sempre un giardino di cui dovresti prenderti cura.
Perché la durabilità è fondamentale
Van Horn: "Queste cose devono sopravvivere a un riavvio."
Ecco cosa significa durabilità nella pratica:
Requisito
Cosa significa
Perché un semplice ciclo while fallisce
Ripetizione indipendente dei passaggi
Se il passo 3 di 5 fallisce, ripeti il passo 3, non i passi 1 e 2
Un riavvio del loop riesegue tutto da capo
Ciclo di vita del sub-agente
Crea un'attività figlia, attendi (forse ore), annulla se il genitore viene annullato
Nessuna gestione integrata del ciclo di vita genitore-figlio
Consegna garantita degli eventi
Se un evento viene attivato mentre l'agente è giù, deve essere comunque elaborato
Gli eventi vengono persi se il processo non è in esecuzione
Osservabilità a posteriori
Vedi cosa è successo dopo: ogni passo, ogni decisione, ogni tentativo
I log sono la tua unica opzione, e sono effimeri
Hot-deploy senza tempi di inattività
Distribuisci una nuova versione della funzione senza uccidere le esecuzioni in corso
Il riavvio del processo uccide tutto
Controllo della concorrenza
Esegui solo N istanze di una competenza alla volta
Nessun primitivo di concorrenza integrato
"Eseguilo in un container" ti dà uptime. Non ti dà correttezza. Un container che si riavvia dopo un crash riporta il processo in vita, ma ogni loop in corso ricomincia da capo. Ogni passo viene rieseguito. Ogni chiamata LLM viene rifatta. Il loop sembra essere in esecuzione, ma è in esecuzione alla cieca.
Confronto con gli strumenti esistenti
Alcuni strumenti potrebbero offrirti una soluzione "pronta all'uso" per questo tipo di sistema, oppure potresti scegliere di mettere insieme alcuni strumenti di livello inferiore e creare il tuo sistema. Nessuna delle due scelte è sbagliata, ma il giusto livello di architettura dovrebbe permettere a te, e al tuo agente, di evolversi nel tempo. Flessibile, dinamico, durevole.
Primitivi di esecuzione durevole che si adattano bene a un agente, che un agente può facilmente scrivere, e l'osservabilità e le API per osservare e consentire all'agente stesso di essere consapevole dell'orchestrazione.
Un esempio funzionante
Stiamo testando questi pattern internamente in Inngest e puoi vedere un concept di questo nel repository del progetto "utah" qui: https://github.com/inngest/utah: È un harness per agenti costruito sull'orchestrazione durevole di Inngest che è anche consapevole dell'orchestrazione.
Il sistema ha un processo sidecar che consente all'agente principale di scrivere e modificare funzioni Inngest nel proprio spazio di lavoro, estendendosi con "competenze" (nel contesto di questo articolo). Presto, abbiamo in programma di fornire un intero sistema con loop iniziali come esempi, ma le idee presenti lì possono dimostrare i concetti di questo articolo in modo più chiaro.
Il loop che si accumula
Il recente post di Satya Nadella ha dato un nome a ciò che l'industria stava percependo: il fossato non è il modello — è il loop.
La sua definizione: ci sono due tipi di capitale. Il capitale umano, la conoscenza e il giudizio che il tuo team ha costruito in anni. E quello che lui chiama capitale token, i flussi di lavoro IA, i pattern decisionali e le competenze apprese che un'azienda costruisce sui modelli fondazionali.
La tesi: questi si accumulano insieme. Ogni flusso di lavoro migliorato genera segnali migliori. Segnali migliori producono un comportamento IA più preciso. Un comportamento più preciso libera attenzione umana per lavori di più alto giudizio. Una macchina che scala le colline.
Questo è ciò che l'architettura del loop dell'agente abilita concretamente:
- Ogni competenza durevole che l'agente distribuisce è conoscenza istituzionale codificata come infrastruttura eseguibile. Persiste. Viene eseguita che un umano la stia guardando o meno.
- Un loop di revisione attivato da cron che valuta le prestazioni delle competenze e itera. Questa è la macchina che scala le colline resa reale. Non un diagramma di un volano in una presentazione. Una funzione con un trigger cron.
- Se le tue competenze muoiono al riavvio del processo, l'accumulo si azzera. La durabilità è ciò che fa persistere l'investimento.
Il punto chiave di Nadella: "Un'azienda dovrebbe essere in grado di cambiare un modello 'generalista' senza perdere la competenza da 'veterano aziendale' costruita nel suo sistema di apprendimento." Questo è il pattern della libreria di competenze. Le funzioni durevoli non si preoccupano di quale LLM le chiami.
Costruisci di conseguenza
Il dibattito è stato su cosa fanno gli agenti: loop, strumenti, ragionamento, ingegneria del contesto. La prossima conversazione è su cosa gestisce gli agenti.
Tre strati: loop, competenza, orchestratore. Il loop è l'unità di lavoro. La competenza è il valore. Il motore di orchestrazione è ciò che rende entrambi durevoli. Il pattern sidecar è il modello: un agente scrive le proprie competenze durevoli, le distribuisce, rivede come si comportano e itera. Non un esperimento mentale. È un modello funzionante.
Abbiamo costruito Inngest per essere il motore di orchestrazione per questo: step.run(), step.invoke(), trigger cron, controllo del flusso guidato da eventi, controlli di concorrenza e osservabilità completa a livello di passo. Ma il pattern architetturale è più grande di qualsiasi singolo strumento. Se stai costruendo loop per agenti in produzione, definisci i tre strati.
I primitivi esistono oggi. Costruisci di conseguenza.





