Atvirojo kodo „Codex“ orkestravimo specifikacija: „Symphony“
Alex Kotliarskyi, Victor Zhu ir Zach Brock
Prieš šešis mėnesius, kuriant vidinį našumo įrankį, mūsų komanda priėmė tuo metu prieštaringai vertintą sprendimą: sukurti saugyklą be nė vienos žmogaus parašytos kodo eilutės. Kiekviena eilutė mūsų projekto saugykloje turėjo būti sugeneruota „Codex“.
Norėdami tai įgyvendinti, iš pagrindų pertvarkėme savo inžinerinę darbo eigą. Sukūrėme agentams pritaikytą saugyklą, daug investavome į automatinius testus ir apsaugas, o su „Codex“ elgėmės kaip su visaverčiu komandos nariu. Tą kelią aprašėme ankstesniame tinklaraščio įraše apie infrastruktūros inžineriją.
Tai pasiteisino, bet tada susidūrėme su kita kliūtimi: konteksto perjungimu.
Šiai problemai išspręsti sukūrėme sistemą Symphony. Symphony(atsidaro naujame lange) – agentų orkestravimo priemonė, projektų valdymo lentą, pavyzdžiui, „Linear“, paverčianti kodavimo agentų valdymo skydeliu. Kiekvienai atvirai užduočiai priskiriamas agentas, agentai veikia nuolat, o žmonės peržiūri rezultatus.
Šiame įraše pasakojame, kaip sukūrėme „Symphony“ — dėl jos kai kuriose komandose sujungtų išsiuntimo užklausų skaičius išaugo 500 proc. — ir kaip ją naudoti, norint savo užduočių sekiklį paversti nuolat veikiančiu agentų orkestratoriumi.
Interaktyviųjų kodavimo agentų ribos
Nors jais naudotis darosi vis lengviau, kodavimo agentai – nesvarbu, ar pasiekiami per saityno programas, ar per CLI — išlieka interaktyvūs įrankiai.
Augant agentų atliekamo darbo mastui „OpenAI“, susidūrėme su nauju iššūkiu. Kiekvienas inžinierius atsidarydavo kelias „Codex“ sesijas, priskirdavo užduotis, peržiūrėdavo rezultatą, nukreipdavo agentą ir kartodavo procesą. Praktikoje dauguma žmonių galėjo patogiai valdyti nuo trijų iki penkių sesijų vienu metu, kol konteksto perjungimas netapdavo pernelyg varginantis. Viršijus šią ribą, produktyvumas krisdavo. Pamiršdavome, kuri sesija ką daro, perjunginėdavome terminalus, kad vėl nukreiptume agentus reikiama linkme, ir derindavome ilgai trunkančias užduotis, kurios įstrigdavo pusiaukelėje.
Agentai dirbo greitai, bet susidūrėme su sistemos kliūtimi: žmogaus dėmesiu. Iš esmės buvome sukūrę itin pajėgių jaunesniųjų inžinierių komandą, o tada paskyrėme savo inžinierius jiems smulkmeniškai vadovauti. Taip plėstis nepavyktų.
Požiūrio pokytis
Supratome, kad optimizuojame ne tai, ką reikia. Savo sistemą orientavome į kodavimo sesijas ir sujungtas išsiuntimo užklausas, nors išsiuntimo užklausos ir sesijos tėra priemonė tikslui pasiekti. Programinės įrangos darbo eiga daugiausia organizuojama pagal rezultatus: problemas, užduotis, korteles, etapus.
Tad paklausėme savęs, kas nutiktų, jei nustotume tiesiogiai prižiūrėti agentus ir leistume jiems patiems pasiimti darbą iš mūsų užduočių sekiklio.
Ši idėja virto „Symphony“ – aprašyta specifikacija, veikiančia kaip prižiūrėtoja agentų darbui orkestruoti.
Kaip užduočių sekiklį pavertėme agentų orkestratoriumi
„Symphony“ prasidėjo nuo paprastos idėjos: bet kurią atvirą užduotį turėtų perimti ir užbaigti agentas. Užuot valdę „Codex“ sesijas keliose kortelėse, savo užduočių sekiklį pavertėme valdymo skydeliu.
Šioje sistemoje kiekviena atvira „Linear“ užduotis susiejama su atskira darbo erdve. „Symphony“ nuolat stebi užduočių lentą ir užtikrina, kad kiekvienai aktyviai užduočiai būtų priskirtas agentas, veikiantis kol ji bus užbaigta. Jei agentas nustoja veikti arba užstringa, „Symphony“ jį paleidžia iš naujo. Jei atsiranda naujo darbo, „Symphony“ jį perima ir suplanuoja vykdymą.
Savo darbo eigą organizavome pagal užduočių būsenas, naudodami užduočių tvarkytuvę „Linear“ kaip būsenų automatą.
Praktikoje „Symphony“ atsieja darbą nuo sesijų ir išsiuntimo užklausų. Dėl kai kurių problemų sukuriamos kelios išsiuntimo užklausos skirtingose saugyklose; kitais atvejais pakanka tyrimo ar analizės, niekada nepaliečiančios kodo bazės.
Taip apibendrinus darbą, užduotys gali atspindėti gerokai didesnius darbo vienetus.
„Symphony“ nuolat naudojame sudėtingoms funkcijoms ir infrastruktūros migracijoms orkestruoti. Pavyzdžiui, galime sukurti užduotį ir paprašyti agento išanalizuoti kodo bazę, „Slack“ ar „Notion“ ir parengti įgyvendinimo planą. Kai planas mus tenkina, agentas sugeneruoja užduočių medį, padalija darbą į etapus ir apibrėžia užduočių priklausomybę.
Agentai pradeda dirbti tik su neblokuojamomis užduotimis, todėl vykdymas šiame DAG (vykdymo žingsnių sekoje) natūraliai ir optimaliai vyksta lygiagrečiai. Toliau pateiktame pavyzdyje pažymėjome, kad „React“ atnaujinimas stabdomas dėl migracijos į „Vite“. Kaip ir tikėtasi, agentai pradėjo atnaujinti „React“ tik užbaigę migraciją į „Vite“.
Agentai taip pat gali patys susikurti darbo. Įgyvendindami ar peržiūrėdami užduotis jie dažnai pastebi patobulinimus, nepriklausančius dabartinei užduočiai: našumo problemą, refaktorizavimo galimybę ar geresnę architektūrą. Kai taip nutinka, jie tiesiog užregistruoja naują problemą, kurią galime įvertinti ir suplanuoti vėliau – daugelį tokių tęstinių užduočių taip pat perima agentai. Nors šį procesą prižiūrime, agentai dirba organizuotai ir užtikrina, kad darbas vyktų toliau.
Toks darbo būdas gerokai sumažina kognityvinį krūvį pradedant neaiškias užduotis. Jei agentas ką nors padaro neteisingai, gauname naudingos informacijos, o mums tai beveik nieko nekainuoja. Galime mažomis sąnaudomis kurti užduotis agentui – leisti jam kurti prototipus ir tyrinėti, o netinkamus bandymus tiesiog atmesti.
Kadangi orkestratorius veikia kūrėjų sistemose ir niekada nemiega, užduočių galime pridėti iš bet kur ir būti tikri, kad agentas jas perims. Pavyzdžiui, vienas mūsų komandos inžinierius sėdėdamas jaukioje trobelėje su prastu „Wi-Fi“ ryšiu atliko tris reikšmingus pakeitimus per „Linear“ programėlę telefone.
Daugiau galimybių tyrinėti
Stebint darbo su „Symphony“ poveikį, akivaizdžiausiai pasikeitė rezultatai. Kai kuriose „OpenAI“ komandose per pirmąsias tris savaites matėme 6 kartus išaugusį sujungtų išsiuntimo užklausų skaičių. „Linear“ įkūrėjas Karri Saarinen išleidus „Symphony“ pastebėjo sukurtų darbo erdvių šuolį(atsidaro naujame lange). Tačiau svarbiausias pokytis – pakitęs komandų požiūris į darbą.
Kai mūsų inžinieriai nebegaišta laiko prižiūrėdami „Codex“ sesijų, kodo keitimo procesas iš esmės pasikeičia. Kiekvienas pakeitimas atrodo mažiau kainuojantis, nes nereikia žmogaus pastangų pačiam įgyvendinimui valdyti.
Tai pakeitė mūsų įpročius. Su „Symphony“ tapo itin paprasta kurti eksperimentines užduotis. Galite išbandyti idėją, ištyrinėti refaktorizavimo galimybes, patikrinti hipotezę ir pasilikti tik perspektyvius rezultatus.
Taip pat išsiplėtė ratas žmonių, galinčių inicijuoti darbą. Mūsų produkto vadovas ir dizaineris dabar gali tiesiogiai teikti naujų funkcijų užklausas į „Symphony“. Jiems nereikia klonuoti saugyklos ar valdyti „Codex“ sesijos. Jie aprašo funkciją ir gauna peržiūros paketą su vaizdo demonstracija, kaip funkcija veikia realiame produkte.
„Symphony“ taip pat puikiai veikia didelėse „monorepo“ saugyklose (tokiose, kokią naudojame „OpenAI“), kur paskutinis išsiuntimo užklausos integravimo etapas lėtas ir pažeidžiamas. Sistema stebi CI, prireikus atlieka perkėlimą (angl. „rebase“), sprendžia konfliktus, pakartoja nestabilius testus ir apskritai prižiūri pakeitimus viso proceso metu. Kai užduotis pasiekia Merging būseną, galime būti tikri, kad pakeitimas pateks į pagrindinę šaką be žmogaus priežiūros.
Pažanga kuria naujus iššūkius
Darbas šiame lygyje reikalauja kompromisų. Kai nuo interaktyvaus agentų nukreipimo perėjome prie darbo priskyrimo užduočių lygmeniu, praradome galimybę nuolat juos koreguoti ir prireikus pakreipti kursą. Kartais agentas sukurdavo tai, kas visiškai neatitikdavo tikslo. Tačiau tai išėjo į naudą – tokios nesėkmės atskleisdavo sistemos spragas ir padėdavo ją padaryti patikimesnę.
Užuot rankiniu būdu taisę rezultatą, įdiegėme apsaugos priemones ir suteikėme naujų įgūdžių, kad kitą kartą agentams pavyktų. Ilgainiui tai paskatino papildyti savo infrastruktūrą naujomis galimybėmis, pavyzdžiui, paleisti ištisinius (angl. „end-to-end“) testus, valdyti programą per „Chrome DevTools“ ir tvarkyti kokybės užtikrinimo (angl. „Quality Assurance“, QA) paviršinius (angl. „smoke“) testus. Smarkiai pagerinome dokumentaciją ir aiškiau apibrėžėme, kaip atrodo geras rezultatas.
Ne kiekviena užduotis pritaikoma „Symphony“ darbo modeliui. Sprendžiant kai kurias problemas vis dar reikia, kad inžinieriai dirbtų tiesiogiai su interaktyviomis „Codex“ sesijomis, ypač kai situacija neaiški arba užduotims reikia stiprių sprendimų ir kompetencijos. Praktikoje tai dažniausiai pačios įdomiausios užduotys, kurioms mūsų inžinieriai mielai skiria laiką.
Skirtumas tas, kad „Symphony“ gali perimti didžiąją dalį rutininių įgyvendinimo darbų. Tai leidžia inžinieriams susitelkti į vieną sudėtingą problemą vienu metu, užuot nuolat perjunginėjus kontekstą tarp mažesnių užduočių.
Taip pat supratome, kad laikyti agentus griežtais būsenų automato mazgais nepasiteisino. Modeliai tampa išmanesni ir gali išspręsti didesnes problemas nei rėmai, į kuriuos bandome juos įsprausti. Pavyzdžiui, ankstyvosiose versijose visos „GitHub“ integracijos buvo išorinės infrastruktūros dalis – iš pradžių buvo tikimasi, kad „Codex“ atliks tik kodo pakeitimus, o visa kita proceso dalis (pakeitimų pateikimas, testų paleidimas) buvo aprašyta kode. Ankstyvosiose mūsų agentų atliekamo darbo versijose „Codex“ buvo prašoma tik įgyvendinti užduotį. Toks požiūris pasirodė pernelyg ribotas. „Codex“ puikiai geba sukurti kelias išsiuntimo užklausas, taip pat perskaityti peržiūros grįžtamąjį ryšį ir į jį sureaguoti. Todėl suteikėme jam įrankių – gh CLI, gebėjimą skaityti CI žurnalus ir t. t. – ir dabar galime paprašyti „Codex“ padaryti daugiau, pavyzdžiui, uždaryti senas išsiuntimo užklausas arba pateikti ataskaitas apie užbaigtą ir apleistą darbą. Tokios užduotys gerokai peržengė pradinio funkcijos įgyvendinimo rėmus.
Todėl galiausiai pradėjome agentams kelti tikslus, o ne griežtus perėjimus – panašiai kaip geras vadovas paskiria tikslą tiesiogiai jam atskaitingam komandos nariui. Modelių galia kyla iš jų gebėjimo protauti, todėl suteikus įrankių ir konteksto belieka leisti jiems dirbti.
„Symphony“ pasitelkimas pačiai „Symphony“ kurti
Atidarę „Symphony“ saugyklą, pirmiausia pastebėsite, kad techniškai „Symphony“ tėra SPEC.md failas – problemos ir numatyto sprendimo apibrėžtis. Užuot kūrę sudėtingą priežiūros sistemą, apibrėžėme problemą ir numatytus sprendimus, suteikdami agentams bendrąją kryptį.
Etaloniniam įgyvendinimui pasirinkome „Elixir“ – nes kai kodas beveik nieko nekainuoja, galima rinktis kalbas pagal jų stipriąsias puses, pavyzdžiui, „Elixir“ pritaikymą lygiagretiesiems procesams – tačiau pagrindinę idėją galima išreikšti paprastu „Markdown“ dokumentu. Nukreipkite mėgstamą kodavimo agentą į specifikaciją ir paprašykite jo sukurti savąją versiją.
Pirmoji „Symphony“ versija – paprasta tmux aplinkoje veikianti „Codex“ sesija, tikrinanti „Linear“ ir naujoms užduotims paleidžianti antrinius agentus. Tai veikė, bet nebuvo itin patikima. Antroji versija perkelta į pagrindinę projekto saugyklą, pritaikytą agentams. Jau buvome sukūrę agentų infrastruktūrą, suteikiančią jiems reikiamų įgūdžių ir konteksto kokybiškai dirbti šioje saugykloje, tad „Symphony“ tiesiog viską sujungė.
Sukurę bazines funkcijas, „Symphony“ naudojome pačiai „Symphony“ kurti.
Įmonės viduje pristatę sistemą, valdančią užduotis ir pridedančią atlikto darbo vaizdo įrašą, sulaukėme itin teigiamos reakcijos: „Symphony“ projekto kanalas išaugo, o įvairios komandos pradėjo natūraliai ja naudotis. Vidinis produkto ir rinkos atitikimas – būtina sąlyga prieš pristatant produktus už „OpenAI“ ribų. Matydami aktyvų naudojimą pačioje „OpenAI“, supratome, kad „Symphony“ verta dalytis ir su visuomene.
Todėl idėją aprašėme atskirame SPEC.md faile ir paprašėme „Codex“ ją įgyvendinti. Etaloniniam įgyvendinimui pasirinkome „Elixir“ — palyginti nišinę kalbą, išsiskiriančią puikiais primityvais lygiagretiesiems procesams orkestruoti ir prižiūrėti. „Codex“ sukūrė „Elixir“ įgyvendinimą iš pirmo karto, o nuo tada toliau tobulinome ir specifikaciją, ir įgyvendinimą. Kad nušlifuotume specifikaciją, net paprašėme „Codex“ ją įgyvendinti keliomis kitomis kalbomis — „TypeScript“, „Go“, „Rust“, „Java“, „Python“ — ir remiantis rezultatais pašalinti neaiškumus bei supaprastinti sistemą. Tai pavyko padaryti kiekviena kalba.
Pasitelkę „Codex“ pašalinome daug nereikalingo sudėtingumo, pavyzdžiui, priklausomybę nuo konkrečių saugyklų ar „Linear“ MCP. „Symphony“ nebesiremia mūsų vidinėmis saugyklomis ar darbo eigomis. Pagrindinis principas tapo paprastas:
kiekvieną atvirą užduotį atskiroje darbo erdvėje vykdo agentas.
Agentai ne tik padeda atlikti aktyvų darbą, bet ir patys žino kūrimo darbo eigą bei jos laikosi. Kūrimo darbo eiga – darbas su problema, saugyklos klonavimas, užduoties pažymėjimas vykdoma, kad produkto vadovas žinotų, jog su ja dirbama, išsiuntimo užklausos pridėjimas, jos perkėlimas į peržiūros būseną, vaizdo įrašų pridėjimas ir t. t. – dabar aprašyta paprastame WORKFLOW.md faile. Anksčiau šio proceso laikėsi žmonės, tačiau jis niekada nebuvo dokumentuotas. Užuot rėmęsi šiuo nerašytu žingsnių rinkiniu, dabar jį dokumentuojame, o „Symphony“ užtikrina, kad agentai jo laikytųsi. Tai leidžia mums kurti agentus, dirbančius greta mūsų. Jei nuspręsime, kad agentai prie užbaigto darbo taip pat turėtų pridėti savirefleksiją, įtrauksime tai į WORKFLOW.md, o „Symphony“ nukreips agentus ir šiam žingsniui atlikti.
Taip pat galėjome naudoti „Codex“ programos serverio režimu(atsidaro naujame lange) – tai integruotas „Codex“ režimas be vartotojo sąsajos. Šis režimas leido paleisti „Codex“ ir programiškai su juo bendrauti per gerai dokumentuotą JSON-RPC API, atliekant tokius veiksmus kaip gijos pradėjimas ar reagavimas į veiksmus. Tai kur kas patogesnis ir lengviau pritaikomas būdas nei bandyti sąveikauti su „Codex“ per CLI ar tiesiogines tmux sesijas.
„Codex App Server“ idealiai tiko mūsų tikslui: pasinaudojame „Codex“ teikiama infrastruktūra ir kartu turime valdymo priemonių bei prijungimo taškų integracijai. Pavyzdžiui, kad antriniams agentams neatskleistume „Linear“ prieigos žetono, naudojame dinaminius įrankių iškvietimus(atsidaro naujame lange), kad pateiktume neapdorotą linear_graphql funkciją, vykdančią bet kokias užklausas „Linear“, nesiremdami MCP ir neatskleisdami prieigos žetono programinėms vykdymo aplinkoms.
Kas toliau
„Symphony“ yra sąmoningai minimalus orkestravimo sluoksnis. Skelbiame jį kaip atvirąjį kodą, kad pademonstruotume „Codex App Server“ galią derinant jį su skirtingais darbo eigos įrankiais, pavyzdžiui, „Linear“. Todėl neplanuojame palaikyti „Symphony“ kaip atskiro produkto. Tai – veikiau etaloninis įgyvendinimas. Panašiai kaip daugelis programuotojų nukreipė savo kodavimo agentus į įrašą apie infrastruktūros inžineriją, kad susikurtų savo saugyklų pagrindus, tikimės, kad ir jūs nukreipsite savo mėgstamą kodavimo agentą į „Symphony“ specifikaciją(atsidaro naujame lange) ir saugyklą(atsidaro naujame lange), kad susikurtumėte savo versijas, pritaikytas jūsų aplinkoms.
Tikroji galia slypi „Codex“ ir jo programos serveryje. „Symphony“ padėjo sujungti „Codex“ su „Linear“ – dvi jau naudotas priemones – ir taip išspręsti darbo valdymo problemą. Kodavimo agentams vis geriau protaujant ir vykdant nurodymus, įtariame, kad kitose įmonėse kliūtys taip pat pasislinks nuo kodo rašymo prie agentų atliekamo darbo valdymo. Geriausia tai, kad eksperimentuoti su šiomis kodavimo agentų sistemomis dabar stebėtinai lengva. Galite tiesiog kurti sprendimus naudodami „Codex“.
Bendruomenės įvertinimas
Džiaugiamės matydami, kad inžinierių bendruomenė aktyviai naudoja „Symphony“ praėjus vos kelioms savaitėms po išleidimo, o iki balandžio 23 d. projektas jau buvo surinkęs daugiau nei 15 tūkst. „GitHub“ žvaigždučių(atsidaro naujame lange).