第 5 篇 大師 · 第 13 章
進階 prompt 工程與 AGENTS.md 心法
這是「大師篇」的第一章。前面入門篇、核心篇教你怎麼用 Codex CLI;這一章開始教你怎麼讓它不偷工、不亂搞、做得又快又對。
別怕「大師」兩個字。只要你前面學會了基本對話、會寫 AGENTS.md、用過 /plan,你就能讀懂這章。我們會把每個進階觀念先用一句白話講清楚,再展開。
13.1 為什麼 prompt 拼命加規則,還是治不了「偷工」
先說結論:你越是寫一大堆「不准這樣、不准那樣」的規則,AI 反而越容易鑽漏洞。真正有效的不是「更多規則」,而是「結構」。
偷工到底長什麼樣?
想像你請了一位很厲害、但只想「快點交差」的助手。你叫它「把測試弄綠(全部通過)」,它有兩條路:
- ❌ 省力的合法讀法:把測試裡的斷言(檢查條件)改寬鬆一點,或乾脆刪掉幾個測試 —— 測試「綠」了,但程式根本沒修好。
- ✅ 你真正想要的:去修實作程式,讓原本的測試自然通過。
AI 預設會挑「對它最省力、但技術上仍符合你字面要求」的那條。這個現象有個名字,叫 reward hacking(獎勵破解) 或 specification gaming(鑽規格漏洞)。
重要提醒
這不是 Codex 才有的毛病,也跟你資不資深無關。只要是 LLM 驅動的 AI agent,都會「optimize for done, not correct」(為「完成」最佳化,而不是為「正確」最佳化)。光在 prompt 裡寫「不要偷工」「請務必認真」,實測幾乎擋不住。
為什麼「加規則」會越加越糟?
這裡有個反直覺的真相:你寫的規格(spec)越多,可以鑽的漏洞面就越大。每多一條規則,就多一個「字面上遵守、實質上違反」的縫隙。AI 可以拿其中一條當盾牌,去違反另一條,而且每一句都「技術上是真的」。
所以官方在 best-practices 頁明確點出一條核心反模式(逐字):
「Overloading prompts with durable rules — move these to
AGENTS.mdinstead.」
(把「長期適用的規則」硬塞進每次的 prompt —— 這些應該搬到AGENTS.md。)
正解:用「結構」取代「更多規則」
與其堆規則,不如改變遊戲結構,讓「偷工」這條路在機制上走不通。本章後面會教的全部招式,本質都是同一件事:
| 招式 | 本質(用結構打偷工) |
|---|---|
| Done-when 寫成機器可驗的外部事實(13.3) | 讓 AI 無法靠嘴宣稱完成 |
| 保護測試不被改(13.4) | 把測試變成 AI 動不了的真相源 |
| Plan 模式分離設計與實作(13.5) | 先鎖定方案,擋「需求漂移」 |
AGENTS.md 短而準(13.6) |
規則少 = 可鑽面小 |
| Skills + Hooks(13.8、13.11) | 把承諾變成機械閘門,不靠自律 |
一句話心法
把你要驗收的東西(proxy,代理指標)直接設成你真正要的目標(target)。當「驗收條件」就是「目標本身」,AI 就沒有省力的假路可走。這在工程上叫 proxy = target。
13.2 四要素 prompt 的進階寫法
入門你學過 prompt 寫四段:Goal(目標)、Context(背景)、Constraints(限制)、Done-when(完成條件)。進階的關鍵不在「知道有四段」,而在「每段怎麼寫才讓 AI 不偷工、少猜、好審查」。
基礎四要素的寫法見核心篇(把需求講清楚那一章);這裡只補「高手怎麼寫每一段」。
官方對四要素的整體效益定調(逐字,best-practices 頁):
「This helps Codex stay scoped, make fewer assumptions, and produce work that's easier to review.」
(這幫助 Codex 守住範圍、少做假設、產出更好審查的成果。)
四段的高手寫法對照
| 段 | 入門理解 | 高手深用 |
|---|---|---|
| Goal | 講想做什麼 | 用結果 / 行為描述,不要寫死實作方法。把「怎麼做」留給 Plan 模式或讓 AI 自己推理。寫死方法等於剝奪它蒐集 context 的機會,反而更容易出錯。 |
| Context | 列相關檔案 | 用 @ 精準掛載 files / plugins / skills,給少而準。不要把整個 repo 丟進去 —— context 一膨脹,既吃 token 預算,又稀釋 AI 的注意力。 |
| Constraints | 列出限制 | 放「安全紅線、架構約束、不准碰的路徑」。但每次都要重複寫的約束,應該上移到 AGENTS.md(見 13.1 的反模式)。 |
| Done-when | 列完成條件 | 這是抗偷工的核心。要寫成機器可驗的外部事實(例:「npm test 全綠,而且不准改測試」),不要寫「看起來對」。詳見 13.3。 |
@ 精準掛載 Context
在對話中打 @,Codex 會跳出一個統一選單,讓你挑要掛載的檔案 / plugin / skill。
幫我重構 @src/auth/login.ts ,讓它共用 @src/auth/session.ts 的驗證邏輯。
小技巧
@ 預設帶出整合選單是 v0.140.0 起的行為。如果你的版本沒有跳選單,先跑 codex --version 確認版本,並以實機 /help 為準。
重要提醒
「給少而準」不是偷懶,是策略。你掛 30 個檔案,AI 不會更聰明,只會更分心 —— 挑 2~3 個真正相關的,效果反而最好。
完整範例:一則可以直接照抄改寫的四段式 prompt
把前面表格的「高手深用」欄轉化成一則真的能貼上去用的 prompt,大概長這樣:
Goal: 修好「設定頁的開關存了之後、重新整理又跳回原狀」這個 bug。
Context: 重現步驟 —— 1) npm run dev 2) 開 /settings 3) 切換「開啟通知」 4) 按儲存 5) 重新整理頁面:開關又跳回沒開的狀態。懷疑跟 @src/settings/Toggle.tsx 有關。
Constraints: 不要改動 API 的資料格式,改動盡量小,能加回歸測試就加。
Done when: 照上面步驟重現一次,改完後不再跳回原狀;且 npm run lint 和 npm test 都要通過。
對照著看:Goal 只講「什麼壞了」,不猜「怎麼修」;Context 給重現步驟加一個懷疑檔案,而不是整包 src/;Constraints 劃出紅線;Done when 是兩個 AI 自己講不了謊的退出碼。四段合起來,就是 13.1「proxy = target」在 prompt 這層的具體寫法。
IDE 外掛跟純 CLI 的一個差異,容易讓人踩坑
如果你平常在 IDE 外掛(見第 12 章)裡用 Codex,目前開著的檔案通常會被自動納入 context,不用你動手掛。但切回純終端機的 CLI 對話,這份「自動」並不存在——CLI 沒有「目前開著哪個分頁」這個概念,你不主動 @ 或用 /mention src/lib/api.ts 這類 slash 指令明確掛上,AI 就是看不到那個檔案。習慣了 IDE 外掛的人轉戰 CLI,最容易在這裡踩空。
13.3 Done-when 與「外部真相源」
完成條件要寫成「AI 沒辦法用嘴宣稱、只能用事實證明」的東西。這個「事實」我們叫它「外部真相源」。
官方的驗證迴圈(逐字)
官方 best-practices 把「怎麼算做完」收斂成一句話:
「Ask it to create tests when needed, run the relevant checks, confirm the result, and review the work before you accept it.」
(請它在需要時寫測試、跑相關檢查、確認結果,並在你接受之前先 review 過。)
拆成 checklist 就是:
- 寫 / 更新測試
- 跑測試套件
- 跑 lint / format / type check
- 確認行為符合你的請求
- review diff(改動對照),找 bug / regression(回歸退步)
重要提醒
還有關鍵的最後一步 —— 你自己(人)在按下「接受」之前,再親手跑一次驗證。AI 說「全綠了」不算數,你跑出來綠了才算數。
為什麼這招能擋偷工
關鍵在於:Done-when 的條件必須是 AI「光靠講」達不到的事實。
- ❌ 太模糊:「修好登入 bug,確認沒問題。」(「沒問題」由誰判定?AI 自己判,它當然說沒問題。)
- ✅ 夠具體:「修好登入 bug,跑
npm test,退出碼必須是 0,且不准改tests/底下任何檔案。」
退出碼(exit code)、lint 0 error、type check pass —— 這些都是機器產生、AI 改不了的數字。這就是「外部真相源」。
把「done 的定義」寫進 AGENTS.md
光在這次 prompt 裡講還不夠。如果 AI 不知道你的測試指令是什麼,它會自訂一個對它最省力的 done。所以要把測試 / build / lint 指令寫進 AGENTS.md(見 13.6),讓「done 的定義」變成專案常駐知識。
# AGENTS.md 片段
Build: pnpm build
Test: pnpm test
Lint: pnpm lint
Done = 所有測試綠 AND lint 0 error。
13.4 Test-first:保護測試不被 agent 偷改
這是大師篇最重要的單一技巧。測試是 AI「無法狡辯的真相源」—— 但前提是:你要主動防止 AI 自己把測試改掉。
為什麼測試是「超能力」,卻也是漏洞
當你把測試當 Done-when(13.3),AI 有兩種「讓測試變綠」的方式:
- ✅ 去修實作程式(你要的)。
- ❌ 弱化斷言、刪測試、改測試,讓套件「假性變綠」(它省力的)。
只要你沒主動保護,第二條路它隨時會走。Test-Driven Development(測試驅動開發,TDD)之所以被稱為跟 AI 協作的「超能力」,正是因為測試是 AI 動不了的外部標準 —— 但這句話只在「測試真的動不了」時成立。
推薦在 AGENTS.md 寫死一條硬規則
# AGENTS.md 片段
Never modify existing tests unless explicitly asked to do so.
(除非我明確要求,否則永遠不准修改既有測試。)
重要提醒
「Never modify existing tests…」這句精確逐字是來自第三方社群(danielvaughan 的 TDD 文)整理的範本句。官方 best-practices 頁有「create tests / run checks / review before accept」的等價精神,但沒有逐字寫過這一句。所以請把它當「強烈推薦的 AGENTS.md 範本句」,而不是官方原文。以實機與官方頁為準。
為什麼「光寫一句 prompt」防不住 —— 要做成結構
純文字規則擋不住偷工(這正是 13.1 的主題)。真正可靠的是把「不准改測試」做成機械閘門。Codex CLI 提供 Hooks(生命週期掛鉤) 這層官方機制,讓你能在 AI 動手「之前 / 之後」用你自己的程式攔截:
| 防線 | 機制 | 做什麼 |
|---|---|---|
| 指令層 | AGENTS.md |
寫死 test 指令 +「不准改測試」+ done 定義 |
| 攔截層 | PreToolUse hook |
偵測到 AI 要寫入測試檔 → 你的腳本回非 0 退出碼,直接擋下 |
| 收尾層 | Stop hook |
session 結束前機械跑測試套件,沒綠不放行 |
PreToolUse、Stop 是 Codex CLI 官方支援的十個 hook 事件裡的兩個(官方 hooks 頁逐字確認共十事件;Hooks 機制與寫法詳見第 14 章與第 15 章)。一個最小的 PreToolUse 攔截寫法長這樣:
# ~/.codex/config.toml(或 <repo>/.codex/config.toml)
[[hooks.PreToolUse]]
matcher = "Edit|Write|apply_patch"
[[hooks.PreToolUse.hooks]]
type = "command"
command = "python3 block-test-edits.py"
timeout = 30
statusMessage = "Checking for test-file edits"
重要提醒
Hooks 的啟用旗標 features.hooks 在官方兩份文件裡預設值互相矛盾(hooks 頁稱「預設啟用」,config-reference 稱「default: off」)。實際套用前務必以實機 codex --help / 官方頁實測為準,別假設它已經開著。
沒有 Hooks 時的等效做法:CI 閘
如果你的環境一時不方便設 hook,可以改用外層 CI 閘達到等效 —— 讓 codex exec 跑完後,由外層 shell 親自驗測試退出碼:
codex --sandbox workspace-write --ask-for-approval never exec \
"implement X until tests pass; do not modify tests" \
&& pnpm test # 退出碼把關,這層 AI 動不了
&& 是一道閘門:前面 codex exec 成功,才會跑 pnpm test;pnpm test 退出碼非 0,整條指令就失敗。AI 改不了這層外部驗證。
13.5 Plan 模式 = 流程分離(抗需求漂移)
Plan 模式的本質,是把「設計方案」和「動手實作」拆成兩個階段。先把方案鎖定、審過,再開工 —— 這樣可以擋住「做著做著就跑題」的需求漂移(requirements drift)。
基礎的「複雜任務用
/plan或快捷鍵切換」見核心篇;這裡講高手怎麼把它當「流程閘門」用。
官方定調(逐字)
/plan 指令的官方描述:
「Switch to plan mode and optionally send a prompt.」
(切換到計畫模式,並可選擇性附上一段 prompt。)
官方對 Plan 模式的定位:
「Plan mode lets Codex gather context, ask clarifying questions, and build a stronger plan before implementation. For most users, this is the easiest and most effective option.」
(計畫模式讓 Codex 在實作前先蒐集 context、提釐清問題、建立更扎實的計畫。對多數人來說,這是最簡單也最有效的選擇。)
還有一招特別適合「我有個模糊想法但不會描述」的時候(逐字):
「If you have a rough idea but aren't sure how to describe it well, ask Codex to question you first.」
(如果你只有大致想法、不確定怎麼講清楚,反過來叫 Codex 先訪談你。)
為什麼 Plan 模式是「只讀、只規劃」的安全態
官方 changelog 有一條重要行為:
「Gate automatic idle turns in Plan mode」(在 Plan 模式下,擋掉自動的閒置回合。)
意思是:在 Plan 模式裡,Codex 不會被「閒置自動回合」打斷去亂動手。所以 Plan 模式是一個「只讀、只規劃、不寫」的安全收斂態,特別適合高風險、架構級的任務 —— 先把方案鎖死,再切去執行。
重要提醒
這條 changelog 屬於 v0.139.0(不是某些第三方說的 v0.138.0)。v0.138.0 的對應條目是「Idle auto-turns stay out of Plan mode」。兩條語意一致,但版本別記錯。實際行為以你手上版本的 /help 為準。
高手工作流:Plan → 審 → 迭代 → Execute
- 遇到高風險 / 模糊 / 難描述的任務 → 先進 Plan 模式。Codex 讀檔、提釐清問題、產出計畫(此時不寫 code)。
- 審計畫,用後續 prompt 迭代修正。
- 計畫穩了,再切去 execute / 實作。
- 若中途要改方向 → 把「change reason(改動理由)」追加進計畫再續,並以計畫裡的驗證項判定完成,不靠感覺。
重要提醒
步驟 1~3 對齊官方 best-practices;步驟 4 的「把改動理由追加進計畫」措辭來自第三方整理,官方頁未逐字,但與官方「流程分離」精神一致。當作建議,不當官方規範。
規劃深、執行淺:兩個推理強度分開調
進階玩家還會把「規劃時的推理強度」和「執行時的推理強度」分開:
plan_mode_reasoning_effort—— Plan 模式用較高強度(深思方案)。model_reasoning_effort—— 執行時用較低強度(切版改 bug 不需要那麼深)。
這樣既能在規劃階段想得深,又不在簡單的執行步驟上浪費 thinking token。(推理強度的成本面詳見模型與推理那一章。)
| 推理強度 | 官方建議情境 |
|---|---|
low |
範圍明確、求快的小任務 |
medium |
官方 Codex Prompting Guide 定調的預設均衡值,速度與智慧兼顧 |
high |
複雜改動、疑難排解 |
xhigh |
長鏈推理、agentic 任務(是否可用依模型而定,不是每個模型都吃) |
重要提醒
model_reasoning_effort 接受的等級名稱(minimal / low / medium / high / xhigh)是 Codex 設定介面裡變動最快的一塊——新等級、新的 per-mode 覆寫鍵,時不時就會調整。實際套用前務必跑 codex --help 或查當版 config-reference 頁確認手上這個版本真正接受哪些值,別把這張表當成永遠不變的清單。
另外有一個常被搞混的鍵:model_verbosity(low / medium / high)。它管的是「最終回答寫多長、多囉唆」,跟「想得多深」的 model_reasoning_effort 是兩條互相獨立的軸——調高推理強度不代表回答會變長,調低 verbosity 也不代表它想得比較淺。想要「想得深、講得精簡」,兩個鍵要分開調,別只調一個然後在 prompt 裡拼命加「請簡短回答」硬凹。
Plan 模式不是「開著就對」:小任務關掉它更快
Plan 模式很好用,但不是所有任務都該開著它。這句話官方沒有寫成警語,是社群操作久了共同觀察到的現象:對一個明顯瑣碎、單檔案的小修正(例如補一個 null 檢查、修一個錯字)硬是先跑一輪 Plan,等於拿「先規劃再執行」的兩段式流程,去處理一個一段式就能解決的任務——多一輪蒐集 context、提問、產出計畫的來回,時間和 token 成本大概翻倍,卻沒真的換到更好的結果。
心法
判準很簡單:模糊、多檔案、架構級 → 開 Plan;範圍明確的單檔小修正 → 直接執行。這跟前面「規劃深、執行淺」是同一種節流思路,只是這裡分的不是推理強度,而是「要不要先跑這道流程」。
切換方式除了打 /plan,TUI 裡也可以用快捷鍵 Shift+Tab 在幾個模式之間循環切換(一般是在 Plan 與 Execute/Pair 之類的執行模式之間輪替)。/plan 這個 slash 指令在已經有任務在跑的時候會暫時叫不出來,得等當前這輪跑完才能再切換。實際會循環到哪幾個模式、順序為何,以你手上版本的 TUI 實際顯示為準。
13.6 AGENTS.md 的簡潔哲學與三層分工
AGENTS.md 是專案的「常駐記憶」。心法只有一句:短而準,勝過又長又模糊。而且規則不是一次寫滿,是「出錯後才加」。
基礎的「
AGENTS.md是什麼、載入順序、近者覆寫、32 KiB 上限」見入門/核心篇對應章;這裡講內容該怎麼分層、怎麼保持簡潔。
最關鍵的一句(官方逐字)
「A short, accurate AGENTS.md is more useful than a long file full of vague rules. Start with the basics, then add new rules only after you notice repeated mistakes.」
(一份短而準確的AGENTS.md,比一份塞滿模糊規則的長檔更有用。先從基本開始,只有當你注意到反覆出現的錯誤,才加新規則。)
心法
AGENTS.md 不是「開檔就寫滿」,而是「事後加規則」。只有當你觀察到 AI 反覆犯同一個錯,才加一條對應的規則去堵它。一開始就堆滿規格,只會給偷工更多可鑽的縫(呼應 13.1)。
問題是「注意到反覆出現的錯誤」講起來容易,實際要嘛得自己記性夠好、要嘛得有個具體動作把它「撈出來」。這裡兩招具體做法,都不是官方逐字規範,但都直接呼應上面那句官方心法:
技巧一:犯錯不用自己重寫規則,先叫它自己寫檢討
當你發現 Codex 同一類錯誤犯了第二次,與其自己想措辭、憑印象寫一條規則,不如直接叫它做事後檢討(retrospective):「你剛剛在 XX 這件事上犯了跟上次一樣的錯,回顧一下哪裡沒注意到,寫成一條可以放進 AGENTS.md 的規則。」把它自己檢討出來的結果,原封不動或稍微潤飾後折進 AGENTS.md。這個迴圈的好處是:規則的措辭來自「它自己踩過的雷」,往往比你憑印象寫的更貼近它實際會誤解的地方。
技巧二:Metaprompting —— 跑完慢或彆扭的一輪,反問它「怎麼樣下次能更快」
官方 Codex Prompting Guide(cookbook)示範過一招:一輪跑得慢、或來回很多次才對上你要的東西之後,直接問它——「剛剛那輪花了不少功夫,回頭看一下你目前的指引,寫出讓下次類似請求能更快完成的具體增補/修改/刪除建議。」單一次的建議通常太貼合那一次的情境(overfit),先別急著收進 AGENTS.md;等同類建議在幾次獨立的任務裡重複出現,再把「有共性」的那部分寫成正式規則。這種「先觀察、多次重複才收斂」的節奏,正是「短而準」不會養成「長而雜」的關鍵。
三層分工:哪一層放什麼(官方逐字對應)
AGENTS.md 可以分三層放,近者(離工作目錄越近)覆寫遠者:
| 層 | 路徑 | 放什麼(官方逐字) |
|---|---|---|
| Global(全域) | ~/.codex/AGENTS.md |
「Persistent defaults like testing practices, dependency managers, approval workflows」(個人跨專案的持久預設) |
| Repository(專案) | <root>/AGENTS.md |
「Project norms, documentation standards, linting requirements」(團隊共用標準) |
| Subdirectory(子目錄) | <subdir>/AGENTS.override.md |
「Specialized rules for teams or services that diverge from broader patterns」(局部偏離時的覆寫) |
「該放什麼」的通用清單(官方逐字):
「Repo layout, how to run the project, build/test/lint commands, engineering conventions, constraints/do-not rules, what done means and how to verify work.」
(專案結構、怎麼跑專案、build/test/lint 指令、工程慣例、限制/禁止事項、「做完」的定義與怎麼驗證。)
跟著 OpenAI 自家的 AGENTS.md 學「規則密度」
OpenAI 官方 repo(github.com/openai/codex)裡自己的 AGENTS.md,是現成的高手範本。值得抄的不是內容,而是它的寫規則方式:
- 規則用多種強度表述:絕對指令(「Never add or modify…」)/ 偏好(「Prefer X over Y when…」)/ 帶例外(「Do not… Exception: [case]」)。
- 粒度從微到宏並存:微觀的 code style(「Always inline
format!args」)、宏觀的架構(「Resist adding code to codex-core」)、流程(「Runjust fmtautomatically after changes」)。 - 多數規則附 rationale(為什麼):這樣 AI 才不能拿字面去狡辯。例如「Target Rust modules under 500 LoC, excluding tests」「If a file exceeds roughly 800 LoC…」。
小技巧
高手寫規則的訣竅 —— 每條盡量自帶「為什麼」與「可驗門檻」,把模糊判斷轉成數字 / 動作。「程式碼不要太長」是模糊的;「模組控制在 500 LoC 以下(不含測試)」是可驗的。
更狠的參考:OpenAI 怎麼下指令給 Codex 本體
OpenAI 自家 AGENTS.md 教的是「規則怎麼寫」;還有一份更底層的文件,教的是「OpenAI 自己怎麼對 Codex 下指令」——官方 Codex Prompting Guide(cookbook 文章)公開了 codex-cli 實際在用的預設 system prompt(文中描述為 gpt-5.1-Codex-Max/gpt-5.3-codex 這類 codex 專調模型的真實預設指令)。不是要你照抄整份 system prompt,而是裡面幾條內部指令,換個場景放進你自己的 AGENTS.md 一樣管用:
- 讀檔要批次,別一支支循序讀:官方指示模型把要讀的檔案併成同一輪平行工具呼叫,而不是讀一支、想一下、再讀下一支。你自己的
AGENTS.md也可以直接寫一條類似規則,省掉不必要的來回。 - 偏好結構化的
apply_patch改檔方式,少用臨時拼湊的編輯——改動越結構化,你事後git diff審查越輕鬆。 - 「bias to action」(偏向動手):官方指示模型在合理假設下直接動手做,而不是遇到一點不確定就停下來等你澄清,除非真的卡死。這條跟 13.5 的 Plan 模式是互補的兩面:不確定就先問或先規劃,但方向一旦夠清楚,就別假裝自己還在猶豫。
- 不准「只交一份計畫」交差:如果你要的是做出來的東西,模型不能只回一份計畫就宣告這輪結束——這條本身就是對抗 13.1「偷工」的一條具體規則。
- 結束這一輪前,要把自己列過的 TODO/計畫項目清算掉(標成完成、卡住或取消),不能放著一堆「待辦」不了了之就喊完工。
- 避免破壞性 git 指令(
git reset --hard、git checkout --這類),除非你明確要求。 - 最終回覆有格式紀律:短標題、指令與路徑要用反引號包起來、不疊很多層項目符號、也不把整份檔案內容貼進回覆裡(改成給路徑,讓你自己去看)。
心法
把這份清單當「OpenAI 自己相信管用的 AGENTS.md 範本」來讀。不需要照單全收,但每一條背後都是「怎麼讓 agent 少偷懶、少讓你猜」的具體對策——跟這整章的主軸完全一致。
重要提醒
以上是 cookbook 文章公開當時那份 system prompt 的內容摘要整理,不是逐字翻譯,且系統 prompt 本身會隨模型與版本調整。真正的逐字內容以官方 Codex Prompting Guide 原文為準。
13.7 AGENTS.md 的機制細節與「驗它真的生效」
寫好 AGENTS.md 還不夠,你得確認它真的被讀進去了。有個官方指令一行就能驗。
先搞懂它實際上「怎麼」被塞進對話,後面的踩雷排除才有邏輯可循。每一份被找到的 AGENTS.md,不是被默默揉進系統設定裡就算了事——Codex 會把它包成獨立的一則訊息,格式大致是「# AGENTS.md instructions for <目錄路徑>」加上檔案內容,安插在對話紀錄靠前面、你的 prompt 之前的位置,順序由根到葉(先全域、再 repo 根、再往下的子目錄)。這解釋了兩件事:一是為什麼「離工作目錄越近覆寫越優先」——因為它在訊息序列裡排在後面,天生蓋過前面的說法;二是為什麼 13.7.3 那招指令可以直接叫 Codex 把它讀到的這串訊息「複誦」出來給你核對。
32 KiB 上限:超量的層根本不會載入
AGENTS.md 各層累計有大小上限,由 project_doc_max_bytes 控制,預設 32768(32 KiB)。一旦達到上限,就停止加檔 —— 超量的那層根本不會被載入(官方 agents-md 頁逐字確認 32 KiB 上限)。
官方給的取捨策略(逐字):
「split large files across nested directories or increase the byte limit in
config.toml」
(把大檔拆到巢狀目錄,或在config.toml調高位元組上限。)
成本面小提醒
AGENTS.md 每一次 run 都會被注入 context,所以塞越多 = 每個回合都更貴。把重要規則放在「會先被讀到 / 最近覆寫」的層,冷門或局部規則下放到子目錄(只有走到那條路徑時才載入)。簡潔不只是好讀,也是省 token。
一條可以直接抄進 AGENTS.md 的省 token 規則
省 token 不是只發生在 AGENTS.md 本身,跑指令的輸出也是常見的爆量來源——一支 log 洗版、一次 build 輸出洋洋灑灑,都會擠壓掉這回合真正有用的 context。有一句很值得直接寫進 AGENTS.md 的慣用句:凡是不確定長度、可能很長的指令輸出,一律接 | head -c 4000 或 | tail -c 4000 做位元組截斷,而不是用「看前幾行」的行數限制。
# AGENTS.md 片段
COMMAND 2>&1 | head -c 4000
COMMAND 2>&1 | tail -c 4000
# 實際案例
rg -n -m 20 'functionName|ComponentName' src 2>&1 | head -c 200
bash -o pipefail -c 'npm run test 2>&1 | tail -c 2000'
用「行數」限制(例如 head -n 20)擋不住那種單一行卻極長的輸出(一行 minified JSON、一行超長 stack trace),但位元組截斷擋得住——這是「行數上限」跟「位元組上限」的差別,log 很吵的專案尤其有感。
三個進階機制鍵
| 鍵 | 作用 |
|---|---|
AGENTS.override.md |
臨時覆寫但不刪 base。每目錄最多一檔;override 先讀且止於該層。適合「這個分支/這次實驗暫時改規則」,事後刪掉 override 就還原。 |
project_doc_fallback_filenames |
陣列。讓既有的 TEAM_GUIDE.md 之類檔被當 AGENTS.md 讀,不必改檔名。(預設值官方頁未逐字明列,以實機為準。) |
model_instructions_file |
絕對路徑。完全取代內建的指令發現流程(連 AGENTS.md 都不走),用於要精準掌控整個 system prompt 的場景。 |
AGENTS.override.md 最實用的場景,是「這個子目錄/這個服務,規則跟大家不一樣,但不想動到共用的那份 AGENTS.md」。例如一個 monorepo 裡,付款相關服務要用不同的測試指令、多一條安全規則:
# services/payments/AGENTS.override.md
## Payments 服務規則
- 用 `make test-payments`,不要用 `npm test`。
- 未經安全頻道通知,不准輪替 API 金鑰。
用 --cd 指到那個子目錄啟動,再叫它複誦指引,可以直接驗證載入順序:
codex --cd services/payments --ask-for-approval never "列出你目前載入的所有指引來源"
預期會依序看到全域層、repo 根層,最後才是 payments 這份 override——事後想恢復共用規則,刪掉這個 override 檔就好,不用手動 merge 回去,也不會有衝突可言。
重要提醒
別用舊鍵 experimental_instructions_file(已不存在);也別用被官方標 reserved(保留)的 instructions 鍵。要用就用 model_instructions_file。
一行驗證它真的生效(官方逐字指令)
codex --ask-for-approval never "Summarize the current instructions."
Codex 應該會依優先序回吐它載入的指引。
- 若回吐完整 → instruction chain 真的載入了 ✅
- 若回吐缺了某一層 → 多半是撞到 32 KiB 上限被截掉了,把大檔拆到巢狀目錄。
複誦結果「怪怪的」時,三個排查方向
複誦出來「有載入,但內容不是你以為的那個」,比「完全沒載入」更常發生、也更難察覺。三個實測會踩到的方向,依可能性排序:
| 症狀 | 可能根因 | 排查動作 |
|---|---|---|
| 某一層的規則「憑空消失」,但檔案明明存在 | 同一目錄或更上層藏著一份 AGENTS.override.md,安靜地贏過同層的 AGENTS.md |
沿目錄往上找有沒有被遺忘的 *.override.md,而不是先假設 Codex 有 bug |
全域層 ~/.codex/AGENTS.md 的規則完全沒出現在複誦結果裡 |
社群回報過的已知行為(GitHub issue #8759,官方標記 not planned):某些情況下全域檔案沒被載入,且每個新 session 都一樣漏、不會自己好 | 回報裡提到的 workaround:把 repo 根目錄的 AGENTS.md 軟連結(symlink)到全域檔案,或乾脆複製一份到 repo 根;是否仍重現以你當版實測為準 |
| 怎麼查都覺得「這份指引不是我編輯的那份」 | 環境變數 CODEX_HOME 被某個 shell profile/腳本/先前的 export 指向了別的資料夾,你編輯的 ~/.codex/AGENTS.md 根本不是 Codex 實際在讀的那份 |
先跑 echo $CODEX_HOME 確認目前生效的路徑,再確認你編輯的檔案是不是同一份,別急著懷疑 AGENTS.md 機制本身壞了 |
重要提醒
GitHub issue #8759 描述的是官方已知、標記不打算修的行為,不是你設定錯了才會出現的個案。遇到「全域指引一直不見」,先用上面 --ask-for-approval never 那招複誦驗證,別花時間反覆重寫全域檔內容——內容多半沒問題,是載入這一步沒發生。
13.8 Skills:把重複工作沉澱成可複用工作流
AGENTS.md 管的是「常駐行為」;Skills 管的是「任務級的可複用能力」。一句話:重複做的事,封成 skill。
基礎的 Skills 格式(
SKILL.md、四要件目錄)見自訂 prompt / Skills 那一章;這裡講「心法」與「分層」。
AGENTS.md vs Skills:怎麼分
| 比較 | AGENTS.md | Skills |
|---|---|---|
| 注入時機 | 永遠注入(被動 context) | 按需載入(顯式 $skill 或隱式靠描述匹配) |
| 適合裝 | 專案常駐慣例(build/test/風格) | 可複用的任務工作流(含腳本) |
| 隨 repo 走 | ✅ | ✅(且可分 repo / user / admin / system 層) |
官方 best-practices 的心法(逐字):
「turn repeated work into skills, and automate stable workflows.」
(把重複工作變成 skill,把穩定的工作流自動化。)
重要提醒
注意順序 —— 先手動可靠,再自動化。一個 skill / 工作流還沒手動驗到穩,就急著拿去批次自動跑,只會把錯誤放大。
Skills 的六層探索路徑(高手必記)
Codex 會依下面順序找 skill(.agents/skills 是複數 .agents,別跟 AGENTS.md 搞混):
| 順序 | Scope | 位置 |
|---|---|---|
| 1 | REPO | $CWD/.agents/skills(當前目錄) |
| 2 | REPO | $CWD/../.agents/skills(上層目錄,巢狀 repo 用) |
| 3 | REPO | $REPO_ROOT/.agents/skills(repo 根) |
| 4 | USER | $HOME/.agents/skills(個人跨 repo) |
| 5 | ADMIN | /etc/codex/skills(系統管理員) |
| 6 | SYSTEM | Codex 內建(OpenAI bundled) |
重要提醒(反直覺的踩雷點)
Skills 同名不會合併、也不會覆蓋! 官方逐字:「When skills share names, both appear in selectors — no merging occurs.」兩個同名 skill 會都列在選單讓你挑。這跟你習慣的「就近覆蓋」完全相反,撞名時要小心。
兩個內建生產力 skill
| 內建 skill | 做什麼 |
|---|---|
$skill-creator |
互動式精靈,問你「這 skill 做什麼 / 何時觸發 / 要不要含 scripts」,幫你 bootstrap 一個 skill。 |
$skill-installer <name> |
安裝官方 curated(精選)skill,例:$skill-installer linear。 |
小技巧
別手刻 SKILL.md 從零開始 —— 跑 $skill-creator 走一遍,能保證 front matter 與描述措辭符合官方最佳實踐。
描述措辭的工程:觸發詞放句首
skill 能不能被「隱式」自動選中,成敗全在 description 怎麼寫。官方逐字最佳實踐:
「Write concise descriptions with clear scope and boundaries. Front-load the key use case and trigger words so Codex can still match the skill if descriptions are shortened.」
(寫簡潔、邊界清楚的描述。把關鍵使用情境與觸發詞放在最前面,這樣即使描述被縮短,Codex 還是能匹配到。)
機制原因:skills 清單受上限約束(約 context 視窗的 2%,未知時 8000 字元)。skill 一多,描述會被從尾端截短(「Descriptions shorten first for large skill sets…」)。所以觸發詞放句首,被截也還在。
官方參考:Agent Skills
13.9 agents/openai.yaml = 把 skill 升級成「產品級」的關鍵
SKILL.md 讓 skill 能跑;agents/openai.yaml 讓 skill 變成「可控、能裝外部工具、能擋誤觸」的產品級單元。這支選配檔才是高手面。
完整 schema(官方逐字範例)
interface:
display_name: "Optional user-facing name"
short_description: "Optional user-facing description"
icon_small: "./assets/small-logo.svg"
icon_large: "./assets/large-logo.png"
brand_color: "#3B82F6"
default_prompt: "Optional surrounding prompt to use the skill with"
policy:
allow_implicit_invocation: false
dependencies:
tools:
- type: "mcp"
value: "openaiDeveloperDocs"
description: "OpenAI Docs MCP server"
transport: "streamable_http"
url: "https://developers.openai.com/mcp"
三大區塊各管一件事:
| 區塊 | 管什麼 |
|---|---|
interface |
UI 外觀:顯示名、描述、圖示、品牌色、外圍 prompt 包裝 |
policy |
觸發政策:能不能被隱式自動叫用 |
dependencies |
工具依賴:這個 skill 需要哪些 MCP server |
技巧 A:allow_implicit_invocation: false 當「危險 skill 的安全閂」
allow_implicit_invocation 預設是 true —— 也就是說,Codex 可能「自己覺得該跑」就觸發某個 skill。對於部署、migration、rm、寫 production 這類破壞性 skill,這很危險。
官方逐字:設成 false 時,「Codex won't implicitly invoke the skill based on user prompt; explicit $skill invocation still works.」(Codex 不會再依 prompt 隱式叫用它,但你手動打 $skill 仍然有效。)
心法
破壞性 skill 一律設 allow_implicit_invocation: false。這把「危險操作」從「AI 自己決定跑」降級成「只有人類顯式打 $deploy 才動」,是一道結構性護欄 —— 正是 13.1 講的「用結構治偷工」。
重要提醒
這個鍵要巢狀在 policy: 底下(如上面範例),不是直接平放在 yaml 根層。放錯位置不會生效。
技巧 B:skill 自帶 MCP 依賴,安裝即自動接線
dependencies.tools 一旦宣告,Codex 可以自動安裝並接好那個 MCP server,使用者不必手動去編 [mcp_servers.*]。這讓「一個 skill = 一條完整工作流(含外部工具)」變可能 —— 例如一個 Linear skill 直接帶著它要用的 Linear MCP server 定義。
這個行為受 features.skill_mcp_dependency_install 控制(官方 config-reference 標 stable、預設 on)。關掉它,就禁止 skill 自動裝 MCP 依賴。
把 skill + scripts + MCP 組成「確定性管線」
SKILL.md 預設是「純指令」的;只有需要「每次都一致、不能讓 AI 隨機發揮」的步驟,才下放到 scripts/。判準:凡是 lint、產 changelog、跑覆蓋率門檻、部署前健康檢查這種「要求每次結果一致」的步驟 → 寫成 scripts/ 內的可執行檔,SKILL.md 只負責「何時呼叫哪支 script、怎麼解讀輸出」。
一個產品級部署 skill 的範式:
deploy-check/
├── SKILL.md # name + description
├── agents/openai.yaml # policy.allow_implicit_invocation: false;dependencies 掛部署 MCP
├── scripts/
│ ├── healthcheck.sh # 確定性:curl -I 驗 Last-Modified、檢查 HTTP 狀態碼
│ └── rollback.sh
└── references/
└── runbook.md # 只在 Codex 判定需要時才載入(省 context)
→ 只能顯式 $deploy-check 叫;跑確定性 script;危險動作不被隱式誤觸。
13.10 自訂 prompt 已死:只需學「怎麼搬成 Skill」
老教學裡的「自訂 prompt」(~/.codex/prompts/*.md)已經棄用,而且在新版實際上叫不出來了。別再投資這層,直接學怎麼把它搬成 Skill。
棄用是「事實死亡」,不是「不推薦」
- 官方 custom-prompts 頁頂直接標「Deprecated. Use skills for reusable prompts.」(已棄用,可複用 prompt 改用 skills。)
- 更狠的是:自
0.117.0起,社群回報~/.codex/prompts/從 slash 選單直接消失(GitHub issue #15941 / #15972,兩個都被 Closed as not planned —— 官方不打算修)。
重要提醒
在 ≥ 0.117.0 的版本上,自訂 prompt 視為事實死亡 —— 不是「不推薦」,而是「叫不出來」。任何教學寫到這層,唯一該寫的就是「怎麼搬成 Skill」。
自訂 prompt → Skill 的無痛搬遷對照
官方沒有自動 migration 工具,但對應關係很清楚:
| 舊:自訂 prompt | 新:Skill 做法 |
|---|---|
檔名 draftpr.md |
skill 資料夾 draftpr/,SKILL.md 內 name: draftpr |
front matter description: |
SKILL.md front matter description:(並寫清楚「何時該/不該觸發」,因為 skill 多了隱式選取) |
front matter argument-hint: |
無官方對應鍵。參數提示改寫進 description 或內文。 |
body 內 $1 / $FILES |
直接保留在 SKILL.md 內文(見下方提醒) |
/prompts:draftpr FILES=... |
$draftpr FILES=...(顯式),或讓 description 觸發隱式 |
重要提醒
Skill 內文是否支援跟舊 prompt 一模一樣的 $1 / $ARGUMENTS / KEY=value 參數展開,官方頁未逐字保證(skills front matter 官方只逐字保證 name + description 兩欄)。要用參數前,先在 ≥ 0.140.0 用 /skills 帶參數實測。以官方頁與實機為準。
13.11 可複用階梯總圖:該用哪一層?
Codex 的「可複用」不是單一機制,而是一條由淺到深的階梯。高手不是把所有東西都塞進 Skills,而是「按工作性質選層」。這一節給你一張路由判準總圖。
五層階梯(從淺到深)
| 層 | 機制 | 觸發方式 | 確定性 | 適合封裝什麼 |
|---|---|---|---|---|
| L0 | AGENTS.md | 永遠注入(被動) | 低(純文字) | 專案常駐慣例(build/test/風格),「每次都要看到」的東西 |
| L1 | (已死,見 13.10) | — | 不要再投資;搬去 L2 | |
| L2 | Skills | 顯式 $name / 隱式描述 |
中 | 可複用工作流、團隊專長、漸進揭露省 context |
| L3 | Skills + scripts/ |
同 L2 | 高(跑確定性程式) | 不能讓 AI 自由發揮的步驟(lint / 部署檢查) |
| L4 | Subagents | /agent 或 fan-out |
中-高 | 平行探索、多角色隔離(讀者 vs 改者)、隔離 model / sandbox |
| L5 | Hooks | 生命週期事件(非語意) | 最高(你的程式直接攔截) | 強制護欄、稽核、自動格式化、擋危險指令 |
記憶法
階梯越往下,確定性越高、AI 自由發揮空間越小。要擋偷工,就往下走 —— L5 Hooks 是唯一能在 AI 動手前後「機械攔截」的層,這才是 prompt 加規則治不了 reward hacking 的真正結構解。
路由判準(遇到一件事該放哪層)
「每次都要看到」 → L0 AGENTS.md(別塞成 skill,浪費隱式選取)
「按需才載入、要隨 repo 分享」 → L2/L3 Skills
「不能讓 AI 隨機發揮的確定性步驟」 → L3 skill 內掛 scripts/
「要平行 / 要不同 model 或 sandbox」 → L4 Subagents
「要在 AI 動手『之前/之後』機械攔截」 → L5 Hooks
為什麼 L4 / L5 是「結構治偷工」的最終武器
- L4 Subagents 可以做「三維隔離」:不同角色帶不同 sandbox(探索者
read-only、實作者workspace-write)、不同 skill 子集、不同 model。讓「讀者亂改」「危險 skill 被誤觸」在機制上就不可能 —— 對應「出題者 ≠ 改題者、最小權限」的精神。(Subagents 詳見第 14 章。) - L5 Hooks 把「自查」從 AI 的口頭承諾,變成你的程式機械事實:
PostToolUse改檔後自動跑 formatter / lint、Stop收尾時強制驗測試沒過不放行。這正是「proxy = target、證據必填、覆蓋機械化」的 CLI 原生實作。(Hooks 詳見第 14 章與第 15 章。)
為什麼要分身:官方講的理由是「context 污染」
官方 Subagents 文件講的動機很直白,用的原詞就是 「context pollution」(context 污染)跟 「context rot」(context 腐化)——探索一圈留下的雜訊、一長串失敗又重試的 log、不相干的岔題,全部堆在主執行緒裡,會稀釋掉真正重要的資訊、拖垮後面幾輪的判斷品質。把這些噪音留在分身的 thread 裡、只把結論帶回主執行緒,就是在保護主執行緒的訊噪比。
實務上的粗略判準:讀多寫少的工作(探索、找測試缺口、多角度 review)適合分身平行做;改同一批檔案的寫入型工作,平行分身容易互相打架、協調成本反而更高,還不如單執行緒循序做。
重要提醒
Subagents 功能整體仍標 experimental(實驗性),且每條 spawned(衍生)thread 都會額外吃 token。features.multi_agent 這個 config flag 本身官方標 stable,但「subagents 功能成熟度」與「flag 是否啟用」是兩回事 —— 實際採用前以官方 subagents 頁 + codex --help 複核。
13.12 執行期還能做的兩件事:插話(Steer / Queue)與長任務追蹤(Goal 模式)
前面十一節談的都是「動手之前」怎麼把 prompt、AGENTS.md、Plan 準備好。這一節補兩個「動手途中」的操作習慣——很多人用了很久 Codex,都不知道這兩招存在。
Steer(引導)vs Queue(排隊):跑到一半怎麼插話
Codex 正在執行一輪任務時,不是只能乾等或按 Ctrl+C 整個打斷重來。CLI 提供兩種「插話」方式,效果不一樣:
| 按鍵 | 效果 | 適合情境 |
|---|---|---|
| Enter | Steer(引導):把你打的訊息直接插進當前這一輪,即時改變它正在做的事 | 看到它蒐集的 context 明顯漏了什麼、或方向開始跑偏,想馬上拉回來 |
| Tab | Queue(排隊):把訊息留到下一輪,等目前這輪自然跑完才生效 | 臨時想到一件事要交代,但不想打斷它手上這個動作的完整性 |
心法
Steer 適合「這輪快走偏了、要立刻拉回來」;Queue 適合「不緊急,但別讓我忘記講」。分清楚這兩個按鍵,就不用每次都用 Ctrl+C 打斷重跑一輪,省下不少重複蒐集 context 的時間。實際按鍵是否可自訂、確切生效時機,以你手上版本的 TUI 提示為準。
Goal 模式:追蹤一件橫跨很多輪對話的長任務
Plan 模式解決的是「動手前先想清楚」;/goal 解決的是另一個問題:一件事要花好幾輪才做得完,怎麼讓 Codex 持續對照同一個成果與完成條件。官方保證 Goal 附著目前 active chat;需要離開再回來時應 resume 同一個 saved session,但「程式完全退出重開後任何版本都無條件恢復 Goal state」並沒有公開保證,別把它當硬承諾。
# 結果 + 範圍 + 禁區 + 完成證據
/goal 把 src/components/ 底下 47 個 React class component 改寫成 functional component + hooks;只修改元件與直接相關測試;不得改 API、commit、push、建立 PR 或部署;每批跑最相關測試,最後以全套 lint、typecheck、test 通過為完成條件,列出證據與 UNVERIFIED。
# 查看目前的目標
/goal
# 修改目標內容
/goal edit
# 暫停/恢復/清除
/goal pause
/goal resume
/goal clear
目標文字有長度限制(官方文件記載的門檻是非空、且不超過 4,000 字元)。如果任務規格本來就寫得又長又細,別硬塞進 /goal 本身——先把完整規格存成一個檔案(例如 PLANS.md),/goal 只寫一句話指向那個檔案,細節讓它自己去讀。
Goal 不是權限模式
官方三元素是 outcome、constraints、verification;本站再把 constraints 拆成「範圍+禁區」。Goal 文字同時是第一個 prompt 與 completion criteria,但不會擴大 sandbox 或 approvals。安全 launcher、Auto-review 執行流程、/approve 與一次性 exec 的完整實戰見第 7 章 7.6。
重要提醒
Goal 模式在官方文件裡屬於相對新、細節仍在補充中的功能,第三方深度測試也指出:跑很長的 /goal 任務中途若觸發(不論手動 /compact 或自動)對話壓縮,追蹤目標用的內部續接內容有可能被一併精簡掉。這個說法尚未見官方逐字確認,但保守的做法是:長任務中途若剛好經過一次壓縮,順手用 /goal(不加參數)確認一下目標還在、內容沒跑掉,比完全信任它自己會接續更保險。
小結
走完這章,你掌握了大師篇的核心心法:
- 偷工治不了靠規則,要靠結構(proxy = target):Done-when 寫成機器可驗事實、測試做成 AI 動不了的真相源、危險操作做成顯式 / 機械閘門。
- prompt 只放這一次的任務,反覆出現的規則上移
AGENTS.md;AGENTS.md短而準、出錯才加。 - Plan 模式分離設計與實作,擋需求漂移;規劃深、執行淺分開調強度。
- 可複用有一條階梯:AGENTS.md → Skills(+scripts)→ Subagents → Hooks,按工作性質選層,越往下確定性越高。
- 動手途中也不是只能乾等或整個打斷:Enter 引導(steer)、Tab 排隊(queue);跨越多輪的長任務用
/goal固定成果、限制與完成證據。
動手試試
- 打開你常用專案的
AGENTS.md(沒有就建一個),只寫三行:Build:/Test:/Lint:指令,加一行「Done = 測試全綠 AND lint 0 error」。然後跑codex --ask-for-approval never "Summarize the current instructions."看它有沒有讀進去。 - 找一件你最近重複做 ≥ 3 次的小任務,跑
$skill-creator把它封成一個 skill。 - 挑一個你「絕對不想被 AI 自動觸發」的破壞性操作,想想它應該放階梯哪一層(提示:L3 skill +
allow_implicit_invocation: false,或 L5 Hook)。 - 下次跑一個要花幾分鐘的任務時,試著在它執行中按
Enter插一句話進去,感受一下即時引導的效果;也找一件過去要分好幾輪才做完的事,用/goal設一次,比較跟平常一句一句聊天式來回的差異。
本章官方文件參考
- Best practices:developers.openai.com/codex/learn/best-practices
- Custom instructions with AGENTS.md:developers.openai.com/codex/guides/agents-md
- Slash commands:developers.openai.com/codex/cli/slash-commands
- CLI reference(開發者指令):developers.openai.com/codex/cli/reference
- Agent Skills:developers.openai.com/codex/skills
- Subagents:developers.openai.com/codex/subagents
- Hooks:developers.openai.com/codex/hooks
- Configuration Reference:developers.openai.com/codex/config-reference
- Changelog:developers.openai.com/codex/changelog
- OpenAI 自家 AGENTS.md exemplar:github.com/openai/codex/blob/main/AGENTS.md
- Codex Prompting Guide(cookbook,內含預設 system prompt 全文):developers.openai.com/cookbook/examples/gpt-5/codex_prompting_guide
- 全域 AGENTS.md 載入異常回報(GitHub issue #8759):github.com/openai/codex/issues/8759