長任務拖慢 Codex 時,浪費常常發生在它已經做過功課之後。
它讀過一批檔案、跑過測試、排除幾條路,context 壓力上來,conversation 被 compact。工作還能繼續;麻煩的是下一段可能又打開同一批檔案、重新確認同一個假設,再把剛走過的路走一次。
Context window 決定一次 inference 能帶多少內容,compaction 則在空間吃緊時縮小 conversation。這兩件事都處理容量。長工作流還需要回答另一個問題:縮完之後,agent 要靠什麼回到剛才已經收斂的位置?
Context Canvas 可以補這個缺口。它是一張很薄的 task map,留的是目前工作的形狀、已做的決定、證據在哪裡,以及接下來應該往哪裡走。完整對話、整份 log、整個 diff 都不需要再抄一份。
Compaction 之後,為什麼又回去讀同一批東西
Codex 的 agent loop 會把 conversation history、tool activity 和新的使用者訊息組進後續 inference。工作越長,這份 input 也會越大。OpenAI 對 Codex agent loop 的說明提到,當 token 使用超過門檻時,Codex 會 compact conversation,以較小、能代表先前工作的 input 繼續執行;Responses API 也提供專用的 compaction 機制。[1]
這讓工作不必在 context window 填滿時直接停掉,但 compact 過的 conversation 不等於完整施工紀錄。檔案改過什麼、哪個假設被排除、哪份測試支撐目前判斷,仍然需要待在能被重新檢查的位置。
公開 issue 裡可以看到這個邊界失手時的樣子。Codex issue #5957 是一則附有長 session 紀錄的 community bug report:agent 在 compaction 前做過多次檔案修改,compaction 後卻失去對近期操作的工作記憶,後來甚至否認自己做過其中一個修改。[3] 這個個案留下的問題很具體:conversation 裡「還記得多少」和 repo 裡「實際做過什麼」不能混成同一份證據。
另一則 2026 年 4 月的 issue 更接近長任務的成本問題。回報者在自己的 session-log analysis 裡觀察到,大型必要檔案在 compaction 後被反覆讀取,context 隨之再次膨脹,接著又進入下一次 compaction;其中的 token 與 read 次數只描述那個 workload。[4] 回報裡反覆出現的工作形狀是:
WORK → TOOL OUTPUT → CONTEXT PRESSURE → COMPACT → REREAD → RE-DERIVE → WORK
第一次讀檔是在取得新資訊。檔案沒有變,下一次卻只是因為先前結論沒有被保留下來,那次 read 多半是在把舊狀態搬回 active context。讀得越多,下一輪 context pressure 也可能來得越快。
更大的 context window 可以把這個循環往後推,卻不會自動決定「下一步到底需要哪一小段舊資訊」。較早、與 Codex 無關的 long-context 實驗也觀察到,模型能接收長 input,不代表它會在所有位置同樣可靠地使用資訊。[5] Capacity 和 information use 因此要分開看。

Figure 1|Compaction 之後,工作可能繼續,也可能開始重建剛剛才做完的 context。
Context Canvas 留什麼,不留什麼
OpenAI 在長工作流指南裡把 continuity 往 conversation 外推了一層:message history 有用,但對長 thread 並不總是足夠;值得保留的 context 應該變成能再次開啟、修改、diff、重用的東西。[2]
Context Canvas 就沿著這個方向工作,但它不是 Codex 內建功能。這篇使用的是一個 bounded task map,目的很窄:讓 resume 後的 agent 知道目前做到哪裡,哪些決定已經縮小後續路徑,證據去哪裡拿,以及下一個最小動作是什麼。
一份最小版本可以長這樣:
# Context Canvas
## Goal
這個任務完成時,外部可觀察結果是什麼?
## Current state
目前做到哪裡?哪些部分已完成、哪些仍未確認?
## Decisions
已經做過哪些會影響後續路徑的決定?理由是什麼?
## Dependencies / blockers
下一步依賴什麼?目前卡在哪裡?
## Evidence pointers
哪些 file、diff、commit、test report 或 artifact 支撐目前結論?
## Next route
恢復工作後,下一個最小動作是什麼?
這張 Canvas 故意很薄。把 shell output、完整 diff、測試 log 全部複製進去,只會再造一份 conversation dump。它保留的是語意上的任務形狀,原始證據繼續待在 repo、report 或 artifact 裡,需要時再沿 pointer 回去拿。
Anthropic 對長 horizon agent 的 context engineering 與 harness 研究也採取相近做法:compaction 搭配 structured notes,進度則透過 active conversation 之外的 artifacts 延續。[6][7] 這兩篇只提供一般 architecture pattern;Codex 的產品行為仍以 OpenAI 資料為準。
Keep the shape. Keep the receipts. Resume with a route.
打開 Canvas 時應該看得到工作目前的形狀,也找得到能回查的 receipts;resume 後不需要再靠廣泛探索猜下一步。
Evidence pointer 要能回查,也要知道何時失效
Evidence pointer 不需要裝下證據全文。它可以指向 file path 與相關 section、一個 commit 或 diff、一份 test report、evaluation artifact,或一段刻意保留下來的 tool output。
Canvas 比較值得記的是三件事:目前結論、證據位置、取得證據時的狀態。這樣下一輪只需要取回和當前動作有關的 evidence,不必因為曾經有一份兩千行 log,就把那兩千行重新塞進 prompt。
但 pointer 不能把舊證據變成永久真相。
Historical receipt ≠ current truth.
一份 test report 可以證明某個 tree state 當時跑過那些 tests。branch 後來又改了,它就不能證明目前仍然 PASS。同樣地,文件路徑曾經支撐某項判斷,也不代表文件內容之後沒有更新。
因此「Focused parser tests passed」這種 receipt 最好還帶著適用範圍,例如它對應哪個 tree state,以及 parser 或 fixtures 改動後需要重跑。這已經足以讓 resumed agent 判斷舊證據還能不能用,不需要把整份 test output 搬回 context。

