Отключване на свръзка Codex: как създадохме сървъра за приложения
От Селия Чен, член на техническия персонал
Кодиращият агент на OpenAI, Codex, съществува на много различни платформи: уеб приложението(отваря се в нов прозорец), CLI(отваря се в нов прозорец), разширението за IDE(отваря се в нов прозорец) и новото приложение Codex за macOS. Под повърхността всички те се захранват от една и съща свръзка Codex — цикълът на агента и логиката, които са в основата на всички изживявания с Codex. Критичната връзка между тях? Codex App Server(отваря се в нов прозорец), удобен за клиентите, двупосочен JSON-RPC1 API.
В тази публикация ще представим Codex App Server, ще споделим наученото досега за най-добрите начини да внедрите възможностите на Codex в своя продукт, за да помогнете на потребителите си да ускорят значително работните си процеси. Ще разгледаме архитектурата и протокола на App Server и как се интегрира с различни интерфейси на Codex, както и съвети за това как да използвате Codex, независимо дали искате да го превърнете в инструмент за преглед на код, SRE агент или асистент по кодиране.
Преди да се потопим в архитектурата, е полезно да знаете предисторията на App Server. Първоначално App Server беше практичен начин за повторно използване на свръзката Codex в различни продукти, който постепенно се превърна в нашия стандартен протокол.
Codex CLI започна като TUI (терминален потребителски интерфейс), което означава, че Codex се използва чрез терминала. Когато създадохме разширението за VS Code (по-удобен за IDE начин за взаимодействие с агентите на Codex), ни трябваше начин да използваме същата свръзка, за да управляваме същия цикъл на агента от потребителския интерфейс на IDE, без да го имплементираме отново. Това означаваше поддръжка на богати модели на взаимодействие отвъд заявка/отговор, като например разглеждане на работното пространство, предаване на напредъка, докато агентът разсъждава, и извеждане на разлики. Първо експериментирахме с излагането на Codex като MCP сървър(отваря се в нов прозорец), но поддържането на семантиката на MCP по начин, който да има смисъл за VS Code, се оказа трудно. Вместо това въведохме JSON-RPC протокол, който отразяваше цикъла на TUI и се превърна в неофициалната първа версия(отваря се в нов прозорец) на App Server. По онова време не очаквахме други клиенти да зависят от App Server, затова той не беше проектиран като стабилен API.
С нарастването на приемането на Codex през следващите няколко месеца, вътрешните екипи и външните партньори искаха възможността да вграждат същата свръзка в собствените си продукти, за да ускорят работните процеси на своите потребители за разработка на софтуер. Например JetBrains и Xcode искаха изживяване с агент на ниво IDE, докато настолното приложение Codex трябваше да ръководи много агенти на Codex паралелно. Тези изисквания ни подтикнаха да проектираме платформа, на която както нашите продукти, така и интеграциите на партньорите ни да могат безопасно да разчитат с течение на времето. Трябваше да бъде лесно за интегриране и обратно съвместимо, което означава, че можем да развиваме протокола, без да нарушаваме съществуващите клиенти.
След това ще разгледаме как проектирахме архитектурата и протокола, така че различни клиенти да могат да използват една и съща свръзка.
Първо, нека се фокусираме върху това, което се намира вътре в свръзката Codex, и как Codex App Server го предоставя на клиентите. В последния ни блог за Codex разгледахме основния цикъл на агента, който координира взаимодействието между потребителя, модела и инструментите. Това е основната логика на свръзката Codex, но има и още неща, които допринасят за пълноценното използване на агента:
1. Жизнен цикъл и постоянство на нишката. Нишката е разговор в Codex между потребител и агент. Codex създава, възобновява, клонира и архивира нишки и съхранява историята на събитията, така че клиентите да могат да се свържат отново и да рендират последователна времева линия.
2. Конфигурация и удостоверяване. Codex зарежда конфигурацията, управлява настройките по подразбиране и изпълнява потоци за удостоверяване като „Вход с ChatGPT“, включително състоянието на идентификационните данни.
3. Изпълнение на инструменти и разширения. Codex изпълнява инструменти за команден ред/файлове в изолирана среда и свързва интеграции като MCP сървъри и умения, така че да могат да участват в цикъла на агента при последователен модел на политики.
Цялата логика на агента, която споменахме тук, включително основният цикъл на агента, се намира в част от кодовата база на Codex CLI, наречена „Codex core(отваря се в нов прозорец)“. Codex core е едновременно библиотека, в която се намира целият код на агента, и среда за изпълнение, която може да бъде стартирана, за да изпълнява цикъла на агента и да управлява постоянството на една нишка Codex (разговор).
За да бъде полезна, свръзката Codex трябва да бъде достъпна за клиентите. Тук се намесва сървърът за приложения.
Сървърът за приложения е както протоколът JSON-RPC между клиента и сървъра, така и дълготраен процес, който хоства основните нишки на Codex. Както можем да видим от диаграмата по-горе, процесът на App Server има четири основни компонента: stdio четецът, процесорът на съобщения Codex, мениджърът на нишки и основните нишки. Мениджърът на нишки създава по една основна сесия за всяка нишка, а след това процесорът за съобщения на Codex комуникира директно с всяка основна сесия, за да подава заявки на клиенти и да получава актуализации.
Една заявка на клиент може да доведе до множество актуализации на събития, а тези подробни събития ни позволяват да изградим богат потребителски интерфейс върху App Server. Освен това stdio четецът и процесорът за съобщения на Codex служат като слой за превод между клиентските и основните нишки на Codex. Те преобразуват клиентските JSON-RPC заявки в основни операции на Codex, следят вътрешния поток от събития на ядрото на Codex и след това преобразуват тези събития от ниско ниво в малък набор от стабилни, готови за потребителски интерфейс JSON-RPC известия.
Протоколът JSON-RPC между клиента и App Server е напълно двупосочен. Една типична нишка има заявка от клиент и много известия от сървъра. Освен това сървърът може да инициира заявки, когато агентът се нуждае от входни данни, като например одобрение, и след това да постави заявката на пауза, докато клиентът отговори.
След това ще разгледаме подробно примитивите на разговора, които са градивните елементи на протокола на App Server. Проектирането на API за цикъл на агента е предизвикателство, защото взаимодействието между потребителя и агента не е просто заявка/отговор. Една потребителска заявка може да се разгърне в структурирана последователност от действия, които клиентът трябва да представи вярно: входните данни на потребителя, поетапния напредък на агента, артефактите, създадени по пътя (напр. разлики). За да направим този поток от взаимодействия лесен за интегриране и устойчив в различни потребителски интерфейси, се спряхме на три основни примитива с ясни граници и жизнени цикли:
1. Елемент: Елементът е основната единица за вход/изход в Codex. Елементите са типизирани (напр. съобщение на потребителя, съобщение на агент, изпълнение на инструмент, заявка за одобрение, разлика) и всеки има изрично определен жизнен цикъл:
item/started, когато елементът започва- незадължителни събития
item/*/deltaкато потоци от съдържание (за поточно предаване на типове елементи) item/completed, когато елементът се финализира с крайния си полезен товар
Този жизнен цикъл позволява на клиентите да започнат да визуализират веднага при started, да предават постепенни актуализации при delta и да финализират при completed.
2. Ход: Ходът е единица работа на агент, инициирана от въвеждане на потребител. Процесът започва, когато клиентът подаде входни данни (например „изпълни тестове и обобщи неуспехите“) и завършва, когато агентът приключи с генерирането на изходи за тези данни. Един ход съдържа последователност от елементи, които представляват междинните стъпки и резултатите, произведени по пътя.
3. Низ: Низът е траен контейнер за текуща сесия на Codex между потребител и агент. Съдържа няколко хода. Низовете могат да бъдат създавани, възобновявани, разклонявани и архивирани. Историята на низа се съхранява, за да могат клиентите да се свържат отново и да създадат последователна времева линия.
Сега ще разгледаме опростен разговор между клиент и агент, при който разговорът е представен чрез примитиви:
В началото на разговора клиентът и сървърът трябва да установят ръкостискането initialize. Клиентът трябва да изпрати една-единствена заявка initialize преди който и да е друг метод, а сървърът потвърждава с отговор. Това дава възможност на сървъра да обяви своите възможности и позволява на двете страни да се споразумеят за версионирането на протокола, флаговете за функции и настройките по подразбиране, преди да започне същинската работа. Ето примерен полезен товар от разширението VS Code на OpenAI:
Ето какво връща сървърът:
Когато клиент направи нова заявка, първо ще се създаде нишка, а след това и ход. Сървърът ще изпрати обратно известия за напредъка (thread/started и turn/started). Също така ще изпраща обратно входовете, които регистрира като елементи, като например съобщението на потребителя тук.
Заявките на инструменти също се изпращат обратно към клиента като елементи. Освен това сървърът може да поиска одобрение от клиента, преди да изпълни действие, като изпрати заявка към сървъра. Одобрението ще постави хода на пауза, докато клиентът не отговори с „позволи“ или „откажи“. Ето как изглежда потокът на одобрение в разширението VS Code:

В крайна сметка сървърът изпраща съобщение до агента и след това завършва хода с turn/completed. Делта събитията на съобщението на агента пренасят части от съобщението обратно, докато съобщението не бъде завършено с item/completed.
Съобщенията в диаграмата са опростени за по-лесно четене. Ако желаете да видите JSON за цял ход, можете да стартирате тестовия клиент от хранилището на Codex CLI:
Сега нека разгледаме как различни клиентски повърхности вграждат Codex чрез сървъра за приложения. Ще разгледаме три модела: локални приложения и IDE, уеб среда за изпълнение на Codex и TUI.
И при трите транспортът е JSON-RPC през stdio (JSONL). JSON-RPC улеснява създаването на клиентски връзки на избрания от Вас език. Повърхностите на Codex и партньорските интеграции са имплементирали клиенти на App Server на езици, включително Go, Python, TypeScript, Swift и Kotlin. За TypeScript Вие можете да генерирате дефиниции директно от протокола Rust, като изпълните:
За други езици можете да генерирате пакет с JSON схема и да го подадете към предпочитания от Вас генератор на код, като изпълните:

Локалните клиенти обикновено пакетират или извличат двоичен файл на App Server, специфичен за платформата, стартират го като дългосрочно работещ дъщерен процес и поддържат отворен двупосочен stdio канал за JSON-RPC. Например в нашето разширение VS Code и приложение за настолни компютри доставеният артефакт включва специфичния за платформата двоичен файл на Codex и е прикрепен към тествана версия, така че клиентът винаги изпълнява точните битове, които сме валидирали.
Не всяка интеграция може често да изпраща актуализации на клиентите. Някои партньори, като Xcode, разделят циклите на издаване, като поддържат клиента стабилен и му позволяват при нужда да посочи към по-нова двоична версия на App Server. По този начин те могат да внедряват подобрения от страна на сървъра (например по-добро автоматично компактиране в ядрото на Codex или нови поддържани ключове за конфигурация) и да разпространяват поправки на грешки, без да чакат издание на клиента. JSON-RPC интерфейсът на App Server е проектиран да бъде обратно съвместим, така че по-старите клиенти да могат се свързват безопасно с по-новите сървъри.

Codex Web използва свръзката Codex, но я изпълнява в изолирана среда. Служител подготвя контейнер с извлеченото работно пространство, стартира двоичния файл на App Server в него и поддържа дълготраен JSON-RPC канал през stdio2. Уеб приложението (което работи в раздела на браузъра на потребителя) комуникира с бекенда на Codex чрез HTTP и SSE, които предават събития за задачи, генерирани от служителя. Така се поддържа лек потребителския интерфейс от страна на браузъра, като в същото време се осигурява последователно време за изпълнение на работния плот и в уеб мрежата.
Тъй като уеб сесиите са краткотрайни (разделите се затварят, мрежите прекъсват), уеб приложението не може да бъде надежден източник за дълготрайни задачи. Поддържането на състоянието и напредъка на сървъра означава, че работата продължава, дори ако разделът изчезне. Протоколът за поточно предаване и сесиите със запазени нишки улесняват повторното свързване на нова сесия, която може да започне от мястото, където е спряла, и да навакса изоставането си, без да е необходимо да се възстановява състоянието в клиента.

В миналото TUI беше „native“ клиент, който работеше в същия процес като цикъла на агента и комуникираше директно с типовете ядра на Rust, а не с протокола приложение-сървър. Това направи ранната итерация бърза, но също така превърна TUI в повърхност за специални случаи.
След като App Server съществува, планираме да рефакторираме TUI(отваря се в нов прозорец), за да го използваме така, че да се държи като всеки друг клиент: да стартираме дъщерен процес на App Server, да изговаряме JSON-RPC през stdio и да рендираме същите поточни събития и одобрения. Това отключва работни потоци, при които TUI може да се свърже със сървър на Codex, работещ на отдалечена машина, като държи агента близо до изчислителните ресурси и продължава работа дори ако лаптопът заспи или се разкачи, като същевременно предоставя актуализации в реално време и контрол на място.
Codex App Server ще бъде първокласният метод за интеграция, който ще поддържаме занапред, но има и други методи с по-ограничена функционалност. По подразбиране бихме препоръчали клиентите да използват Codex App Server за интеграция с Codex, но си струва да разгледате различните методи за интеграция и да разберете техните предимства и недостатъци. По-долу са най-често срещаните начини за управление на Codex и кога всеки от тях може да е подходящ.
Стартирайте codex mcp-server(отваря се в нов прозорец) и се свържете от всеки MCP клиент, който поддържа stdio сървъри (напр. OpenAI Agents SDK(отваря се в нов прозорец)). Това е добър избор, ако вече имате работен процес, базиран на MCP, и искате да използвате Codex като инструмент, който може да бъде извикан. Недостатъкът е, че получавате само това, което MCP предоставя, така че специфичните за Codex взаимодействия, които разчитат на по-богата семантика на сесията (напр. актуализации на разлики), може да не се пренасят ясно през крайните точки на MCP.
Някои екосистеми предлагат преносим интерфейс, който може да бъде насочен към множество доставчици на модели и среди за изпълнение. Това може да бъде добро решение, ако желаете една абстракция, която координира множество агенти. Компромисът се състои в това, че тези протоколи често се обединяват върху общото подмножество от възможности, което може да затрудни представянето на по-богати взаимодействия, особено когато семантиката на специфичните за доставчика инструменти и сесии е от значение. Тази област се развива бързо и очакваме, че ще се появят повече общи стандарти, тъй като ще открием най-добрите примитиви за представяне на работните процеси на агентите в реалния свят (уменията(отваря се в нов прозорец) са добър пример за това).
Изберете App Server, когато искате пълната свръзка Codex да бъде изложена като стабилен, удобен за потребителския интерфейс поток от събития. Получавате както пълната функционалност на цикъла на агента, така и други поддържащи функции като вход с ChatGPT, откриване на модели и управление на конфигурацията. Основните разходи са свързани с работата по интеграцията, тъй като трябва да изградите връзката JSON-RPC от страна на клиента на Вашия език. На практика обаче Codex може да извърши голяма част от тежката работа, ако му предоставите JSON схемата и документацията. Много екипи, с които работихме, успяха бързо да постигнат работеща интеграция с помощта на Codex.
Лек скриптируем режим на CLI за еднократни задачи и CI изпълнения. Това е подходящо за автоматизация и конвейери, когато искате една команда да се изпълни докрай без взаимодействие, да предава структурирани изходни данни за регистри и да завърши с ясен сигнал за успех или неуспех.
Библиотека на TypeScript за програмно управление на локални агенти на Codex от Вашето собствено приложение. Най-добре е, когато искате собствен интерфейс на библиотека за сървърни инструменти и работни процеси, без да изграждате отделен JSON-RPC клиент. Тъй като беше пуснат по-рано от App Server, в момента поддържа по-малко езици и по-малка функционалност. Ако има интерес от страна на разработчиците, може да добавим допълнителни SDK, които обгръщат протокола на App Server, така че екипите да могат да покрият по-голяма част от повърхността на свръзката, без да пишат JSON-RPC обвързвания.
В тази публикация споделихме как подхождаме към проектирането на нов стандарт за взаимодействие с агенти и как да превърнем свръзката Codex в стабилен и удобен за клиентите протокол. Разгледахме как App Server предоставя достъп до ядрото на Codex, позволява на клиентите да управляват пълния цикъл на агента и захранва широк набор от интерфейси, включително TUI, локални интеграции на IDE и уеб среда за изпълнение.
Ако това е предизвикало идеи за интегриране на Codex в собствените Ви работни процеси, струва си да опитате App Server. Целият изходен код се намира в хранилището с отворен код Codex CLI репо(отваря се в нов прозорец). Не се колебайте да споделите обратната Ви връзка и заявки за функции. Радваме се да чуем Вашите мнения и да продължим да правим агентите по-достъпни за всички.
Автор
Благодарности
Специални благодарности на Майкъл Болин, Оуен Лин, Ерик Траут и Расмус Рюгорд, които допринесоха за тази публикация, и на целия екип на Codex, който работи по App Server.
Бележки под линия
- 1
Използваме вариант „JSON‑RPC lite“: той запазва формата на заявка/отговор/известие, но пропуска
"jsonrpc": "2.0"header и е оформен като JSONL през stdio, а не като строг JSON‑RPC 2.0. - 2
„stdio“ се отнася до stdin/stdout на сървъра за приложения вътре в контейнера. В хоствани конфигурации тези потоци често се тунелират през постоянна мрежова връзка (напр. подобна на WebSocket) към средата за изпълнение на контейнера, така че се държат като stdio, дори ако не са буквално локален канал.


