Series: AI Agent 實戰 (1/3)
- A single conversation turn runs dozens of 'inference → tool call → feed the result back into the prompt' loops behind the scenes; the user only sees the final result.
- The payload sent to the Responses API has three layers: Instructions (static system directives), Tools (JSON-schema tool definitions), and Input (conversation history). Static content goes first so it can benefit from the prompt cache.
- The key to letting an agent run for a long time is context management: auto compaction squeezes history into an encrypted summary as it approaches the limit, and the prompt cache turns quadratic growth into linear growth.
Table of Contents
Most people using the Codex CLI only see “type a sentence, and then code appears.” But during that process, the agent loop has actually run dozens of inferences and tool calls. OpenAI’s Michael Bolin wrote a piece titled Unrolling the Codex agent loop that fully opens up this black box. Below is a summary of the core content.
What Is the Agent Loop
At the core of every AI agent is a loop:
- Receive user input
- Assemble the prompt (including instructions, tool definitions, and conversation history)
- Send it to the model for inference
- The model returns a result — which may be a tool call, or it may be a final reply
- If it’s a tool call: execute the tool, append the result to the prompt, and go back to step 3
- If it’s a final reply: the loop ends, and we wait for the next user input
One of Bolin’s key points is: the agent’s “output” is not just the assistant message. For a coding agent, the truly valuable output is the code it writes or modifies on the local machine; the assistant message at the end of each turn is merely a signal marking “this round is done.”
flowchart TD
A[用戶輸入] --> B[組建 Prompt]
B --> C[模型推理 Inference]
C --> D{回傳類型?}
D -- 工具呼叫 --> E[本機執行工具]
E --> F[把結果附加到 Prompt]
F --> C
D -- 最終回覆 --> G[回傳給用戶]
G --> A
A single “conversation turn” can contain dozens of inference-tool loops; what the user sees is only the final result.
The Three-Layer Structure of the Prompt
The payload Codex sends to the Responses API has three core fields:
Instructions: Comes from ~/.codex/config.toml or a model-specific built-in config file; these are static system-level directives.
Tools: Codex’s built-in tools (shell execution, file operations) + the Responses API’s native tools + tools the user mounts via MCP. Tool definitions are JSON schemas that the model uses to decide when and how to call a tool.
Input: The conversation history, including system, developer, user, and assistant role messages, along with the current sandbox permissions and project context.
After the API server receives the payload, it rearranges it into the final structure: system message → tool definitions → instructions → input messages. This ordering has a direct impact on the prompt cache hit rate (more on that below).
How Tokens Flow
The inference process is essentially a translation:
文字 prompt → 輸入 tokens → 模型取樣 → 輸出 tokens → 文字
Because tokens are generated one at a time, the output can be streamed back — which is why LLM applications usually show a “typewriter effect.” Each model has a fixed context window — the total cap on input plus output tokens — and this limit is one of the most important constraints in agent loop design.
Context Window Management: Auto Compaction
As the conversation grows, the accumulated tokens approach the context window cap. Codex’s solution is auto compaction:
- Trigger condition: The
auto_compact_limitsetting; once token usage exceeds the threshold, compaction triggers automatically. - Compaction endpoint: A dedicated
/responses/compactendpoint that returns summary items which can directly replace the history. - Encrypted storage: The compaction result is stored as an item with
type=compaction. The model’s “latent understanding” is preserved, but the original messages no longer occupy the context.
This design also supports Zero Data Retention (ZDR) customers: because the model is requested statelessly, the server doesn’t need to persist the original conversation, and the encrypted compaction item can still carry the model’s reasoning forward.
flowchart LR
A[對話歷史累積] --> B{token 用量 > auto_compact_limit?}
B -- 否 --> C[繼續 loop]
B -- 是 --> D[呼叫 /responses/compact]
D --> E[加密 compaction item]
E --> F["替換歷史,釋放空間"]
F --> C
Prompt Cache Optimization
Every inference has to send the entire prompt. If the server can reuse the portions it computed before (a prompt cache hit), you can compress quadratic growth down to linear growth. Codex’s optimization strategies:
Put static content first: Instructions, tool definitions, sandbox settings — these unchanging things go at the start of the prompt so they can be cached.
MCP tool ordering: If the order in which an MCP server enumerates tools is nondeterministic, it differs every time, causing every request to be a cache miss. Codex solves this by enforcing a consistent tool ordering — an easily overlooked but highly impactful detail.
Effect: “Even though the request payload grows at a quadratic rate, model sampling can still stay in linear time.”
Overall
The core of the Codex agent loop design is a few mutually balancing tradeoffs:
- autonomy vs. safety: IDE integration allows continuous adjustment from “Q&A mode” to “fully autonomous execution.”
- stateless vs. continuity: Stateless requests satisfy compliance needs, while encrypted compaction preserves reasoning continuity.
- context depth vs. cost: Auto compaction makes long conversations feasible, and the prompt cache makes them affordable.
For anyone wanting to build their own coding agent, the most valuable part of this article isn’t “how Codex is implemented,” but the reasons behind these design decisions — context management is not an optional feature; it’s a necessary condition for letting an agent run for more than a few minutes.
References
Answers come from this article only. Click any prompt below or open the chat at the bottom right.
🇺🇸 English
Most people who use the Codex CLI experience it as something almost magical: you type a sentence, and code appears. But in the gap between your sentence and that code, something far busier is happening. The agent has quietly run dozens of inferences and tool calls. OpenAI's Michael Bolin wrote a piece called "Unrolling the Codex agent loop" that pries open this black box, and it's genuinely worth understanding — whether you use Codex or want to build something like it yourself.
So let's start with the heart of it: the agent loop. Every AI agent, underneath all the polish, is running a loop. It receives your input. It assembles a prompt — and that prompt isn't just your words, it bundles in the system instructions, the definitions of every tool the agent can use, and the conversation history so far. Then it sends all of that to the model for inference. The model returns something, and that something is one of two things. Either it's a tool call — meaning the model wants to run a shell command or edit a file — or it's a final reply. If it's a tool call, the agent executes the tool locally, takes the result, appends it back onto the prompt, and loops right back to ask the model again. If it's a final reply, the loop stops and waits for your next message.
Now here's one of Bolin's sharpest points, and it reframes how you should think about these agents. The agent's real output is not the message it writes back to you. For a coding agent, the valuable output is the code — the files it created or changed on your machine. That chatty assistant message at the end? That's just a signal. It's the agent saying "okay, this round is done." The work lives on disk, not in the text.
And that's why a single conversation turn — one sentence from you — can hide dozens of these inference-and-tool cycles. You see the final result. The loop saw everything in between.
Let's go a layer deeper into that prompt, because Codex structures it in three parts. First, the instructions — these come from your config file or a model-specific built-in config, and they're the static, system-level directives that set the ground rules. Second, the tools — and this is a rich set: Codex's own built-in tools like shell execution and file operations, plus the Responses API's native tools, plus anything you've mounted yourself through MCP. Each tool is described as a JSON schema, which is how the model knows when a tool exists and how to call it. And third, the input — the actual conversation history across all the roles: system, developer, user, assistant, along with the current sandbox permissions and project context.
Here's a detail that matters more than you'd guess. When the API server receives this payload, it reorders everything into a final structure: system message first, then tool definitions, then instructions, then the input messages. That ordering isn't cosmetic — it directly affects how well the prompt cache works, and we'll come back to why.
Now, how does the model actually turn that prompt into output? Think of inference as translation. Your text prompt becomes input tokens. The model samples, producing output tokens one at a time. Those tokens get turned back into text. And because they're generated one at a time, they can be streamed straight back to you — that's the typewriter effect you see in basically every LLM app. But there's a hard constraint hiding here: the context window. Every model has a fixed ceiling on the total number of tokens — input plus output combined. And that ceiling shapes everything about how you design an agent loop.
Which brings us to the problem that defines long conversations. As you keep talking, the tokens pile up, and you start creeping toward that context window cap. Codex handles this with something called auto compaction. The trigger is a setting — once your token usage crosses a defined threshold, compaction fires automatically. It calls a dedicated compaction endpoint, which returns summary items that can directly replace the bloated history. And the clever part: the result is stored as an encrypted compaction item. The model's understanding — its sense of what's been going on — is preserved, but the original raw messages stop eating your context.
This design has a nice secondary benefit. It supports Zero Data Retention customers — companies that, for compliance reasons, don't want their conversations stored on the server. Because Codex makes its requests statelessly, the server never needs to hold onto your original conversation. The encrypted compaction item carries the model's reasoning forward on its own. Compliance and continuity, at the same time.
Now let's talk about cost, because this is where a quiet optimization saves enormous amounts of compute. Remember: every single inference has to send the entire prompt. So as the conversation grows, the cost of each step grows too — and naively, that's quadratic growth. Painful. The fix is the prompt cache. If the server can recognize and reuse the parts of the prompt it already computed last time — a cache hit — you collapse that quadratic growth down to linear.
So how does Codex earn those cache hits? Two main moves. First, put the static stuff at the front. Instructions, tool definitions, sandbox settings — the things that don't change — go at the very start of the prompt, so they can be cached once and reused. This is exactly why that reordering we mentioned earlier matters. Second, and this is the subtle one: MCP tool ordering. If an MCP server lists its tools in a nondeterministic order — different every time — then the prompt looks different every time, and every single request becomes a cache miss. So Codex enforces a consistent ordering of tools. Easy to overlook, huge in impact. The payoff, in Bolin's words: even though the request payload grows quadratically, model sampling can still stay in linear time.
Step back and you can see the whole design is a set of balanced tradeoffs. Autonomy versus safety — the IDE integration lets you dial anywhere from cautious question-and-answer mode all the way to fully autonomous execution. Stateless versus continuity — stateless requests keep you compliant, while encrypted compaction keeps the reasoning thread alive. And context depth versus cost — auto compaction makes long conversations possible at all, and the prompt cache makes them affordable.
So let me leave you with the three things worth holding onto. One: an agent's real output isn't the message it sends you — for a coding agent, it's the code on your disk, and that assistant message is just a "done" signal. Two: the context window is the master constraint, and auto compaction is how you survive it — summarize and encrypt the history so the model keeps its understanding without drowning in tokens. And three: the prompt cache is what makes any of this economically sane, and something as humble as keeping your tool ordering consistent is the difference between linear and quadratic cost.
And maybe the deepest takeaway is the one Bolin points at directly: if you want to build your own coding agent, the lesson isn't how Codex is implemented — it's why these decisions were made. Context management isn't a nice-to-have feature you bolt on later. It's the precondition for letting an agent run for more than a few minutes at a time.
🇹🇼 中文
大多數人用 Codex CLI 的體感,就是輸入一句話,然後 code 就自己冒出來了。但你看不到的是,在這短短一瞬間,背後那個 agent loop 已經跑了幾十次推理跟工具呼叫。OpenAI 的 Michael Bolin 寫了一篇文章,叫《Unrolling the Codex agent loop》,把這層黑盒子整個攤開來看。我們今天就來拆解一下。
先講最核心的東西——什麼是 agent loop。其實每個 AI agent 的本質都是一個迴圈。它收到你的輸入,組建一個 prompt,這個 prompt 裡面包含指令、工具定義、還有整段對話歷史。接著把它送進模型做推理。模型回傳結果,這個結果有兩種可能:一種是工具呼叫,一種是最終回覆。如果是工具呼叫,agent 就在本機把工具跑起來,把結果接回 prompt,再丟回去推理一次;這樣一圈一圈轉,直到模型給出最終回覆,這一輪才算結束,然後等你下一句話。
這裡 Bolin 有個觀念我覺得特別值得記住:對一個 coding agent 來說,它真正的「輸出」其實不是螢幕上那段 assistant message。真正有價值的,是它在你本機寫進去、改掉的那些程式碼。最後那段話只是一個信號,告訴你「這一輪我跑完了」。所以一個你以為很單純的對話 turn,背後可能藏了幾十次「推理、執行工具、再推理」的循環。
接著看 prompt 的結構。Codex 送給 Responses API 的 payload,核心有三塊。第一塊是 Instructions,這是靜態的系統層指令,來自設定檔或模型內建的設定。第二塊是 Tools,包含 Codex 內建的 shell 執行、檔案操作,加上 Responses API 原生工具,還有你自己透過 MCP 掛上去的工具——這些工具用 JSON schema 來定義,讓模型知道什麼時候、該怎麼呼叫。第三塊是 Input,也就是對話歷史,涵蓋 system、developer、user、assistant 各種角色的訊息,外加當前的沙箱權限跟專案 context。
有個細節很關鍵:server 收到 payload 之後,會重新排列成 system message、工具定義、instructions、然後才是 input messages 這個順序。這個順序不是隨便排的,它直接影響到 prompt cache 的命中率,等一下會講到為什麼。
那 token 是怎麼流動的?推理本質上就是一場翻譯:文字 prompt 變成輸入 token,模型取樣之後產生輸出 token,再變回文字。因為 token 是一個一個生出來的,所以輸出可以邊算邊串流回來——這就是為什麼 LLM 應用都有那種打字機效果。而每個模型都有一個固定的 context window,也就是輸入加輸出 token 的總上限。這個上限,是整個 agent loop 設計裡最重要的約束之一。
為什麼最重要?因為對話一長,token 就一直累積,很快會逼近上限。Codex 的解法叫自動壓縮,auto compaction。它的觸發很單純:你設一個閾值,token 用量一超過,就自動壓縮。壓縮會打到一個專用的 compact endpoint,回傳一批摘要 item,直接拿去替換掉原本的歷史。重點是,壓縮結果是以加密的方式存下來,模型的「潛在理解」被保留住了,但那些原始訊息就不再佔 context 空間。
這個設計還順帶解決了一個合規問題,就是支援 Zero Data Retention 的客戶。因為請求模型本身是無狀態的,伺服器不需要把原始對話存下來;而那個加密的壓縮 item,又能帶著模型的推理繼續往下跑。一舉兩得。
再來是 prompt cache 的優化,這塊特別有意思。每次推理都要把整個 prompt 重送一遍,如果不做優化,成本會以二次方往上飆。但如果能讓 server 重複利用之前算過的部分,也就是 cache hit,就能把二次方壓回線性。Codex 怎麼做的?第一,把靜態內容放最前面——instructions、工具定義、沙箱設定這些不會變的東西擺在開頭,才有辦法被 cache 住。第二,這個我覺得最容易被忽略:MCP 工具的排序。如果 MCP server 每次枚舉工具的順序都不一樣,那每個 request 都會 cache miss。Codex 強制讓工具排序一致,就把這個坑補起來了。效果就是,即使 request payload 以二次方在長大,模型取樣還是能維持線性時間。
最後拉高來看,整個 Codex agent loop 的設計,其實就是在幾組相互拉扯的取捨之間找平衡。autonomy 對上 safety——從問答模式到全自主執行,可以連續調節。stateless 對上 continuity——無狀態請求滿足合規,加密壓縮保留推理的連貫。context depth 對上 cost——自動壓縮讓長對話變可能,prompt cache 讓它變得負擔得起。
好,總結一下三個核心要點。第一,你看到的一個對話 turn,背後是幾十次推理跟工具呼叫的迴圈,而 coding agent 真正的輸出是程式碼,不是那段回話。第二,context window 是最硬的約束,Codex 用加密的自動壓縮來換取長對話的續航,同時還顧到了 Zero Data Retention。第三,prompt cache 的關鍵在於靜態內容前置加上工具排序一致,把成本從二次方壓回線性。
如果你也想自己做一個 coding agent,這篇文章最值錢的地方,不是 Codex 怎麼實作,而是這些決策背後的原因——context 管理從來不是可選功能,它是讓你的 agent 能撐過幾分鐘、真正派上用場的必要條件。
Tags
Related Articles
RAG's Five Stages: From Pipeline to Reasoning Retrieval, and the Naive RAG on My Own Site
Over the past two years RAG evolved from a 'linear pipeline' to 'loop-based reasoning'. It maps cleanly to five stages: Naive, Advanced, Modular, Graph, Agentic. The real inflection point is control moving from pipeline to agent — a System 1 → System 2 shift. Looking back at engineer-news's own RAG stack, it's stuck at the Naive edge — so this post also lays out what to fix next.
Building a Real RAG: 5 Infra Lessons from InfiniFlow's 2024 Year-in-Review
The previous post zoomed out for a five-stage panorama of RAG. This one zooms in on the five infra lessons any real RAG has to face: document ingestion, contextualized chunking, three-lane hybrid search, tensor reranker, and GraphRAG's semantic gap. Each lesson is checked against engineer-news's current stack, ending with a priority list for a personal site.
J-lens: Anthropic's New Interpretability Tool for Reading Claude's Inner Thoughts via a 'Global Workspace'
Anthropic proposes J-lens, an interpretability tool that captures the 'verbalizable' representations inside a Transformer, and uses it to show that Claude contains a privileged subspace analogous to the neuroscientific 'global workspace' — a small set of vectors that broadcast, drive reasoning, respond to external steering, and even leak signals during deception and evaluation awareness.