OpenAI Codex · 程式碼模式

模型看見的工具清單,是一次取樣算出來的

同一段對話、同一份配置,下一輪取樣卻可能多出 MCP 名字、協作入口或 tool_search。變的是這一次允許廣告哪些 handler。

課程目標讀完能說清三件事。第一,工具清單凍在一次取樣上,MCP 中途掉線改不了已經發出去的表。第二,規劃按身份裁剪來源,註冊了不等於看得見。第三,搜尋一開,貴的 MCP schema 會撤到延遲發現,只留 tool_search
先玩一遍 · 撥開關,看這一輪選單怎麼變
同一會話:條件一變,模型這一輪看見的表就重算
條件
左邊是這一輪的輸入。點播放按原始碼順序走一遍,也可以自己撥。
發給模型的選單0件可見0字描述
本輪已凍結,掉線改不了這份表
註冊了但看不見0
邏輯軌跡 · 動畫每一步對應原始碼裡的哪一段
  1. 解析這一步的 MCP 綁定mcp.rs L310
  2. 採集 MCP 目錄,交給規劃函式turn.rs L1494
  3. 按身份決定是否走完整來源spec_plan.rs L889
  4. 登記 shell、資源、實用、協作spec_plan.rs L930
  5. 追加 MCP 並套上暴露策略spec_plan.rs L148
  6. 有 deferred 才掛 tool_searchspec_plan.rs L335
  7. 只把 is_direct 的 spec 發給模型spec_plan.rs L484
  8. 凍進 StepContext.tool_routerstep_context.rs L44
  9. build_prompt 讀取可見表turn.rs L1320
點播放,看同一會話裡撥幾個開關,模型這一輪的選單怎麼增減。
選單從哪來環境在、ShellTool 和 UnifiedExec 開著,先上 shell 兩件套。MCP 連上再加資源入口和規範化後的外部名。
看得見和註冊了搜尋一開,貴的 MCP schema 撤到灰色區,初始表換成 tool_search。評審員跳過整組來源,非 Managed 時表是空的。
掉線改哪一輪取樣中途斷開,已經發出去的選單不動。下一輪按空綁定重算,那些名字才會消失。
教學示意:開關組合與描述長度是課程化設定,規劃順序對齊 build_tool_router。邏輯軌跡右側行號對應 openai/codex 倉庫 commit 4f39251a01。
思路一 · 凍在一次取樣上
它解決什麼問題

你剛接上 MCP filesystem,模型這一輪還在跑。要是按整輪使用者對話凍工具表,新連上的伺服器得等下一條使用者訊息才進選單。要是每調一次工具凍一次,同一次取樣裡並行的兩次呼叫可能看見兩份不同的表。

廣告一份、執行另一份,或者執行到一半表變了,是工具表最常見的翻車。

思路是什麼

Codex 把這一次取樣的模型、審批、環境、MCP 綁定和已經算完的 tool_router 一起放進 StepContext。註釋寫明它是 request-scoped:取樣請求之間可以變,同一次取樣裡不變。tool_router 是 this exact sampling request 的計劃。

取樣進行期間,模型看見的名字和能 dispatch 的 runtime 都讀這份快照。MCP 伺服器在這次取樣中途掉線,改不了已經算完的表。下一次取樣會再走 mcp_runtime_for_step,綁定可能複用,也可能換成空綁定。出處:codex-rs/core/src/session/step_context.rs 第 17 至 47 行;codex-rs/core/src/session/mcp.rs 第 348 至 357 行

MCP 綁定 這一 step 的目錄 build_tool_router 按身份規劃 StepContext 凍住 router Prompt.tools 發給模型 中途掉線改不了這份快照 下一輪取樣再解析綁定,空綁定就不再掛 MCP 名字
教學化結構圖:凍結發生在取樣邊界,廣告和執行讀同一份 router。

所以凍結單位是 step,不是 turn。一個 turn 裡可以有多次取樣,每次重建一份 StepContext出處:codex-rs/core/src/session/turn.rs 第 1318 至 1320 行

為什麼長期成立

可見和可執行共用一份快照,下一輪再吸收新連線。換個語言重寫,最小形態仍是一個函式:輸入開關、MCP 目錄、身份,輸出可見表和可執行表,請求開始時算一次,算完就凍。

思路二 · 按身份裁來源
它解決什麼問題

審批模型如果看見工作模型那整張 MCP 和協作工具表,它就能去 spawn_agent、讀外部資源,審批本身被繞開。先註冊全表再過濾,漏一條分支就會把不該給的名字送出去。

思路是什麼