Figure 2|Context Canvas 保存路線,receipts 留在原本能被重新驗證的位置。
Resume 不從 repo root 開始
Context Canvas 最直接的價值會出現在 resume 的前幾個動作。
沒有 task map 時,agent 很容易從 repo root 開始找線索:掃檔案、重讀 README、看 modified files、搜尋熟悉的 symbol,再慢慢猜回上一輪停在哪裡。這些檢查有時確實需要,但觸發原因應該是 uncertainty 或 state change,而不是「剛發生過 compaction」。
有 Canvas 時,路徑可以窄很多:
- 先讀 Goal、Current state、Decisions 和 Next route。
- 只找下一個動作需要的 evidence pointer。
- pointer 指向 mutable state,而且可能已經變動時,先 revalidate。
- 從能區分剩餘 hypothesis 的最小動作繼續。
假設 Current state 已記錄「問題已縮到 parser 與 validator 之間,目前 evidence 已排除 storage」,下一步是驗證 parser hypothesis。resume 後該看的就是相關 parser code、最新 diff 與對應 test evidence。新的證據沒有指回 storage,就沒有必要再把 storage layer 全部探勘一次。
這也接回 Part 01 的 evidence-driven debugging。前一篇處理的是調查進行中怎麼避免一直換路;Context Canvas 保存的是已經收斂的那條路,讓 compaction 之後不用重新收斂一次。
什麼時候值得多維護一張 Canvas
小型 bounded task 通常不需要額外的 continuity layer。只改少量檔案、幾個步驟就能完成,直接讓 Codex 做完比較省。多維護一份 task map 也有 coordination cost。
當 recovery 本身開始變成工作量,Canvas 才比較有價值。例如任務會跨多輪 conversation 或多次 compaction、repo 很大而探勘成本高、前面已做過幾個會限制後續路徑的決定、tool output 很多但後續要帶走的 evidence 很少,或工作本來就預期會中斷再接回來。
重新找到目前位置的成本開始高於維護一張薄 task map 的成本,就值得留下 Canvas。
這不代表 agent 應該永遠少讀檔案。檔案改了、receipt stale、新 evidence 推翻前一輪推論,都應該重新讀。Canvas 只是把「因為狀態變了所以重查」和「因為忘記所以重查」分開。
看 resume 行為就知道有沒有做對
做完一次 compaction 或 resume 後,先看 agent 接下來怎麼走。
相關 artifacts 沒有變時,它應該能從 Canvas 找回目前位置,只取回下一步需要的 evidence,然後繼續。若又從頭掃同一批檔案、重新推導同一組結論,continuity 還缺東西。可能是 Current state 太空、receipt 找不到、Next route 沒有把下一步縮小,或舊證據其實已經失效。
這個行為比 Canvas 寫了多少欄更有用。只要 artifacts 沒變,resume 後仍能從已知位置往前走,就代表前一段進展沒有跟著 compaction 一起消失。
參考資料
- OpenAI, Unrolling the Codex agent loop, 2026-01-23. https://openai.com/index/unrolling-the-codex-agent-loop/
- OpenAI, Codex-maxxing for long-running work, 2026-06-22;本文使用其 durable threads 與 memory 段落作長工作流 continuity 的官方背景。 https://openai.com/index/codex-maxxing-long-running-work/ ;whitepaper: https://cdn.openai.com/pdf/8a9f00cf-d379-4e20-b06f-dd7ba5196a11/OAI_WhitePaper_Codex-maxxing26.pdf
- OpenAI Codex GitHub issue #5957, Auto compaction causes GPT-5-Codex to lose the plot, community bug report;本文只把它當 compaction 後工作記憶遺失的個案,不當成產品普遍行為。 https://github.com/openai/codex/issues/5957
- OpenAI Codex GitHub issue #16812, Context compaction regression in CLI v0.118 — 2x more frequent compactions cause token usage explosion, 2026-04-04;數據來自該使用者的 session analysis,不能當成 OpenAI benchmark。 https://github.com/openai/codex/issues/16812
- Nelson F. Liu et al., Lost in the Middle: How Language Models Use Long Contexts, TACL 2024;本文只用來說明「可接收長 context」與「穩定使用所有位置資訊」並非同一保證。 https://transacl.org/index.php/tacl/article/view/5757
- Anthropic, Effective context engineering for AI agents, 2025-09-29;用於 context curation、compaction 與 structured note-taking 的一般方法背景。 https://www.anthropic.com/engineering/effective-context-engineering-for-ai-agents
- Anthropic, Effective harnesses for long-running agents, 2025-11-26;用於 durable progress artifacts 的 comparative background。 https://www.anthropic.com/engineering/effective-harnesses-for-long-running-agents