平凡的持續學習
文章認為長上下文長度與高品質的 AI 生成文檔可以替代權重更新,在不需要理論突破的情況下實現實用的持續學習。我提出了一個強化學習框架,用以訓練模型在不同任務中有效地編寫與利用記憶及文檔。
或者:當記憶變得強大時 —— 無需理論突破的預設路徑
認識狀態:對核心論點相當有信心(在大多數實際用途中,上下文 + 記憶可以取代權重更新)。強化學習(RL)訓練迴圈僅為草案,而非經過測試的提案。尚未進行徹底的文獻回顧。
假設在持續學習(continual learning)方面沒有重大突破 —— 也就是說,假設我們仍然難以利用運行時(runtime)收集的信息來更新特定 AI 模型實例的權重。如果你今天嘗試在運行時更新權重,通常會導致災難性遺忘,或者你會發現利用手頭極少量的有用數據只能進行微小的更新
^([1])
。
那麼,如果你無法將一整天的信息訓練進模型中,你如何能得到一個運作起來就像是在工作中學習的東西呢?
長上下文長度、高質量摘要與詳細文檔
^([2])
^([[3]](#fn-ebQzLg2A8fmGaJEGb-3))
。
這是一個直截了當的想法,而且目前基本上已經在做了,只是做得還不夠好。具體流程如下:
-
模型執行某項任務。在此過程中,它收集了大量信息,比方說相當於十幾本小說的量。它可以一次性將這些內容全部放入上下文(context)中。
-
模型完成任務。在結束時,它寫下:
一些它應該永遠記住的簡短筆記(我們稱之為記憶),例如「這家公司偏好我用德語溝通」、「文檔可在這個文件夾路徑中找到」,以及;
-
關於它所做的一切和所學到的一切的詳細文檔
^([4])
。這可以非常冗長。 -
記憶保留在上下文窗口中。文檔存儲在磁盤上,可以根據需要隨時調用。
就這樣。
為什麼現在行不通?
首先 —— 它某種程度上是行得通的。在我自己的軟體項目中,我維護一個簡潔的 Claude.md 文件(在每個新代理啟動時傳遞給它),以及 Claude.md 指向的大量文檔(Claude 可以隨時搜索)。Claude 和 ChatGPT 已經通過現有的框架以這種方式產生並存儲「記憶」。這些功能運作尚可,而且我們知道模型可以有效地進行上下文學習(in-context learning)。
但目前效果還不是很好。我懷疑這是因為目前的模型還不擅長撰寫或使用這些筆記。
這實際上是一項非常艱鉅的任務。我們基本上是讓模型問自己:「我知道哪些新鮮實例不知道、且對未來所有實例都有用的信息?」然後要求它用盡可能少的標記(tokens)將其寫下來。
為了做好這件事,模型需要理解它所知道的信息是來自當前的上下文還是來自其權重,並準確猜測未來的實例會如何對這些記憶做出反應。基本上,它需要具備良好的「心智理論」(theory of mind)。
我認為這項任務的難度是記憶功能剛推出時表現特別糟糕的主要原因。例如,在 ChatGPT 內部產生無關記憶的例子屢見不鮮。
訓練出能理解記憶是什麼以及如何使用記憶的模型也需要時間。以前,模型在無關的上下文中會過度關注記憶,在不該出現的地方提出筆記內容。根據我的經驗,Kimi K2.5 在這方面仍有困難,它會將上下文窗口開頭的筆記視為非常重要且相關,即使在不適用的情況下也是如此。
Claude 忽略了關於蘋果的筆記。Kimi 總能找到方法把它提款出來。
但記憶功能正在變得越來越好,新模型的使用也更加成功。我預計隨著模型變得更加智能,它們對記憶和文檔的使用將繼續改進,特別是在對此進行明確訓練的情況下。模型處理長上下文窗口中密集信息檢索的能力也在提升,因此,預測這些趨勢持續下去,將使平庸的「持續學習」在 2026 年和 2027 年變得相當有用。
還應注意到,這類記憶在功能上與「壓縮」(compaction,AI 在達到上下文窗口末尾時寫下的摘要,以便繼續工作)是相同的。在這兩種情況下,模型都在編寫壓縮信息以傳遞給未來的實例,以期(希望)表現得更好。這已經是前沿實驗室的優化目標。
我們如何讓它運作得更好
我們可以輕易地將創建和使用記憶訓練成一項強化學習(RL)任務。勾勒一個簡單的方法 —— 假設在完成任務時,我們不是立即對模型的表現評分,而是讓模型寫下記憶和文檔,然後在相同、相似和不相似的任務上運行一個新實例
^([5])
,並附帶這些記憶和文檔,然後由獎勵函數對綜合表現進行評分(對記憶長度給予微小懲罰)。流程如下:
用於實際參數更新的獎勵函數將是各個模型得分的函數,加上相對於記憶長度和模型總上下文長度的懲罰。
<mjx-container jax="CHTML" display="true"> <mjx-math display="true" class="MJX-TEX"> <mjx-mi class="TEX-I"><mjx-c class="mjx-c1D445"></mjx-c></mjx-mi> <mjx-mi class="TEX-I"><mjx-c class="mjx-c1D452"></mjx-c></mjx-mi> <mjx-mi class="TEX-I"><mjx-c class="mjx-c1D464"></mjx-c></mjx-mi> <mjx-mi class="TEX-I"><mjx-c class="mjx-c1D44E"></mjx-c></mjx-mi> <mjx-mi class="TEX-I"><mjx-c class="mjx-c1D45F"></mjx-c></mjx-mi> <mjx-mi class="TEX-I"><mjx-c class="mjx-c1D451"></mjx-c></mjx-mi> <mjx-mo space="4"><mjx-c class="mjx-c3D"></mjx-c></mjx-mo> <mjx-mi class="TEX-I" space="4"><mjx-c class="mjx-c1D453"></mjx-c></mjx-mi> <mjx-mo><mjx-c class="mjx-c28"></mjx-c></mjx-mo> <mjx-mi class="TEX-I"><mjx-c class="mjx-c1D460"></mjx-c></mjx-mi> <mjx-mi class="TEX-I"><mjx-c class="mjx-c1D450"></mjx-c></mjx-mi> <mjx-mi class="TEX-I"><mjx-c class="mjx-c1D45C"></mjx-c></mjx-mi> <mjx-mi class="TEX-I"><mjx-c class="mjx-c1D45F"></mjx-c></mjx-mi> <mjx-mi class="TEX-I"><mjx-c class="mjx-c1D452"></mjx-c></mjx-mi> <mjx-msub><mjx-mi class="TEX-I"><mjx-c class="mjx-c1D456"></mjx-c></mjx-mi><mjx-script size="s"><mjx-mi class="TEX-I"><mjx-c class="mjx-c1D45B"></mjx-c></mjx-mi><mjx-mi class="TEX-I"><mjx-c class="mjx-c1D460"></mjx-c></mjx-mi><mjx-mi class="TEX-I"><mjx-c class="mjx-c1D461"></mjx-c></mjx-mi></mjx-script></mjx-msub> <mjx-mo><mjx-c class="mjx-c2C"></mjx-c></mjx-mo> <mjx-mo space="2"><mjx-c class="mjx-c2026"></mjx-c></mjx-mo> <mjx-mo><mjx-c class="mjx-c29"></mjx-c></mjx-mo> <mjx-mo space="4"><mjx-c class="mjx-c2212"></mjx-c></mjx-mo> <mjx-mi class="TEX-I" space="4"><mjx-c class="mjx-c1D459"></mjx-c></mjx-mi><mjx-mi class="TEX-I"><mjx-c class="mjx-c1D452"></mjx-c></mjx-mi><mjx-mi class="TEX-I"><mjx-c class="mjx-c1D45B"></mjx-c></mjx-mi><mjx-mi class="TEX-I"><mjx-c class="mjx-c1D454"></mjx-c></mjx-mi><mjx-mi class="TEX-I"><mjx-c class="mjx-c1D461"></mjx-c></mjx-mi><mjx-mi class="TEX-I"><mjx-c class="mjx-c210E"></mjx-c></mjx-mi> <mjx-mo><mjx-c class="mjx-c28"></mjx-c></mjx-mo> <mjx-mi class="TEX-I"><mjx-c class="mjx-c1D45A"></mjx-c></mjx-mi><mjx-mi class="TEX-I"><mjx-c class="mjx-c1D452"></mjx-c></mjx-mi><mjx-mi class="TEX-I"><mjx-c class="mjx-c1D45A"></mjx-c></mjx-mi><mjx-mi class="TEX-I"><mjx-c class="mjx-c1D45C"></mjx-c></mjx-mi><mjx-mi class="TEX-I"><mjx-c class="mjx-c1D45F"></mjx-c></mjx-mi><mjx-mi class="TEX-I"><mjx-c class="mjx-c1D456"></mjx-c></mjx-mi><mjx-mi class="TEX-I"><mjx-c class="mjx-c1D452"></mjx-c></mjx-mi><mjx-mi class="TEX-I"><mjx-c class="mjx-c1D460"></mjx-c></mjx-mi> <mjx-mo><mjx-c class="mjx-c29"></mjx-c></mjx-mo> </mjx-math> </mjx-container>當然,還有其他幾種方法可以實現類似的效果,有些會比我這裡列出的更有效率。我主要是想傳達幾個核心想法:
-
你可以自動訓練記憶和文檔的質量,而無需對目前的後訓練(post-training)體系進行重大改動。
-
你還可以通過對多次連續運行的表現進行評分,訓練模型對記憶和文檔進行迭代改進(編輯和刪除不必要或錯誤的部分)。
-
在傳遞記憶和文檔時,你應該對相似和不相似任務的表現都進行評分,以教導模型何時該真正使用傳遞過來的信息
^([6])
。 -
你應該根據長度對記憶使用(可能還有文檔
^([7])
)進行懲罰,否則記憶最終會長到無法放入上下文窗口,而你不希望在那時發生性能斷層。
總體而言,我預計這將同時獎勵模型編寫和理解其記憶與文檔的能力,儘管存在將模型推向極其密集、難以閱讀的記憶方式的風險(類似語言漂移)。
我還沒有啟動實驗來進行經驗測試,但未來可能會做。如果有人感興趣或已經做過,請告訴我!
這能取代真正的持續學習嗎?如果信息不在權重中,會損失智能增益嗎?
這裡有兩件事需要理清。第一件是關於模型擁有正確的信息來實現其目標。這是放入記憶和文檔中的內容,也是平庸持續學習所解決的問題。
第二件是我們關心如何增加模型的智能。它如何能用更少的信息做更多的事,或者發現未被告知的新事物,或者在一般意義上變得更擅長在世界上行動。
在平庸持續學習中,真正的智能增益只發生在下一代 AI 模型中。
假設 Claude 5 發布時擁有 100 萬標記的上下文窗口,且足夠聰明能寫出高質量的
^([8])
文檔和記憶。如果一項任務使用約 50 萬的上下文,並產生約 1000 標記的新記憶,那麼每天執行十項任務,你可以運行該模型 50 天,才會達到存儲記憶的上限
^([9])
^([[10]](#fn-ebQzLg2A8fmGaJEGb-10))
。
然後,大約 50 天後,Claude 5.1 發布,通過常規流程提升了能力。Claude 5.1 繼承了現有的記憶和文檔,並立即著手改進和壓縮它們
^([11])
。結合更長的上下文窗口,新的 Claude 5.1 可能又爭取到了另外 50 天的記憶空間
^([12])
。
如此循環往復,或者至少直到 Claude N 通過運行時的參數更新解決了真正的持續學習。
通過這種方式,特定部署中的教訓(例如,為特定公司接聽電話的模型)可以輕而易舉地從一代傳遞到下一代,同時能力通過常規訓練持續提升。在實踐中,我們還需要真正的持續學習做更多事嗎?
^([13])
能給個大腦的類比嗎?
持續學習之所以成為如此受歡迎的概念,原因之一是人類具備這種能力,這使得它成為「AI 還不能做什麼?」這個問題的一個非常有吸引力的答案。
人類的學習過程看起來有點像上面的圖表,我們擁有一個顯式、離散且極其微小的「工作記憶」,一次大約只能在記憶中保留 10 個對象。這可能以前額葉皮層的激活形式存在。它類似於 LLM 的上下文窗口,是無損且顯式的,但規模要小得多。
接著,人類有一種「緩衝區」,信息以有損但易於獲取的方式存儲,時間跨度從數小時到數週不等。這似乎存儲在海馬體中。你可以將其與 AI 閱讀文檔做一個微弱的類比,它是對發生過的事情進行部分處理後的摘要,通過幾秒鐘的思考即可獲取。
當然,人類也可以閱讀文檔,但相比之下閱讀速度極慢。AI 閱讀文檔的速度更接近於人類回憶特定記憶的速度。
接下來,人類擁有「長期記憶」,它以天為單位緩慢更新,可能是通過讀取海馬體的「緩衝區」並據此更新
^([14])
。如果我們知道如何在運行時正確更新實例的參數,這就是 LLM 持續學習中缺失的那一塊類比。
最後,即使是人類,在成年後智能也不再增加
^([15])
。我們依靠進化選擇來對人類智能進行任何重大改變。這裡的類比是下一代 AI 模型的訓練,儘管那發生的速度要快得多。
這樣列出來後,你可以看到雖然缺失了「長期記憶」更新步驟,但「上下文窗口 + 文檔」的存儲容量比人類的工作記憶和短期記憶大得離譜,且「智能增益」步驟短得多,因此跳過運行時的權重更新可能是可行的。人類需要與記憶相關的參數更新,是因為我們無法在工作記憶或短期記憶中存儲太多信息,但如果我們的工作記憶大到一生都填不滿,情況就會完全不同。
結論
思考過這些後,我對「持續學習是近期 AI 能力的一個真正問題」的看法有所降溫
^([16])
。
對於通用能力的提升,它似乎並非必要,每隔幾個月發布一個新模型的體系運作良好。
對於公司特定的工作,它似乎也非必要,你可以將所有需要的信息存儲在文檔和上下文中。
我認為「它必須由模型顯式地編寫和使用」這一事實,為「為什麼它到目前為止效果不佳」提供了一個令人滿意的答案 —— 之前的模型根本不夠聰明,無法做好這件事。
我也看好這個問題的進展速度,因為這種性能可以通過無監督強化學習直接優化,包括訓練模型處理和編輯陳舊記憶。
總之……該死,我想我們現在正在製造持續學習者。
-
人們認為持續學習的目標是「模型可以在工作中學習」,所以從實際角度來看,主要用例是針對該模型部署所特有的、不可推廣的特定數據。當我說你沒有足夠的數據來有效地做到這一點時,我的意思是,一整天(或一個月)的工作記錄對於微調模型來說是非常微量的數據。你無法通過這種方式可靠地學習新事物,儘管你可能能夠引發模型中已有的知識。↩︎
-
這不是一個新想法。Dario 在 Dwarkesh 的訪談中提到過,快速的 Claude 搜索顯示有幾篇不同的論文討論過這個概念,其中大部分我還沒有詳細閱讀。我寫這篇文章是因為我以前沒有看到它在公開場合被清晰地整合在一起,而且或許對 RL 訓練迴圈以及為什麼顯式記憶對模型來說很難做對有一些有趣的探索。↩︎
-
我們今天也有這一切的各種版本,這就是為什麼它是「平庸的」持續學習。↩︎
-
你還可以包括模型為自己構建的工具、它在網上找到並想記下來的信息,以及任何為模型使用而創建或策劃的內容,而無需將整個內容存儲在活動上下文窗口中。↩︎
-
相同任務意味著字面上完全相同的任務
^([17])
。
相似任務意味著從相同狹窄分佈中提取的任務。例如,某個員工在一家公司工作中可能做的一系列事情。我們希望鼓勵在這種相對狹窄的領域中通用的記憶。
不相似任務意味著從截然不同的分佈中提取的任務。編程、心理支持、創意小說等。我認為我們需要在批次中包含一定比例的不相似任務,以訓練模型不要過度依賴記憶。在部署時,模型確實可能會被給予與當前任務無關的記憶。
如果我要隨機猜測給定批次中每種類型任務的比例,我會對分佈進行加權,使得第 N+1 個任務有 89% 的可能性來自相似分佈,10% 的可能性來自不相似分佈,1% 的可能性是完全相同的任務重複。↩︎
- 模型應該針對成功和失敗的嘗試都寫下記憶和文檔 —— 無論哪種方式,它都可能有關於嘗試或不嘗試什麼的有用信息。我還設想,出於推理效率的考慮,訓練時對總體標記使用量會有某種懲罰 —— 如果這能讓後續實例更有效率,這將激勵通過記憶和文檔傳遞有用的技巧和教訓。
甚至通過記憶傳遞整個解決方案也是可以的,只要模型學會了何時不適用,並且已經針對記憶長度受到了適當的懲罰。我認為我們可以通過調整一起評分的相同、相似和不相似任務的比例來獲得這個結果 —— 也就是說,如果我們運行相似任務 n 次,不相似任務 m 次(可能還有相同任務 p 次),並將記憶和文檔傳遞給給定的獎勵計算,我們可以選擇 n、m 和 p,使得通用的技巧比冗長且具體的指令更受青睞。↩︎
-
我不確定文檔是否應該受到長度懲罰。通過衡量模型使用文檔的表現,你可以在某種程度上實現這一點。我傾向於可能不需要,原則是讓訓練過程自行選擇短文檔還是長文檔更好。我假設我們使用一種工具,允許模型選擇一次讀取合理數量的標記,而不是冒著因塞入整個文件或僅在文件變得很長時才截斷而搞壞事情的風險。↩︎
-
在記憶的情況下,「好」意味著它們能弄清楚在未來所有運行中哪些信息是有用的,並能通過稍後編輯來從錯誤或缺失的記憶中恢復。在文檔的情況下,這意味著它們能準確包含所有相關信息,避免包含廢話,然後利用這些信息比沒有信息時更有效率。↩︎
-
我這裡編造了一些數字只是為了展示空間有多大。在這種情況下,我得到 100 萬標記的上下文窗口,減去 50 萬的任務緩衝,剩下 50 萬標記給記憶。以每天 10,000 標記的速度,我們得到 50 天的記憶緩衝。
這也是一種「最壞情況」。每項任務 1000 標記的記憶是非常高的,因為大多數記憶可以只是指向實際細節所在位置的指針,而且你很快就會沒什麼新東西可寫。你會每天都記住相當於約 6000 字的新信息,並終生不忘嗎?如果你能將每天的新記憶壓縮到只有 1000 個新標記而不是 10,000 個,你就能獲得超過一年的運行時間。或者,將上下文長度從目前的 100 萬標記增加也能提供緩衝空間。↩︎
-
不同的任務在這裡會有非常不同的特徵。例如,編程可能只需要非常短的記憶,而引導機器人穿過工廠可能需要包含地圖和模型在之前行程中所犯每個錯誤說明的記憶。↩︎
-
我們可以預期新版本會更擅長創建和使用記憶與文檔這項困難任務,特別是如果它對此進行了顯式訓練。這裡有一些可能性,都指向更短且更少的記憶:
模型是否能更容易地理解一段記憶想要表達的意思,從而讓它將現有記憶壓縮成更少的標記?
-
模型是否更擅長以更密集的方式編寫信息?
-
模型是否內在地知道更多信息,從而允許它從顯式上下文中移除這些信息?
-
模型是否更清楚自己知道什麼,從而允許它剪掉不必要的記憶?
-
新版本如何改變記憶和文檔緩存之間的權衡?例如,它閱讀文檔的速度是否更快?它是否更清楚在給定特定目標時何時以及該閱讀哪些文檔?
-
我非常有信心記憶的使用增長速度可以足夠慢,使得為特定公司工作的 Claude 能將所需的一切放入上下文和顯式文檔中。如果情況並非如此,你必須假設需要極大量的信息(相當於多本書),並且你發現必須保留在上下文中(而不是在可以查閱的文檔中)的新信息的速率超過了上下文窗口增長的速率,且未來的模型將無法顯著壓縮現有記憶,也無法憑藉更擅長判斷何時查閱資料而將現有記憶轉移到文檔中。↩︎
-
據我所知,在極限情況下,這個過程在功能上與持續學習是相同的。想像一下模型發布之間的 50 天縮短到很短的時間,比如一天或一小時,並想像傳遞下去的書面記憶變得越來越密集,成為一種為部署而加載的抽象初始化模式(就像靜態鏡像)。
反過來想同樣的場景,想像一個具有傳統權重更新持續學習的模型。它不是直接更新權重,而是(像人類一樣)使用短期記憶緩衝區來存儲新信息,並將私有信息與權重隔離。每小時,前一小時工作中相關的教訓被訓練進模型的一個副本中,然後無縫切換,並更新緩衝區。↩︎
-
我不知道你是否曾注意到自己的長期記憶在更新,我覺得我有過。你是否曾遇到過重大事件,然後在幾天後才鞏固了行為改變,儘管你從事件發生那一刻起就知道改變是必要的?↩︎
-
他們會繼續學習更多,這使得他們的晶體智能(知識和技能)上升,但他們的流體智能(抽象推理、解決新問題的能力等)在成年早期後會下降。↩︎
-
我甚至開始覺得持續學習對大多數平凡用途來說反而更糟 —— 假設你有一個自己的模型版本,其權重已更新以存儲特定於你和你的用例的信息。當新模型發布時會發生什麼?你必須重新訓練?批處理(batching)帶來的優化會怎樣?↩︎
-
我實際上認為,是否應該將字面上相同的任務作為第 n 個實例(帶有由第 n-1 個實例準備的記憶和文檔)的可選任務,是值得商榷的。如果你這樣做,模型可能只會在記憶中包含整個解決方案,但老實說,對於某些生產用途和任務類型,這可能是一個合理且可行的策略。
我認為總體上我們應該嘗試在與部署相同的分佈上進行訓練,因此是否將字面上相同的任務(而不僅僅是相似任務)作為一個可能的選項,取決於你是否認為這種情況在實踐中可能發生(也許是多次設置相同的編程環境?),以及你是否能從中獲得什麼(快速使用緩存的程序?)。↩︎