OpenAI公式が明かす:Codexがタスクを完了させるまでのステップ

さっき、OpenAI開発者チームがブログ記事を投稿し、Codex CLIの「カーネル」を直接分解しました。

画像

この記事では、ユーザー入力から最終応答までの全プロセスを完全に解説しており、プロンプト構築、モデル推論、ツール呼び出し、コンテキスト管理などの核心的な詳細が含まれています。

画像

AIプログラミングアシスタントの基盤メカニズムを理解したい開発者、独自のAgentシステムを構築しているエンジニア、Codexに興味のあるユーザーにとって、この記事は読む価値があります。

全文以下

Codexにコマンドを送ってから結果が返ってくるまでの間に何が起こっているのか、考えたことがありますか?

各ラウンドの対話は次のプロセスを経ます:入力の組み立て、推論の実行、ツールの実行、結果をコンテキストに戻す

このループはタスクが完了するまで続きます。

これはOpenAIによるCodex技術開示シリーズの第1部であり、OpenAIは今後さらに多くのコンテンツを公開すると約束しています。

Agent Loopとは?

Agent Loop(エージェントループ)はCodex CLIのコアロジックであり、ユーザー、モデル、ツール間の相互作用を調整する役割を担います。

簡単に言えば、プロセスは以下の通りです:

Agent loop diagram
Agent loop diagram

Agentはユーザーの入力を受け取り、モデルへの指示(つまりプロンプト)として組み立てます。

次のステップは推論です:プロンプトをモデルに送信し、応答を生成させます。推論过程中、テキストプロンプトはまず一連のトークン(整数インデックス)に変換され、モデルはこれらのトークンに基づいてサンプリングし、新しいトークンシーケンスを生成します。

出力トークンはテキストに変換され、モデルの応答となります。トークンは1つずつ生成されるため、多くのLLMアプリケーションはストリーミング出力をサポートしています。回答が1文字ずつ表示されるのを見ることができます。

推論後、モデルは(1)最終的な答えを直接出すか、(2)ツール呼び出しの実行を要求します(例:「lsコマンドを実行して結果を教えてください」)。後者の場合、Agentはツールを実行し、出力を元のプロンプトの後ろに連結してから、モデルを再クエリします。

このプロセスはループし続けます。モデルがツール呼び出しを要求せず、ユーザーへのメッセージ(OpenAIの用語ではアシスタントメッセージ)を生成するまで。

このメッセージはユーザーの質問に直接答えていることもあれば、ユーザーに追質問していることもあります。

ユーザー入力からAgent応答までのこのプロセスを1「ラウンド」の対話と呼びます。Codexでは「スレッド」と呼ばれます。

1ラウンドの対話ですが、「モデル推論→ツール呼び出し」の反復が複数回含まれることがあります。

Multi-turn agent loop
Multi-turn agent loop

ユーザーが既存の対話に新しいメッセージを送信するたびに、以前の対話履歴(以前のメッセージとツール呼び出しを含む)は新しいプロンプトの一部となります。

つまり、対話が長ければ長いほど、プロンプトも長くなるということです。

これは非常に重要です。なぜなら、すべてのモデルにはコンテキストウィンドウ(単一の推論で処理できる最大トークン数)があるからです。このウィンドウには入力と出力のトークンの両方が含まれます。

Agentは1回の対話で数百回のツール呼び出しを行うことがあり、簡単にコンテキストを圧倒してしまいます。

したがって、コンテキストウィンドウ管理はAgentの重要な責務の1つです。

モデル推論

Codex CLIはResponses APIにHTTPリクエストを送信してモデル推論を実行します。

Codex CLIが使用するResponses APIエンドポイントは設定可能であるため、Responses APIを実装する任意のエンドポイントと互換性があります:

  • ChatGPTでログインする場合、エンドポイントはhttps://chatgpt.com/backend-api/codex/responsesです

  • APIキーで認証する場合、エンドポイントはhttps://api.openai.com/v1/responsesです

  • --ossパラメータでgpt-ossを実行する場合(ollama 0.13.4+またはLM Studio 0.3.39+と組み合わせて)、デフォルトでローカルのhttp://localhost:11434/v1/responsesを使用します

  • AzureなどのクラウドサービスプロバイダーがホストするResponses APIを使用することもできます

初期プロンプトの構築

ユーザーとして、完全なプロンプトを自分で書く必要はありません。

リクエスト内でさまざまな入力を指定するだけで、Responses APIサーバーがこれらの情報をモデルが理解できるプロンプトにどのように組み立てるかを決定します。