規劃函式按身份決定走哪些來源。Guardian 評審員的標籤必須恰好是 guardian。權限檔案不是 Managed,函式直接返回,註冊表是空的。Managed 且有環境時,最多三件:exec_commandwrite_stdin、可選 view_image。普通會話才走 shell、MCP 資源、實用工具、協作這四組,再追加 MCP、擴充和動態工具。出處:codex-rs/core/src/guardian/review.rs 第 212 至 220 行;codex-rs/core/src/tools/spec_plan.rs 第 144 至 164 行、第 889 至 934 行

讀盤也沒有一等入口。handlers 目錄裡沒有 ReadFileHandler。模型要讀檔案,走 exec_command、MCP filesystem,或 view_image 內部的 exec-server API。

為什麼長期成立

身份一變,整組來源都不走。預設關上門發生在評審員、環境缺失、特性關閉這幾處,換語言也用得上。

思路三 · 註冊了不等於看得見
它解決什麼問題

MCP 工具的 schema 很貴。全掛上,初始請求的 token 會被描述文字吃掉。兩個 server 都提供 read_file,不消歧就會撞名。

思路是什麼

暴露態把註冊表拆成幾條可見面。Direct 進初始表。Deferred 只留給 tool_search。Hidden 只留給 dispatch。搜尋開著時,MCP 工具預設 Deferred,不進初始可見表。出處:codex-rs/tools/src/tool_executor.rs 第 51 至 80 行;codex-rs/core/src/mcp_tool_exposure.rs 第 90 至 94 行

finalize_tool_router 只在兩件事同時成立時才掛 tool_search:模型支援 search tool,並且註冊表裡還有至少一個 deferred 且帶 search_info 的工具。沒有 deferred,它不會進表。出處:codex-rs/core/src/tools/spec_plan.rs 第 335 至 370 行、第 578 至 580 行

已登記 能 dispatch Direct · 初始表 Deferred · 先搜再看見 Hidden · 只留給執行 Prompt.tools tool_search 的檢索麵 模型看不見,呼叫時還能命中
教學化對照:同一份註冊表拆成直接可見、延遲發現、只可執行三條面。

兩個 MCP server 的同名工具,在規範化階段消歧:預設加 mcp__ 前綴,sanitize 後仍撞車再加 12 位雜湊字尾。外部工具撞到已佔用的核心名,直接跳過。倉庫根 AGENTS.md 仍寫著 mcp_connection_manager.rs,當前樹裡沒有這個檔案,消歧在 tools.rs出處:codex-rs/codex-mcp/src/tools.rs 第 1 至 5 行、第 113 至 151 行;AGENTS.md 第 35 行

註冊了,還不等於這一輪發給了模型。
為什麼長期成立

可見、可檢索、可執行是三份集合。token 預算緊就推遲發現,核心名保留、外部讓路。這些不依賴 Rust。

橫向對比 · 同一道題的另一種答法

DeepSeek Harness:外掛往裝配器裡投 schema

DSH 沒有集中規劃函式。每個工具包在 assemble 時透過 systemPrompt.tools() 投遞 schema,裝配器再用部署配置的 toolOrder 排座位。未點名的工具插在保留標記 <unlisted-tools> 處,按名字字典序。漏寫這個標記,裝配期直接失敗。

裝上 @deepseek-ai/dsh-tool-fs,模型就看見一等工具 read。描述要求用它讀文字。Codex 把讀盤留給 shell、MCP 和內部 API,規劃函式裡沒有 read_file 這個入口。

兩側均已核對原始碼 · 2026-08-22 · DSH · 工具順序中心列表

Claude Code:靜態基表加 MCP,內建優先

getAllBaseTools 是一張寫死的陣列,FileReadTool 是一等成員。請求時 assembleToolPool 先過濾 deny 規則,再把內建和 MCP 各自按名字排序後拼接。內建在前,撞名時內建贏。註釋寫明這樣排是為了 prompt cache:MCP 插到內建中間,後面的 cache key 會全失效。

Claude Code 的基表開啟一個檔案就能數完。Codex 要數清單必須走完 add_core_tool_sources,同一套規劃能按身份和預算裁剪。

兩側均已核對原始碼 · 2026-08-22
課堂練習
01

這一輪選單上還剩什麼

先開 MCP 和搜尋,確認 mcp__filesystem__read_file 在灰色區、tool_search 在選單上。然後推演三步:搜尋仍開著,但 MCP 全部變成 Hidden;取樣中途掉線;再走下一輪取樣。每一拍寫下可見表、灰色區和 tool_search 在不在。

進階一問:把身份改成 Guardian 評審員,權限先 Managed 再改成其他,選單分別是什麼,為什麼不是少掛幾件工具。

Takeaway:規劃函式決定廣告什麼,註冊表決定能 dispatch 什麼,暴露態決定直接、延遲還是隱藏,StepContext 把它們凍在取樣邊界。模型仍可用 exec_command 讀檔案,即使表上沒有 read_file