AI News HubLIVE
站内改写5 分鐘閱讀

當上下文崩潰:教會智能體檢測和恢復丟失的記憶

本文是智能體工程系列文章的第八篇,探討AI智能體在複雜多步驟任務中面臨的上下文丟失問題。作者提出了外部化-識別-再水合(ERR)模式,通過將狀態保存到磁盤文件、檢測上下文退化、從文件恢復,幫助智能體自主應對上下文丟失。文章以歷史比喻(640K內存限制)和實際案例(Copilot會話崩潰)説明問題,並詳細介紹了執行連續性和任務連續性兩層狀態的外部化方法。

來源O'Reilly AI & ML Radar作者: Andrew Stellman

本文是智能體工程和AI驅動開發系列文章的第八篇。閲讀第一篇、第二篇、第三篇、第四篇、第五篇、第六篇和第七篇。

“640K對任何人來説都足夠了。”——比爾·蓋茨(據稱)

如果你正在構建執行復雜多步驟工作的AI智能體,你一定會遇到上下文丟失問題。智能體的工作記憶填滿,舊信息被靜默丟棄或壓縮,而智能體繼續運行卻不知道自己已經忘記了某些內容。這篇關於上下文管理的雷達文章三部曲中的第三篇,探討了我一直在改進的一種檢測和恢復該問題的模式,我稱之為外部化-識別-再水合模式(ERR,我認為這實際上是一個很好的錯誤恢復模式縮寫):將智能體的狀態保存到磁盤文件,檢測上下文何時退化,並從文件重新加載以恢復。單獨的技術在智能體和技能工程中是標準做法——檢查點、進度文件、狀態驗證——但真正的力量來自於將它們組合成一個連貫的工作流程,你可以現場使用或構建到智能體中。我將逐步介紹每個步驟,並提供你可以為自己的智能體和編碼會話改編的具體提示。

這讓我想到記憶。蓋茨多次表示他從未説過開頭引用的那句話,但它之所以流傳,是因為它抓住了那個時代的一個核心限制,一個人們不斷與之鬥爭的限制,以至於我們現在可以嘲笑它。那時我正在使用一台擁有1 MB RAM的286電腦。那是兆字節,不是千兆字節。MS-DOS 3.3給我提供了640K的常規內存加上384K的上層內存,我花了大量時間想辦法利用每一比特。我配置內存管理器,將設備驅動程序加載到高端,使用(並編寫!)終止並駐留程序,這些程序將自己移出常規內存以釋放空間,並且通常將內存視為一種需要積極、精心設計的資源。有很多我想做的事情無法容納在640K內,像當時大多數人一樣,我竭盡全力來彌補內存限制。

我們正處於AI開發的640K階段。上下文窗口是新的RAM天花板。當今大多數模型提供大約200K到2M令牌的工作記憶(就像1980年代末和1990年代初的內存一樣,這些數字在不斷增長),如果你構建執行復雜多步驟工作的智能體,你會碰到這個天花板。當這種情況發生時,AI開始壓縮:壓縮或丟棄對話的較舊部分以騰出空間。就像在286上耗盡常規內存一樣,事情開始出錯,而你不確定原因。

20年後,我們回顧今天微不足道的上下文窗口,會疑惑2020年代的開發者如何僅憑几百萬令牌就完成了任何事情。因為這一切都不是新的。如果你不相信我,這是一張我父親在1970年代初在普林斯頓大學使用Evans and Sutherland LDS-1圖形計算機的照片,這是第一台商用矢量圖形機器,連接到PDP-10大型機:

實際的LDS-1在背景的大機櫃中,直接位於顯示器後面。旁邊,在圖片之外,是一個更大的機櫃,裝有一個擁有16K磁芯內存(實際上是8K字)的內存單元。

所以可以想象,僅僅十年後,640K在一個容納於桌面的小型PC中就顯得非常奢侈。

在本系列的前兩篇文章(《為什麼沒人教開發者關於上下文管理?》和《你的AI智能體已經忘記了你告訴它的一半內容》)中,我討論了什麼是上下文以及為什麼上下文管理很重要,並分享了將重要信息保存在文件中而不是留在AI上下文窗口中的實用技術和提示。本文更具技術性。我想在這些策略的基礎上,討論如何構建能夠檢測自身上下文丟失並自主恢復的智能體。

用暴力方式應對上下文丟失

我進行這種上下文管理已經有一段時間了,遠在我要描述的具體工具存在之前。但最近的一次崩潰給了我一個清晰的例子,展示了該過程在最暴力形式下的樣子。

我正在Copilot中處理一個七步計劃,一步一步進行,每一步都讓另一個AI審查後才繼續。第一步和第二步進展順利。到了第三步,我給出提示後,它直接跳到了第四步。這種事情可能非常令人沮喪,因為一個足夠聰明以實現複雜功能的AI似乎應該能夠(嗯)數到四。

當AI丟失步驟或無法在提示之間計數時,保持冷靜的關鍵是記住它擅長什麼以及它如何記憶事物。如果你使用的AI出現這種情況,請檢查對話歷史。你可能會看到類似“正在總結對話歷史”或“正在壓縮對話”的信息出現在你的上一條消息上方。這告訴你AI丟失了位置,因為那個計數實際上已從其記憶中被清除。