プロンプトを「リスト」として考えることができます。

初期プロンプトの各エントリには役割があり、その内容の重み付けを示します。重みが高い順に、systemdeveloperuserassistantです。

Responses APIが受け付けるJSONには多くのパラメータがありますが、最も重要なのは以下の3つです:

  • instructions:モデルのコンテキストに挿入されるsystem(またはdeveloper)メッセージ

  • tools:モデルが呼び出せるツールのリスト

  • input:モデルに送信されるテキスト、画像、またはファイル入力のリスト

Codexでは、instructionsフィールドは~/.codex/config.toml内のmodel_instructions_fileから来ます。設定されていない場合は、モデルに組み込まれているbase_instructionsを使用します。

異なるモデルの指示ファイルはCLIにパッケージ化されています(例:gpt-5.2-codex_prompt.md)。

toolsフィールドはツール定義のリストであり、Codex CLIに組み込まれたツール、Responses APIが提供するツール、およびユーザーがMCPサーバー経由で設定したツールが含まれます:

[
// ローカルでコマンドを実行するためのCodex組み込みシェルツール
{
"type": "function",
"name": "shell",
"description": "Runs a shell command and returns its output...",
"strict": false,
"parameters": {
"type": "object",
"properties": {
"command": {"type": "array", "description": "The command to execute", ...},
"workdir": {"description": "The working directory...", ...},
"timeout_ms": {"description": "The timeout for the command...", ...},
...
},
"required": ["command"],
}
},

// Codex組み込みの計画ツール
{
"type": "function",
"name": "update_plan",
"description": "Updates the task plan...",
"strict": false,
"parameters": {
"type": "object",
"properties": {"plan":..., "explanation":...},
"required": ["plan"]
}
},

// Responses APIが提供するウェブ検索ツール
{
"type": "web_search",
"external_web_access": false
},

// ユーザー設定のMCPサーバー(例:天気照会)
{
"type": "function",
"name": "mcp__weather__get-forecast",
"description": "Get weather alerts for a US state",
"strict": false,
"parameters": {
"type": "object",
"properties": {"latitude": {...}, "longitude": {...}},
"required": ["latitude", "longitude"]
}
}
]

inputフィールドはエントリのリストです。ユーザーーメッセージを追加する前に、Codexは以下を挿入します:

1. role=developerのメッセージで、サンドボックス環境を説明しますが、Codexに組み込まれたshellツールにのみ適用されます。つまり、MCPサーバーが提供するツールはCodexのサンドボックス保護の対象外であり、独自のセキュリティメカニズムを実装する必要があります。

このメッセージはテンプレートを使用して生成され、コアコンテンツはCLIにパッケージ化されたMarkdownファイル(workspace_write.mdon_request.mdなど)から来ます:

<permissions instructions>
- サンドボックス説明、ファイル権限とネットワークアクセスの解説
- いつシェルコマンド実行のユーザー許可を求めるべきか
- Codが書き込み可能なフォルダのリスト(存在する場合)
</permissions instructions>

2. (オプション)role=developerのメッセージで、ユーザーのconfig.toml内のdeveloper_instructionsの内容です。

3. (オプション)role=userのメッセージ、つまり「ユーザー指示」です。これは単一のファイルではなく、複数のソースから集約されます。より具体的な指示ほど後ろに現れます:

  • $CODEX_HOMEディレクトリ内のAGENTS.override.mdAGENTS.mdの内容

  • Git/プロジェクトルートディレクトリから現在のディレクトリまでの各フォルダで(32 KiBの制限あり)、AGENTS.override.mdAGENTS.md、またはproject_doc_fallback_filenamesで指定されたファイルを検索

  • スキルが設定されている場合:

    • スキルに関する簡単な説明

    • 各スキルのメタデータ

    • スキルの使用方法に関する説明

4. role=userのメッセージで、Agentが現在実行されているローカル環境を説明します。現在の作業ディレクトリとユーザーのシェルが含まれます:

<environment_context>
<cwd>/Users/mbolin/code/codex5</cwd>
<shell>zsh</shell>
</environment_context>

上記の計算が完了すると、Codexはユーザーーメッセージをinputに追加し、対話を開始します。

input要素はJSONオブジェクトであり、typerolecontentを含みます:

{
"type": "message",
"role": "user",
"content": [
{
"type": "input_text",
"text": "Add an architecture diagram to the README.md"
}
]
}

