Symphony: una specifica open-source per l'orchestrazione di agenti
An open-source spec for Codex orchestration: Symphony
Sei mesi fa, mentre lavorava a uno strumento interno per la produttività, il nostro team ha preso una decisione all'epoca controversa: avremmo costruito il nostro repository senza alcun codice scritto da esseri umani. Ogni riga del repository del nostro progetto doveva essere generata da Codex.
Per realizzare ciò, abbiamo riprogettato il nostro flusso di lavoro ingegneristico da zero. Abbiamo costruito un repository "agent-friendly", investito massicciamente in test automatizzati e guardrail, e trattato Codex come un collega a pieno titolo. Abbiamo documentato questo percorso nel nostro precedente post del blog sull'ingegneria dell'imbracatura (harness engineering).
E ha funzionato, ma poi ci siamo imbattuti nel successivo collo di bottiglia: il cambio di contesto.
Per risolvere questo nuovo problema, abbiamo costruito un sistema chiamato Symphony. Symphony è un orchestratore di agenti che trasforma una bacheca di gestione dei progetti come Linear in un piano di controllo per agenti di codifica. Ogni task aperto ottiene un agente, gli agenti operano continuamente e gli esseri umani revisionano i risultati.
Questo post spiega come abbiamo creato Symphony — che ha portato a un aumento del 500% dei pull request finalizzati in alcuni team — e come usarlo per trasformare il proprio sistema di tracciamento dei problemi in un orchestratore di agenti sempre attivo.
Il limite degli agenti di codifica interattivi
Anche se diventano più facili da usare, gli agenti di codifica — sia che vi si acceda tramite app web o CLI — sono ancora strumenti interattivi.
Man mano che la portata del lavoro svolto dagli agenti aumentava in OpenAI, abbiamo riscontrato un nuovo tipo di onere. Ogni ingegnere apriva alcune sessioni di Codex, assegnava compiti, revisionava l'output, guidava l'agente e ripeteva il processo. In pratica, la maggior parte delle persone riusciva a gestire comodamente da tre a cinque sessioni alla volta prima che il cambio di contesto diventasse doloroso. Oltre questo limite, la produttività diminuiva. Ci si dimenticava quale sessione stesse facendo cosa, si saltava tra i terminali per rimettere in carreggiata gli agenti, e si dovevano debuggare compiti a lunga esecuzione che si bloccavano a metà. Gli agenti erano veloci, ma avevamo un collo di bottiglia nel sistema: l'attenzione umana. Avevamo effettivamente costruito una squadra di ingegneri junior estremamente capaci, e poi avevamo assegnato ai nostri ingegneri umani il compito di microgestirli. Questo non era scalabile.
Un cambio di prospettiva
Ci siamo resi conto che stavamo ottimizzando la cosa sbagliata. Stavamo orientando il nostro sistema attorno a sessioni di codifica e PR (pull request) fuse, quando i PR e le sessioni sono in realtà un mezzo per un fine. I flussi di lavoro del software sono in gran parte organizzati attorno ai "deliverable": problemi, task, ticket, milestone.
Così ci siamo chiesti cosa sarebbe successo se avessimo smesso di supervisionare direttamente gli agenti e li avessimo invece lasciati prelevare il lavoro dal nostro tracker dei task.
Questa idea è diventata Symphony, una specifica scritta che funziona come supervisore per orchestrare il lavoro degli agenti.
Trasformare il nostro issue tracker in un orchestratore di agenti
Symphony è nato con un concetto semplice: ogni task aperto dovrebbe essere preso in carico e completato da un agente. Invece di gestire le sessioni di Codex in più schede, abbiamo reso il nostro issue tracker il piano di controllo.
In questa configurazione, ogni issue aperto su Linear (un popolare strumento di gestione dei task) è mappato a un workspace dedicato di un agente. Symphony monitora continuamente la bacheca dei task e garantisce che ogni task attivo abbia un agente in esecuzione nel ciclo fino a quando non è completato. Se un agente si blocca o si arresta in modo anomalo, Symphony lo riavvia. Se appare nuovo lavoro, Symphony lo raccoglie e inizia a organizzarlo.
Abbiamo costruito il nostro flusso di lavoro basato sugli stati dei ticket, utilizzando il gestore dei task Linear come una macchina a stati.
In pratica, Symphony disaccoppia il lavoro dalle sessioni e dai pull request. Alcuni problemi producono più PR su diversi repository; altri sono pura investigazione o analisi che non toccano mai la codebase.
Una volta che il lavoro è astratto in questo modo, i ticket possono rappresentare unità di lavoro molto più grandi.
Utilizziamo regolarmente Symphony per orchestrare funzionalità complesse e migrazioni infrastrutturali. Ad esempio, potremmo aprire un task chiedendo all'agente di analizzare la codebase, Slack o Notion e produrre un piano di implementazione. Una volta soddisfatti del piano, l'agente genera un albero di task, suddividendo il lavoro in fasi e definendo le dipendenze tra i task.
Gli agenti iniziano a lavorare solo su task che non sono bloccati, quindi l'esecuzione si svolge naturalmente e in modo ottimale in parallelo per questo DAG (Directed Acyclic Graph, una sequenza di passaggi di esecuzione). Ad esempio, abbiamo contrassegnato l'aggiornamento di React come bloccato su una migrazione a Vite. Come previsto, gli agenti hanno iniziato ad aggiornare React solo dopo che la migrazione a Vite è stata completata.
Gli agenti possono anche creare lavoro autonomamente. Durante l'implementazione o la revisione, spesso notano miglioramenti che esulano dallo scopo del task corrente: un problema di prestazioni, un'opportunità di refactoring o un'architettura migliore. Quando ciò accade, semplicemente aprono un nuovo issue che possiamo valutare e programmare in seguito — molti di questi task di follow-up vengono anch'essi presi in carico dagli agenti. Mentre supervisioniamo questo processo, gli agenti rimangono organizzati e mantengono il lavoro in movimento.
Questo modo di lavorare riduce drasticamente il costo cognitivo di avviare lavori ambigui. Se l'agente sbaglia qualcosa, è comunque un'informazione utile, e il costo per noi è quasi nullo. Possiamo aprire ticket a basso costo affinché l'agente prototipi ed esplori, e scartare qualsiasi esplorazione che non ci piace.
Poiché l'orchestratore gira sui devbox e non dorme mai, possiamo aggiungere task da qualsiasi luogo e sapere che un agente li prenderà in carico. Ad esempio, un ingegnere del nostro team ha apportato tre modifiche significative dall'app Linear sul suo telefono da un'accogliente baita con una connessione Wi-Fi scadente.
Un aumento dell'esplorazione grazie a questo modo di lavorare
Osservando gli effetti del lavoro con Symphony, il cambiamento più ovvio è stato l'output. Tra alcuni team di OpenAI, abbiamo visto il numero di PR finalizzati aumentare del 500% nelle prime tre settimane. Al di fuori di OpenAI, il fondatore di Linear, Karri Saarinen, ha evidenziato un picco nella creazione di workspace al momento del rilascio di Symphony. Tuttavia, il cambiamento più profondo riguarda il modo in cui i team concepiscono il lavoro.
Quando i nostri ingegneri non passano più tempo a supervisionare le sessioni di Codex, l'economia delle modifiche al codice cambia completamente. Il costo percepito di ogni cambiamento diminuisce perché non stiamo più investendo sforzi umani per guidare l'implementazione stessa.
Questo ha cambiato il nostro comportamento. È diventato banale avviare task speculativi in Symphony. Provare un'idea, esplorare un refactoring, testare un'ipotesi e conservare solo i risultati promettenti.
Inoltre, amplia la platea di chi può avviare il lavoro. Il nostro product manager e il designer possono ora inoltrare richieste di funzionalità direttamente in Symphony. Non hanno bisogno di fare il checkout del repository o di gestire una sessione di Codex. Descrivono la funzionalità e ricevono un pacchetto di revisione che include una video dimostrazione della funzionalità che opera all'interno del prodotto reale.
Symphony eccelle anche in grandi monorepo (come quello che abbiamo in OpenAI) dove l'ultima fase della finalizzazione di un PR è lenta e fragile. Il sistema monitora la CI (Continuous Integration), esegue il rebase quando necessario, risolve i conflitti, garantendo che il codice sia sempre aggiornato e integrato senza intoppi. Questo automatismo elimina gran parte della frizione manuale che normalmente affligge i processi di sviluppo su larga scala, permettendo ai team di concentrarsi su innovazione e creazione di valore anziché su attività ripetitive e time-consuming.
In sintesi, Symphony non è solo un orchestratore di agenti, ma un catalizzatore per un cambio di paradigma nel modo in cui il software viene sviluppato, rendendo il processo più efficiente, scalabile e accessibile a un pubblico più ampio di collaboratori.