AI擅長執行指令。它們不擅長在長對話中跟蹤自己的狀態,而管理內存的方式是其中很大一部分原因。本文旨在找到構建AI工具的方法,這樣你就不必依賴它們做最不擅長的事情。

但壓縮並非AI丟失上下文的唯一方式。幾周前,我深入使用Copilot進行一個多階段代碼審查的長時間會話。我花了一段時間與AI建立關於代碼庫和我們共同決策的上下文。我正要進入下一階段,然後我得到了這個:

整個上下文被清除了,這可能是一個非常令人沮喪的問題,因為我有很長的會話歷史,它已經積累了大量關於我們正在做什麼的知識。這原來是Opus 4.6與Copilot對話歷史交互中的一個bug,我也看到其他人遇到同樣的情況。我面對着一個空的新提示。

所以我做了一件事後看來是本篇文章主題的一個很好的暴力版本的事情。我識別出上下文丟失了(整個對話消失,很難錯過)。我將整個對話從Copilot複製出來並粘貼到一個文本文件中。然後我給新會話一個提示:

我們正在一個長對話中,然後出現錯誤,整個上下文被清除了。我將對話副本保存在#file:chat_history.txt中,請閲讀它並讓自己跟上進度。

它成功了!這使新會話回到了我需要的地方。

這個簡單的錯誤和恢復實際上勾勒出一個處理上下文丟失的不錯模式:

外部化狀態。將重要信息從對話中取出並保存在磁盤文件中,這樣當上下文窗口重組時它不會消失。

識別丟失。注意智能體的工作上下文已被清除或退化,無論是明顯的(如崩潰)還是微妙的(如輸出突然變得不合理)。

從文件再水合。將新會話指向該文件,讓它從記錄的內容重建理解。

各個機制在認知科學(認知卸載、任務恢復)、軟件工程(備忘錄模式、React再水合)和知識管理(SECI模型)中都有充分記錄。我並非聲稱發明了它們中的任何一個。但將這三個階段抽象為一個統一命名的模式並應用於AI上下文管理,據我所知是新的。這是綜合和編纂,而非發明。

在這個案例中,我通過複製粘貼完成,這並不優雅,但對我有效。但這是一個粗暴的工具,因為原始對話轉儲既過多又過少:過多是因為它充滿了噪聲,比如工具調用、死衚衕、不再重要的來回對話;過少是因為在會話期間靜默壓縮的上下文已經消失。當你將這些機制構建到智能體和技能中時,你可以以更加微妙和自動化的方式完成。

外部化:為智能體添加兩層狀態

外部化的想法,即定期保存智能體的狀態,源於我在構建Quality Playbook(一個開源AI編碼技能,執行結構化代碼審查)時與AI助手的一次對話。該Playbook將結構化代碼審查作為單一過程運行,但如果嘗試一次性完成,它很容易變成一個1500萬令牌的請求。在本系列上一篇文章中,我描述瞭如何將其分為六個階段,而這之所以可能,是因為每個階段的上下文已經被外部化。每個階段從文件讀取輸入,完成工作,將輸出寫入文件,然後停止。下一階段從文件而非智能體記憶的內容開始。如果這聽起來像是常見的建議——在要求AI實施之前先要求其規劃——那麼這是相同的原則應用於上下文管理。分離每個步驟並持久化輸出意味着你可以檢查它,並且下一步不依賴於智能體的記憶。

但這些文件應該包含什麼?我發現AI實際上很擅長弄清楚這一點。有一次我問助手:

智能體在處理過程中將更多上下文記錄到文件中以確保沒有遺漏是否合理?即使將其分解為單獨的提示,它也應該有效,因為每一步的結果都被持久化了。此外,我們可以審計其推理以進行調試和改進。

那個提示就足夠了。助手自己設計了文件結構:一個進度跟蹤器,記錄哪個階段處於活動狀態以及哪些已完成;一個JSONL工件文件(JSONL只是一個包含一組JSON對象的文件,每行一條記錄),每次運行追加輸出;以及一組簡要文檔描述每個階段的目的。你不需要過度工程化。告訴智能體你想要保存什麼,讓它找出文件佈局。

結果出現分為兩類,我稱之為執行連續性和任務連續性:

執行連續性:智能體在任務中間恢復工作所需的狀態:當前步驟、已完成的內容、到目前為止所做的決策。這些文件隨着智能體工作而不斷變化。

任務連續性:在執行期間不改變的更廣泛上下文:整個任務的內容、成功的標準、結構約束。這些文件只寫一次,每次恢復時讀取。

當智能體在疑似壓縮後需要恢復時,它會讀回兩層。任務連續性文件將其錨定回整個工作的內容。執行連續性文件將其放回工作中間。一起,它們給智能體足夠的信息以繼續,而不依賴於可能已被壓縮的任何東西。

關鍵在於外部化不是在任務開始時只做一次。你希望智能體在頻繁的檢查點保存其狀態,這樣如果壓縮在運行中發生,最近的檢查點接近智能體正在工作的地方。以下是處理逐條記錄任務的指令示例:

每條記錄後更新進度文件,而不是批量更新。先寫入輸出行,然後用新的游標更新進度文件,並

[由於AI成本控制,原文截斷]