跳至主要內容
OpenAI

2026年1月23日

工程

展開 Codex 智慧體的運作循環

由技術成員 Michael Bolin 撰寫

載入中…

Codex CLI(在新視窗中開啟) 是我們的跨平台的本機軟體智慧體,旨在安全且高效地在你的機器上運作,同時產出高品質、可靠的軟體變更。自從 4 月首次推出 CLI 以來,我們已學到許多如何打造一流軟體智慧體的知識。為了深入探討這些見解,我們將推出一系列文章,而這是第一篇。我們將在其中探討 Codex 的運作方式的各個面向,以及得之不易的寶貴經驗。(若要更詳細地瞭解 Codex CLI 的建置方式,請查看我們的開源程式碼庫:https://github.com/openai/codex(在新視窗中開啟)。若要深入瞭解,請在 GitHub issue 和拉取要求中查看我們的設計決策詳情。)

首先,我們將聚焦於 智慧體的運作循環,這是 Codex CLI 中的核心邏輯,負責協調使用者、模型和模型呼叫,以執行有意義的軟體工作的工具之間的互動。希望這篇文章能讓你清楚瞭解我們的智慧體 (或「harness」) 在運用 LLM 時所扮演的角色。

開始之前,先快速說明一下術語:在 OpenAI,「Codex」指的是一套軟體智慧體產品,包括 Codex CLI、Codex Cloud 和 Codex VS Code 擴充功能。本文聚焦於 Codex harness,它提供核心智慧體的運作循環與執行邏輯,作為所有 Codex 體驗的基礎,並透過 Codex CLI 呈現出來。為求方便起見,我們將在此交替使用「Codex」和「Codex CLI」。

智慧體的運作循環

每個 AI 智慧體的核心是所謂的「智慧體運作循環」。智慧體運作循環的簡化示意圖如下:

標題為「智慧體的運作循環」的圖表,說明 AI 系統如何處理使用者要求、呼叫工具、觀察結果、更新其計畫,並回傳輸出。箭頭連接步驟,例如使用者輸入、模型推理、工具操作和最終回應。

首先,智慧體會從使用者取得輸入,並將其納入它為模型準備的一組文字指令,該模型稱為提示詞

下一步是傳送指示以查詢模型,並要求它生成回應,這個過程稱為推論。在推理過程中,提示詞會先轉換成一系列的輸入 Token(在新視窗中開啟),即索引到模型詞彙表的整數。然後使用這些 token 來對模型進行採樣,生成新的輸出 token 序列。

輸出 token 會翻譯回文字,成為模型的回應。因為 token 是逐步生成的,所以翻譯可以在模型運行時進行,這就是為什麼許多基於 LLM 的應用程式會顯示串流輸出。在實務中,推論通常封裝在一個對文字進行操作的 API 之後,進而抽象化 Token 化處理的細節。

作為推論步驟的結果,模型會 (1) 對使用者的原始輸入產生的最終回應,或 (2) 要求智慧體預期要執行的工具呼叫 (例如「執行 ls 並回報輸出」)。在 (2) 的情況下,智慧體會執行工具呼叫,並將其輸出附加到原始提示詞。此輸出用來生成新的輸入,以重新查詢模型;智慧體接著可以將這些新的資訊納入考量並再試一次。

這個過程會重複進行,直到模型停止發出工具調用,並改為產生一則給使用者的訊息 (在 OpenAI 模型中稱為助理訊息)。在很多情況下,這則訊息直接回答了使用者的原始要求,但也可能是使用者提出的後續問題。

因為智慧體能執行修改本機環境的工具呼叫,所以其「輸出」不僅限於助理訊息。在許多情況下,軟體智慧體的主要輸出是它在你電腦上撰寫或編輯的程式碼。然而,每一回合總是以一則助理訊息結束,例如「我已新增你要求的 architecture.md」,這表示智慧體運作循環的終止狀態。從智慧體的角度來看,它的工作已完成,控制權回到使用者手中。

如圖所示,從使用者輸入智慧體回應的過程,稱為對話的一個回合(在 Codex 中稱為「對話串」)。不過,這個對話回合可能包含多次在模型推論工具呼叫之間的反覆迭代。每次你向現有對話傳送新訊息時,對話記錄都會包含在新回合的提示詞中,其中包括先前回合中的訊息和工具呼叫:

標題為《多回合智慧體循環》的圖表,顯示 AI 智慧體如何反覆接收使用者輸入、產生動作、諮詢工具、更新狀態,並回傳結果。包含標示步驟、箭頭和範例工具輸出,以說明智慧體的推理循環。

這表示隨著對話的深入,用來對模型進行採樣的提示詞的長度也會增加。這個長度很重要,因為每個模型都有一個 上下文視窗,它是模型在一次推理呼叫中可以使用的最大 Token 數。請注意,此視窗同時包含輸入輸出 token。如你所想像,智慧體可能會在單一回合中決定進行數百次工具呼叫,進而會耗盡上下文視窗。因此,上下文視窗管理是智慧體的眾多職責之一。現在一起來瞧瞧 Codex 如何運行智慧體循環。

模型推理

Codex CLI 會將 HTTP 要求傳送至 Responses API(在新視窗中開啟) 以執行模型推論。我們將探討資訊如何在 Codex 中流動,而 Codex 使用 Responses API 來驅動智慧體的運作循環。

Codex CLI 使用的 Responses API 端點是 可配置的(在新視窗中開啟),因此能與任何實作 Responses API(在新視窗中開啟)的端點一起使用:

一起來探索 Codex 如何在對話中為第一次推理呼叫建立提示詞。

建立初始提示詞

作為終端使用者,在查詢 Responses API 時,你不會逐字指定用來採樣模型的提示詞。相反地,你會在查詢中指定各種輸入類型,而 Responses API 伺服器會決定如何將這些資訊結構化為提示詞,以供模型使用。你可以將提示詞視為「項目清單」;本節將解釋你的查詢如何轉換成該清單。

在初始提示詞中,清單中的每個項目都與一個角色相關聯。role 用來表示相關內容的重要程度,其可取以下其中一種值 (依優先順序由高至低):systemdeveloperuserassistant

Responses API(在新視窗中開啟) 接收包含多個參數的 JSON 承載。我們將重點擺在以下三者:

在 Codex 中, instructions 欄位會從 model_instructions_file(在新視窗中開啟) (位於 ~/.codex/config.toml 中)讀取(若有指定);否則,會使用 base_instructions (在新視窗中開啟)(與模型相關聯的指令)。特定模型的指令位於 Codex 儲存庫中,並隨 CLI 一併打包(例如:gpt-5.2-codex_prompt.md(在新視窗中開啟))。

tool 欄位是工具定義的清單,這些工具定義符合 Responses API 所定義的結構描述。對 Codex 而言,這包括由 Codex CLI 提供的工具、由 Responses API 提供且應提供給 Codex 使用的工具,以及由使用者提供的工具 (通常是透過 MCP 伺服器):

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
]

