Zum Hauptinhalt springen
OpenAI

23. Januar 2026

Ingenieurwesen

Die Codex-Agent-Schleife entpackt

Von Michael Bolin, Mitglied des technischen Personals

Laden …

Codex CLI(wird in einem neuen Fenster geöffnet) ist unser plattformübergreifender lokaler Software-Agent, der dafür entwickelt wurde, qualitativ hochwertige, zuverlässige Softwareänderungen zu erzeugen und dabei sicher und effizient auf deinem Computer zu arbeiten. Seit dem ersten Launch der CLI im April haben wir enorm viel darüber gelernt, wie man einen Software-Agenten auf Weltklasse-Niveau baut. Um diese Erkenntnisse aufzuschlüsseln, ist dies der erste Beitrag einer fortlaufenden Serie, in der wir verschiedene Aspekte der Funktionsweise von Codex sowie mühsam erarbeitete Lektionen beleuchten werden. (Für einen noch detaillierteren Einblick in den Aufbau der Codex CLI wirf einen Blick in unser Open-Source-Repository unter https://github.com/openai/codex(wird in einem neuen Fenster geöffnet). Viele Feinheiten unserer Designentscheidungen sind in GitHub-Issues und Pull Requests festgehalten, falls du tiefer einsteigen möchtest.)

Zum Einstieg konzentrieren wir uns auf die Agent-Schleife, also die Kernlogik der Codex CLI, die für die Orchestrierung der Interaktion zwischen dem Benutzer, dem Modell und den Tools verantwortlich ist, die das Modell aufruft, um sinnvolle Softwarearbeit zu leisten. Wir hoffen, dass dieser Beitrag dir einen guten Einblick in die Rolle unseres Agenten (oder „Harness“) beim Einsatz eines LLMs gibt.

Bevor wir einsteigen, ein kurzer Hinweis zur Terminologie: Bei OpenAI umfasst „Codex“ eine ganze Reihe von Software-Agent-Angeboten, darunter Codex CLI, Codex Cloud und die Codex-VS-Code-Erweiterung. Dieser Beitrag konzentriert sich auf das Codex-Harness, das die zentrale Agent-Schleife und Ausführungslogik bereitstellt, die allen Codex-Erfahrungen zugrunde liegt und über die Codex CLI verfügbar gemacht wird. Der Einfachheit halber verwenden wir hier die Begriffe „Codex“ und „Codex CLI“ synonym.

Die Agent-Schleife

Im Kern jedes KI-Agenten steckt etwas, das man „die Agent-Schleife“ nennt. Eine vereinfachte Darstellung der Agent-Schleife sieht so aus:

Diagramm mit dem Titel „Agent-Schleife“, das zeigt, wie ein KI-System eine Benutzeranfrage verarbeitet, Tools aufruft, Ergebnisse beobachtet, seinen Plan aktualisiert und Ausgaben zurückgibt. Pfeile verbinden Schritte wie Benutzereingabe, Modell-Reasoning, Tool-Aktionen und die finale Antwort.

Zu Beginn nimmt der Agent Eingaben vom Benutzer entgegen und integriert sie in den Satz textueller Anweisungen, den er für das Modell vorbereitet und der als Prompt bekannt ist.

Im nächsten Schritt wird das Modell abgefragt, indem ihm diese Anweisungen gesendet werden und es aufgefordert wird, eine Antwort zu generieren – ein Prozess, der als Inferenz bezeichnet wird. Während der Inferenz wird der textuelle Prompt zunächst in eine Sequenz von Eingabe-Tokens(wird in einem neuen Fenster geöffnet) übersetzt – Ganzzahlen, die auf Einträge im Vokabular des Modells verweisen. Diese Tokens werden dann verwendet, um dem Modell Samples zu entnehmen, wodurch eine neue Sequenz von Ausgabe-Tokens entsteht.

Die Ausgabe-Tokens werden anschließend wieder in Text übersetzt, der zur Antwort des Modells wird. Da Tokens schrittweise erzeugt werden, kann diese Übersetzung bereits während der Laufzeit des Modells erfolgen – deshalb zeigen viele LLM-basierte Anwendungen Streaming-Ausgaben an. In der Praxis ist die Inferenz meist hinter einer API gekapselt, die auf Textebene arbeitet und die Details der Tokenisierung abstrahiert.

Als Ergebnis des Inferenzschritts tut das Modell entweder (1) eine finale Antwort auf die ursprüngliche Benutzereingabe ausgeben oder (2) einen Tool-Aufruf anfordern, den der Agent ausführen soll (z. B. „führe ls aus und melde die Ausgabe“). Im Fall von (2) führt der Agent den Tool-Aufruf aus und hängt dessen Ausgabe an den ursprünglichen Prompt an. Diese Ausgabe wird verwendet, um eine neue Eingabe zu erzeugen, mit der das Modell erneut abgefragt wird; der Agent kann diese neuen Informationen dann berücksichtigen und es erneut versuchen.

Dieser Prozess wiederholt sich, bis das Modell keine Tool-Aufrufe mehr ausgibt, sondern stattdessen eine Nachricht für den Benutzer erzeugt (bei OpenAI-Modellen als Assistentennachricht bezeichnet). In vielen Fällen beantwortet diese Nachricht direkt die ursprüngliche Anfrage des Benutzers, sie kann aber auch eine Rückfrage an den Benutzer sein.

Da der Agent Tool-Aufrufe ausführen kann, die die lokale Umgebung verändern, ist seine „Ausgabe“ nicht auf die Assistentennachricht beschränkt. In vielen Fällen ist die eigentliche Hauptausgabe eines Software-Agenten der Code, den er auf deinem Rechner schreibt oder bearbeitet. Dennoch endet jede Runde immer mit einer Assistentennachricht – etwa „Ich habe die architecture.md hinzugefügt, um die du gebeten hast“ – die einen Endzustand in der Agent-Schleife signalisiert. Aus Sicht des Agenten ist seine Arbeit damit abgeschlossen und die Kontrolle geht zurück an den Benutzer.

Der Weg von der Benutzereingabe zur Agentenantwort, der im Diagramm dargestellt ist, wird als eine Runde eines Gesprächs (ein Thread in Codex) bezeichnet, wobei diese Gesprächsrunde viele Iterationen zwischen Modellinferenz und Tool-Aufrufen enthalten kann. Jedes Mal, wenn du eine neue Nachricht an ein bestehendes Gespräch sendest, wird der bisherige Gesprächsverlauf als Teil des Prompts für die neue Runde eingebunden, einschließlich der Nachrichten und Tool-Aufrufe aus vorherigen Runden:

Diagramm mit dem Titel „Multi-Runden-Agent-Schleife, das zeigt, wie ein KI-Agent iterativ Benutzereingaben entgegennimmt, Aktionen generiert, Tools konsultiert, den Zustand aktualisiert und Ergebnisse zurückgibt. Enthält beschriftete Schritte, Pfeile und Beispiel-Tool-Ausgaben, die den Reasoning-Zyklus des Agenten veranschaulichen.

Das bedeutet, dass mit wachsender Konversation auch die Länge des Prompts wächst, der zum Sampling des Modells verwendet wird. Diese Länge ist relevant, da jedes Modell über ein Kontextfenster verfügt – die maximale Anzahl von Tokens, die es in einem einzelnen Inferenzaufruf verwenden kann. Dieses Fenster umfasst sowohl Eingabe- als auch Ausgabetokens. Wie du dir vorstellen kannst, könnte ein Agent in einer einzigen Runde Hunderte von Tool-Aufrufen ausführen und damit potenziell das Kontextfenster ausschöpfen. Aus diesem Grund ist das Management des Kontextfensters eine der vielen Aufgaben des Agenten. Jetzt tauchen wir tiefer ein und schauen uns an, wie Codex die Agent-Schleife ausführt.

Modellinferenz

Die Codex CLI sendet HTTP-Anfragen an die Responses API(wird in einem neuen Fenster geöffnet), um die Modellinferenz auszuführen. Wir werden untersuchen, wie Informationen durch Codex fließen, das die Responses API nutzt, um die Agent-Schleife zu steuern.

Der Responses-API-Endpunkt, den die Codex CLI verwendet, ist konfigurierbar(wird in einem neuen Fenster geöffnet) und kann daher mit jedem Endpunkt genutzt werden, der die Responses API implementiert(wird in einem neuen Fenster geöffnet):

Schauen wir uns an, wie Codex den Prompt für den ersten Inferenzaufruf in einer Konversation erstellt.

Erstellung des initialen Prompts

Als Endbenutzer gibst du den Prompt, der zum Sampling des Modells verwendet wird, beim Abfragen der Responses API nicht wortwörtlich vor. Stattdessen gibst du verschiedene Eingabetypen als Teil deiner Anfrage an, und der Responses-API-Server entscheidet, wie diese Informationen zu einem Prompt strukturiert werden, der für das Modell vorgesehen ist. Du kannst dir den Prompt als eine „Liste von Elementen“ vorstellen; in diesem Abschnitt wird erklärt, wie deine Anfrage in diese Liste umgewandelt wird.

Im initialen Prompt ist jedes Element der Liste einer Rolle (role) zugeordnet. Die role gibt an, wie viel Gewicht der zugehörige Inhalt haben soll, und ist einer der folgenden Werte (in absteigender Priorität): system, developer, user, assistant.

Die Responses API(wird in einem neuen Fenster geöffnet) akzeptiert einen JSON-Payload mit vielen Parametern. Wir konzentrieren uns auf diese drei:

In Codex wird das Feld instructions aus der model_instructions_file(wird in einem neuen Fenster geöffnet) in ~/.codex/config.toml gelesen, sofern angegeben; andernfalls werden die einem Modell zugeordneten base_instructions verwendet(wird in einem neuen Fenster geöffnet). Modellspezifische Anweisungen liegen im Codex-Repository und werden in die CLI gebündelt (z. B. gpt-5.2-codex_prompt.md(wird in einem neuen Fenster geöffnet)).

Das Feld tools ist eine Liste von Tool-Definitionen, die einem von der Responses API definierten Schema entsprechen. Für Codex umfasst dies Tools, die von der Codex CLI bereitgestellt werden, Tools, die von der Responses API bereitgestellt werden und Codex zur Verfügung stehen sollen, sowie Tools, die vom Benutzer bereitgestellt werden, meist über MCP-Server.

JavaScript

1
[
2
// Codex's default shell tool for spawning new processes locally.
3
{
4
"type": "function",
5
"name": "shell",
6
"description": "Runs a shell command and returns its output...",
7
"strict": false,
8
"parameters": {
9
"type": "object",
10
"properties": {
11
"command": {"type": "array", "description": "The command to execute", ...},
12
"workdir": {"description": "The working directory...", ...},
13
"timeout_ms": {"description": "The timeout for the command...", ...},
14
...
15
},
16
"required": ["command"],
17
}
18
}
19

20
// Codex's built-in plan tool.
21
{
22
"type": "function",
23
"name": "update_plan",
24
"description": "Updates the task plan...",
25
"strict": false,
26
"parameters": {
27
"type": "object",
28
"properties": {"plan":..., "explanation":...},
29
"required": ["plan"]
30
}
31
},
32

33
// Web search tool provided by the Responses API.
34
{
35
"type": "web_search",
36
"external_web_access": false
37
},
38

39
// MCP server for getting weather as configured in the
40
// user's ~/.codex/config.toml.
41
{
42
"type": "function",
43
"name": "mcp__weather__get-forecast",
44
"description": "Get weather alerts for a US state",
45
"strict": false,
46
"parameters": {
47
"type": "object",
48
"properties": {"latitude": {...}, "longitude": {...}},
49
"required": ["latitude", "longitude"]
50
}
51
}
52
]

Schließlich ist das input-Feld des JSON-Payloads eine Liste von Elementen. Codex fügt die folgenden Elemente(wird in einem neuen Fenster geöffnet) vor dem Hinzufügen der Benutzernachricht in input hinzu:

1. Eine Nachricht mit role=developer, die die Sandbox beschreibt, die ausschließlich für das in dem tools-Abschnitt definierte, von Codex bereitgestellte shell-Tool gilt. Das heißt, andere Tools, etwa solche aus MCP-Servern, werden von Codex nicht in einer Sandbox ausgeführt und sind selbst dafür verantwortlich, ihre eigenen Schutzmechanismen durchzusetzen.

Diese Nachricht wird aus einer Vorlage erzeugt, bei der die zentralen Inhalte aus in die Codex CLI gebündelten Markdown-Snippets stammen, etwa workspace_write.md(wird in einem neuen Fenster geöffnet) und on_request.md(wird in einem neuen Fenster geöffnet).

Reiner Text

1
<permissions instructions>
2
- description of the sandbox explaining file permissions and network access
3
- instructions for when to ask the user for permissions to run a shell command
4
- list of folders writable by Codex, if any
5
</permissions instructions>

2. (Optional) Eine Nachricht mit role=developer, deren Inhalt dem Wert developer_instructions entspricht, der aus der config.toml-Datei des Benutzers gelesen wird.

3. (Optional) Eine Nachricht mit role=user, deren Inhalt die „User Instructions“ sind. Diese stammen nicht aus einer einzelnen Datei, sondern werden aus mehreren Quellen aggregiert(wird in einem neuen Fenster geöffnet). In der Regel erscheinen spezifischere Anweisungen weiter hinten:

4. Eine Nachricht mit role=user, die die lokale Umgebung beschreibt, in der der Agent aktuell arbeitet. Das legt das aktuelle Arbeitsverzeichnis und die Benutzer-Shell fest(wird in einem neuen Fenster geöffnet):

Reiner Text

1
<environment_context>
2
<cwd>/Users/mbolin/code/codex5</cwd>
3
<shell>zsh</shell>
4
</environment_context>

Sobald Codex alle oben genannten Berechnungen zur Initialisierung der Eingabe abgeschlossen hat, fügt es die Benutzernachricht hinzu, um die Konversation zu beginnen.

Die vorherigen Beispiele haben sich auf den Inhalt jeder Nachricht konzentriert, aber beachte, dass jedes Eingabe-Element ein JSON-Objekt mit type, role(wird in einem neuen Fenster geöffnet) und content ist, wie folgt:

JSON

1
{
2
"type": "message",
3
"role": "user",
4
"content": [
5
{
6
"type": "input_text",
7
"text": "Add an architecture diagram to the README.md"
8
}
9
]
10
}

Sobald Codex den vollständigen JSON-Payload für die Weiterleitung an die Responses API aufgebaut hat, stellt es die HTTP-POST-Anfrage mit einem Authorization-Header, abhängig davon, wie der Responses-API-Endpunkt in ~/.codex/config.toml konfiguriert ist (zusätzliche HTTP-Header und Query-Parameter werden hinzugefügt, falls angegeben).

Wenn ein OpenAI-Responses-API-Server die Anfrage erhält, verwendet er das JSON, um daraus den Prompt für das Modell abzuleiten, wie folgt (zur Klarstellung: eine benutzerdefinierte Implementierung der Responses API könnte hier eine andere Entscheidung treffen):

Snapshot-Diagramm, das einen einzelnen Schritt in einer KI-Agent-Schleife zeigt. Eine Benutzeranfrage gelangt in das Modell, das einen Gedanken, eine Aktion mit einem Tool-Namen und eine Tool-Eingabe erzeugt. Das Diagramm hebt diesen Zwischenschritt des Reasonings hervor, bevor das Tool aufgerufen wird.

Wie man sehen kann, wird die Reihenfolge der ersten drei Elemente im Prompt vom Server bestimmt, nicht vom Client. Allerdings wird von diesen drei Elementen nur der Inhalt der Systemnachricht ebenfalls vom Server kontrolliert, da die Tools und Anweisungen vom Client festgelegt werden. Darauf folgt die Eingabe aus dem JSON-Payload, um den Prompt zu vervollständigen.

Jetzt, da wir unseren Prompt haben, sind wir bereit, dem Modell Samples zu entnehmen.

Die erste Runde

Diese HTTP-Anfrage an die Responses API initiiert die erste „Runde“ einer Konversation in Codex. Der Server antwortet mit einem Server-Sent-Events-(SSE(wird in einem neuen Fenster geöffnet)-)Stream. Die Daten jedes Events sind ein JSON-Payload mit einem „type“, der mit „response“ beginnt, zum Beispiel so (eine vollständige Liste der Events findet sich in unserer API-Dokumentation(wird in einem neuen Fenster geöffnet)):

Reiner Text

1
data: {"type":"response.reasoning_summary_text.delta","delta":"ah ", ...}
2
data: {"type":"response.reasoning_summary_text.delta","delta":"ha!", ...}
3
data: {"type":"response.reasoning_summary_text.done", "item_id":...}
4
data: {"type":"response.output_item.added", "item":{...}}
5
data: {"type":"response.output_text.delta", "delta":"forty-", ...}
6
data: {"type":"response.output_text.delta", "delta":"two!", ...}
7
data: {"type":"response.completed","response":{...}}

Codex verarbeitet den Event-Stream(wird in einem neuen Fenster geöffnet) und veröffentlicht ihn erneut als interne Event-Objekte, die von einem Client verwendet werden können. Events wie response.output_text.delta werden genutzt, um Streaming in der UI zu unterstützen, während andere Events wie response.output_item.added in Objekte umgewandelt werden, die an die Eingabe für nachfolgende Responses-API-Aufrufe angehängt werden.

Angenommen, die erste Anfrage an die Responses API enthält zwei response.output_item.done-Events: eines mit type=reasoning und eines mit type=function_call. Diese Events müssen im input-Feld des JSON repräsentiert sein, wenn wir das Modell erneut abfragen, zusammen mit der Antwort auf den Tool-Aufruf: 

JavaScript

1
[
2
/* ... original 5 items from the input array ... */
3
{
4
"type": "reasoning",
5
"summary": [
6
"type": "summary_text",
7
"text": "**Adding an architecture diagram for README.md**\n\nI need to..."
8
],
9
"encrypted_content": "gAAAAABpaDWNMxMeLw..."
10
},
11
{
12
"type": "function_call",
13
"name": "shell",
14
"arguments": "{\"command\":\"cat README.md\",\"workdir\":\"/Users/mbolin/code/codex5\"}",
15
"call_id": "call_8675309..."
16
},
17
{
18
"type": "function_call_output",
19
"call_id": "call_8675309...",
20
"output": "<p align=\"center\"><code>npm i -g @openai/codex</code>..."
21
}
22
]

Der resultierende Prompt, der zum Entnehmen von Samples aus dem Modell im Rahmen der nachfolgenden Abfrage verwendet wird, würde so aussehen:

Diagramm mit der Beschriftung „Snapshot 2“, das einen KI-Agenten nach einem Tool-Aufruf zeigt. Das Modell empfängt eine Tool-Beobachtung und erzeugt einen neuen Gedanken und eine neue Aktion. Pfeile verbinden Eingaben, Beobachtungen und Ausgaben und verdeutlichen, wie der Agent seine Reasoning-Schleife iteriert.

Insbesondere ist zu beachten, dass der alte Prompt ein exaktes Präfix des neuen Prompts ist. Das ist beabsichtigt, da nachfolgende Anfragen dadurch deutlich effizienter werden, weil wir Prompt-Caching nutzen können (darauf gehen wir im nächsten Abschnitt zur Performance ein).

Wenn wir auf unser erstes Diagramm der Agent-Schleife zurückblicken, sehen wir, dass es viele Iterationen zwischen Inferenz und Tool-Aufrufen geben kann. Der Prompt kann weiter anwachsen, bis wir schließlich eine Assistentennachricht erhalten, die das Ende der Runde signalisiert:

Reiner Text

1
data: {"type":"response.output_text.done","text": "I added a diagram to explain...", ...}
2
data: {"type":"response.completed","response":{...}}

In der Codex-CLI präsentieren wir dem Benutzer die Assistentennachricht und fokussieren das Eingabefeld, um anzuzeigen, dass nun seine „Runde“ ist, die Konversation fortzusetzen. Wenn der Benutzer antwortet, müssen sowohl die Assistentennachricht aus der vorherigen Runde als auch die neue Nachricht des Benutzers an die Eingabe in der Responses-API-Anfrage angehängt werden, um die neue Runde zu starten:

JavaScript

1
[
2
/* ... all items from the last Responses API request ... */
3
{
4
"type": "message",
5
"role": "assistant",
6
"content": [
7
{
8
"type": "output_text",
9
"text": "I added a diagram to explain the client/server architecture."
10
}
11
]
12
},
13
{
14
"type": "message",
15
"role": "user",
16
"content": [
17
{
18
"type": "input_text",
19
"text": "That's not bad, but the diagram is missing the bike shed."
20
}
21
]
22
}
23
]

Erneut gilt: Da wir eine Konversation fortsetzen, wächst die Länge der Eingabe, die wir an die Responses API senden, weiter an:

Diagramm mit der Beschriftung „Snapshot 3“, das die letzte Phase einer KI-Agent-Schleife zeigt. Nach dem Empfang der Tool-Ergebnisse erzeugt das Modell einen abschließenden Gedanken und eine finale Antwort, die an den Benutzer zurückgegeben wird. Pfeile veranschaulichen den Übergang von der Tool-Ausgabe zur fertigen Antwort.

Untersuchen wir, was dieser immer weiter wachsende Prompt für die Performance bedeutet.

Überlegungen zur Performance

Vielleicht fragst du dich: „Moment mal, ist die Agent-Schleife nicht quadratisch in Bezug auf die Menge an JSON, die im Verlauf der Konversation an die Responses API gesendet wird?“ Und damit hast du recht. Zwar unterstützt die Responses API einen optionalen Parameter previous_response_id(wird in einem neuen Fenster geöffnet), um dieses Problem abzumildern, Codex nutzt ihn derzeit jedoch nicht – vor allem, um Anfragen vollständig zustandslos zu halten und Zero-Data-Retention-(ZDR-)Konfigurationen (Konfigurationen ohne Datenaufbewahrung) zu unterstützen.

Der Verzicht auf previous_response_id vereinfacht die Dinge für den Anbieter der Responses API, da dadurch sichergestellt ist, dass jede Anfrage zustandslos ist. Das erleichtert auch die Unterstützung von Kunden, die „keine Datenaufbewahrung“ (Zero Data Retention, ZDR)(wird in einem neuen Fenster geöffnet) verwenden, da das Speichern der zur Unterstützung von previous_response_id erforderlichen Daten im Widerspruch zu ZDR stünde. ZDR-Kunden müssen dabei nicht auf die Möglichkeit verzichten, von proprietären Reasoning-Nachrichten aus früheren Runden zu profitieren, da das zugehörige encrypted_content serverseitig entschlüsselt werden kann. (OpenAI speichert den Entschlüsselungsschlüssel eines ZDR-Kunden, aber nicht dessen Daten.) Siehe PRs #642(wird in einem neuen Fenster geöffnet) und #1641(wird in einem neuen Fenster geöffnet) für die entsprechenden Änderungen an Codex zur Unterstützung von ZDR.

Im Allgemeinen übersteigen die Kosten für das Sampling des Modells die Kosten für den Netzwerkverkehr deutlich, weshalb Sampling das primäre Ziel unserer Effizienzmaßnahmen ist. Genau deshalb ist Prompt-Caching so wichtig: Es ermöglicht uns, Berechnungen aus einem früheren Inferenzaufruf wiederzuverwenden. Bei Cache-Treffern ist das Sampling des Modells linear statt quadratisch. Unsere Dokumentation zum Prompt-Caching (wird in einem neuen Fenster geöffnet)erklärt das genauer:

Cache-Treffer sind nur bei exakten Präfix-Übereinstimmungen innerhalb eines Prompts möglich. Um Caching-Vorteile zu realisieren, solltest du statische Inhalte wie Anweisungen und Beispiele an den Anfang deines Prompts setzen und variable Inhalte, etwa benutzerspezifische Informationen, ans Ende. Das gilt auch für Bilder und Tools, die zwischen Anfragen identisch sein müssen.

Vor diesem Hintergrund schauen wir uns an, welche Arten von Operationen in Codex einen „Cache Miss“ verursachen können:

  • Ändern der dem Modell zur Verfügung stehenden Tools mitten in der Konversation.
  • Ändern des Modells, das Ziel der Responses-API-Anfrage ist (in der Praxis ändert dies das dritte Element im ursprünglichen Prompt, da es modellspezifische Anweisungen enthält).
  • Ändern der Sandbox-Konfiguration, des Genehmigungsmodus oder des aktuellen Arbeitsverzeichnisses.

Das Codex-Team muss sehr sorgfältig sein, wenn neue Funktionen in der Codex-CLI eingeführt werden, die das Prompt-Caching beeinträchtigen könnten. Ein Beispiel: Unsere erste Unterstützung für MCP-Tools führte einen Programmierfehler ein, bei dem wir die Tools nicht in einer konsistenten Reihenfolge aufgelistet haben(wird in einem neuen Fenster geöffnet), was zu Cache Misses führte. MCP-Tools sind besonders heikel, da MCP-Server die Liste der bereitgestellten Tools dynamisch über eine notifications/tools/list_changed(wird in einem neuen Fenster geöffnet)-Benachrichtigung ändern können. Das Berücksichtigen dieser Benachrichtigung mitten in einer langen Konversation kann einen teuren Cache Miss auslösen.

Wenn möglich, behandeln wir Konfigurationsänderungen, die während einer Konversation auftreten, indem wir der Eingabe eine neue Nachricht hinzufügen, die die Änderung widerspiegelt, statt eine frühere Nachricht zu verändern:

Wir unternehmen große Anstrengungen, um aus Performance-Gründen Cache-Treffer sicherzustellen. Daneben gibt es eine weitere zentrale Ressource, die wir managen müssen: das Kontextfenster.

Unsere allgemeine Strategie, um ein Überlaufen des Kontextfensters zu vermeiden, besteht darin, die Konversation zu verdichten, sobald die Anzahl der Tokens einen bestimmten Schwellenwert überschreitet. Konkret ersetzen wir die Eingabe durch eine neue, kleinere Liste von Elementen, die repräsentativ für die Konversation ist und es dem Agenten ermöglicht, mit einem Verständnis des bisherigen Verlaufs fortzufahren. Eine frühe Implementierung dieser Verdichtung(wird in einem neuen Fenster geöffnet) erforderte, dass der Nutzer den Befehl /compact manuell aufruft, der die Responses API mit der bestehenden Konversation plus individuellen Anweisungen zur Zusammenfassung(wird in einem neuen Fenster geöffnet) abfragt. Codex nutzte anschließend die resultierende Assistentennachricht mit der Zusammenfassung als neue Eingabe(wird in einem neuen Fenster geöffnet) für nachfolgende Konversationsrunden.

Seitdem hat sich die Responses API weiterentwickelt und unterstützt nun einen speziellen /responses/compact-Endpunkt(wird in einem neuen Fenster geöffnet), der die Verdichtung effizienter durchführt. Er gibt eine Liste von Elementen(wird in einem neuen Fenster geöffnet) zurück, die anstelle der vorherigen Eingabe verwendet werden kann, um die Konversation fortzusetzen und zugleich das Kontextfenster freizumachen. Diese Liste enthält einen speziellen type=compaction-Eintrag mit einem opaken encrypted_content-Element, das das latente Verständnis des Modells für die ursprüngliche Konversation bewahrt. Heute nutzt Codex diesen Endpunkt automatisch, um die Konversation zu verdichten, sobald das auto_compact_limit(wird in einem neuen Fenster geöffnet) überschritten wird.

Nächste Schritte

Wir haben die Codex-Agent-Schleife vorgestellt und erläutert, wie Codex beim Abfragen eines Modells seinen Kontext erstellt und verwaltet. Dabei haben wir praktische Überlegungen und Best Practices hervorgehoben, die für jeden relevant sind, der eine Agent-Schleife auf Basis der Responses API entwickelt.

Doch auch wenn die Agent-Schleife das Fundament von Codex bildet, ist sie erst der Anfang. In kommenden Beiträgen werden wir tiefer in die Architektur der CLI eintauchen, untersuchen, wie Tool-Nutzung umgesetzt ist, und uns das Sandbox-Modell von Codex genauer ansehen.

Autor

Michael Bolin

Danksagungen

Besonderer Dank gilt dem gesamten Team, das die Codex CLI entwickelt hat.