Specifikacija otvorenog koda za Codex orkestraciju: Symphony
Autori: Alex Kotliarskyi, Victor Zhu i Zach Brock
Prije šest mjeseci, dok smo radili na internom alatu za produktivnost, naš tim je donio (u to vrijeme) kontroverznu odluku: izgradit ćemo naš repozitorij bez ijedne linije koda koju je napisao čovjek. Svaka linija u repozitoriju našeg projekta morala je biti generisana pomoću Codexa.
Da bismo to omogućili, redizajnirali smo naš inženjerski radni tok iz temelja. Izgradili smo repozitorij prilagođen agentima, mnogo ulagali u automatizirane testove i zaštitne mehanizme te tretirali Codex kao punopravnog saigrača. To putovanje dokumentovali smo u našoj prethodnoj objavi na blogu o harness engineeringu (razvoju infrastrukturnog okvira za agente).
I uspjelo je, ali tada smo naišli na sljedeće usko grlo: stalno mijenjanje konteksta.
Da bismo riješili ovaj novi problem, izgradili smo sistem pod nazivom Symphony. Symphony(otvara se u novom prozoru) je orkestrator agenata koji tablu za upravljanje projektima poput Lineara pretvara u kontrolnu ravan za agente za kodiranje. Svaki otvoreni zadatak dobija agenta, agenti rade neprekidno, a ljudi pregledaju rezultate.
Ova objava objašnjava kako smo kreirali Symphony—što je u nekim timovima rezultiralo povećanim brojem spojenih pull requestova od 500%—i kako ga iskoristiti da vlastiti alat za praćenje problema pretvorite u uvijek aktivan orkestrator agenata.
Granice interaktivnih agenata za kodiranje
Mada postaju lakši za korištenje, agenti za kodiranje—bilo da im se pristupa kroz web aplikacije ili CLI—su i dalje interaktivni alati.
Kako se obim agentskog rada povećavao u OpenAI-ju, otkrili smo novu vrstu opterećenja. Svaki inženjer bi otvorio nekoliko Codex sesija, dodijelio zadatke, pregledao rezultate, usmjeravao agenta i to ponavljao. U praksi, većina osoba je mogla udobno upravljati s tri do pet sesija istovremeno prije nego što bi im promjena konteksta postala problem. Nakon toga je produktivnost opadala. Zaboravljali bismo koja sesija šta radi, skakali između terminala da agente vratimo na pravi put i otklanjali probleme u dugotrajnim zadacima koji bi zastali na pola.
Agenti su bili brzi, ali imali smo usko grlo u sistemu: ljudsku pažnju. U suštini smo izgradili tim izuzetno sposobnih mlađih inženjera, a zatim smo naše ljude, inženjere, zudužili da ih mikromenadžuju. Takav sistem nije mogao da raste.
Promjena perspektive
Shvatili smo da optimizujemo pogrešnu stvar. Naš sistem smo orijentisali oko sesija kodiranja i spojenih PR-ova, iako su PR-ovi i sesije zapravo samo sredstvo do cilja. Radni tokovi u razvoju softvera u velikoj mjeri su organizovani oko isporuka: problema, zadataka, tiketa, prekretnica.
Zato smo se zapitali šta bi se dogodilo kada bismo prestali direktno nadzirati agente i umjesto toga im dopustili da sami preuzimaju posao iz našeg alata za praćenje zadataka.
Ta ideja postala je Symphony, pisana specifikacija koja funkcioniše kao supervizor za orkestraciju agentskog rada.
Pretvaranje našeg alata za praćenje prpoblema u orkestratora agenata
Symphony je počeo s jednostavnim konceptom: svaki otvoreni zadatak treba da preuzme i završi agent. Umjesto upravljanja Codex sesijama u više kartica, naš alat za praćenje problema pretvorili smo u upravljački panel.
U ovoj postavci, svaki otvoreni problem u Linearu se mapira na namjenski radni prostor agenta. Symphony neprekidno prati tablu zadataka i osigurava da svaki aktivni zadatak ima agenta koji radi u petlji dok zadatak ne bude završen. Ako se agent sruši ili zastane, Symphony ga ponovo pokreće. Ako se pojavi novi posao, Symphony ga preuzima i počinje organizovati rad.
Naš radni tok smo izgradili na osnovu statusa tiketa, koristeći alat za upravljanje zadacima, Linear, kao mašinu stanja.
U praksi, Symphony razdvaja posao od sesija i od pull requesta. Neki problemi proizvode više PR-ova kroz različite repozitorije; drugi su čisto istraživanje ili analiza koji nikada ne dodirnu bazu koda.
Kada se posao apstrahuje na taj način, tiketi mogu predstavljati mnogo veće cjeline rada.
Symphony redovno koristimo za orkestraciju složenih funkcionalnosti i migracije infrastrukture. Naprimjer, možemo kreirati zadatak u kojem tražimo od agenta da analizira bazu koda, Slack ili Notion, te izradi plan implementacije. Kada budemo zadovoljni planom, agent generiše stablo zadataka, razlažući posao na faze i definišući zavisnosti između zadataka.
Agenti počinju raditi samo na zadacima koji nisu blokirani, tako da se izvršavanje za ovaj DAG (niz koraka izvršavanja) odvija prirodno i optimalno paralelno. U primjeru ispod označili smo da je React nadogradnja blokirana migracijom na Vite. Očekivano, agenti su počeli nadograđivati React tek nakon što je migracija na Vite bila završena.
Agenti mogu i sami kreirati posao. Tokom implementacije ili pregleda, oni često uoče poboljšanja koja izlaze izvan opsega trenutnog zadatka: problem s performansama, priliku za refaktorisanje ili bolju arhitekturu. Kada se to desi, oni jednostavno kreiraju novi problem koji kasnije možemo procijeniti i rasporediti—mnoge od tih naknadnih zadataka također preuzimaju agenti. Dok mi nadgledamo ovaj proces, agenti ostaju organizovani i održavaju posao u pokretu.
Ovakav način rada drastično smanjuje kognitivni trošak pokretanja nejasno definisanog posla. Ako agent nešto pogriješi, to je i dalje korisna informacija, a naš trošak je skoro nula. Možemo vrlo jeftino kreirati tikete da agent ode praviti prototipe i istraživati, i odbaciti sva istraživanja koja nam se ne dopadnu.
Budući da orkestrator radi na razvojnim mašinama i nikada ne spava, zadatke možemo dodavati odakle god želimo, znajući da će ih agent preuzeti. Naprimjer, jedan inženjer u našem timu napravio je tri značajne promjene iz Linear aplikacije na svom telefonu, iz udobne kolibe na lošem wifi-ju.
Rast istraživanja zahvaljujući ovakvom načinu rada
Kada smo posmatrali efekte rada sa Symphonyjem, najočitija promjena je uočena u izlazu. U nekim timovima u OpenAI-ju vidjeli smo da se broj spojenih PR-ova povećao 6 puta u prve tri sedmice. Izvan OpenAI-ja, osnivač Lineara, Karri Saarinen, istakao je porast broja kreiranih radnih prostora(otvara se u novom prozoru) nakon što smo objavili Symphony. Međutim, dublja promjena nastala je u načinu na koji timovi razmišljaju o poslu.
Kada naši inženjeri više ne provode vrijeme nadzirući Codex sesije, ekonomika promjene koda potpuno se mijenja. Percipirani trošak svake promjene opada jer više ne ulažemo ljudski trud u samo sprovođenje implementacije.
To je promijenilo naše ponašanje. Postalo je trivijalno pokretati spekulativne zadatke u Symphonyju. Dovoljno je isprobati ideju, istražiti refaktorisanje, testirati hipotezu i zadržati samo rezultate koji djeluju obećavajuće.
To također proširuje krug onih koji mogu inicirati posao. Naš produkt menadžer i dizajner sada mogu direktno slati zahtjeve za funkcionalnosti u Symphony. Ne moraju preuzimati repozitorij niti upravljati Codex sesijom. Dovoljno je da opišu funkcionalnost i dobit će paket za pregled koji sadrži video obilazak funkcionalnosti koja radi unutar stvarnog proizvoda.
Symphony se također ističe u velikim monorepozitorijima (poput onog koji imamo u OpenAI-ju), gdje je posljednji korak spajanja PR-a spor i osjetljiv. Sistem prati CI, po potrebi radi rebase, rješava konflikte, ponavlja nepouzdane provjere i općenito provodi promjene kroz cijeli tok. Do trenutka kada tiket dođe do statusa Spajanje, velika je vjerovatnoća da će promjena ući u glavnu granu bez ljudske intervencije.
Nakon implementacije Symphonyja, više posla delegiramo agentima i fokusiramo se na teže zadatke koji su više istraživačkog tipa.
Napredak donosi nove, drugačije probleme
Rad na ovom nivou nosi kompromise. Kada smo prešli sa interaktivnog usmjeravanja agenata na dodjeljivanje posla na nivou tiketa, izgubili smo mogućnost da ih stalno usmjeravamo usred rada i korigujemo kurs kada je potrebno. Ponekad bi agent proizveo nešto potpuno pogrešno. To je bilo korisno—ti neuspjesi su otkrili praznine u sistemu i pomogli nam da ga učinimo robusnijim.
Umjesto da rezultat ručno ispravljamo, dodali smo zaštitne mehanizme i sposobnosti kako bi agenti sljedeći put uspjeli. Vremenom nas je to navelo da našem harnessu dodamo nove mogućnosti, kao što su pokretanje end-to-end testova, upravljanje aplikacijom kroz Chrome DevTools i vođenje QA smoke testova. Značajno smo unaprijedili dokumentaciju i pojasnili kako izgleda dobar rezultat.
Nije svaki zadatak pogodan za Symphony. Neki problemi i dalje zahtijevaju da inženjeri rade direktno s interaktivnim Codex sesijama, posebno kada su u pitanju nejasni problemi ili posao koji traži snažno prosuđivanje i stručnost. U praksi su to obično najzanimljiviji i najugodniji zadaci na koje naši inženjeri troše vrijeme.
Razlika je u tome što Symphony može preuzeti većinu rutinskog implementacijskog rada. To omogućava inženjerima da se fokusiraju na jedan težak problem odjednom, umjesto da stalno mijenjaju kontekst prelazeći između manjih zadataka.
Također smo naučili da tretiranje agenata kao rigidnih čvorova u mašini stanja ne funkcioniše dobro. Modeli postaju pametniji i mogu rješavati veće probleme od okvira u koji ih pokušavamo smjestiti. Naprimjer, rane verzije su imale sve GitHub integracije kao dio vanjskog harnessa—naprimjer, rane verzije su očekivale da Codex pravi samo izmjene koda, a ostatak procesa (slanje promjena, pokretanje testova) bio je definisan u kodu. Naše rane verzije rada sa agentima su od Codexa tražile samo da implementira zadatak. Taj pristup se pokazao previše ograničavajućim. Codex je sasvim sposoban da kreira više PR-ova, kao i da čita povratne informacije iz pregleda i reagira na njih. Zato smo mu dali alate—gh CLI, sposobnosti čitanja CI logova itd.—i sada možemo tražiti od Codexa da radi više, poput zatvaranja starih PR-ova ili izvlačenja izvještaja o završenom naspram napuštenom poslu. Ove vrste zadataka bile su daleko izvan početnog okvira implementacije funkcionalnosti.
Zato smo se na kraju usmjerili ka tome da agentima dajemo ciljeve umjesto strogih tranzicija, slično kao što bi dobar menadžer dodijelio cilj direktnom saradniku u svom timu. Snaga modela dolazi iz njihove sposobnosti da rezonuju, zato im dajte alate i kontekst i pustite ih da rade.
Korištenje Symphonyja za izgradnju Symphonyja
Kada otvorite Symphony repozitorij, prvo što ćete primijetiti jeste da je Symphony tehnički samo datoteka SPEC.md—definicija problema i namjeravanog rješenja. Umjesto izgradnje složenog sistema nadzora, definisali smo problem i namjeravana rješenja, dajući agentima usmjeravanje na visokom nivou.
Referentna implementacija je napisana u Elixiru—jer kada je kôd praktično besplatan, konačno možete birati jezike prema njihovim prednostima, poput one koje ima Elixir—ali osnovna ideja se može izraziti u jednostavnom Markdown dokumentu. Podstičemo vas da svog omiljenog agenta za kodiranje usmjerite na specifikaciju i navedete ga da na osnovu nje implementira vlastitu verziju.
Prvu verziju Symphonyja činila je samo Codex sesija pokrenuta u tmuxu, koja je periodično provjeravala Linear i pokretala podagente za nove zadatke. Radila je, ali nije bila naročito pouzdana. Druga verzija je bila smještena unutar našeg glavnog repozitorija projekta, koji je bio napravljen baš za agente. Već smo imali postavljen okvir za agente koji im daje potrebne funkcionalnosti i kontekst da kvalitetno rade u ovom repozitoriju, tako da ih je Symphony jednostavno sve povezao.
Kada je osnovna funkcionalnost uspostavljena, iskoristili smo Symphony da napravimo Symphony.
Kada smo interno demonstrirali sistem koji upravlja zadacima i prilaže videozapis kao dokaz svog rada, reakcija je bila izuzetno pozitivna: naš projektni kanal za Symphony je rastao, a timovi širom organizacije počeli su ga spontano koristiti. Osnovni preduslov za eksterno lansiranje u OpenAI-ju jeste da proizvod zadovolji interno tržište. Na osnovu upotrebe koju smo vidjeli u OpenAI-ju, postalo je jasno da Symphony trebamo podijeliti i van kompanije.
Zato smo izdvojili ideju u samostalni SPEC.md i zatražili od Codexa da ga implementira. Za referentnu implementaciju odabrali smo Elixir, relativno rijedak jezik s odličnim primitivama za orkestraciju i nadzor konkurentnih procesa. Codex je Elixir implementaciju izgradio iz jednog pokušaja, a mi smo odatle nastavili iterirati i na specifikaciji i na implementaciji. Da bismo dotjerali specifikaciju, čak smo tražili od Codexa da je implementira i u nekoliko drugih jezika—TypeScript, Go, Rust, Java, Python—te da rezultate iskoristi za prepoznavanje nejasnoća i pojednostavljivanje sistema. Uspio je u svakom jeziku.
Kroz proces izgradnje Codexa uklonili smo mnogo usputne složenosti, poput zavisnosti od specifičnih repozitorija ili Linear MCP-a. Symphony više ne zavisi od naših internih repozitorija ni radnih tokova. Osnovni pristup postao je jednostavan:
Za svaki otvoreni zadatak osiguraj da agent radi u vlastitom radnom prostoru.
Osim što olakšava aktivni rad, radni tok razvoja je sada nešto što agenti poznaju i prate. Radni tok razvoja—rad na problemu, preuzimanje repozitorija, stavljanje u status "u toku" kako bi PM znao da se na tome radi, dodavanje PR-a, prebacivanje u status "Pregled", prilaganje videozapisa itd.—sada je zabilježen u jednostavnoj datoteci WORKFLOW.md. Sve je to proces koji su i ljudi slijedili, ali nikada nije bio dokumentovan. Umjesto oslanjanja na ovaj implicitni skup koraka, sada ga dokumentujemo, a Symphony vodi računa da ga se agenti pridržavaju. To nam omogućava da gradimo agente koji rade uz nas. Ako odlučimo da agenti trebaju da prilože samorefleksiju uz završeni rad, dodat ćemo to u WORKFLOW.md, a Symphony će agente usmjeriti na taj korak.
Također smo dobili priliku da koristimo Codex u režimu app servera(otvara se u novom prozoru), ugrađenom headless režimu za Codex. Ovaj režim nam je omogućio da pokrećemo Codex i programski komuniciramo s njim putem dobro dokumentovanog JSON-RPC API-ja za stvari poput pokretanja niti ili reagiranja na poteze. To je mnogo praktičniji i skalabilniji način od pokušaja interakcije s Codexom putem CLI-ja ili živih tmux sesija.
Codex App Server savršeno je odgovarao našem slučaju upotrebe: koristimo harness koji Codex pruža, a pritom imamo kontrole i priključke za integraciju. Naprimjer, da bismo izbjegli davanje pristupnog tokena za Linear podagentima, koristimo dinamička pozivanja alata(otvara se u novom prozoru) da izložimo sirovu funkciju linear_graphql, koja izvršava proizvoljne zahtjeve u Linearu, bez oslanjanja na MCP ili izlaganja pristupnog tokena kontejnerima.
Šta je sljedeće
Symphony je namjerno urađen kao minimalistički sloj za orkestraciju. Otvoreno objavljujemo njegov kôd kako bismo demonstrirali moć Codex App Servera kada se upari s različitim alatima za radni tok, poput Lineara. Kao takav, ne planiramo održavati Symphony kao samostalan proizvod. Posmatrajte ga kao referentnu implementaciju. Slično kao što su mnogi programeri usmjeravali svoje agente za kodiranje na objavu o harness inženjeringu da bi izgradili svoje repozitorije, nadamo se da ćete usmjeriti svog omiljenog agenta za kodiranje na Symphony specifikaciju(otvara se u novom prozoru) i repozitorij(otvara se u novom prozoru) kako biste izgradili vlastite verzije prilagođene svojim okruženjima.
Snaga dolazi od Codexa i njegovog app servera. Symphony je bio način da povežemo Codex i Linear, dva alata koja smo već koristili, kako bismo riješili problem upravljanja radom. Kako agenti za kodiranje postaju bolji u rezonovanju i praćenju instrukcija, pretpostavljamo da će se usko grlo i u drugim kompanijama pomjeriti sa pisanja koda prema upravljanju radom agenata. Posebno je uzbudljivo to što je barijera za eksperimentisanje s ovim sistemima agenata za kodiranje sada iznenađujuće niska; dovoljno je graditi koristeći Codex.
Pohvale zajednici
Oduševljeni smo što vidimo da inženjerska zajednica koristi Symphony u sedmicama nakon objave, uz više od 15 hiljada GitHub zvjezdica(otvara se u novom prozoru) zaključno s 23. aprilom.