Codexが完全なJSONを構築すると、HTTP POSTリクエストをResponses APIに送信します(Authorizationヘッダーと設定で指定された他のヘッダーおよびパラメータを含む)。

OpenAIのResponses APIサーバーがリクエストを受信すると、JSONからプロンプトを構築します:

Snapshot 1
Snapshot 1

可以看出、最初の3つの項目の順序はサーバーによって決まり、クライアントによって決まりません

ただし、この3つの中では、システムメッセージの内容もサーバーが制御し、toolsinstructionsはクライアントが決定します。その後はJSON内のinputが、完全なプロンプトを構成します。

プロンプトがあれば、モデルをサンプリングできます。

最初の対話ラウンド

Responses APIに送信されるHTTPリクエストにより、Codex対話の最初の「ラウンド」が開始されます。サーバーはServer-Sent Events(SSE)ストリームの形式で応答を返します。各イベントのdataはJSONであり、typeresponseで始まります。以下のような形式です:

data: {"type":"response.reasoning_summary_text.delta","delta":"ah ", ...}
data: {"type":"response.reasoning_summary_text.delta","delta":"ha!", ...}
data: {"type":"response.reasoning_summary_text.done", "item_id":...}
data: {"type":"response.output_item.added", "item":{...}}
data: {"type":"response.output_text.delta", "delta":"forty-", ...}
data: {"type":"response.output_text.delta", "delta":"two!", ...}
data: {"type":"response.completed","response":{...}}

Codexはこれらのイベントストリームを消費し、クライアントで使用する内部イベントオブジェクトとして再公開します。response.output_text.deltaのようなイベントはUIのストリーミング表示をサポートするために使用され、response.output_item.addedのようなイベントはオブジェクトに変換され、後続のResponses API呼び出しのinputに追加されます。

最初のリクエストが2つのresponse.output_item.doneイベントを返したと仮定します:1つはtype=reasoning、もう1つはtype=function_callです。モデルを再クエリする場合、これらのイベントはinputに反映される必要があります:

[
/* ... 元の入力配列の5つのエントリ ... */
{
"type": "reasoning",
"summary": [
{
"type": "summary_text",
"text": "**Adding an architecture diagram for README.md**\n\nI need to..."
}
],
"encrypted_content": "gAAAAABpaDWNMxMeLw..."
},
{
"type": "function_call",
"name": "shell",
"arguments": "{\"command\":\"cat README.md\",\"workdir\":\"/Users/mbolin/code/codex5\"}",
"call_id": "call_8675309..."
},
{
"type": "function_call_output",
"call_id": "call_8675309...",
"output": "<p align=\"center\"><code>npm i -g @openai/codex</code>..."
}
]

後続のクエリのプロンプトは以下のようになります:

Snapshot 2
Snapshot 2

注意してください、古いプロンプトは新しいプロンプトの正確なプレフィックスです。これは意図的な設計であり、後続のリクエストがプロンプトキャッシュを利用できるようにし、効率を大幅に向上させます(後述)。

最初のAgent Loop図に戻ると、推論とツール呼び出しの間に多くの反復が含まれる可能性があります。プロンプトは最終的にアシスタントメッセージを受信するまで増加し続け、このラウンドの終了を示します:

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

Codex CLIでは、アシスタントメッセージをユーザーに表示し、入力ボックスにフォーカスを当て、ユーザーが対話を続行する番であることを示します。ユーザーが返信した場合、前のラウンドのアシスタントメッセージとユーザーの新しいメッセージは、新しいリクエストのinputに追加される必要があります:

[
/* ... 前のResponses APIリクエストのすべてのエントリ ... */
{
"type": "message",
"role": "assistant",
"content": [
{
"type": "output_text",
"text": "I added a diagram to explain the client/server architecture."r> }
]
},
{
"type": "message",
"role": "user",
"content": [
{
"type": "input_text",
"text": "That's not bad, but the diagram is missing the bike shed."r> }
]
}
]

対話を続行しているため、Responses APIに送信されるinputの長さは持続的に増加します:

Snapshot 3
Snapshot 3

パフォーマンスの考慮事項

「待って、このAgent Loopが対話全体で送信するJSON量は2乗級に増加するの?」と疑問に思うかもしれません。

そうです。Responses APIはオプションのprevious_response_idパラメータをサポートしてこの問題を軽減しますが、Codexは現在それを使用していません。主にリクエストを完全にステートレスに保ち、ゼロデータ保持(ZDR)設定をサポートするためです