最後,JSON 承載內容的 input 欄位是一個項目清單。Codex 將下列項目插入(在新視窗中開啟)input 中,然後再新增使用者訊息:

1.一則 role=developer 訊息,用來描述僅適用於 tools 區段中所定義、由 Codex 提供shell 工具之沙箱環境。也就是說,其他工具(例如由 MCP 伺服器提供的工具)不在 Codex 的沙箱範圍內,需自行負責落實各自的防護機制。

訊息是由範本建構而成,關鍵內容來自隨 Codex CLI 一同封裝的 Markdown 片段,例如 workspace_write.md(在新視窗中開啟)on_request.md(在新視窗中開啟)

純文字

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. (選用) 一則 role=developer 的訊息,其內容是從使用者的 config.toml 檔案中讀取的 developer_instructions 值。

3. (選用) 一則 role=user 的訊息,內容為「使用者指示」,這些指示並非來自單一檔案,而是彙整自多個來源(在新視窗中開啟)。一般來說,較具體的指示會在後面出現:

4. 一則 role=user 的訊息,描述智慧體目前運行的本地環境。它指定目前的工作目錄和使用者的 shell(在新視窗中開啟)

純文字

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

一旦 Codex 完成上述所有運算以初始化 input,便會附加使用者訊息以開始對話。

前面的範例著重於每則訊息的內容,但請注意,input 的每個元素都是一個 JSON 物件,包含 typerole(在新視窗中開啟)content,如下所示:

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
}

