Codex CLI(otevře se v novém okně) je náš multiplatformní lokální softwarový agent, který je navržen tak, aby vytvářel vysoce kvalitní a spolehlivé softwarové změny a zároveň fungoval bezpečně a efektivně na tvém počítači. Od dubna, kdy jsme poprvé spustili CLI, jsme se naučili obrovské množství informací o tom, jak vytvořit špičkového softwarového agenta. Chceme teď tyto poznatky rozvést a toto je první příspěvek v pokračující sérii, ve které se podíváme na různé aspekty fungování Codexu a také na těžce nabyté poznatky. (Pokud máš zájem o ještě podrobnější pohled na to, jak je Codex CLI sestaven, podívej se na naše open-source úložiště na https://github.com/openai/codex(otevře se v novém okně). Pokud se chceš dozvědět více, tak mnoho přesnějších detailů našich rozhodnutí při designování je zdokumentováno v problémech a žádostech o přijetí změn na GitHubu.
Na začátku se zaměříme na smyčku agenta, což je základní logika nástroje Codex CLI, která je zodpovědná za řízení interakce mezi uživatelem, modelem a nástroji, které model vyvolává, tak, aby software odváděl smysluplnou práci. Doufáme, že ti tento příspěvek poskytne dobrý pohled na roli, kterou náš agent (nebo „rámec“) hraje při využívání LLM.
Než se do toho pustíme, krátká poznámka k terminologii: v OpenAI „Codex“ zahrnuje sadu nabídek softwarových agentů, mezi které patří Codex CLI, Codex Cloud a rozšíření Codex pro VS Code. Tento příspěvek se zaměřuje na rámec Codexu, který poskytuje základní smyčku agenta a řídicí logiku, na které stojí všechny aplikací s Codexem a která je přístupná prostřednictvím rozhraní Codex CLI. Pro zjednodušení zde budeme používat termíny „Codex“ a „Codex CLI“ zaměnitelně.
Srdcem každého AI agenta je něco, čemu se říká „smyčka agenta“. Zjednodušená ilustrace smyčky agenta vypadá takto:
Na začátku agent přijme od uživatele vstupní údaje, které zahrne do sady textových instrukcí připravených pro model – do tzv. promptu.
Dalším krokem je dotazování se modelu tím, že mu pošleme naše pokyny a požádáme ho, aby vygeneroval odpověď. To je proces známý jako inference. Během inference se textový prompt nejprve přeloží do posloupnosti vstupních tokenů(otevře se v novém okně) – celých čísel, která se indexují slovníku modelu. Tyto tokeny se pak použijí k vzorkování modelu a vytvoří se nová sekvence výstupních tokenů.
Výstupní tokeny se přeloží zpět na text, který se stane odpovědí modelu. Protože se tokeny vytvářejí postupně, může tento překlad probíhat současně s během modelu. To je důvod, proč mnoho aplikací založených na LLM zobrazuje streamovaný výstup. V praxi je inference obvykle zapouzdřena za rozhraním API, které pracuje s textem a abstrahuje od podrobností tokenizace.
V důsledku kroku inference model buď (1) vytvoří finální odpověď na původní vstup uživatele, nebo (2) požádá o volání nástroje, které má agent provést (např. „spusť ls a uveď výstup“). V případě (2) agent provede volání nástroje a připojí jeho výstup k původnímu promptu. Tento výstup se použije k vygenerování nového vstupu, který se použije k novému dotazu na model; agent pak může vzít tyto nové informace v úvahu a zkusit to znovu.
Tento proces se opakuje, dokud model nepřestane generovat volání nástrojů a nevytvoří místo toho zprávu pro uživatele (v modelech OpenAI označovanou jako zpráva asistenta). V mnoha případech tato zpráva přímo odpovídá na původní požadavek uživatele, ale může se jednat i o doplňující otázku pro uživatele.
Protože agent může provádět volání nástrojů, která upravují místní prostředí, jeho „výstup“ se neomezuje pouze na zprávu asistenta. V mnoha případech je hlavním výstupem softwarového agenta kód, který na tvém počítači píše nebo upravuje. Nicméně každý tah vždy končí zprávou asistenta – například „Přidal jsem architecture.md, o který jsi požádal“ – která signalizuje ukončení smyčky agenta. Z pohledu agenta je jeho práce dokončena a řízení se vrací uživateli.
Cesta od uživatelského vstupu k odpovědi agenta zobrazená v diagramu se nazývá jeden tah konverzace (ve vlákně Codexu jako vlákno ). Tento tah konverzace však může zahrnovat mnoho iterací mezi závěry modelu a voláním nástrojů. Pokaždé, když pošleš novou zprávu do existující konverzace, historie konverzace se zahrne jako součást promptu pro nový tah, který zahrnuje zprávy a volání nástrojů z předchozích tahů:
To znamená, že jak se konverzace rozvíjí, prodlužuje se i délka promptu používaného k vzorkování modelu. Tato délka je důležitá, protože každý model má kontextové okno, což je maximální počet tokenů, které může použít pro jedno volání inference. Upozorňujeme, že toto okno zahrnuje vstupní i výstupní tokeny. Jak si asi dokážeš představit, agent by se mohl rozhodnout provést v jediném tahu stovky volání nástrojů, což by mohlo vyčerpat kontextové okno. Z tohoto důvodu je správa kontextového okna jednou z mnoha povinností agenta. Teď se pojďme podívat, jak Codex spouští smyčku agenta.
Codex CLI odesílá HTTP požadavky na rozhraní Responses API(otevře se v novém okně), aby se spustila inference modelu. Podívejme se na to, jak informace proudí přes Codex, který používá Responses API k řízení smyčky agenta.
Koncový bod rozhraní Responses API, který používá Codex CLI, je možné konfigurovat(otevře se v novém okně), takže ho můžeš použít s jakýmkoli koncovým bodem, který implementuje rozhraní Responses API(otevře se v novém okně):
- Při použití přihlášení přes ChatGPT(otevře se v novém okně) s Codex CLI se jako koncový bod používá
https://chatgpt.com/backend-api/codex/responses - Při použití ověřování pomocí API klíče(otevře se v novém okně) u hostovaných modelů OpenAI se jako koncový bod používá
https://api.openai.com/v1/responses - Když spustíš Codex CLI s
--osspro použití gpt-oss s ollama 0.13.4+(otevře se v novém okně) nebo LM Studio 0.3.39+(otevře se v novém okně) se ve výchozím nastavení použijehttp://localhost:11434/v1/responsesběžící lokálně na tvém počítači. - Codex CLI lze používat s rozhraním Responses API hostovaným poskytovatelem cloudu, jako je Azure.
Pojďme prozkoumat, jak Codex vytváří prompt pro první volání inference v konverzaci.
Jako koncový uživatel při odesílání dotazu na rozhraní Responses API doslovně neurčuješ prompt použitý k vzorkování modelu. Místo toho zadáš různé typy vstupů jako součást svého dotazu a server API Responses rozhodne, jak tyto informace strukturovat do promptu, který má model využít. Prompt si můžeš představit jako „seznam položek“; tato část vysvětlí, jak se tvůj dotaz přemění na tento seznam.
V úvodním promptu je každá položka v seznamu přiřazena k roli. Role určuje, jakou váhu má mít přidružený obsah, a má jednu z následujících hodnot (v sestupném pořadí priority): systém, vývojář, uživatel, asistent.
Responses API(otevře se v novém okně) přijímá datový obsah ve formátu JSON s mnoha parametry. Zaměříme se na tyto tři oblasti:
pokyny(otevře se v novém okně): systémová (nebo vývojářská) zpráva vložená do kontextu modelunástroje(otevře se v novém okně): seznam nástrojů, které může model volat při generování odpovědivstup(otevře se v novém okně): seznam textových, obrázkových nebo souborových vstupů do modelu
V Codexu se pole pokyny načítá ze souboru model_instructions_file(otevře se v novém okně) v ~/.codex/config.toml (pokud je tento soubor zadán); jinak se použijí base_instructions spojené s modelem(otevře se v novém okně). Pokyny specifické pro model jsou v repozitáři Codex a jsou zahrnuty do CLI (např. gpt-5.2-codex_prompt.md(otevře se v novém okně)).
Pole nástroje je seznam definic nástrojů, které odpovídají schématu definovanému rozhraním Responses API. V případě Codexu se jedná o nástroje poskytované rozhraním Codex CLI, nástroje poskytované rozhraním Responses API, které by měly být zpřístupněny Codexu, a také nástroje poskytované uživatelem, obvykle prostřednictvím serverů MCP:
A konečně pole vstup datového obsahu JSON je seznam položek. Codex vloží následující položky(otevře se v novém okně) do vstupu před přidáním uživatelské zprávy:
1. Zprávu s parametrem role=developer, která popisuje sandbox vztahující se pouze na nástrojshell poskytovaný společností Codex definovaný v sekci nástroje. To znamená, že jiné nástroje, např. ty poskytované ze serverů MCP, nejsou Codexem sandboxované a musí si samy zajistit ochranná opatření.
Zpráva je sestavena ze šablony, jejíž klíčové části obsahu pocházejí z fragmentů Markdown začleněných do rozhraní Codex CLI, jako jsou workspace_write.md(otevře se v novém okně) a on_request.md:(otevře se v novém okně)
2. (Volitelné) Zpráva s parametrem role=developer, jejímž obsahem je hodnota developer_instructions přečtená ze souboru config.toml uživatele.
3. (Volitelné) Zpráva s parametrem role=user, jejímž obsahem jsou „uživatelské pokyny“, které nejsou z jednoho souboru, ale jsou shromážděny z více zdrojů(otevře se v novém okně). Obecně platí, že konkrétnější pokyny se objeví později:
- Obsah souborů
AGENTS.override.mdaAGENTS.mdv$CODEX_HOME - Až do limitu (ve výchozím nastavení 32 KB) prohledej každou složku od kořene Git/project
cwd(pokud existuje) až po samotnécwd: přidej obsah libovolného souboruAGENTS.override.md,AGENTS.mdnebo jakéhokoliv názvu souboru určeného v souboruproject_doc_fallback_filenames v config.toml. - Pokud byly nakonfigurovány nějaké dovednosti(otevře se v novém okně):
- krátký úvod o dovednostech
- metadata dovedností(otevře se v novém okně) pro každou dovednost
- sekce o tom, jak používat dovednosti(otevře se v novém okně)
4. Zpráva s parametrem role=user, která popisuje místní prostředí, ve kterém agent právě pracuje. Určuje aktuální pracovní adresář a shell uživatele(otevře se v novém okně):
Jakmile Codex provede všechny výše uvedené výpočty k inicializaci vstupu, připojí uživatelskou zprávu, aby zahájil konverzaci.
Předchozí příklady se zaměřovaly na obsah každé zprávy, ale je třeba si všimnout, že každý prvek vstupu je JSON objekt s typem, rolí(otevře se v novém okně) a obsahem, jak je popsáno níže:
Jakmile Codex sestaví kompletní datový obsah JSON k odeslání do rozhraní Responses API, provede požadavek HTTP POST s hlavičkou Authorization podle toho, jak je koncový bod Responses API nakonfigurován v ~/.codex/config.toml (pokud jsou zadány, přidají se také další HTTP hlavičky a parametry dotazu).
Když server rozhraní OpenAI Responses API obdrží požadavek, použije JSON k odvození promptu pro model následujícím způsobem (vlastní implementace rozhraní Responses API může pro jistotu zvolit jiný způsob):
Jak vidíš, pořadí prvních tří položek v promptu určuje server, ne klient. Znamená to, že z těchto tří položek řídí server pouze obsah systémové zprávy, protože nástroje a pokyny určuje klient. Po nich následuje vstup z datového obsahu JSON tak, aby byl prompt dokončen.
Teď, když máme náš prompt, jsme připraveni vzorkovat model.
Tento požadavek HTTP na Responses API zahajuje první „tah“ konverzace v Codexu. Server odpovídá streamem událostí zasílaných serverem (SSE(otevře se v novém okně)). Data každé události je datový obsah JSON s „typem“začínajícím na „response“, což může vypadat například takto (úplný seznam událostí najdeš v našich API dokumentech(otevře se v novém okně)):
Codex zpracuje stream událostí(otevře se v novém okně) a znovu je publikuje jako interní objekty událostí, které může klient použít. Události jako response.output_text.delta se používají k podpoře streamování v uživatelském rozhraní, zatímco jiné události jako response.output_item.added se transformují na objekty, které se připojují ke vstupu pro další volání API Responses.
Předpokládejme, že první požadavek na rozhraní API Responses obsahuje dvě události response.output_item.done: jednu s typem=reasoning a druhou s typem=function_call. Tyto události musí být při dalším dotazu na model s odpovědí na volání nástroje uvedeny ve vstupním poli input v JSON:
Výsledný prompt použitý pro vzorkování modelu v rámci následného dotazu by vypadal takto:
Všimněte si zejména toho, že starý prompty je přesně vložen před nový prompt. Je to záměr, protože díky tomu jsou následné požadavky mnohem efektivnější a umožňuje mám to využívat pohotové ukládání do mezipaměti (o kterém si povíme v další části o výkonu).
Když se podíváme zpět na náš první diagram smyčky agenta, vidíme, že mezi inferencí a voláním nástrojů může proběhnout mnoho iterací. Prompt může dál narůstat až do doby, dokud neobdržíme zprávu asistenta, která signalizuje konec tahu:
V rozhraní Codex CLI zobrazíme uživateli zprávu asistenta a aktivujeme editor, abychom mu naznačili, že je na řadě pokračovat v konverzaci. Pokud uživatel odpoví, musí se k zahájení nového tahu připojit ke vstupu v požadavku na rozhraní Responses API jak zpráva asistenta z předchozího tahu, tak i nová zpráva uživatele:
Znovu, protože pokračujeme v konverzaci, délka vstupu, který posíláme do rozhraní Responses API, se stále zvětšuje:
Podívejme se, jaký vliv má tento stále rostoucí prompt na výkon.
Možná se ptáš: „Počkat, nenarůstá smyčka agenta, pokud jde o množství JSON odeslané do Responses API během konverzace, kvadratickou řadou ?“ Ano, je to tak. Ačkoli rozhraní Responses API podporuje volitelný parametr previous_response_id(otevře se v novém okně), který tento problém zmírňuje, Codex ho dnes nepoužívá, především. Důvodem je potřeba, aby požadavky zůstaly plně bezstavové a podporovaly konfigurace s nulovým uchováváním dat (ZDR).
Vyhnutí se previous_response_id zjednodušuje práci pro poskytovatele rozhraní API Responses, protože zajišťuje, že každý požadavek je bezstavový. Usnadňuje také podporu zákazníků, kteří se rozhodli pro službu nulového uchovávání dat (ZDR)(otevře se v novém okně). Ukládání dat potřebných pro podporu previous_response_id by bylo v rozporu s pravidly ZDR. Upozorňujeme, že zákazníci služby ZDR se nevzdávají možnosti využívat proprietární zprávy o uvažování z předchozích tahů, protože související encrypted_content lze na serveru dešifrovat. (OpenAI uchovává dešifrovací klíč zákazníka služby ZDR, ale ne jeho data.) Pro změny v Codexu související s podporu ZDR se podívejte na tiskové zprávy č. 642(otevře se v novém okně) a 1641(otevře se v novém okně).
Náklady na vzorkování modelu obecně převažují nad náklady na síťový provoz, takže vzorkování je hlavním cílem našich snah o efektivitu. Proto je tak důležité ukládání promptů do mezipaměti. Umožňuje nám totiž znovu využít výpočet z předchozího volání inference. Když máme zásahy v mezipaměti, vzorkování modelu je lineární, nikoli kvadratické. Naše dokumentace k ukládání promptů do mezipaměti (otevře se v novém okně)to vysvětluje podrobněji:
Zásahy v mezipaměti jsou možné pouze při přesné shodě prefixu v rámci promptu. Pro využití výhod ukládání do mezipaměti je třeba umístit statický obsah, jako jsou pokyny a příklady, na začátek promptu a proměnlivý obsah, například informace pro konkrétní uživatele, na konec. To platí i pro obrázky a nástroje, které musí být v jednotlivých požadavcích stejné.
S ohledem na to se podívejme, jaké typy operací by mohly v Codexu způsobit „výpadek mezipaměti“:
- Změna dostupných
nástrojůpro model během konverzace. - Změna
modelu, který je cílem požadavku rozhraní Responses API (v praxi se tím změní třetí položka v původním promptu, protože obsahuje pokyny specifické pro model). - Změna konfigurace sandboxu, režimu schvalování nebo aktuálního pracovního adresáře.
Tým Codex musí být obezřetný při zavádění nových funkcí v rozhraní Codex CLI, které by mohly ohrozit ukládání promptů do mezipaměti. Jako příklad lze uvést naši počáteční podporu nástrojů MCP, která způsobila chybu, kdy se nám nepodařilo vyjmenovat nástroje v konzistentním pořadí(otevře se v novém okně). Důsledkem byl výpadek mezipaměti. Upozorňujeme, že nástroje MCP mohou být obzvlášť záludné, protože servery MCP mohou za běhu měnit seznam poskytovaných nástrojů prostřednictvím oznámení notifications/tools/list_changed(otevře se v novém okně). Respektování tohoto oznámení během dlouhé konverzace může způsobit nákladný výpadek mezipaměti.
Pokud je to možné, řešíme změny konfigurace, ke kterým dojde během konverzace, tak,že pro zohlednění změny k výstupu připojíme novou zprávu a neupravujeme zprávu předchozí:
- Pokud se změní konfigurace sandboxu nebo režim schvalování, vložíme(otevře se v novém okně) novou zprávu
role=developerve stejném formátu jako původní položka<permissions instructions>. - Pokud se změní aktuální pracovní adresář, vložíme(otevře se v novém okně) novou zprávu
role=userve stejném formátu jako původní<environment_context>.
Dáváme si záležet na tom, abychom pro zvýšení výkonu zajistili zásahy v mezipaměti. Je tu ještě jeden klíčový prostředek, o který se musíme starat: kontextové okno.
Naše obecná strategie, jak se vyhnout vyčerpání kontextového okna, je komprimace konverzace, jakmile počet tokenů překročí určitou prahovou hodnotu. Konkrétně nahradíme vstup novým, menším seznamem položek, který představuje konverzaci, a umožníme agentovi pokračovat s porozuměním tomu, co se dosud stalo. Raná implementace komprimace(otevře se v novém okně) vyžadovala, aby uživatel ručně spustil příkaz /compact, který pro shrnutí(otevře se v novém okně) zasílal dotazy na rozhraní Responses API pomocí stávající konverzace a vlastních instrukcí. Codex použil výslednou zprávu asistenta obsahující shrnutí jako nový vstup(otevře se v novém okně) v dalších tazích konverzace.
Od té doby se rozhraní Responses API vyvinulo tak, aby podporovalo speciální /responses/compact koncový bod(otevře se v novém okně), který provádí kompakci efektivněji. Vrací seznam položek(otevře se v novém okně), které lze použít místo předchozího input k pokračování v konverzaci a zároveň k uvolnění kontextového okna. Tento seznam zahrnuje speciální položku type=compaction s neprůhlednou položkou encrypted_content, která uchovává latentní porozumění modelu původní konverzaci. Codex teď automaticky použije tento koncový bod ke komprimaci konverzace, když je překročen limit auto_compact_limit(otevře se v novém okně).
Představili jsme si smyčku agenta Codex a prošli jsme si, jak Codex vytváří a spravuje svůj kontext při dotazování modelu. Zároveň jsme upozornili na praktické aspekty a osvědčené postupy, které se vztahují na všechny, kdo vytvářejí smyčku agenta nad rozhraním API Responses.
Smyčka agenta je sice základem Codexu, ale je to jen začátek. V příštích příspěvcích prozkoumáme architekturu rozhraní CLI, zjistíme, jak je implementováno používání nástrojů, a blíže se podíváme na model sandboxu Codex.


