Deblocarea sistemului Codex: cum am creat serverul de aplicații
De Celia Chen, membru al echipei tehnice
Agentul de programare Codex de la OpenAI este disponibil pe mai multe platforme: aplicația web(se deschide într-o fereastră nouă), CLI(se deschide într-o fereastră nouă), extensia IDE(se deschide într-o fereastră nouă) și noua aplicație Codex pentru macOS. Sub capotă, toate sunt alimentate de același sistem Codex — bucla agentului și logica aflate la baza tuturor experiențelor Codex. Legătura critică dintre ele? Serverul de aplicații Codex(se deschide într-o fereastră nouă), un API JSON-RPC1 bidirecțional, prietenos pentru clienți.
În această postare, vom prezenta serverul de aplicații Codex; vom împărtăși cunoștințele noastre de până acum despre cele mai bune modalități de a integra capabilitățile Codex în produsul tău pentru a ajuta utilizatorii să își îmbunătățească fluxurile de lucru. Vom acoperi arhitectura și protocolul serverului de aplicații și modul în care se integrează cu diferite suprafețe Codex, precum și sfaturi despre cum să utilizezi Codex, indiferent dacă dorești să transformi Codex într-un recenzor de cod, un agent SRE sau un asistent de codare.
Înainte de a aprofunda arhitectura, e util să știi povestea din spatele serverului de aplicații. Inițial, serverul de aplicații a fost o modalitate practică de a reutiliza sistemul Codex în produse, care a evoluat treptat în protocolul nostru standard.
Codex CLI a început ca un TUI (interfață de utilizator terminal), ceea ce înseamnă că Codex este accesibil prin terminal. Când am construit extensia VS Code (o modalitate mai prietenoasă cu IDE-ul de a interacționa cu agenții Codex), aveam nevoie de o modalitate de a folosi același mecanism, astfel încât să putem rula aceeași buclă a agentului dintr-o interfață UI de IDE fără a o reimplementa. Asta a însemnat susținerea unor tipare de interacțiune bogate dincolo de cerere/răspuns, cum ar fi explorarea spațiului de lucru, transmiterea în flux a progresului pe măsură ce agentul raționează și emiterea de diferențe. Am experimentat inițial cu expunerea Codex ca server MCP(se deschide într-o fereastră nouă), dar menținerea semanticii MCP într-un mod care să aibă sens pentru VS Code s-a dovedit a fi dificilă. În schimb, am introdus un protocol JSON-RPC care reflecta bucla TUI, devenind prima versiune neoficială(se deschide într-o fereastră nouă) a serverului de aplicații. La momentul respectiv, nu ne așteptam ca alți clienți să depindă de serverul de aplicații, așa că nu a fost proiectat ca un API stabil.
Pe măsură ce adoptarea Codex a crescut în următoarele câteva luni, echipele interne și partenerii externi au dorit să poată încorpora același sistem în produsele lor pentru a accelera fluxurile de lucru ale utilizatorilor în dezvoltarea de software. De exemplu, JetBrains și Xcode au dorit o experiență de agent la nivel de IDE, în timp ce aplicația desktop Codex trebuia să orchestreze mulți agenți Codex în paralel. Aceste cerințe ne-au împins să proiectăm o suprafață de platformă pe care atât produsele noastre, cât și integrările partenerilor să se poată baza în siguranță de-a lungul timpului. Trebuia să fie ușor de integrat și compatibil cu versiunile anterioare, ceea ce însemna că puteam evolua protocolul fără a afecta clienții existenți.
În continuare, vom parcurge modul în care am proiectat arhitectura și protocolul, astfel încât clienți diferiți să poată folosi același sistem.
Mai întâi, să ne concentrăm pe ce se află în interiorul sistemului Codex și cum îl expune serverul aplicației Codex către clienți. În ultimul nostru blog Codex, am analizat bucla de bază a agentului care orchestrează interacțiunea dintre utilizator, model și instrumente. Aceasta este logica de bază a sistemului Codex, dar experiența completă a agentului oferă mai mult:
1. Ciclul de viață al firului și persistența. Un fir de discuție este o conversație Codex între un utilizator și un agent. Codex creează, reia, bifurcă și arhivează firele și păstrează istoricul evenimentelor, astfel încât clienții să se poată reconecta și să redea o cronologie consistentă.
2. Config și autentificare. Codex încarcă configurația, gestionează setările implicite și rulează fluxuri de autentificare precum „Conectează-te cu ChatGPT”, inclusiv starea credențialelor.
3. Execuția instrumentului și extensiile. Codex execută instrumente shell/fișiere într-un sandbox și conectează integrări precum servere MCP și competențe, astfel încât acestea să poată participa la bucla de agenți sub un model de politici consistent.
Toată logica agentului pe care am menționat-o aici, inclusiv bucla de bază a agentului, se află într-o parte a bazei de cod Codex CLI numită „Nucleu Codex(se deschide într-o fereastră nouă)”. Nucleul Codex este atât o bibliotecă unde se află tot codul agentului, cât și un runtime care poate fi pornit pentru a rula bucla agentului și a gestiona păstrarea unui fir de discuție Codex (conversație).
Pentru a fi util, sistemul Codex trebuie să fie accesibil clienților. Acolo intervine serverul de aplicații.
Serverul de aplicații este atât protocolul JSON-RPC dintre client și server, cât și un proces de lungă durată care găzduiește firele principale ale Codex. După cum putem vedea din diagrama de mai sus, un proces al serverului de aplicații are patru componente principale: cititorul stdio, procesorul de mesaje Codex, managerul de fire și firele de bază. Managerul de fire inițiază câte o sesiune de bază pentru fiecare fir, iar procesorul de mesaje Codex comunică apoi direct cu fiecare sesiune de bază pentru a trimite cereri ale clientului și a primi actualizări.
O cerere de la un client poate duce la multe actualizări de evenimente, iar aceste evenimente detaliate sunt cele care ne permit să construim o interfață bogată pentru utilizator deasupra serverului de aplicații. În plus, cititorul stdio și procesorul de mesaje Codex servesc ca strat de traducere între client și firele principale ale Codex. Acestea traduc cererile JSON-RPC ale clientului în operațiuni de bază ale Codex, ascultă fluxul intern de evenimente al nucleului Codex și apoi transformă acele evenimente de nivel scăzut într-un set mic de notificări JSON-RPC stabile, gata pentru interfața utilizator.
Protocolul JSON-RPC dintre client și serverul de aplicații este complet bidirecțional. Un fir tipic are o cerere de la client și multe notificări de la server. În plus, serverul poate iniția cereri atunci când agentul are nevoie de informații, cum ar fi o aprobare, și apoi poate pune pauză până când clientul răspunde.
În continuare, vom descompune primitivele conversației, elementele fundamentale ale protocolului serverului de aplicații. Proiectarea unui API pentru bucla agentului este dificilă, deoarece interacțiunea utilizator/agent nu este o simplă cerere/răspuns. O cerere a unui utilizator se poate desfășura într-o secvență structurată de acțiuni pe care clientul trebuie să le reprezinte cu fidelitate: intrarea utilizatorului, progresul incremental al agentului, artefactele produse pe parcurs (de exemplu, diferențe). Pentru a face ca acel flux de interacțiune să fie ușor de integrat și rezistent în toate interfețele de utilizator, am ajuns la trei primitive de bază, cu limite și cicluri de viață clare:
1. Element: un element este unitatea atomică de intrare/ieșire în Codex. Elementele sunt tipizate (de exemplu, mesaj de utilizator, mesaj de agent, execuție de instrument, solicitare de aprobare, diferență) și fiecare are un ciclu de viață explicit:
item/startedcând începe elementul- elemente opționale
item/*/deltaca fluxuri de conținut (pentru tipuri de elemente de streaming) item/completedcând elementul se finalizează cu sarcina sa finală
Acest ciclu de viață le permite clienților să înceapă randarea imediat la started, să transmită actualizări incrementale la delta și să finalizeze la completed.
2. Tur: un tur este o unitate de lucru a agentului, inițiată de intrarea utilizatorului. Procesul începe când clientul trimite o intrare (de exemplu, „rulează testele și rezumă eșecurile”) și se încheie când agentul finalizează producerea rezultatelor pentru acea intrare. Un tur conține o secvență de elemente care reprezintă pașii intermediari și rezultatele obținute pe parcurs.
3. Fir de conversație: un fir de conversație este un container durabil pentru o sesiune Codex în desfășurare între un utilizator și un agent. Conține mai multe ture. Firele de conversație pot fi create, reluate, bifurcate și arhivate. Istoricul conversației este păstrat, astfel încât clienții să se poată reconecta și să afișeze o cronologie consecventă.
Acum, vom analiza o conversație simplificată între un client și un agent, unde conversația este reprezentată prin primitive:
La începutul conversației, clientul și serverul trebuie să stabilească strângerea de mână initialize. Clientul trebuie să trimită o singură cerere initialize înainte de orice altă metodă, iar serverul confirmă cu un răspuns. Acest lucru oferă serverului ocazia de a-și promova capabilitățile și permite ambelor părți să cadă de acord asupra versiunilor de protocol, a indicatorilor de funcționalitate și a valorilor implicite înainte de a începe munca propriu-zisă. Iată un exemplu de sarcină utilă din extensia VS Code a OpenAI:
Iată ce returnează serverul:
Când un client face o solicitare nouă, va crea mai întâi un fir de discuție și apoi un tur. Serverul va trimite notificări de progres (thread/started și turn/started). De asemenea, va trimite înapoi datele de intrare pe care le înregistrează ca elemente, cum ar fi mesajul utilizatorului de aici.
Apelurile la instrumente sunt trimise înapoi clientului ca elemente. În plus, serverul poate cere aprobarea clientului înainte de a putea executa o acțiune, trimițând o cerere către server. Aprobarea va întrerupe turul până când clientul răspunde fie cu „permit”, fie cu „refuz”. Așa arată fluxul de aprobare în extensia VS Code:

La final, serverul trimite un mesaj al agentului și apoi încheie turul cu turn/completed. Evenimentele delta ale mesajelor agentului transmit fragmente ale mesajului înapoi până când mesajul este finalizat cu item/completed.
Mesajele din diagramă sunt simplificate pentru a fi ușor de citit. Dacă vrei să vezi JSON-ul pentru un tur complet, poți rula clientul de test din depozitul Codex CLI:
Acum, să vedem cum diferite suprafețe client încorporează Codex prin intermediul serverului de aplicații. Vom acoperi trei tipare: aplicații locale și IDE-uri, runtime-ul web Codex și TUI.
În toate cele trei cazuri, transportul este JSON-RPC prin stdio (JSONL). JSON-RPC simplifică construirea legăturilor client în limbajul ales de tine. Suprafețele Codex și integrările cu parteneri au implementat clienți ai serverului de aplicații în limbaje precum Go, Python, TypeScript, Swift și Kotlin. Pentru TypeScript, poți genera definiții direct din protocolul Rust rulând:
Pentru alte limbi, poți genera un pachet JSON Schema și să-l introduci în generatorul tău de cod preferat rulând:

Clienții locali, de obicei, includ într-un pachet sau preiau un binar de pe serverul de aplicații specific platformei, îl lansează ca proces-copil de lungă durată și mențin deschis un canal stdio bidirecțional pentru JSON-RPC. În extensia noastră VS Code și în aplicația noastră pentru desktop, de exemplu, artefactul livrat include binarul Codex specific platformei și este fixat la o versiune testată, astfel încât clientul să ruleze întotdeauna exact biții pe care i-am validat.
Nu fiecare integrare poate livra frecvent actualizări pentru clienți. Unii parteneri, precum Xcode, decuplează ciclurile de lansare menținând clientul stabil și permițându-i să indice către un binar mai nou din serverul de aplicații atunci când este necesar. Astfel, ei pot adopta îmbunătățiri pe partea de server (de exemplu, o auto-compactare mai bună în nucleul Codex sau chei de configurare nou acceptate) și pot implementa remedieri de erori fără să aștepte o lansare a clientului. Suprafața JSON-RPC a serverului de aplicații este proiectată să fie compatibilă în revers, astfel încât clienții mai vechi să poată comunica în siguranță cu serverele mai noi.

Codex Web folosește sistemul Codex, dar îl rulează într-un mediu de containere. Un lucrător aprovizionează un container cu spațiul de lucru extras, lansează binarul serverului de aplicații în interiorul acestuia și menține un canal JSON-RPC de lungă durată prin stdio2. Aplicația web (care rulează în fila de browser a utilizatorului) comunică cu backend-ul Codex prin HTTP și SSE, care transmite în flux evenimentele de sarcină produse de lucrător. Acest lucru menține interfața de utilizare din browser ușoară, oferindu-ne în același timp un timp de execuție consecvent pe desktop și pe web.
Pentru că sesiunile web sunt efemere (filele se închid, rețelele cad), aplicația web nu poate fi sursa de adevăr pentru sarcini de lungă durată. Păstrarea stării și a progresului pe server înseamnă că munca continuă chiar dacă fila dispare. Protocolul de streaming și sesiunile de conversație salvate fac ușoară reconectarea unei sesiuni noi, permițându-ți să continui de unde ai rămas și să recuperezi fără a reconstrui starea în client.

Istoric, TUI a fost un client „nativ” care rula în același proces ca bucla agentului și comunica direct cu tipurile de bază Rust, în loc să folosească protocolul serverului de aplicații. Asta a făcut ca iterația timpurie să fie rapidă, dar a transformat și TUI într-o suprafață de caz special.
Acum că serverul de aplicații există, plănuim să refactorizăm TUI(se deschide într-o fereastră nouă) pentru a-l folosi astfel încât să se comporte ca orice alt client: să lanseze un proces-copil al serverului de aplicații, să comunice JSON-RPC prin stdio și să redea aceleași evenimente și aprobări în flux. Acest lucru deblochează fluxuri de lucru în care TUI se poate conecta la un server Codex care rulează pe o mașină la distanță, menținând agentul aproape de resursele de calcul și continuând munca chiar dacă laptopul intră în repaus sau se deconectează, oferind în același timp actualizări live și controale local.
Serverul de aplicații Codex va fi metoda de integrare de primă clasă pe care o vom menține pe viitor, dar există și alte metode cu funcționalitate mai limitată. În mod implicit, am recomanda clienților să folosească serverul de aplicații Codex pentru a se integra cu Codex, dar merită să analizezi diferite metode de integrare și să le înțelegi avantajele și dezavantajele. Mai jos sunt cele mai comune modalități de a utiliza Codex și când fiecare ar putea fi o alegere bună.
Rulează codex mcp-server(se deschide într-o fereastră nouă) și conectează-te de la orice client MCP care suportă servere stdio (de ex., OpenAI Agents SDK(se deschide într-o fereastră nouă)). Aceasta este o alegere bună dacă ai deja un flux de lucru bazat pe MCP și vrei să folosești Codex ca un instrument apelabil. Dezavantajul este că primești doar ceea ce expune MCP, așa că interacțiunile specifice Codex care se bazează pe o semantică de sesiune mai bogată (de exemplu, actualizări de diferențe) s-ar putea să nu se mapeze curat prin punctele finale MCP.
Unele ecosisteme oferă o interfață portabilă care poate viza mai mulți furnizori de modele și runtime-uri. Aceasta poate fi o alegere bună dacă vrei o singură abstractizare care să coordoneze mai mulți agenți. Compromisul este că aceste protocoale converg adesea către subsetul comun de capabilități, ceea ce poate face mai dificilă reprezentarea interacțiunilor mai bogate, mai ales atunci când semantica instrumentelor și a sesiunilor specifice furnizorului contează. Acest spațiu evoluează rapid și ne așteptăm să apară standarde mai comune pe măsură ce vom identifica cele mai bune primitive pentru a reprezenta fluxurile de lucru ale agenților din lumea reală, (abilitățile(se deschide într-o fereastră nouă) sunt un bun exemplu în acest sens).
Alege serverul de aplicații atunci când vrei ca întregul sistem Codex să fie expus ca un flux de evenimente stabil și prietenos pentru interfața cu utilizatorul. Primești atât funcționalitatea completă a buclei agentului, cât și alte funcții de suport, precum Conectare cu ChatGPT, descoperirea modelelor și managementul configurației. Costul principal este munca de integrare, deoarece trebuie să construiești legătura JSON-RPC pe partea de client în limbajul tău. În practică, însă, Codex poate face o mare parte din munca grea dacă îi furnizezi schema JSON și documentația. Multe echipe cu care am lucrat au reușit să facă rapid o integrare funcțională folosind Codex.
Un mod CLI ușor și scriptabil pentru sarcini unice și rulări CI. Este o alegere bună pentru automatizare și conducte în care dorești ca o singură comandă să se execute până la finalizare, neinteractiv, să transmită în flux ieșire structurată pentru jurnale și să se încheie cu un semnal clar de succes sau eșec.
O bibliotecă TypeScript pentru a controla programatic agenții Codex locali din aplicația ta. Este cel mai bine când vrei o interfață nativă de bibliotecă pentru instrumente și fluxuri de lucru pe partea de server, fără a construi un client JSON-RPC separat. Deoarece a fost lansat mai devreme decât serverul de aplicații, în prezent suportă mai puține limbi și o suprafață de funcționalitate mai mică. Dacă există interes din partea dezvoltatorilor, am putea adăuga SDK-uri suplimentare care să învelească protocolul serverului de aplicații, astfel încât echipele să poată acoperi mai mult din suprafața de lucru fără a scrie legături JSON-RPC.
În această postare, am împărtășit cum abordăm proiectarea unui nou standard pentru interacțiunea cu agenții și cum să transformăm sistemul Codex într-un protocol stabil și prietenos pentru clienți. Am discutat despre cum serverul de aplicații expune nucleul Codex, permite clienților să controleze întreaga buclă a agentului și alimentează o varietate de suprafețe, inclusiv TUI, integrări IDE locale și runtime-ul web.
Dacă acest lucru ți-a stârnit idei pentru integrarea Codex în fluxurile tale de lucru, merită să încerci serverul de aplicații. Tot codul sursă se află în depozitul(se deschide într-o fereastră nouă) open source Codex CLI. Simte-te liber să împărtășești feedbackul și solicitările de funcționalități. Suntem încântați să îți auzim părerile și să continuăm să facem agenții mai accesibili pentru toată lumea.
Autor
Mulțumiri
Mulțumiri speciale lui Michael Bolin, Owen Lin, Eric Traut și Rasmus Rygaard, care au contribuit la acest articol, și întregii echipe Codex care a lucrat la serverul de aplicații.
Note de subsol
- 1
Folosim o variantă „JSON‑RPC lite”: aceasta păstrează forma cerere/răspuns/notificare, dar omite antetul
"jsonrpc": "2.0"și este încadrat ca JSONL peste stdio, și nu ca JSON‑RPC 2.0 strict. - 2
„stdio” se referă la stdin/stdout ale serverului de aplicații din interiorul containerului. În configurațiile găzduite, aceste fluxuri sunt adesea tunelate printr-o conexiune de rețea persistentă (de ex., asemănătoare WebSocket) către runtime-ul containerului — astfel încât se comportă ca stdio chiar dacă nu este o conductă locală propriu-zisă.


