Codex CLI(åpnes i et nytt vindu) er vår lokale programvareagent som fungerer på alle plattformer, og er utviklet for å produsere pålitelige programvareendringer av høy kvalitet, samtidig som den opererer trygt og effektivt på maskinen din. Vi har lært enormt mye om hvordan man bygger en programvareagent i verdensklasse siden vi først lanserte CLI-en i april. Dette er det første innlegget i en serie der vi vil vise deg denne innsikten og utforske diverse aspekter av hvordan Codex fungerer, i tillegg til det vi lærte gjennom prøving og feiling. (For å få en enda mer detaljert oversikt over hvordan Codex CLI er bygget opp, kan du se åpen-kildekode-lageret vårt på https://github.com/openai/codex(åpnes i et nytt vindu). Mange av de finere detaljene av designbeslutningene er dokumentert i GitHub-saker og pull-forespørsler, hvis du vil vite mer.)
Vi starter med et fokus på agentløkken, som er kjernelogikken i Codex CLI og ansvarlig for orkestrering av samspillet mellom brukeren, modellen og verktøyene modellen bruker, til å utføre meningsfullt programvarearbeid. Vi håper dette innlegget gir deg et godt innblikk i rollen agenten vår (eller styringsrammeverket), har i bruken av en LLM.
Før vi kaster oss inn i det, har vi en kort merknad om terminologi: i OpenAI omfatter «Codex» en pakke med programvareagenttilbud, inkludert Codex CLI, Codex Cloud og Codex VS Code-utvidelsen. Dette innlegget fokuserer på Codex-en styringsrammeverket, som gir den grunnleggende agentløkken og utførelseslogikken som ligger til grunn for alle Codex-opplevelser og gjøres tilgjengelig gjennom Codex CLI. For enkelhets skyld her bruker vi begrepene «Codex» og «Codex CLI» om hverandre.
I kjernen av enhver AI-agent er det noe som kalles «agentløkken». En forenklet illustrasjon av agentløkken ser slik ut:
Agenten starter ved å ta inndata fra brukeren for å inkludere dem i tekstinstruksjoner den klargjør for modellen. Dette er kjent som en prompt.
Neste trinn er å spørre modellen ved å sende den instruksjonene våre og be den om å generere et svar. Denne prosessen kalles en inferens. Under inferensen blir tekstprompten først oversatt til en sekvens av inndata-tokener(åpnes i et nytt vindu) – heltall som indekseres inn i modellens vokabular. Disse tokenene brukes deretter til å sample modellen, og så produserer de en ny sekvens av utdata-tokener.
Tokenene oversettes tilbake til tekst, som blir modellens svar. Fordi tokener produseres trinnvis, kan denne oversettelsen skje mens modellen kjører, og derfor viser mange LLM-løsninger løpende resultater. I praksis er inferens vanligvis innkapslet bak en API som jobber med tekst, og som skjuler detaljene ved tokenisering.
Som et resultat av inferenstrinnet, vil modellen enten (1) produsere et endelig svar på brukerens opprinnelige inndata, eller (2) be om et verktøykall som agenten skal utføre (f.eks. «kjør ls og rapporter utdataene»). I tilfelle (2) utfører agenten verktøykallet og legger til utdataene i den opprinnelige prompten. Disse utdataene brukes til å generere nye inndata som brukes til å spørre modellen på nytt. Agenten kan deretter ta denne nye informasjonen i betraktning og prøve igjen.
Denne prosessen gjentas til modellen slutter å sende ut verktøykall og i stedet produserer en melding til brukeren (kalt en assistentmelding i OpenAI-modeller). I mange tilfeller besvarer denne meldingen den opprinnelige forespørselen direkte, men den kan også være et oppfølgingsspørsmål til brukeren.
Fordi agenten kan utføre verktøykall som endrer det lokale miljøet, er utdata ikke begrenset til assistentens melding. I mange tilfeller er de primære utdataene fra en programvareagent koden den skriver eller redigerer på maskinen din. Likevel ender hver runde alltid med en assistentmelding – som for eksempel «Jeg la til architecture.md som du ba om» – som signaliserer en avslutningstilstand i agentløkken. Fra agentens perspektiv er arbeidet fullført, og kontrollen går tilbake til brukeren.
Reisen fra brukerens inndata til agentens svar som vist i diagrammet, kalles én runde i en samtale (en tråd i Codex). Men denne samtalerunden kan inkludere mange iterasjoner mellom modell og verktøykall. Hver gang du sender en ny melding til en eksisterende samtale, inkluderes samtalehistorikken som en del av prompten for den nye runden, som inkluderer meldingene og verktøykallene fra tidligere runder:
Dette betyr at etter hvert som samtalen vokser, øker også lengden på prompten som brukes til å sample modellen. Denne lengden er viktig fordi hver modell har et kontekstvindu, som er det maksimale antallet tokener den kan bruke på én inferenskall. Merk at dette vinduet inkluderer både inndata- og utdatatokener. Som du kanskje kan forestille deg, kan en agent velge å foreta hundrevis av verktøykall i én enkelt runde, noe som potensielt kan fylle opp hele kontekstvinduet. Derfor er håndtering av kontekstvinduet en av agentens mange ansvarsområder. Nå skal vi se nærmere på hvordan Codex kjører agentløkken.
Codex CLI sender HTTP-forespørsler til Responses API-en(åpnes i et nytt vindu) for å kjøre modellinferens. Vi skal undersøke hvordan informasjon flyter gjennom Codex, som bruker Responses API-en til å drive agentløkken.
Responses API-endepunktet som Codex CLI bruker, er konfigurerbart(åpnes i et nytt vindu), så det kan brukes med et hvilket som helst endepunkt som implementerer Responses API-en(åpnes i et nytt vindu):
- Når du bruker ChatGPT‑innlogging(åpnes i et nytt vindu) med Codex CLI, bruker den
https://chatgpt.com/backend-api/codex/responsessom endepunkt - Når du bruker API-nøkkelautentisering(åpnes i et nytt vindu) med OpenAI-driftede modeller, benytter den
https://api.openai.com/v1/responsessom endepunkt - Når du kjører Codex CLI med
--ossfor å bruke gpt-oss med ollama 0.13.4+(åpnes i et nytt vindu) eller LM Studio 0.3.39+(åpnes i et nytt vindu), er standardinnstillingenhttp://localhost:11434/v1/responsessom kjører lokalt på datamaskinen din - Codex CLI kan brukes med Responses API-en som driftes av en skyleverandør som Azure
La oss se nærmere på hvordan Codex lager prompten til den første inferensforespørselen i en samtale.
Som sluttbruker behøver du ikke å angi den eksakte prompten som brukes til å sample modellen ordrett, når du sender en forespørsel til Responses API-en. I stedet spesifiserer du ulike inndatatyper som en del av forespørselen din, og Responses API-serveren bestemmer hvordan denne informasjonen skal struktureres til en prompt som modellen kan bruke. Du kan tenke på prompten som en «liste over elementer». Denne delen forklarer hvordan forespørselen blir omgjort til en slik liste.
I den innledende prompten er hvert element i listen tilknyttet en rolle. Role angir hvor mye vekt det tilknyttede innholdet skal ha, og er en av følgende verdier (i synkende rekkefølge etter prioritet): system, developer, user, assistant.
Responses API-en(åpnes i et nytt vindu) tar en JSON-nyttelast med mange parametere. Vi skal fokusere på disse tre:
instructions(åpnes i et nytt vindu): systemmelding (eller utviklermelding) satt inn i modellens konteksttools(åpnes i et nytt vindu): en liste over verktøy som modellen kan bruke når den genererer et svarinput(åpnes i et nytt vindu): en liste med tekst-, bilde- eller filinndata til modellen
I Codex leses feltet instructions fra model_instructions_file(åpnes i et nytt vindu) i ~/.codex/config.toml, hvis det er spesifisert; ellers brukes base_instructions som er tilknyttet en modell(åpnes i et nytt vindu). Modellspesifikke instruksjoner finnes i Codex-lageret og er inkludert i CLI-en (f.eks. gpt-5.2-codex_prompt.md(åpnes i et nytt vindu)).
Feltet tools er en liste over verktøydefinisjoner som samsvarer med et skjema definert av Responses API-en. For Codex inkluderer dette verktøy som gjøres tilgjengelig av Codex CLI, verktøy som gjøres tilgjengelig av Responses API-en og som bør være tilgjengelig for Codex, samt verktøy som gjøres tilgjengelig av brukeren, vanligvis via MCP-servere:
Endelig er input-feltet i JSON-nyttelasten en liste over elementer. Codex setter inn følgende elementer(åpnes i et nytt vindu) i input før den legger til brukermeldingen:
1. En melding med role=developer som beskriver sandkassen som at den bare gjelder for det Codex-leverte shell-verktøyet definert i tools-delen. Det vil si at andre verktøy, som de som leveres fra MCP-servere, ikke blir beskyttet i sandkasse av Codex og er ansvarlige for å håndheve sine egne sikkerhetsmekanismer.
Meldingen er bygget på en mal der nøkkelinnholdet kommer fra utdrag av Markdown som er inkludert i Codex CLI, som for eksempel workspace_write.md(åpnes i et nytt vindu) og on_request.md(åpnes i et nytt vindu):
2. (Valgfritt) En melding med role=developer der innholdet er verdien developer_instructions lest fra brukerens config.toml-fil.
3. (Valgfritt) En melding med role=user der innholdet er «brukerinstruksjonene», som ikke er hentet fra én enkelt fil, men samlet fra flere kilder(åpnes i et nytt vindu). Som regel kommer mer spesifikke instruksjoner senere:
- Innholdet i
AGENTS.override.mdogAGENTS.mdi$CODEX_HOME - Med forbehold om en grense (32 KiB, som standard), søk i hver mappe fra Git-/prosjektroten for
cwd(hvis den finnes) opp til selvecwd: Legg til innholdet fra enAGENTS.override.md,AGENTS.mdeller et hvilket som helst filnavn angitt avproject_doc_fallback_filenames i config.toml - Hvis noen ferdigheter(åpnes i et nytt vindu) er blitt konfigurert:
- en kort innledning om ferdigheter
- ferdighetsmetadata(åpnes i et nytt vindu) for hver ferdighet
- en del om hvordan ferdigheter kan brukes(åpnes i et nytt vindu)
4. En melding med role=user som beskriver det lokale miljøet der agenten driver nå. Dette spesifiserer den gjeldende arbeidskatalogen og brukerens shell(åpnes i et nytt vindu):
Når Codex har utført alle de ovennevnte beregningene for å initialisere input, legger den til brukermeldingen for å starte samtalen.
De tidligere eksemplene fokuserte på innholdet i hver melding, men merk at hvert element i input er et JSON-objekt med type, role(åpnes i et nytt vindu) og content som følger:
Når Codex har bygget opp hele JSON-nyttelasten som skal sendes til Responses API-en, sender den en HTTP POST-forespørsel med en Authorization-overskrift avhengig av hvordan Responses API-endepunktet er konfigurert i ~/.codex/config.toml (ytterligere HTTP-overskrifter og spørringsparametere legges til hvis det er spesifisert).
Når en OpenAIs Responses API-server mottar forespørselen, bruker den JSON-en til å lage prompten for modellen slik (en tilpasset implementering av Responses API kan selvfølgelig gjøre et annet valg):
Som du ser, bestemmes rekkefølgen på de tre første elementene i prompten av serveren, ikke klienten. Når det er sagt, så er det av disse tre elementene bare innholdet i systemmeldingen som også styres av serveren, da tools og instructions bestemmes av klienten. Disse følges av input fra JSON-nyttelasten for å fullføre prompten.
Nå som vi har prompten vår, er vi klare til å prøve modellen.
Denne HTTP-forespørselen til Responses API starter den første «runden» i en samtale i Codex. Serveren svarer med en Server-Sent Events-strøm (SSE(åpnes i et nytt vindu)). Data-feltet i hver hendelse er en JSON-nyttelast med en "type" som starter med "response", som ser omtrent sånn ut (en fullstendig liste over hendelser finner du i API-dokumentasjonen(åpnes i et nytt vindu) vår):
Codex tar imot hendelsesstrømmen(åpnes i et nytt vindu) og gjør den om til interne hendelsesobjekter som kan brukes av en klient. Hendelser som response.output_text.delta brukes til å støtte strømming i brukergrensesnittet, mens andre hendelser som response.output_item.added gjøres om til objekter som legges til i input for påfølgende kall til Responses API-en.
Tenk deg at den første forespørselen til Responses API-en inkluderer to response.output_item.done-hendelser: én med type=reasoning og én med type=function_call. Disse hendelsene må representeres i input-feltet i JSON når vi spør modellen igjen med svaret på verktøykallet:
Den resulterende prompten som brukes til å sample modellen som en del av den påfølgende forespørselen, ser da slik ut:
Legg spesielt merke til hvordan den gamle prompten er en nøyaktig prefiks i den nye prompten. Dette er med hensikt, da dette gjør påfølgende forespørsler mye mer effektive ved at vi kan dra nytte av prompt-bufring (som vi skal snakke om i neste avsnitt om ytelse).
Når vi igjen ser på vårt første diagram av agentløkken, ser vi at det kan være mange iterasjoner mellom inferens og verktøykall. Prompten kan fortsette å vokse til vi endelig mottar en assistentmelding, som indikerer slutten på runden:
I Codex CLI viser vi assistentmeldingen til brukeren og setter fokuset på skrivefeltet for å fortelle brukeren at det er vedkommendes tur til å fortsette samtalen. Hvis brukeren svarer, må både assistentmeldingen fra forrige runde og brukerens nye melding legges til i input i Responses API-forespørselen for å starte den nye runden:
Nok en gang øker lengden på input vi sender til Responses API, fordi vi fortsetter en samtale:
La oss undersøke hva denne stadig voksende prompten betyr for ytelsen.
Du tenker kanskje: «Stopp en hal, er ikke agent-loopen kvadratisk med hensyn til mengden JSON som sendes til Responses API-en i løpet av samtalen?» I så fall har du rett. Selv om Responses API-en støtter en valgfri previous_response_id(åpnes i et nytt vindu)-parameter for å redusere dette problemet, bruker ikke Codex den i dag. Dette er hovedsakelig for å holde forespørsler helt uavhengige og for å støtte konfigurasjoner for ZDR (Zero Data Retention – ingen oppbevaring av data).
Det er enklere for leverandøren av Responses API å unngå previous_response_id fordi det sikrer at alle forespørsler er uavhengige. Dette gjør det også enkelt å støtte kunder som har valgt ZDR (ingen oppbevaring av data)(åpnes i et nytt vindu), siden lagring av dataene som kreves for å støtte previous_response_id, ville være i strid med ZDR. ZDR-kunder mister ikke muligheten til å dra nytte av proprietær resonnering fra tidligere runder, ettersom tilknyttet encrypted_content kan dekrypteres på serveren. (OpenAI lagrer dekrypteringsnøkkelen til ZDR-kunder, men ikke dataene deres.) Se PR-er #642(åpnes i et nytt vindu) og #1641(åpnes i et nytt vindu) for de relaterte endringene i Codex for å støtte ZDR.
Som regel er kostnaden av å sample modellen større enn kostnaden av nettverkstrafikk, noe som gjør at sampling er hovedfokuset for effektiviseringstiltakene våre. Dette er grunnen til at prompt-bufring er så viktig, siden det gjør oss i stand til å gjenbruke beregninger fra et tidligere inferenskall. Når vi får treff i hurtigbufferen, er sampling av modellen lineær i stedet for kvadratisk. Dokumentasjonen vår for prompt-bufring (åpnes i et nytt vindu)forklarer dette mer detaljert:
Treff i hurtigbufferen er bare mulig for eksakte prefiks-treff i en prompt. For å oppnå fordelene med hurtigbufring, kan du plassere statisk innhold som instruksjoner og eksempler på begynnelsen av prompten og variabelt innhold, som brukerspesifikk informasjon, på slutten. Dette gjelder også bilder og verktøy, som må være identiske fra den ene forespørselen til den andre.
Med dette i bakhodet kan vi se på hvilke typer operasjoner som kan forårsake en «hurtigbuffer-miss» i Codex:
- Endring av
toolssom er tilgjengelige for modellen, midt i samtalen. - Endring av
modelsom er målet for Responses API-forespørselen (i praksis endrer dette det tredje elementet i den opprinnelige prompten, da det inneholder modellspesifikke instruksjoner). - Endring av sandkassekonfigurasjon, godkjenningsmodus eller gjeldende arbeidskatalog.
Codex-teamet må være forsiktige når de introduserer nye funksjoner i Codex CLI som kan svekke prompt-bufringen. Som et eksempel kan vi nevne at vår første støtte for MCP-verktøy introduserte en feil der vi ikke klarte å liste opp verktøyene i en konsekvent rekkefølge(åpnes i et nytt vindu), noe som førte til hurtigbuffer-misser. MCP-verktøy kan være spesielt lumske fordi MCP-servere kan endre listen over verktøy de tilbyr fortløpende, via et notifications/tools/list_changed(åpnes i et nytt vindu)-varsel. Å ta hensyn til dette varselet midt i en lang samtale kan føre til en kostbar hurtigbuffer-miss.
Når det er mulig, håndterer vi konfigurasjonsendringer som skjer midt i en samtale, ved å legge til en ny melding i input for å gjenspeile endringen, i stedet for å endre en tidligere melding:
- Hvis sandkassekonfigurasjonen eller godkjenningsmodusen endres, setter vi inn(åpnes i et nytt vindu) en ny
role=developer-melding med samme format som det opprinnelige<permissions instructions>-elementet. - Hvis den gjeldende arbeidskatalogen endres, setter vi inn(åpnes i et nytt vindu) en ny
role=user-melding med samme format som den opprinnelige<environment_context>.
Vi strekker oss langt for å sikre hurtigbuffertreff for bedre ytelse. En annen viktig ressurs vi må håndtere, er kontekstvinduet.
Vår generelle strategi for å unngå å fylle opp kontekstvinduet er å komprimere samtalen når antall tokener overstiger en viss terskel. Vi erstatter input med en ny, mindre liste over elementer som er representative for samtalen, slik at agenten kan fortsette med en forståelse av hva som har skjedd så langt. En tidlig implementering av komprimering(åpnes i et nytt vindu) krevde at brukeren kjørte /compact-kommandoen manuelt, som sendte en forespørsel til Responses API-en ved å bruke den eksisterende samtalen pluss tilpassede instruksjoner for oppsummering(åpnes i et nytt vindu). Codex brukte den resulterende assistentmeldingen som inneholdt sammendraget, som ny input(åpnes i et nytt vindu) for påfølgende samtalerunder.
Siden den gang har Responses API-en utviklet seg til å støtte et spesielt /responses/compact-endepunkt(åpnes i et nytt vindu) som utfører komprimering mer effektivt. Den returnerer en liste over elementer(åpnes i et nytt vindu) som kan brukes i stedet for den forrige input, for å fortsette samtalen, samtidig som den frigjør plass i kontekstvinduet. Denne listen inkluderer et spesielt type=compaction-element med et ugjennomsiktig encrypted_content-element som bevarer modellens latente forståelse av den opprinnelige samtalen. Nå bruker Codex automatisk dette endepunktet for å komprimere samtalen når auto_compact_limit(åpnes i et nytt vindu) overskrides.
Vi har introdusert Codex' agentløkke og gått gjennom hvordan Codex utformer og administrerer konteksten sin når den sender en forespørsel til en modell. Underveis fremhevet vi praktiske hensyn og beste praksis som gjelder for alle som bygger en agentløkke basert på Responses API-en.
Selv om agentløkken legger grunnlaget for Codex, er det bare starten. I kommende innlegg vil vi utforske CLI-arkitekturen, undersøke hvordan verktøybruk er implementert, og ta en nærmere titt på Codex' sandkassemodell.