previous_response_idを使用しないことは、Responses APIプロバイダーの実装を簡素化します。なぜなら、各リクエストがステートレスだからです。これにより、ZDRクライアントのサポートも簡単になります:previous_response_idをサポートするために必要なデータを保存することはZDRと矛盾します。ZDRクライアントは、以前のラウンドの独自推論メッセージから利益を得ることができます。関連するencrypted_contentはサーバー側で復号化できるからです。(OpenAIはZDRクライアントの復号キーを保持しますが、データは保持しません。)

一般的に、モデルをサンプリングするコストはネットワーク伝送コストを大幅に上回るため、サンプリングは効率化の主要なターゲットです。これがプロンプトキャッシュが非常に重要な理由です:これにより、以前の推論呼び出しの計算を再利用できます。

キャッシュがヒットした場合、モデルのサンプリングは2乗級ではなく線形です

OpenAIのプロンプトキャッシュドキュメントは次のように説明しています:

キャッシュヒットはプロンプト内での正確なプレフィックス一致のみに有効です。キャッシュの利益を実現するには、静的コンテンツ(指示や例など)をプロンプトの先頭に、可変コンテンツ(ユーザー固有の情報など)を末尾に配置します。画像やツールも同様で、異なるリクエスト間で完全に一致している必要があります。

これを考慮すると、Codexの「キャッシュミス」を引き起こす可能性のある操作は何でしょうか?

  • 対話の途中で利用可能なtoolsを変更する
  • Responses APIリクエストのターゲットmodelを変更する(これは実際には元のプロンプトの第3項目を変更します。なぜなら、モデル固有の指示が含まれているからです)
  • サンドボックス設定、承認モード、または現在の作業ディレクトリを変更する

Codexチームは、プロンプトキャッシュに影響を与える可能性のある新機能を導入する際には慎重に行う必要があります。例えば、MCPツールを最初にサポートしたときのバグでは、ツール列挙順序の不一致によりキャッシュミスが発生しました。MCPツールは特に厄介です。なぜなら、MCPサーバーはnotifications/tools/list_changed経由でツールリストを動的に変更できるからです。長時間の対話の途中でこの通知に応答すると、高価なキャッシュミスが発生する可能性があります。

可能な限り、私たちは対話の途中での設定変更を処理するために、以前のメッセージを変更するのではなく、inputの後に新しいメッセージを追加します:

  • サンドボックス設定または承認モードが変更された場合、元の<permissions instructions>と同じ形式で新しいrole=developerメッセージを挿入します
  • 現在の作業ディレクトリが変更された場合、元の<environment_context>と同じ形式で新しいrole=userメッセージを挿入します

私たちはパフォーマンスを向上させるためにキャッシュヒットを確保するために最善を尽くします。また、管理する必要があるもう一つの重要なリソースはコンテキストウィンドウです。

コンテキストウィンドウを使い果たさないための一般的な戦略は、トークン数が特定の閾値を超えたら、対話を圧縮することです。具体的には、以前の対話の代わりに、元の対話を表すより小さなエントリリストでinputを置き換え、Agentが発生した内容を理解したまま作業を続行できるようにします。

初期の圧縮実装では、ユーザーが手動で/compactコマンドを実行する必要がありました。このコマンドは、既存の対話とカスタム要約指示を使用してResponses APIをクエリし、返されたアシスタントメッセージを後続の対話ラウンドの新しいinputとして使用します。

後で、Responses APIはより効率的に圧縮を実行するための専用の/responses/compactエンドポイントを進化させました。これは、以前のinputを置き換えて対話を続行し、コンテキストウィンドウを解放できるエントリリストを返します。このリストには、不透明なencrypted_contentを持つ特別なtype=compactionエントリが含まれ、モデルの元の対話に対する暗黙的な理解を保持します。現在、auto_compact_limitを超えると、Codexはこのエンドポイントを使用して自動的に対話を圧縮します。

今後の計画

OpenAIはCodexのAgent Loopを紹介し、Codexがモデルをクエリする際にコンテキストをどのように構築および管理するかを詳細に説明しました。また、Responses API上でAgent Loopを構築するすべての人に適用される実践的な考慮事項とベストプラクティスも共有しました。

Agent LoopはCodexの基盤ですが、これは始まりに過ぎません。後続の記事では、CLIアーキテクチャ、ツール使用の実装、Codexのサンドボックスモデルについて深く掘り下げます。

関連リンク:


分享網址
AINews·AI 新聞聚合平台
© 2026 AINews. All rights reserved.