一旦 Codex 建立好要傳送至 Responses API 的完整 JSON 承載內容後,便會根據 ~/.codex/config.toml 中的 Responses API 端點設定,發出包含 Authorization 標頭的 HTTP POST 要求 (若有指定,則會加入額外的 HTTP 標頭與查詢參數)。

OpenAI Responses API 伺服器收到要求時,會使用 JSON 來推導出模型的提示詞,如下所示 (為求嚴謹,Responses API 的自訂實作可能會採用不同的方法):

快照圖顯示 AI 智慧體循環中的一個步驟。使用者要求進入模型,模型會產生一個想法、一個動作 (包含工具名稱),以及一個工具輸入。此圖突顯了呼叫工具之前的中間推理步驟。

如你所見,提示詞中前三個項目的順序是由伺服器 (而非用戶端) 決定。也就是說,在這三項中,只有系統訊息的內容也由伺服器控制,因為 toolsinstructions 是由用戶端決定的。接著會使用 JSON 承載內容中的 input 來完成提示詞。

既然已經有了提示詞,就可以開始對模型進行採樣。

第一回合

此 HTTP 要求會向 Responses API 發出,並在 Codex 中啟動對話的第「回合」。伺服器會以 Server-Sent Events (SSE(在新視窗中開啟)) 串流回應。每個事件的 data 是一個 JSON 承載內容,具有一個以 「response」 開頭的 「type」,可能會像這樣 (完整事件清單請見我們的 API 文件(在新視窗中開啟)):

純文字

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 接收事件串流(在新視窗中開啟)並將其重新發布為可供用戶端使用的內部事件物件。像 response.output_text.delta 這類事件用於支援 UI 中的串流,而其他像 response.output_item.added 這類事件則會轉換為物件,並附加到 input 中,以供後續的 Response API 呼叫使用。

假設對 Responses API 的第一個要求包含兩個 response.output_item.done 事件:一個是 type=reasoning,另一個是 type=function_call。當我們使用工具呼叫的回應再次查詢模型時,這些事件必須在 JSON 的 input 欄位中呈現: 

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
]

用來在後續查詢中採樣模型的提示詞如下:

標示為「Snapshot 2」的圖表,顯示工具呼叫後的 AI 智慧體。此模型接收工具觀察結果,並產生新的想法和行動。箭頭連接輸入、觀察和輸出,以說明智慧體如何反覆執行其推理循環。

特別注意,舊的提示詞是新提示詞的精確前綴。這是有意為之,因為這樣能讓後續要求更有效率,讓我們能夠利用提示詞快取 (我們會在下一節的效能區段討論)。

回顧第一張智慧體運作循環,可以看到推論與工具呼叫之間可能會有多次反覆。提示詞可能會持續增長,直到我們最終收到一則助理訊息,表示回合結束:

純文字

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

在 Codex CLI 中,我們會向使用者呈現助理訊息,並將焦點移至編輯器,以向使用者表示現在輪到他們的「回合」繼續對話。如果使用者回覆,必須將上一回合的助理訊息和使用者的新訊息附加到 Responses API 要求中的 input,以開始新的回合:

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
]

再次重申,由於我們正在延續對話,傳送到 Responses API 的 input 不斷增長:

標示為「Snapshot 3」的圖表,顯示 AI 智慧體運作循環的最終階段。在收到工具結果後,模型會生成總結性想法和最終答案,然後回傳給使用者。箭頭表示從工具輸出到完成回應的過渡過程。

一同檢視這個不斷成長的提示詞對效能有何影響。

效能考量

你可能會問自己:「等等,整段對話中傳送到 Responses API 的 JSON 數量,難道不會讓智慧體運作循環呈現二次方的成長嗎?」你是對的。雖然 Responses API 確實支援選用的 previous_response_id(在新視窗中開啟) 參數來緩解此問題,但 Codex 目前尚未使用它,主要是為了讓要求完全無狀態,並支援零資料保留 (ZDR) 設定。

