Codex CLI(atveras jaunā logā) ir mūsu starpplatformu lokālais programmatūras aģents, kas izstrādāts, lai veiktu augstas kvalitātes un uzticamas programmatūras izmaiņas, vienlaikus droši un efektīvi darbojoties tavā datorā. Mēs esam apguvuši ļoti daudz par to, kā izveidot pasaules klases programmatūras aģentu, kopš aprīlī palaidām CLI. Lai pastāstītu par šīm atziņām, šis ir pirmais raksts sērijā, kurā mēs apskatīsim dažādus Codex darbības aspektus, kā arī smagi gūtas mācības. (Lai iegūtu vēl detalizētāku skatījumu uz to, kā tiek veidots Codex CLI, apskati mūsu atvērtā koda repozitoriju vietnē https://github.com/openai/codex(atveras jaunā logā). Ja vēlies uzzināt vēl vairāk, daudzas sīkākas detaļas par mūsu projektēšanas lēmumiem ir pieminētas GitHub jautājumos un atgādāšanas pieprasījumos.)
Sākumā pievērsīsimies aģenta ciklam, kas ir Codex CLI loģikas kodols, kurš ir atbildīgs par mijiedarbības organizēšanu starp lietotāju, modeli un rīkiem, kurus modelis izsauc, lai veiktu nozīmīgu programmatūras darbu. Mēs ceram, ka šis ieraksts sniegs tev labu ieskatu par to, kāda ir mūsu aģenta (jeb vadības ietvara) loma lielo valodas modeļu (LVM) izmantošanā.
Pirms iedziļināmies, īsa piezīme par terminoloģiju: OpenAI “Codex” aptver programmatūras aģentu piedāvājumu kopumu, tostarp Codex CLI, Codex Cloud un Codex VS Code paplašinājumu. Šis ieraksts koncentrējas uz Codex vadības ietvaru jeb “harness”, kas nodrošina pamata aģenta ciklu un izpildes loģiku, kas ir visu Codex pieredžu pamatā un ir pieejama, izmantojot Codex CLI. Vienkāršības labad šeit terminus "Codex" un "Codex CLI" lietosim savstarpēji aizvietojami.
Katra mākslīgā intelekta aģenta pamatā ir process, ko dēvē par “aģenta ciklu”. Vienkāršota aģenta cikla ilustrācija izskatās šādi:
Vispirms aģents no lietotāja saņem ievadi, ko iekļaut teksta instrukciju kopā, kuru tas sagatavo modelim – to dēvē par uzvedni.
Nākamais solis ir vaicāt modelim, nosūtot tam mūsu norādījumus un prasot ģenerēt atbildi – šo procesu dēvē par inferenci. Inferencē teksta uzvedne vispirms tiek pārvērsta par ievades tekstvienībām(atveras jaunā logā) jeb tokeniem – tie ir veselu skaitļu identifikatori, kas indeksē modeļa vārdnīcu. Pēc tam šīs tekstvienības tiek izmantotas modeļa izvades ģenerēšanai, radot jaunu izvades tekstvienību virkni.
Izvades tekstvienības tiek pārveidotas atpakaļ tekstā, kas kļūst par modeļa atbildi. Tā kā tekstvienības tiek ģenerētas pakāpeniski, šī pārveidošana var notikt, kamēr modelis darbojas, tāpēc daudzas uz LVM balstītas lietojumprogrammas rāda straumētu izvadi. Praksē inference parasti ir slēpta aiz API, kas darbojas ar tekstu, abstrahējot detaļas par dalīšanu tekstvienībās.
Inferences soļa rezultātā modelis vai nu (1) sniedz galīgo atbildi uz lietotāja sākotnējo ievadi, vai (2) prasa rīka izsaukumu, ko aģentam ir paredzēts veikt (piemēram, “palaid ls un ziņo par izvadi”). (2) gadījumā aģents izpilda rīka izsaukumu un pievieno tā izvadi sākotnējai uzvednei. Šī izvade tiek izmantota, lai ģenerētu jaunu ievadi, kas tiek izmantota, lai atkārtoti vaicātu modelim; aģents pēc tam var ņemt vērā šo jauno informāciju un mēģināt vēlreiz.
Šis process atkārtojas, līdz modelis pārstāj veikt rīku izsaukumus un tā vietā izveido ziņojumu lietotājam (OpenAI modeļos to sauc par palīgziņojumu). Daudzos gadījumos šis ziņojums tieši atbild uz lietotāja sākotnējo pieprasījumu, bet tas var būt arī papildu jautājums lietotājam.
Tā kā aģents var izpildīt rīku izsaukumus, kas maina lokālo vidi, tā “izvade” neaprobežojas tikai ar palīgziņojumu. Daudzos gadījumos programmatūras aģenta galvenā izvade ir kods, ko tas raksta vai rediģē tavā datorā. Tomēr katrs solis vienmēr beidzas ar palīgziņojumu – piemēram, “Es pievienoju architecture.md, ko tu prasīji” – kas norāda uz izbeigšanas stāvokli aģenta ciklā. No aģenta skatpunkta tā darbs ir pabeigts, un vadība atgriežas pie lietotāja.
Ceļojums no lietotāja ievades līdz aģenta atbildei, kas parādīts diagrammā, tiek saukts par vienu sarunas kārtu (Codex sistēmā – par pavedienu ). Taču šī sarunas kārta var ietvert daudzas iterācijas starp modeļa inferenci un rīku izsaukumiem. Katru reizi, kad tu nosūti jaunu ziņojumu esošai sarunai, sarunas vēsture tiek iekļauta kā daļa no uzvednes jaunajai kārtai, kas ietver ziņojumus un rīku izsaukumus no iepriekšējām kārtām:
Tas nozīmē, ka, sarunai augot, palielinās arī uzvednes garums, ko izmanto modeļa izvades ģenerēšanai. Šis garums ir svarīgs, jo katram modelim ir konteksta logs, kas ir maksimālais tekstvienību skaits, ko tas var izmantot vienā inferencē. Ņem vērā, ka šajā logā ir iekļautas ievades un izvades tekstvienības. Kā tu droši vien vari iedomāties, aģents varētu izlemt veikt simtiem rīku izsaukumu vienā kārtā, kas varētu izsmelt konteksta logu. Šī iemesla dēļ konteksta loga pārvaldība ir viena no daudzajām aģenta atbildībām. Tagad iedziļināsimies, lai redzētu, kā Codex darbina aģenta ciklu.
Codex CLI sūta HTTP pieprasījumus uz Responses API(atveras jaunā logā), lai veiktu modeļa inferenci. Mēs apskatīsim, kā informācija plūst caur Codex, kas izmanto Responses API, lai darbinātu aģenta ciklu.
Responses API galapunkts, ko izmanto Codex CLI, ir konfigurējams(atveras jaunā logā), tāpēc to var izmantot ar jebkuru galapunktu, kas realizē Responses API(atveras jaunā logā):
- Izmantojot ChatGPT pieteikšanos(atveras jaunā logā) ar Codex CLI, tas izmanto
https://chatgpt.com/backend-api/codex/responseskā galapunktu - Izmantojot API atslēgas autentifikāciju(atveras jaunā logā) ar OpenAI mitinātiem modeļiem, tas izmanto
https://api.openai.com/v1/responseskā galapunktu - Darbinot Codex CLI ar
--oss, lai izmantotu gpt-oss kopā ar ollama 0.13.4+(atveras jaunā logā) vai LM Studio 0.3.39+(atveras jaunā logā), pēc noklusējuma tas izmantohttp://localhost:11434/v1/responses, kas darbojas lokāli uz tava datora - Codex CLI var izmantot ar Responses API, ko mitina mākoņpakalpojumu sniedzējs, piemēram, Azure
Izpētīsim, kā Codex izveido uzvedni pirmajam inferenču izsaukumam sarunā.
Kā galalietotājs tu burtiski nenorādi uzvedni, kas tiek izmantota modeļa izvades ģenerēšanai, kad tu sniedz vaicājumu Responses API. Tā vietā tu savā vaicājumā norādi dažādus ievades tipus, un Responses API serveris izlemj, kā šo informāciju strukturēt uzvednē, ko modelim ir paredzēts izmantot. Tu vari uztvert uzvedni kā “elementu sarakstu”; šajā sadaļā tiks izskaidrots, kā tavs vaicājums tiek pārveidots par šo sarakstu.
Sākotnējā uzvednē katrs saraksta elements ir saistīts ar kādu lomu. role norāda, cik liels svars ir jāpiešķir saistītajam saturam, un tā ir viena no šādām vērtībām (prioritātes dilstošā secībā): system, developer, user, assistant.
Responses API(atveras jaunā logā) pieņem JSON datu kopu ar daudziem parametriem. Mēs pievērsīsimies šiem trim:
instructions(atveras jaunā logā): sistēmas (vai izstrādātāja) ziņojums, kas ievietots modeļa kontekstātools(atveras jaunā logā): to rīku saraksts, ko modelis var izsaukt, ģenerējot atbildiinput(atveras jaunā logā): teksta, attēlu vai failu ievades saraksts modelim
Codex vidē lauks instructions tiek nolasīts no model_instructions_file(atveras jaunā logā), kas atrodas ~/.codex/config.toml, ja tas ir norādīts; pretējā gadījumā tiek izmantotas instrukcijas base_instructions, kas saistītas ar modeli(atveras jaunā logā). Konkrētā modeļa instrukcijas atrodas Codex repozitorijā un ir iekļautas CLI (piemēram, gpt-5.2-codex_prompt.md(atveras jaunā logā)).
Lauks tools ir rīku definīciju saraksts, kas atbilst Responses API definētajai shēmai. Codex gadījumā tas ietver rīkus, ko nodrošina Codex CLI; rīkus, ko nodrošina Responses API, kuriem jābūt pieejamiem Codex; kā arī lietotāja nodrošinātus rīkus, parasti izmantojot MCP serverus:
Visbeidzot, JSON datu kopas input lauks ir vienumu saraksts. Codex ievieto šādus vienumus(atveras jaunā logā) sarakstā input pirms lietotāja ziņojuma pievienošanas:
1. Ziņojums ar role=developer, kas apraksta smilškasti, kas attiecas tikai uz Codex nodrošināto shell rīku, kas definēts tools sadaļā. Tas nozīmē, ka citi rīki, piemēram, MCP serveru nodrošinātie rīki, nav Codex smilškastē un ir paši atbildīgi par savu aizsargmehānismu ieviešanu.
Ziņojums ir veidots no veidnes, kur galvenās satura daļas nāk no Markdown fragmentiem, kas ir iekļauti Codex CLI, piemēram, workspace_write.md(atveras jaunā logā) un on_request.md(atveras jaunā logā):
2. (Neobligāti) Ziņojums ar role=developer, kura saturs ir developer_instructions vērtība, kas nolasīta no lietotāja config.toml faila.
3. (Neobligāti) Ziņojums ar role=user, kura saturs ir “lietotāja norādījumi”, kas nav iegūti no viena faila, bet ir apkopoti no vairākiem avotiem(atveras jaunā logā). Parasti konkrētāki norādījumi parādās vēlāk:
AGENTS.override.mdunAGENTS.mdsaturs, kas atrodas$CODEX_HOME- Ievērojot ierobežojumu (pēc noklusējuma 32 KiB), pārskatīt katru mapi no
cwdGit/projekta saknes (ja pastāv) līdz patcwdpašam: pievienot saturu noAGENTS.override.md,AGENTS.mdvai jebkura faila nosaukuma, kas norādītsproject_doc_fallback_filenames konfigurācijā config.toml - Ja ir konfigurētas jebkādas prasmes(atveras jaunā logā):
- īss ievads par prasmēm
- prasmes metadati(atveras jaunā logā) katrai prasmei
- sadaļa par to, kā izmantot prasmes(atveras jaunā logā)
4. Ziņojums ar role=user, kas apraksta vietējo vidi, kurā aģents pašlaik darbojas. Tas norāda pašreizējo darba direktoriju un lietotāja čaulu(atveras jaunā logā):
Kad Codex ir veicis visus iepriekš minētos aprēķinus, lai inicializētu input, tas pievieno lietotāja ziņojumu, lai sāktu sarunu.
Iepriekšējie piemēri koncentrējās uz katra ziņojuma saturu, bet ņem vērā, ka katrs input elements ir JSON objekts ar type, role(atveras jaunā logā) un content, kā aprakstīts tālāk:
Kad Codex ir izveidojis pilnu JSON datu kopu, ko nosūtīt Responses API, tas veic HTTP POST pieprasījumu ar Authorization galveni atkarībā no tā, kā Responses API galapunkts ir konfigurēts failā ~/.codex/config.toml (ja norādīts, tiek pievienotas papildu HTTP galvenes un vaicājuma parametri).
Kad OpenAI Responses API serveris saņem pieprasījumu, tas izmanto JSON, lai iegūtu uzvedni modelim šādā veidā (taču pielāgota Responses API implementācija varētu izdarīt citādu izvēli):
Kā redzi, uzvednē pirmo trīs elementu secību nosaka serveris, nevis klients. No šiem trim elementiem tikai sistēmas ziņojuma saturu nosaka arī serveris, jo tools un instructions nosaka klients. Tiem seko input no JSON datu kopas, lai pabeigtu uzvedni.
Tagad, kad mums ir uzvedne, mēs esam gatavi modeļa izvades ģenerēšanai.
Šis HTTP pieprasījums uz Responses API uzsāk pirmo sarunas “kārtu” Codex sistēmā. Serveris atbild ar servera sūtīto notikumu (SSE(atveras jaunā logā)) straumi. Katra notikuma data ir JSON datu kopa ar "type", kas sākas ar "response", un tas varētu izskatīties apmēram šādi (pilns notikumu saraksts ir pieejams mūsu API dokumentācijā(atveras jaunā logā)):
Codex uzņem notikumu straumi(atveras jaunā logā) un pārpublicē tos kā iekšējos notikumu objektus, ko var izmantot klients. Tādi notikumi kā response.output_text.delta tiek izmantoti, lai atbalstītu straumēšanu lietotāja saskarnē, savukārt citi notikumi, piemēram, response.output_item.added, tiek pārveidoti par objektiem, kas tiek pievienoti input nākamajiem Responses API izsaukumiem.
Pieņemsim, ka pirmajā pieprasījumā uz Responses API ir iekļauti divi response.output_item.done notikumi: viens ar type=reasoning un viens ar type=function_call. Šie notikumi ir jāatspoguļo JSON laukā input, kad mēs vēlreiz vaicājam modelim ar atbildi uz rīka izsaukumu:
Iegūtā uzvedne, kas tiks izmantota modeļa izvades ģenerēšanai turpmākā vaicājuma ietvaros, izskatīsies šādi:
Ievēro, kā vecā uzvedne ir precīzs jaunās uzvednes prefikss. Tas ir apzināti, jo tas padara turpmākos pieprasījumus daudz efektīvākus, ļaujot mums izmantot uzvedņu kešdarbi (par ko runāsim nākamajā sadaļā par veiktspēju).
Atskatoties uz mūsu pirmo aģenta cikla diagrammu, mēs redzam, ka starp inferenci un rīku izsaukšanu varētu būt daudz iterāciju. Uzvedne var turpināt pieaugt, līdz beidzot saņemam palīgziņojumu, kas norāda uz kārtas beigām:
Codex CLI sistēmā mēs parādām lietotājam palīgziņojumu un fokusējam komponētāju, lai norādītu lietotājam, ka ir viņa “kārta” turpināt sarunu. Ja lietotājs atbild, gan palīgziņojums no iepriekšējās kārtas, gan lietotāja jaunais ziņojums jāpievieno input Responses API pieprasījumā sākt jauno kārtu:
Vēlreiz, tā kā mēs turpinām sarunu, uz Responses API nosūtītā input garums turpina pieaugt:
Apskatīsim, ko šī arvien pieaugošā uzvedne nozīmē veiktspējai.
Iespējams, tu sev jautā: “Paga, vai aģenta cikls nav kvadrātisks attiecībā uz to, cik daudz JSON tiek nosūtīts uz Responses API sarunas laikā?” Un tev būtu taisnība. Lai gan Responses API atbalsta neobligātu previous_response_id(atveras jaunā logā) parametru, lai mazinātu šo problēmu, Codex to šodien neizmanto, galvenokārt, lai pieprasījumi būtu pilnībā bez stāvokļa un lai atbalstītu nulles datu saglabāšanas (ZDR) konfigurācijas.
Izvairīšanās no previous_response_id vienkāršo Responses API nodrošinātāja darbu, jo tas nodrošina, ka katrs pieprasījums ir bez stāvokļa. Tas arī padara vienkāršu atbalsta sniegšanu klientiem, kuri ir izvēlējušies nulles datu saglabāšanu (ZDR)(atveras jaunā logā), jo datu glabāšana, kas nepieciešama, lai atbalstītu previous_response_id, būtu pretrunā ar ZDR. Ņem vērā, ka ZDR klienti nezaudē iespēju gūt labumu no iepriekšējo kārtu spriešanas ziņojumiem, jo saistīto encrypted_content var atšifrēt serverī. (OpenAI saglabā ZDR klienta atšifrēšanas atslēgu, bet ne tā datus.) Skatiet atgādāšanas pieprasījumus #642(atveras jaunā logā) un #1641(atveras jaunā logā) saistītajām Codex izmaiņām, lai atbalstītu ZDR.
Parasti modeļa izvades ģenerēšanas izmaksas ievērojami pārsniedz tīkla trafika izmaksas, padarot to par mūsu efektivitātes centienu galveno mērķi. Tāpēc uzvedņu kešdarbe ir tik svarīga, jo tā ļauj mums atkārtoti izmantot skaitļošanu no iepriekšējā inferences izsaukuma. Kad mēs iegūstam kešatmiņas trāpījumus, modeļa izvades ģenerēšana ir lineāra, nevis kvadrātiska. Mūsu uzvedņu kešdarbes (atveras jaunā logā)dokumentācija to izskaidro sīkāk:
Kešatmiņas trāpījumi ir iespējami tikai tad, ja uzvednē ir precīza prefiksa atbilstība. Lai izmantotu kešdarbes priekšrocības, novieto statisko saturu, piemēram, instrukcijas un piemērus, uzvednes sākumā, bet mainīgo saturu, piemēram, lietotājam specifisku informāciju, beigās. Tas attiecas arī uz attēliem un rīkiem, kuriem jābūt identiskiem starp pieprasījumiem.
Ņemot to vērā, apskatīsim, kāda veida darbības varētu izraisīt kešatmiņas neatbilstību Codex sistēmā:
- Modelim pieejamo
toolsmaiņa sarunas vidū. model, kas ir Responses API pieprasījuma mērķis, maiņa (praktiski tas maina trešo elementu sākotnējā uzvednē, jo tajā ir modelim specifiski norādījumi).- Smilškastes konfigurācijas, apstiprināšanas režīma vai pašreizējā darba direktorija maiņa.
Codex komandai jābūt uzmanīgai, ieviešot jaunas funkcijas Codex CLI, kas varētu apdraudēt uzvedņu kešdarbi. Piemēram, mūsu sākotnējais atbalsts MCP rīkiem ieviesa kļūdu, jo mēs nebijām uzskaitījuši rīkus konsekventā secībā(atveras jaunā logā), tādējādi izraisot kešatmiņas neatbilstības. Ņem vērā, ka MCP rīki var būt īpaši sarežģīti, jo MCP serveri var dinamiski mainīt nodrošināto rīku sarakstu, izmantojot notifications/tools/list_changed(atveras jaunā logā) paziņojumu. Šī paziņojuma apstrāde garas sarunas vidū var izraisīt resursietilpīgu kešatmiņas neatbilstību.
Kad vien iespējams, mēs apstrādājam konfigurācijas izmaiņas, kas notiek sarunas laikā, pievienojot jaunu ziņojumu pie input, lai atspoguļotu izmaiņas, nevis mainot agrāku ziņojumu:
- Ja mainās smilškastes konfigurācija vai apstiprināšanas režīms, mēs ievietojam(atveras jaunā logā) jaunu
role=developerziņojumu ar tādu pašu formātu kā sākotnējam<permissions instructions>elementam. - Ja mainās pašreizējais darba direktorijs, mēs ievietojam(atveras jaunā logā) jaunu
role=userziņojumu, kura formāts ir tāds pats kā sākotnējam<environment_context>.
Mēs pieliekam lielas pūles, lai nodrošinātu kešatmiņas atbilstības veiktspējas uzlabošanai. Ir vēl viens svarīgs resurss, kas mums jāpārvalda: konteksta logs.
Mūsu vispārējā stratēģija, lai izvairītos no konteksta loga izsmelšanas, ir sablīvēt sarunu, kad tekstvienību skaits pārsniedz noteiktu slieksni. Konkrēti, mēs aizstājam input ar jaunu, mazāku elementu sarakstu, kas atspoguļo sarunu, ļaujot aģentam turpināt ar izpratni par to, kas līdz šim ir noticis. Agrīnai sablīvēšanas ieviešanai(atveras jaunā logā) bija nepieciešams, lai lietotājs manuāli izsauktu /compact komandu, kas veiktu vaicājumu Responses API, izmantojot esošo sarunu plus pielāgotas instrukcijas kopsavilkumam(atveras jaunā logā). Codex izmantoja iegūto palīgziņojumu, kas saturēja kopsavilkumu, kā jaunu ievadi(atveras jaunā logā) turpmākajās sarunas kārtās.
Kopš tā laika Responses API ir papildināts, lai atbalstītu īpašu /responses/compact galapunktu(atveras jaunā logā), kas veic sablīvēšanu efektīvāk. Tas atgriež elementu sarakstu(atveras jaunā logā), ko var izmantot iepriekšējā input vietā, lai turpinātu sarunu, vienlaikus atbrīvojot konteksta logu. Šajā sarakstā ir iekļauts īpašs type=compaction elements ar necaurspīdīgu encrypted_content elementu, kas saglabā modeļa latento izpratni par sākotnējo sarunu. Tagad Codex automātiski izmanto šo galapunktu, lai sablīvētu sarunu, kad tiek pārsniegts auto_compact_limit(atveras jaunā logā).
Mēs esam iepazīstinājuši ar Codex aģenta ciklu un izskaidrojuši, kā Codex veido un pārvalda savu kontekstu, veicot vaicājumus modelim. Šajā procesā mēs izcēlām praktiskus apsvērumus un labāko praksi, kas attiecas uz ikvienu, kurš veido aģenta ciklu uz Responses API bāzes.
Lai gan aģenta cikls nodrošina Codex pamatu, tas ir tikai sākums. Turpmākajos ierakstos mēs iedziļināsimies CLI arhitektūrā, izpētīsim, kā tiek ieviesta rīku izmantošana, un aplūkosim tuvāk Codex smilškastes modeli.


