上下文工程:為什麼視窗變大,Agent 卻沒有變可靠?
大型語言模型的上下文視窗,已從早期 8K 暴增至 128K、1M 甚至 2M Tokens。許多開發者曾抱持樂觀想像:既然視窗足以裝下整座專案的程式碼,是否只要把所有檔案與日誌一次傾倒給 Agent,就能輕鬆完成複雜的架構重構?
但實務經驗迅速打破了這項幻想。即便模型宣稱支援超長視窗,在經歷數十輪工具呼叫與除錯後,Agent 依然經常遺忘最初的架構規範、反覆在錯誤路徑打轉,甚至依據舊記憶覆蓋剛寫好的程式碼。
單純擴大實體視窗容量,並不能保證長程任務的穩定性。在現代 Coding Agent 實踐中,決定系統成敗的關鍵已從提示詞句修飾,轉向如何動態維護高品質工作記憶的「上下文工程」(Context Engineering)。
視窗膨脹的陷阱:注意力限制與衰退
電腦科學家 Andrej Karpathy 曾提出一個經典的架構隱喻:將大型語言模型視為新型計算架構中的 CPU,而上下文視窗則是系統的 RAM。
如同作業系統需要嚴格管理虛擬記憶體以防崩潰,Agent 的注意力也是極度稀缺且昂貴的運算資源。超大視窗容易讓人放下戒心,放任原始日誌與無關程式碼填滿 Context,進而引發幾種致命的認知衰退:
- 長程檢索衰退(《Lost in the Middle》):研究顯示,長視窗模型最擅長捕捉上下文開頭與結尾的資訊,但對夾在中段的內容,提取能力會呈現劇烈的 U 型下滑。隨著對話輪次增加、工具輸出越塞越多,夾在中段的系統約束與介面細節極易被模型直接忽略。
- 準確度衰退(Accuracy Degradation):Chroma Research 的 Context Rot 研究指出,長上下文模型的正確率會隨輸入長度增加而持續衰退,且衰退方式不一致——即使任務難度不變、只拉長輸入也會發生。無關 Token 稀釋了注意力權重,導致模型遺漏關鍵邊界條件或產生幻覺。
上下文腐化(Context Rot)的三種常見表現
在長生命週期的任務中,系統效能隨時間推移持續惡化的現象稱為上下文腐化。它在日常開發中的常見表現包括:
- 指令飄移(Goal Drift):隨著大量除錯日誌累積,模型可能忽略最初設定的指令約束,開始擅自修改不該動的核心檔案,或違反專案既有的程式碼風格。
- 錯誤假設的自我強化(Error Self-reinforcement):如果先前嘗試失敗留下的錯誤堆疊追蹤(Stack Traces)未及時清理,模型在後續推理中會反覆將失敗的程式碼結構當成既定事實,陷入無效修復的死循環。
- 過期狀態殘留(Stale State Persistence):檔案內容已在磁碟上更新,但先前的舊版讀檔日誌仍留在視窗內。模型依據過期的行號與變數名稱進行修改,導致新寫好的程式碼被無情覆蓋。
對目前任務有幫助的資訊,例如專案規範、最新程式碼與已驗證的結果,可以視為「訊號」;無關日誌、過期檔案內容與重複訊息,則是「雜訊」。訊噪比(Signal-to-Noise Ratio, SNR)描述的就是兩者的相對多寡:有效資訊越多、干擾越少,模型越容易掌握任務重點。
上下文工程的一個核心目標,就是提高這個比例。用概念性的公式表示:
在正確的時間點,只向模型提供最小且必要的精準資訊。
日常操作一:限制讀取範圍與工具輸出
在 Coding Agent 工作流程中,工具呼叫產生的原始輸出(如 git log、npm test 產生的數百行編譯日誌或全域搜尋結果),往往是最大宗的 Token 黑洞。若放任這些未過濾的輸出堆積,常在十幾輪內就耗盡注意力預算。
使用者可以先從減少不必要的輸入做起:
- 按需讀取(Just-in-Time Retrieval):避免在對話開頭將整個模組或長檔案貼入視窗。可以要求 Agent 先搜尋相關符號,再只讀取必要的行號範圍,找到線索後才擴大閱讀。
- 限制工具輸出:測試或編譯產生大量日誌時,可以將完整輸出存檔,先讓 Agent 查看失敗項目、結束狀態與相關錯誤訊息,需要時再回查完整日誌。只看最後幾行可能漏掉根因;在介面上折疊輸出,也不代表模型收到的內容已減少。
- 整理關鍵摘要:當 Agent 從 2,000 行長檔中確認了需要的 3 個介面簽章,可以請它整理簽章與檔案位置,供後續工作或交接使用。不過,追加摘要不會自動移除先前的讀檔輸出;要釋放上下文空間,仍須使用工具提供的壓縮或清理機制,或另開 Session。
日常操作二:記憶分層與檔案保存
人類工程師在解決複雜架構問題時,不會將所有細節硬記在腦中,而是隨時做筆記。僅仰賴脆弱且容易腐化的對話歷史作為唯一記憶來源,是長程任務失敗的根源。
最穩固的實踐是建立分層記憶,並將任務狀態寫入本機檔案:
| 記憶層級 | 儲存載體 | 內容範疇 | 存取特性 |
|---|---|---|---|
| L1 工作記憶 | Context Window (RAM) | 目前 Prompt、即時工具回傳、最近 3–5 輪對話 | 即時但昂貴,容易腐化 |
| L2 情節記憶 | 本機檔案(進度清單 / 快照) | 任務進度、已驗證的變更、已排除的失敗假設 | 結構化 Markdown,按需讀取 |
| L3 程序記憶 | 專案規範檔案 | AGENTS.md、CLAUDE.md、架構決策紀錄 | 持久載入的上下文規範,非強制合約 |
寫驗分離:防止錯誤記憶固化
記憶若未經妥善驗證,極易累積錯誤資訊。高可靠 Agent 應落實寫驗分離(Write-Verification Separation)原則:
Agent 在推理過程中產生的臨時推論或假設,不能直接視為長期事實;只有在程式碼通過實際編譯、單元測試或特定驗證步驟後,才允許將結論記錄到持久記憶中,避免錯誤認知被固化。
NOTE
何時壓縮上下文,何時另開 Session
不必把對話輪數當成重置門檻:一輪可能只有幾句話,也可能包含大量工具輸出。更值得觀察的,是 Agent 是否開始反覆嘗試已排除的方案、引用舊版程式碼,或忘記既定限制。任務轉換階段時,也適合重新整理接下來需要的資訊。
壓縮上下文(Compaction)適合任務仍連貫、但對話累積了大量細節的時候。例如 Claude Code 的 /compact 會將對話歷史整理成摘要,以縮減活動上下文,讓工作繼續進行。這不等於另開 Session,也不應假定它會替你建立可供交接的 Markdown 檔案;壓縮後仍要確認重要限制與待辦事項有被保留。
另開 Session則適合舊假設反覆干擾工作,或任務已轉向另一個目標的情況。先將目前目標、已驗證的進度、已排除的方案與下一步寫入 task.md,並存好程式碼變更,再開啟新 Session。讓 Agent 讀取交接檔與最新程式碼,可減少舊對話的干擾;交接摘要本身仍可能遺漏或過時,必須以實際檔案與驗證結果核對。
進階實務:資訊屏障與 Prompt Caching 紀律
理解現代語言模型的架構機制,能進一步提升日常開發的可靠性與成本效益:
子 Agent 作為資訊屏障
當遇到龐大的探索型任務(例如追查未知 Bug 或全專案搜尋)時,單一 Session 容易被大量探勘日誌污染。
派遣獨立的 子 Agent(Sub-agent) 是最佳解法:
- 建立資訊屏障(Information Firewall):研究型子 Agent 在自己的隔離視窗中消耗數萬 Token 翻閱檔案,完成後僅向主 Agent 回傳數百字的精煉結論。龐大的探勘雜訊隨子 Agent 結束而被銷毀,主流程得以始終維持乾淨、專注的高層次規劃狀態。
- 獨立審查(Reviewer 模式):讓審查 Agent 依任務要求、專案規範、Git Diff 與測試結果檢查變更,不載入寫程式 Agent 的思考過程與除錯歷史。這能降低先入為主的確認偏誤(Confirmation Bias),但審查者仍可能犯錯,判斷仍須以程式碼與驗證結果為依據。
Prompt Caching 的前綴不變性紀律
在提示詞工程中,API 快取(Prompt Caching / Prefix Caching) 能大幅降低延遲並節省 60% 至 80% 的呼叫成本。但 Prefix Caching 遵循嚴格的前綴字元匹配:只要前綴發生任何微小變動,該位置之後的所有快取將瞬間全數失效。
在日常使用與設定規則時,應遵循以下紀律:
- 結構分層排布:把最穩定的系統設定與專案規範(如
AGENTS.md)固定放在最前端,對話歷史依序往下追加,最易變動的即時資訊(如目前時間或最新單次指令)放在最末尾。 - 追加優先(Append-only):在對話過程中,堅持以追加方式推進對話,避免在歷史訊息開頭動態插入時間戳記或頻繁微調前幾輪的格式。
- 批次重置而非逐輪微調:需要清理上下文時,集中一次性執行 Session Compaction 重建快取,而不是每輪微幅更動歷史破壞快取連續性。
結語:從「提示詞」到「工作記憶管理」
隨著 AI 輔助開發走向長程自主任務,工程師的角色正經歷深刻轉變:我們不再只是「寫 Prompt 的人」,而是「Agent 執行環境與工作記憶的架構師」。
與其期待未來模型擁有無窮大且不失真的神奇視窗,不如在日常開發中落實嚴謹的上下文紀律:按需讀取、適時壓縮上下文或另開 Session、將狀態寫入檔案、並用子任務建立資訊屏障。掌握上下文工程,才能在長程複雜任務中釋放 Agent 的穩定戰力。