避免使用 previous_response_id 可以簡化 Responses API 提供者的工作,因為這確保了每個要求都是無狀態的。這也讓支援選擇加入零資料保留 (ZDR)(在新視窗中開啟) 的客戶變得更為簡單,因為儲存支援 previous_response_id 所需的資料會與 ZDR 的原則相牴觸。請注意,ZDR 客戶不會犧牲從先前回合的專有推理訊息中受益的能力,因為相關的 encrypted_content 可以在伺服器上解密。(OpenAI 會保留 ZDR 客戶的解密金鑰,但不會保留他們的資料。)查看 PR #642(在新視窗中開啟)#1641(在新視窗中開啟),瞭解 Codex 為支援 ZDR 所做的相關變更。

一般來說,模型採樣的成本通常超過網路流量的成本,因此採樣成為我們提高效率的主要目標。這就是為什麼提示詞快取如此重要,因為它讓我們重複使用先前推論呼叫的運算。快取命中時,對模型進行採樣是線性的,而不是二次方的。我們的提示詞快取(在新視窗中開啟)說明文件對此有更詳細的說明:

快取命中只可能在提示詞內進行精確前綴比對時發生。為了實現快取效益,將指令和範例等靜態內容放在提示詞的開頭,並將可變內容 (例如使用者特定資訊) 放在最後。這也適用於圖片和工具,它們在不同的要求中必須完全相同。

考量到這一點,我們來探討在 Codex 中,哪些操作類型可能會導致「快取未命中」:

  • 在對話進行中途變更模型可用的 tool
  • 變更作為 Responses API 要求目標的 模型 (實際上,這會變更原始提示詞中的第三項,因為其中包含模型特定的指示)。
  • 變更沙箱設定、核准模式或目前工作目錄。

Codex 團隊在 Codex CLI 中導入可能危及提示詞快取的新功能時,必須保持謹慎。舉例來說,我們最初對 MCP 工具的支援引入了一個錯誤:我們未能以一致的順序列舉工具(在新視窗中開啟),導致快取未命中。請注意,MCP 工具可能特別棘手,因為 MCP 伺服器可以透過 notifications/tools/list_changed(在新視窗中開啟) 通知,隨時變更其提供的工具清單。在一段冗長對話進行到一半時處理此通知,可能會導致昂貴的快取未命中。

在可能的情況下,當對話中途發生設定變更時,我們會將一則訊息附加到 input,以反映該變更,而不是修改先前的訊息:

  • 如果沙箱設定或核准模式變更,我們會插入(在新視窗中開啟)一則新的 role=developer 訊息,其格式與原始 <permissions instructions> 項目相同。
  • 如果目前的工作目錄變更,我們會插入(在新視窗中開啟)一則新的 role=user 訊息,格式與原始 <environment_context> 相同。

我們竭盡所能確保快取命中,以提升效能。我們也必須管理另一項關鍵資源:上下文視窗。

我們的一般策略是當 token 數量超過某個門檻時,將對話壓縮,以避免耗盡上下文視窗。具體而言,我們將 input 替換為一個新的、更精簡的項目清單,該清單代表對話內容,使智慧體在理解目前為止發生的事情的情況下繼續進行。早期的壓縮實作(在新視窗中開啟)需要使用者手動執行 /compact 命令,該命令會使用現有對話和自訂指令來查詢 Responses API 以進行總結(在新視窗中開啟)。Codex 使用包含摘要的結果助理訊息 作為新的 輸入(在新視窗中開啟),用於後續的對話回合。

從那時起,Responses API 已演進以支援一個特殊的 /responses/compact 端點(在新視窗中開啟),更有效率地執行壓縮。它會傳回項目清單(在新視窗中開啟),可用來取代先前的 input,以繼續對話,同時釋放上下文視窗。此清單包含一個特殊的 type=compaction 項目,以及一個不透明的 encrypted_content 項目,保留模型對原始對話的潛在理解。現在,當超出 auto_compact_limit(在新視窗中開啟) 時,Codex 會自動使用此端點來壓縮對話。

即將到來

我們已經介紹了 Codex 智慧體運作循環,並詳細說明 Codex 在查詢模型時如何建構及管理其上下文。在此過程中,我們強調了適用於任何在 Responses API 上建置智慧體運作循環的人的實務考量與最佳做法。

雖然智慧體運作循環為 Codex 奠定了基礎,但這僅是個開端。在接下來的文章中,我們將深入探討 CLI 的架構,探索工具使用的實作方式,並更仔細地研究 Codex 的沙箱模型。

作者

Michael Bolin

致謝辭

特別感謝打造 Codex CLI 的整個團隊。