Codex CLI(otvara se u novom prozoru) je naš lokalni softverski agent za više platformi, osmišljen za izradu visokokvalitetnih i pouzdanih promjena softvera, uz siguran i učinkovit rad na vašem računalu. Naučili smo mnogo o tome kako izgraditi prvorazrednog softverskog agenta otkako smo prvi put lansirali CLI u travnju. Kako bismo razjasnili te uvide, ovo je prva objava u kontinuiranom serijalu u kojem ćemo istražiti različite aspekte funkcioniranja Codexa, kao i teško stečene lekcije. (Za još detaljniji uvid u to kako je izgrađen Codex CLI, pogledajte naš repozitorij otvorenog koda na https://github.com/openai/codex(otvara se u novom prozoru). Mnogi finiji detalji naših dizajnerskih odluka zabilježeni su u GitHub issueovima i pull requestovima ako želite saznati više.)
Za početak ćemo se usredotočiti na petlju agenta, koja je temeljna logika u Codex CLI-ju odgovorna za orkestriranje interakcije između korisnika, modela i alata koje model poziva kako bi obavio smislen softverski rad. Nadamo se da vam ovaj post pruža dobar uvid u ulogu koju naš agent (ili „harness”) ima u korištenju LLM-a.
Prije nego što krenemo, kratka napomena o terminologiji: u OpenAI-u, „Codex“ obuhvaća skup ponuda softverskih agenata, uključujući Codex CLI, Codex Cloud i proširenje Codex VS Code. Ova objava usredotočuje se na Codex harness, koji pruža osnovnu petlju agenta i logiku izvršavanja koja je temelj svih Codex iskustava i dostupna je putem Codex CLI-ja. Radi lakšeg razumijevanja, ovdje ćemo pojmove „Codex“ i „Codex CLI“ koristiti naizmjenično.
U središtu svakog AI agenta nalazi se nešto što se naziva „petlja agenta“. Pojednostavljeni prikaz petlje agenta izgleda ovako:
Za početak, agent uzima unos od korisnika kako bi ga uključio u skup tekstualnih uputa koje priprema za model poznat kao upit.
Sljedeći korak je upit modelu slanjem uputa i traženjem da generira odgovor, proces poznat kao inferencija. Tijekom izvođenja zaključivanja, tekstualni upit se najprije prevodi u niz ulaznih tokena(otvara se u novom prozoru)—cijelih brojeva koji indeksiraju u vokabular modela. Ti se tokeni zatim koriste za uzorkovanje modela, stvarajući novi niz izlaznih tokena.
Izlazni tokeni prevode se natrag u tekst, što postaje odgovor modela. Budući da se tokeni generiraju postupno, prijevod se može odvijati dok model radi, što je razlog zašto mnoge aplikacije temeljene na LLM-u prikazuju izlaz u stvarnom vremenu. U praksi se zaključivanje obično skriva iza API-ja koji obrađuje tekst, apstrahirajući detalje tokenizacije.
Kao rezultat koraka izvođenja zaključaka, model ili (1) daje konačan odgovor na korisnikov izvorni unos ili (2) zatraži poziv alata koji agent treba izvršiti (npr. „pokreni ls i prijavi izlaz“). U slučaju (2), agent izvršava poziv alata i dodaje njegov izlaz izvornom upitu. Ovaj izlaz koristi se za stvaranje novog unosa koji se ponovno šalje modelu; agent tada može uzeti u obzir te nove informacije i pokušati ponovno.
Taj se proces ponavlja dok model ne prestane slati pozive alata i umjesto toga ne generira poruku za korisnika (u OpenAI modelima naziva se poruka asistenta). U mnogim slučajevima, ta poruka izravno odgovara na izvorni zahtjev korisnika, ali može biti i dodatno pitanje za korisnika.
Budući da agent može izvršavati pozive alata koji mijenjaju lokalno okruženje, njegov „izlaz“ nije ograničen samo na poruku asistenta. U mnogim slučajevima, glavni rezultat rada softverskog agenta je kôd koji piše ili uređuje na vašem računalu. Ipak, svaki se korak uvijek završava porukom asistenta—poput „Dodao sam architecture.md koji ste tražili”—koja signalizira stanje završetka u petlji agenta. Iz perspektive agenta, njegov je posao završen i kontrola se vraća korisniku.
Put od korisničkog unosa do odgovora agenta prikazan na dijagramu naziva se jednim krugom razgovora (jednom niti u Codexu). Iako ovaj razgovor može uključivati mnogo iteracija između modela zaključivanja i poziva alata. Svaki put kad pošaljete novu poruku u postojeći razgovor, povijest razgovora uključuje se kao dio upita za novi korak, uključujući poruke i pozive alata iz prethodnih koraka:
To znači da kako razgovor raste, tako se povećava i duljina upita koji se upotrebljava za uzorkovanje modela. Ova duljina je važna jer svaki model ima kontekstni prozor, što je maksimalan broj tokena koje može koristiti za jedan poziv inferencije. Napomena: ovaj prozor uključuje ulazne i izlazne tokene. Kao što možete zamisliti, agent bi mogao odlučiti napraviti stotine poziva alata u jednom potezu, što bi moglo iscrpiti kontekstualni prozor. Iz tog razloga, upravljanje kontekstualnim prozorom jedna je od mnogih odgovornosti agenta. Sada zaronimo kako bismo vidjeli kako Codex pokreće petlju agenta.
Codex CLI šalje HTTP zahtjeve Responses API-ju(otvara se u novom prozoru) za pokretanje inferencije modela. Ispitat ćemo kako informacije teku kroz Codex, koji upotrebljava Responses API za pokretanje petlje agenta.
Krajnja točka Responses API-ja koju upotrebljava Codex CLI je podesiva(otvara se u novom prozoru), tako da se može upotrebljavati s bilo kojom krajnjom točkom koja implementira Responses API(otvara se u novom prozoru):
- Kada se upotrebljava prijava u ChatGPT(otvara se u novom prozoru) s Codex CLI-jem, ono upotrebljava
https://chatgpt.com/backend-api/codex/responseskao krajnja točka - Pri korištenju autentifikacije API ključem(otvara se u novom prozoru) s modelima koje udomljuje OpenAI, upotrebljava se
https://api.openai.com/v1/responseskao krajnja točka - Kada pokrećete Codex CLI s
--ossza korištenje gpt-oss s ollama 0.13.4+(otvara se u novom prozoru) ili LM Studio 0.3.39+(otvara se u novom prozoru), zadana adresa jehttp://localhost:11434/v1/responseskoja se pokreće lokalno na vašem računalu - Codex CLI može se upotrebljavati s Responses API-jem koji se udomljava kod pružatelja usluga u oblaku kao što je Azure
Istražimo kako Codex kreira upit za prvi poziv inferencije u razgovoru.
Kao krajnji korisnik, ne specificirate upit koji se koristi za doslovno uzorkovanje modela kada šaljete upit prema Responses API-ju. Umjesto toga, vi navodite različite vrste unosa kao dio svog upita, a poslužitelj Responses API-ja odlučuje kako strukturirati te informacije u upit koji je model osmišljen za obradu. Možete razmišljati o upitu kao o „popisu stavki”; ovaj će odjeljak objasniti kako se vaš upit pretvara u taj popis.
U početnom upitu svaka stavka na popisu povezana je s ulogom. Uloga označava koliku važnost treba imati povezani sadržaj i jedna je od sljedećih vrijednosti (prema opadajućem redoslijedu prioriteta): sustav, razvojni inženjer, korisnik, asistent.
Responses API(otvara se u novom prozoru) prima JSON payload s mnogim parametrima. Usredotočit ćemo se na ta tri područja:
upute(otvara se u novom prozoru): poruka sustava (ili razvojnog inženjera) umetnuta u kontekst modelaalati(otvara se u novom prozoru): popis alata koje model može upotrebljavati prilikom generiranja odgovoraunos(otvara se u novom prozoru): popis tekstualnih, slikovnih ili datotečnih unosa u model
U Codexu se polje instructions čita iz model_instructions_file(otvara se u novom prozoru) u ~/.codex/config.toml, ako je navedeno; u suprotnom se koriste base_instructions povezane s modelom(otvara se u novom prozoru). Upute specifične za model nalaze se u repozitoriju Codex i uključene su u CLI (npr. gpt-5.2-codex_prompt.md(otvara se u novom prozoru)).
Polje tools je popis definicija alata koji su u skladu sa shemom koju definira Responses API. Za Codex, to uključuje alate koje pruža Codex CLI, alate koje pruža Responses API i koji bi trebali biti dostupni Codexu, kao i alate koje pruža korisnik, obično putem MCP poslužitelja:
Na kraju, polje unos u JSON payloadu je popis stavki. Codex umeće sljedeće stavke(otvara se u novom prozoru) u unos prije dodavanja korisničke poruke:
1. Poruka s role=developer koja opisuje sandbox koji se primjenjuje samo na Codexov shell alat definiran u odjeljku tools. To jest, ostali alati, poput onih koje pružaju MCP poslužitelji, nisu u Codexovom sandboxu i odgovorni su za provedbu vlastitih zaštitnih mjera.
Poruka je sastavljena iz predloška gdje ključni dijelovi sadržaja dolaze iz isječaka Markdowna uključenih u Codex CLI, kao što su workspace_write.md(otvara se u novom prozoru) i on_request.md(otvara se u novom prozoru):
2. (Neobavezno) Poruka s role=developer čiji sadržaj predstavlja vrijednost developer_instructions pročitanu iz korisnikove datoteke config.toml.
3. (Neobavezno) Poruka s role=user čiji sadržaj su „korisničke upute”, koje ne potječu iz jedne datoteke, već su prikupljene iz više izvora(otvara se u novom prozoru). Općenito, detaljnije upute pojavljuju se kasnije:
- Sadržaj datoteka
AGENTS.override.mdiAGENTS.mdu$CODEX_HOME - Podložno ograničenju (32 KiB, prema zadanim postavkama), pretražite svaku mapu od korijena Git/projekta za
cwd(ako postoji) do samogcwd: dodajte sadržaj bilo koje datotekeAGENTS.override.md,AGENTS.md, ili bilo koji naziv datoteke naveden uproject_doc_fallback_filenames u config.toml - Ako su vještine(otvara se u novom prozoru) konfigurirane:
- kratki uvod o vještinama
- metapodaci o vještinama(otvara se u novom prozoru) za svaku vještinu
- odjeljak o korištenju vještina(otvara se u novom prozoru)
4. Poruka s role=user koja opisuje lokalno okruženje u kojem agent trenutno radi. Ovo određuje trenutni radni direktorij i korisničku ljusku(otvara se u novom prozoru):
Nakon što Codex obavi sve gore navedene izračune za inicijalizaciju unosa, dodaje korisničku poruku kako bi započeli razgovor.
Prethodni primjeri bili su usmjereni na sadržaj svake poruke, ali imajte na umu da je svaki element unosa JSON objekt s vrstom, ulogom(otvara se u novom prozoru) i sadržajem kako slijedi:
Nakon što Codex izgradi puni JSON payload za slanje na Responses API, šalje HTTP POST zahtjev s autorizacijskim zaglavljem, ovisno o tome kako je krajnja točka Responses API-ja konfigurirana u ~/.codex/config.toml (dodatna HTTP zaglavlja i parametri upita dodaju se ako su navedeni).
Kada poslužitelj OpenAI Responses API-ja primi zahtjev, koristi JSON za generiranje upita za model na sljedeći način (za svaki slučaj, prilagođena implementacija Responses API-ja mogla bi donijeti drugačiji izbor):
Kao što možete vidjeti, redoslijed prve tri stavke u upitu određuje poslužitelj, a ne klijent. Međutim, od te tri stavke, samo je sadržaj sistemske poruke također pod kontrolom poslužitelja, dok alate i upute određuje klijent. Nakon toga slijedi unos iz JSON payloada kako bi se dovršio upit.
Sada kada imamo naš upit, spremni smo uzeti uzorak modela.
Ovaj HTTP zahtjev prema Responses API-ju pokreće prvi „korak“ razgovora u Codexu. Poslužitelj odgovara nizom događaja poslanih od poslužitelja (SSE(otvara se u novom prozoru)). Podatak svakog događaja je JSON payload s "type" koji započinje s "response", što bi moglo izgledati ovako (cjelovit popis događaja možete pronaći u našoj API dokumentaciji(otvara se u novom prozoru)):
Codex konzumira niz događaja(otvara se u novom prozoru) i ponovno ih objavljuje kao interne objekte događaja koje klijent može koristiti. Događaji poput response.output_text.delta koriste se za podršku strujanju u korisničkom sučelju, dok se drugi događaji poput response.output_item.added pretvaraju u objekte koji se dodaju u unos za naknadne pozive API-ja za odgovore.
Pretpostavimo da prvi zahtjev prema Responses API-ju uključuje dva događaja response.output_item.done: jedan s type=reasoning i jedan s type=function_call. Ovi događaji moraju biti predstavljeni u polju unos JSON-a kada ponovno upitamo model s odgovorom na poziv alata:
Rezultirajući upit korišten za uzorkovanje modela kao dio sljedećeg upita izgledao bi ovako:
Posebno obratite pozornost na to kako je stari upit točan prefiks novog upita. To je namjerno tako, jer čini sljedeće zahtjeve mnogo učinkovitijima omogućujući nam da iskoristimo predmemoriranje upita (o čemu ćemo govoriti u sljedećem odjeljku o performansama).
Osvrćući se na naš prvi dijagram petlje agenta, vidimo da može biti mnogo iteracija između zaključivanja i pozivanja alata. Upit može nastaviti rasti sve dok napokon ne primimo poruku asistenta, što označava kraj poteza:
U Codex CLI-ju korisniku prikazujemo poruku asistenta i usmjeravamo uređivač kako bismo korisniku naznačili da je njihov red da nastave razgovor. Ako korisnik odgovori, poruka asistenta iz prethodnog koraka i nova poruka korisnika moraju se dodati u unos u zahtjevu za Responses API kako bi se započeo novi korak:
Još jednom, budući da nastavljamo razgovor, duljina unosa koju šaljemo u Responses API stalno se povećava:
Istražimo što ovaj sve veći upit znači za performanse.
Možda se pitate: „Samo malo, nije li petlja agenta kvadratna u smislu količine JSON-a poslanog na Responses API tijekom razgovora?” I bili biste u pravu. Iako Responses API podržava neobavezni parametar previous_response_id(otvara se u novom prozoru) za ublažavanje tog problema, Codex ga danas ne koristi, prvenstveno kako bi zahtjevi ostali potpuno bez stanja i kako bi se podržale konfiguracije bez zadržavanja podataka (ZDR).
Izbjegavanje previous_response_id pojednostavljuje stvari za pružatelja Responses API-ja jer osigurava da svaki zahtjev bude bez stanja. To također olakšava podršku korisnicima koji su se odlučili za bez zadržavanja podataka (ZDR)(otvara se u novom prozoru), jer bi pohrana podataka potrebnih za podršku previous_response_id bila u sukobu sa ZDR-om. Imajte na umu da korisnici ZDR-a ne gube mogućnost korištenja vlasničkih poruka rasuđivanja iz prethodnih koraka, jer se povezani encrypted_content može dešifrirati na poslužitelju. (OpenAI pohranjuje ključ za dešifriranje ZDR korisnika, ali ne i njihove podatke.) Pogledajte PR-ove #642(otvara se u novom prozoru) i #1641(otvara se u novom prozoru) za povezane promjene u Codexu kako bi se podržao ZDR.
Općenito, trošak uzorkovanja modela nadmašuje trošak mrežnog prometa, zbog čega je uzorkovanje primarni cilj naših nastojanja za povećavanje učinkovitosti. Zato je predmemoriranje upita toliko važno jer omogućuje ponovnu upotrebu izračuna iz prethodnog poziva zaključivanja. Kada dobijemo pogotke predmemorije, uzorkovanje modela postaje linearno umjesto kvadratno. Naša dokumentacija o predmemoriranju upita (otvara se u novom prozoru)to objašnjava u više detalja:
Pogoci predmemorije mogući su samo za točna podudaranja prefiksa unutar upita. Kako biste ostvarili prednosti predmemoriranja, stavite statičan sadržaj poput uputa i primjera na početak upita, a promjenjiv sadržaj, kao što su informacije specifične za korisnika, na kraj. Ovo se odnosi i na slike i alate, koji moraju biti identični u svim zahtjevima.
Imajući to na umu, razmotrimo koje vrste operacija mogu uzrokovati „promašaj predmemorije” u Codexu:
- Promjena
alatadostupnih modelu tijekom razgovora. - Promjena
modelakoji je cilj zahtjeva za Responses API (u praksi, to mijenja treću stavku u izvornom upitu jer sadrži upute specifične za model). - Promjena konfiguracije sandboxa, načina odobravanja ili trenutnog radnog direktorija.
Tim Codex mora biti pažljiv pri uvođenju novih značajki u Codex CLI koje bi mogle ugroziti predmemoriranje upita. Na primjer, naša početna podrška za MCP alate uvela je pogrešku zbog koje nismo uspjeli nabrojati alate u dosljednom redoslijedu(otvara se u novom prozoru), što je uzrokovalo promašaje predmemorije. Imajte na umu da MCP alati mogu biti posebno zahtjevni jer MCP poslužitelji mogu u hodu promijeniti popis alata koje pružaju putem obavijesti notifications/tools/list_changed(otvara se u novom prozoru). Poštivanje te obavijesti usred dugog razgovora može uzrokovati skupi promašaj predmemorije.
Kad god je moguće, promjene konfiguracije koje se dogode usred razgovora rješavamo dodavanjem nove poruke u unos kako bismo odrazili promjenu, umjesto da mijenjamo raniju poruku:
- Ako se promijeni konfiguracija sandboxa ili način odobravanja, umetnemo(otvara se u novom prozoru) novu poruku
role=developers istim formatom kao izvorna stavka<permissions instructions>. - Ako se promijeni trenutni radni direktorij, umetnemo(otvara se u novom prozoru) novu poruku
role=useru istom formatu kao izvorni<environment_context>.
Ulažemo velike napore kako bismo osigurali pogotke predmemorije radi poboljšavanja performansi. Postoji još jedan ključni resurs kojim trebamo upravljati: kontekstni prozor.
Naša opća strategija da izbjegnemo nestanak kontekstnog prozora jest sažimanje razgovora kada broj tokena premaši određeni prag. Konkretno, mijenjamo unos novim, manjim popisom stavki koje su reprezentativne za razgovor, omogućujući agentu da nastavi s razumijevanjem onoga što se dosad dogodilo. Rana implementacija zbijanja(otvara se u novom prozoru) zahtijevala je da korisnik ručno pokrene naredbu /compact, koja bi ispitivala Responses API upotrebom postojećeg razgovora i prilagođene upute za sažimanje(otvara se u novom prozoru). Codex je nekada koristio poruku asistenta koja sadrži sažetak kao novi unos(otvara se u novom prozoru) za sljedeće korake razgovora.
Od tada se API za odgovore razvio kako bi podržavao posebnu /responses/compact krajnju točku(otvara se u novom prozoru) koja učinkovitije obavlja zbijanje. Ono vraća popis stavki(otvara se u novom prozoru) koji se može upotrebljavati umjesto prethodnog unosa za nastavak razgovora te se pritom oslobađa kontekstualni prozor. Taj popis uključuje posebnu stavku type=compaction s neprozirnom stavkom encrypted_content koja čuva latentno razumijevanje modela izvornog razgovora. Sada, Codex automatski upotrebljava tu krajnju točku za zbijanje razgovora kada se premaši auto_compact_limit(otvara se u novom prozoru).
Uveli smo petlju agenta Codex i objasnili kako Codex oblikuje i upravlja svojim kontekstom prilikom upita prema modelu. Usput smo istaknuli praktična razmatranja i najbolje prakse koje se primjenjuju na svakoga tko gradi petlju agenta na temelju Responses API-ja.
Iako petlja agenta pruža temelj za Codex, to je tek početak. U nadolazećim objavama detaljnije ćemo istražiti arhitekturu CLI-ja, istražiti kako je implementirana upotreba alata i pobliže pogledati Codexov model sandboxinga.


