目錄

目錄

會自我進化的 AI Agent,只是在背考題?Google RRSI 的護欄設計

目錄

讓一個 LLM 自動修改 agent 的 harness(模型以外的提示詞、控制流程、工具介面、記憶與 context 管理),再用任務分數當回饋反覆迭代,是這一兩年很熱門的做法。問題是每一輪都拿同一批有限的題目評分,進化用題目的分數會一路上升,換到沒看過的 benchmark,進步卻縮水甚至消失。

Google Cloud AI Research 的 RRSI(Regularized Recursive Self-Improvement of Agent Harnesses,arXiv 2609.24972v2)想管住這件事。它不限制 harness 能改什麼,而是管「怎麼提出修改」和「哪些修改可以被留下」,用一整包規則降低過擬合。

這篇文章分成兩塊。前半依論文順序講問題、方法、實驗與評價,我的判斷是研究價值偏低,工程參考價值中等偏上。後半是九個延伸概念。其中適應性資料重用、贏家詛咒、L0 / L1 / L2 正則化、雜訊帶等脫離這篇論文也成立,是我覺得最值得留下來的部分,其餘幾個則是這篇論文留下的疑點。

只有五分鐘的話,讀「整體評價」加「結論」。想理解方法,讀到「篩選端」為止。想判斷這篇論文值不值得信,看「實驗與結果」和「整體評價」。

閱讀標記:「自編例子」是論文沒有的數字或情境,我為了說明機制自己編的。「推論」是我的判斷,論文沒有這樣寫。「論文未說明」是論文沒交代的細節,這裡不替它補。

讓 LLM 自動改進 harness,看起來是個穩定進步的迴圈,但它有個結構性缺陷:每一輪的決策都在重複使用同一批有限的題目,所以進步可能只是在背這批題目。

論文把 agent 拆成兩塊:權重完全不動的 backbone 模型,加上包在外面的 harness。Harness 指模型以外的所有東西:

  • system prompt 與任務 prompt
  • 控制流程:什麼時候該規劃、行動、反思或停止
  • 工具介面與工具說明
  • 記憶與 skill 檔案
  • context management:每一步要讓模型看到什麼

同一個模型,harness 設計得好不好,決定它會不會先讀檔案再編輯、指令失敗後能不能復原、context 會不會塞爆、最後有沒有把結果寫進交付物。過去這些都靠工程師人工檢視失敗紀錄再手動調整,進度受限於工程師一天能讀多少紀錄。

Harness evolution(harness 進化) 就是把這個人工迴圈自動化:讓另一個 LLM(稱為 proposer)讀失敗紀錄、提出修改,再用任務分數挑選。因為每一輪都是用「目前的系統」產生的回饋去改善「下一版系統」,論文把它稱為 agent 系統層級的 RSI(recursive self-improvement,遞迴式自我改善),只是改的是 harness,不是模型權重。

一輪進化的流程如下:

  1. 目前的 harness Ht H_t 在 evolve set(進化用題目集)上執行。
  2. 產生 trajectories(每題一次完整的執行紀錄),整理成失敗回饋 Ft \mathcal{F}_t (由一個獨立的 analyst LLM 負責整理)。
  3. proposer 根據 Ft \mathcal{F}_t 產生幾個候選 harness。
  4. 候選們在同一個 evolve set 上重新評分。
  5. 在「候選加上原本的 Ht H_t 」裡挑分數最高的,成為下一輪的 Ht+1 H_{t+1} ,回到第 1 步。

寫成式子(論文 Eq. 2):

Ht∼P0(⋅∣Ht,Ft),Ht+1=arg⁡max⁡H′∈Ht∪{Ht}S^(H′; Devolve)\mathcal{H}_t \sim P_0(\cdot \mid H_t, \mathcal{F}_t), \qquad H_{t+1} = \arg\max_{H' \in \mathcal{H}_t \cup \{H_t\}} \hat{S}(H';\, \mathcal{D}_{\text{evolve}})
  • Ht H_t :第 t t 輪在位的 harness。
  • Ht \mathcal{H}_t (花體 H):這一輪 proposer 產生的候選集合。
  • P0 P_0 :沒有任何限制的提案分布,也就是 proposer 想怎麼改就怎麼改。
  • Ft \mathcal{F}_t :這一輪的失敗回饋(後面「延伸」的概念五會細講它是什麼)。
  • S^ \hat{S} :實測分數。帽子表示只跑了有限次,帶有隨機雜訊。
  • arg⁡max⁡ \arg\max :找出讓後面的值最大的那個候選,回傳的是候選本身,不是分數。

注意 arg⁡max⁡ \arg\max 的範圍包含 Ht H_t 自己:如果沒有任何候選比現在的好,Ht H_t 留任,這一輪什麼都不改。

上面第 1 到 4 步一直重複使用同一個 evolve set,而且下一輪要改什麼,取決於前幾輪在同一批題目上量到的結果。這在統計上叫 adaptive data reuse(適應性資料重用):這批題目不再是獨立的檢驗資料,而是被搜尋過程一步步「看過」的資料。結果是 evolve set 的分數一直漲,換到沒看過的任務,進步大幅縮水,甚至比什麼都沒改的原始 harness(記作 H0 H_0 )還差。簡單說,每一輪的決定都建立在這批題目的結果上,這批題目的分數就不再可信,原理在文末的概念一。

散佈圖:橫軸為 evolve 題目上的相對進步,縱軸為沒看過的 benchmark 上的相對進步,四個既有方法落在 1:1 轉移對角線下方,只有 RRSI 在線上方。
圖 1 — 既有方法在進化用題目上進步,換到沒看過的題目卻無法轉移;RRSI 的進步能搬過去。(來源:原始論文。)

圖 1 有多個子圖,這裡看(a),是 agentic workspace 任務的結果;coding 與 engineering 的「四個對手平均」放在(b)、(d)。橫軸是在 evolve 題目上的相對進步,縱軸是在沒看過的 benchmark(OOD)上的相對進步,圖上有一條「1:1 transfer」的對角線,代表進步能完整搬過去。四個既有方法(Meta-Harness、AHE、TTHE、HarnessX)都落在線的下方,有的縱軸甚至是負的(圖上標示 “gain does not transfer”),只有 RRSI 落在上方。

論文歸納出三個互相耦合的行為,合起來把「evolve 分數」和「換題目後的分數」之間的差距越拉越大。這三個行為剛好對應後面的護欄:

行為白話自編例子對應的護欄
benchmark-specific fitting(針對特定 benchmark 的擬合)修改內容直接記住了這批題目的特徵某題失敗是因為公司名稱格式不對,proposer 就在 prompt 裡加一句「遇到 Acme 公司的報表要用 YY 格式」。evolve 分數上升,換一批題目完全派不上用場D(leakage screening)
noise chasing(追逐雜訊)選中的候選只是這次評分運氣好4 個候選真實實力都是 90.0,各自量到 89.7、90.4、89.9、90.1,挑最高的 90.4,看起來進步 0.4,其實一分都沒進步E(分數底線)、雜訊帶 δ \delta
complexity accumulation(複雜度累積)越改越肥,分數靠多花運算換來,不是靠更好的機制表 2 裡沒有任何正則化的進化:evolve 分數最高,token 卻是原始 harness 的 2.4 倍F(成本規則)、G(結構剪枝)

兩個提醒。第一,這三個行為在概念上分得很清楚,實務上很可能同時發生在同一個修改上(推論:例如一個寫死題目特徵的修改,同時也讓 prompt 變長)。第二,論文只用一小段文字介紹這三個行為,沒有各自做實驗量出它們各佔多少,後面的 ablation 是把整組正則化一起拿掉。

  • evolve set:進化過程中被反覆用來評分的題目集。
  • ID held-out(in-distribution held-out):同一個 benchmark 裡,進化時沒用到的題目。
  • OOD(out-of-distribution):進化時完全沒看過的 benchmark。
  • policy:實際執行任務的那個模型。論文主實驗的 policy 固定為 Claude Opus 4.8。
  • trajectory:agent 執行一題任務的完整紀錄,包含每一步的推理、工具呼叫與結果。

RRSI 完全不縮小 harness 能改的範圍,它只管兩件事:proposer 怎麼提出修改(提案端),以及哪些量到的進步可以變成永久狀態(篩選端)。

把 harness 想成一個 repo,把每一輪進化想成一次 PR 流程:

  • 不限制可修改範圍:repo 裡任何檔案都可以動,prompt、工具、記憶、控制流程、subagent 都允許改。論文用 Ω(H) \Omega(H) 代表「從 H H 出發,改任意原始碼所能到達的所有 harness」,並刻意讓它保持開放。
  • 提案端是對「怎麼提 PR」的規範:一個 PR 最多改幾件事(A)、提之前要看過去被退回的紀錄(B)、很久沒進展時要去動沒碰過的模組(C)。
  • 篩選端是 merge 的關卡:CI 分數變高還不夠,還要沒有寫死測試答案(D)、不是 flaky test 運氣好(E)、沒有讓 build 時間暴增卻沒換到對等效益(F)。
  • 永久狀態就是 merge 進 main:被選中的 Ht+1 H_{t+1} 會成為下一輪所有提案的起點,選錯一次,錯誤會疊在後面每一輪。

這個比喻有個不成立的地方:真實的 code review 有獨立的人和獨立的測試,而 RRSI 的「CI」就是同一批 evolve set 的評分,這批評分本身有雜訊,還會被反覆使用。所以 D、E、F 只是補洞,不能取代獨立的驗證(推論)。

RRSI 架構總覽:左側為提案端的三個零件,右側為篩選端的零件,中間以轉移規則串起兩側。
圖 2 — RRSI 總覽。左邊是提案端 A、B、C,右邊是篩選端 D、E、F、G,中間是把兩邊串起來的轉移規則。(來源:原始論文。)
代號名稱在做什麼對付的問題
Aannealed update sparsity(退火式更新稀疏)限制一個候選最多綁幾個修改,隨輪數遞減綁太多修改,容量高又難歸因
Bevidence-aware credit assignment(證據感知的功勞分配)記錄每個修改的結果,之後提案要參考不要一直重試已被否定的點子
Cstructured exploration(結構化探索)進度停滯時,保留名額給沒試過的元件類別提案集中在同一類修改(例如一直改 prompt)
Dleakage screening(洩漏篩檢)評分前由 critic(負責審查的 LLM)讀修改內容,擋寫死題目資訊的修改benchmark-specific fitting
Enoise-adjusted performance floor(雜訊校正的分數底線)候選分數要 ≥ \geq 歷史最高分 − δ -\ \delta noise chasing(實際擋的是連續小退步,見概念四)
Fcomplexity-aware acceptance(複雜度感知接受)多花的 token 要用分數進步來換complexity accumulation
Gstructural pruning(結構剪枝)一段時間沒有正貢獻的元件,列為刪除目標complexity accumulation

D 到 G 與三個行為的對應,是論文在 Section 3.3 開頭自己講的。A 到 C 論文沒有逐項對應,只講了理由。我的推論是:A 到 C 在「源頭」降低容易過擬合的提案,D 到 G 在「出口」把關。

兩側的分法只是概念分類,不是程式分工。Algorithm 1(提案端)裡就已經包含了 D 的評分前篩檢,以及 G 的剪枝目標計算。

舊規則(Eq. 2)的選擇範圍是「所有候選加上 Ht H_t 」。RRSI 的版本(論文 Eq. 8):

Ht∼Preg(⋅∣Ht,Ft,Lt,bt,Et,Bt),Ht+1=arg⁡max⁡H′∈Ht∩AtS^(H′)\mathcal{H}_t \sim P_{\text{reg}}(\cdot \mid H_t, \mathcal{F}_t, \mathcal{L}_t, b_t, \mathcal{E}_t, \mathcal{B}_t), \qquad H_{t+1} = \arg\max_{H' \in \mathcal{H}_t \cap \mathcal{A}_t} \hat{S}(H')

若沒有任何候選通過(交集是空集合),則 Ht+1=Ht H_{t+1} = H_t 。

  • Preg P_{\text{reg}} :受限的提案分布。它其實就是 proposer LLM,只是輸入多了下面幾項。
  • Lt \mathcal{L}_t :過去所有修改的歷史紀錄(零件 B)。
  • bt b_t :這一輪每個候選最多綁幾個修改(零件 A)。
  • Et \mathcal{E}_t :探索指令,停滯時要去試沒試過的元件(零件 C)。
  • Bt \mathcal{B}_t :結構剪枝的刪除目標(零件 G)。
  • At \mathcal{A}_t :admissible set(可接受集合),也就是通過所有關卡的候選,由 D、E、F 與領域 guard 決定誰進來。
  • ∩ \cap :交集。只有「候選」與「可接受」同時成立的才能參賽。

所以只改了兩處:提案分布從無限制的 P0 P_0 換成受限的 Preg P_{\text{reg}} ,挑最高分的範圍從全部候選縮成通過關卡的候選,全滅就維持原樣。

自編例子:Ht H_t 的分數是 90.0,本輪有三個候選。X 是 91.0,被 D 擋下(寫死題目資訊)。Y 是 90.8,被 F 擋下(成本漲太多)。Z 是 90.5,全部通過。舊規則會選 X,RRSI 選 Z。如果 Z 也沒通過,Ht+1=Ht H_{t+1} = H_t ,這一輪什麼都不改。

傳統正則化在最佳化的目標函數裡加一項懲罰,限制模型「能長成什麼樣子」。RRSI 沒辦法這樣做:harness 的候選空間是異質的,一個候選改 prompt,另一個新增 subagent,第三個改控制流程,這些東西放不進同一個參數向量,也就無法定義「參數有多大」。論文在 Appendix C 也直說,它沒有在最佳化任何範數懲罰的目標函數。

所以 RRSI 改成限制搜尋「怎麼一步步走」:不動假設空間,只管提案規則和接受規則。論文把 A 稱為 L0 風格、G 稱為 L1 風格、F 稱為 L2 風格,這只是比喻,名詞不會帶來稀疏或收縮的性質,詳見概念三。

表 2 的 ablation 只有整組拿掉,沒有任何零件單獨的驗證,下面各節不再逐一重複這一點。提案端的三個零件都是交給 proposer 的輸入。只有 A 有明確的數字,B 和 C 是餵給 LLM 的資訊,論文沒有描述怎麼確保 proposer 照做。

proposer 可以把很多不相關的修改綁在一個候選裡。綁越多,越容易擬合眼前這批 feedback 的特例(容量高),而且分數變了也不知道是哪個修改造成的(難歸因)。

RRSI 的做法是每一輪規定一個候選最多能綁 bt b_t 個「獨立可歸因的修改」,而且 bt b_t 隨輪數遞減。早期允許綁多個修改去探索新機制,後期逐步收緊。這就是 learning rate scheduler 式的排程,只是被排程的對象是「一次能改幾件事」。論文 Eq. 4:

bt=⌈ bmin⁡+(bmax⁡−bmin⁡)⋅12(1+cos⁡(πt/T))⌉b_t = \left\lceil\, b_{\min} + (b_{\max}-b_{\min})\cdot \tfrac{1}{2}\Big(1+\cos\big(\pi t/T\big)\Big) \right\rceil

t t 是第幾輪(從 0 開始),T T 是總輪數,bmax⁡ b_{\max} 是起始預算,bmin⁡ b_{\min} 是終點預算,⌈ ⌉ \lceil\ \rceil 是向上取整。中間那個係數會從 1 平滑降到 0,所以 bt b_t 從 bmax⁡ b_{\max} 降到 bmin⁡ b_{\min} (推導見概念六)。

用表 5 的 coding 設定(T=20 T = 20 、bmax⁡=4 b_{\max} = 4 、bmin⁡=1 b_{\min} = 1 )把 20 輪全部算出來(用公式算的,論文沒有列):

輪數 t t 預算 bt b_t 持續幾輪
0 到 748 輪
8 到 1235 輪
13 到 1927 輪
表 5:RRSI 在 coding、agentic workspace、engineering design 三個設定下使用的超參數。
表 5 — 三個領域的超參數。論文說所有數值都只用 evolve 環境選定,沒有參考 held-out 或 OOD 的結果。(來源:原始論文。)

論文裡的真實例子在表 6(Coding R0-A):第 0 輪的候選同時加了「完成前的驗證檢查」和「長時間任務的非阻塞輪詢指引」,evolve set 進步 3.93 分,被接受。第 0 輪預算是 4,允許這樣綁。

用公式與論文超參數可以推出兩個發現:

  • 預算永遠到不了 bmin⁡=1 b_{\min} = 1 。 t<T t < T 時係數一定大於 0,向上取整前的值一定大於 1,所以最小是 2。bt=1 b_t = 1 只會在 t=T t = T 出現,但 Appendix C.1 說一次進化只跑 t=0 t = 0 到 T−1 T - 1 。agentic 與 engineering 的最後一輪也都是 2。但表 5 把 bmin⁡ b_{\min} 標成 “final-round edit budget”,值是 1。有兩種讀法:照公式字面,最後幾輪仍可綁兩個修改,歸因沒有論文宣稱的那麼乾淨。或者實作的取整方式或輪數編號不同,最後一輪真的是 1。論文文字無法判定。
  • 餘弦形狀幾乎是包裝。 取整之後整個排程只剩 4、3、2 三個台階,跟「前 8 輪 4 個、中間 5 輪 3 個、後 7 輪 2 個」的階梯函數沒有實質差別。餘弦只決定台階在哪一輪切換,換成直線遞減會得到幾乎一樣的結果(推論)。論文也沒有單獨對排程形狀或「退火」做 ablation。

B 的做法是替每個被評估過的候選寫一筆「實驗紀錄」,之後每一輪都讓 proposer 讀這份紀錄,避免重試已失敗的點子,也記得已成功的點子。紀錄格式(論文 Eq. 10):

Lt={ (ti, ℓi, hi, di, ΔSi, ΔCi, ai)  :  i≤nt },ai∈{0,1}\mathcal{L}_t = \big\{\,(t_i,\ \ell_i,\ h_i,\ d_i,\ \Delta S_i,\ \Delta C_i,\ a_i) \;:\; i \le n_t \,\big\}, \qquad a_i \in \{0,1\}

每筆紀錄是一個七元組:

  • ti t_i :這個修改是第幾輪提出的。
  • ℓi \ell_i :修改的元件類別(component),例如 prompt、control_flow、memory、subagent。
  • hi h_i :這個修改想驗證的假設(hypothesis)。
  • di d_i :實際的程式碼差異(source diff)。
  • ΔSi \Delta S_i :分數變化,候選相對在位 harness 的分數增益。
  • ΔCi \Delta C_i :成本變化,token 成本增加的比例。
  • ai a_i :有沒有被採用。ai=1 a_i = 1 表示這個修改所屬的候選在該輪贏了。ai=0 a_i = 0 包含所有其他情況,包括被規則擋下的,也包括通過了規則但輸給另一個分數更高的候選(Appendix C.2 明講)。
  • nt n_t :第 t t 輪之前累積的紀錄總數。

一個候選如果綁了多個修改,每個修改各寫一筆,但這些紀錄共用同一組 ΔS \Delta S 、ΔC \Delta C 和結果。

表 6:RRSI 進化過程中的代表性決策,包含 Coding R0-A、R0-B、R8-B 與 Engineering R2,各列出修改內容、結果與說明的重點。
表 6 — 代表性的進化決策。證據顯示一個修改能否被留下,不只看分數,還要看特異性、評估穩定度與推論成本。(來源:原始論文。)

下面是表 6 其中三筆改寫成紀錄的樣子:

案例修改內容ΔS \Delta S ΔC \Delta C ai a_i
Coding R0-A完成前的驗證檢查,加上長任務的非阻塞輪詢指引+3.93 分論文未列1
Coding R0-B類似的驗證提醒,加上長任務指引+1.69 分+26.1%0(被成本規則拒絕)
Engineering R2針對「workdir must be an existing directory」錯誤的復原提示122/244 到 128/244 passes+1.6%1

credit assignment(功勞分配)出自強化學習,問題是「一連串動作之後才拿到一個獎勵,該把功勞分給哪個動作」,常被追溯到 Minsky 1961(這是一般知識,不是論文內容)。這篇論文用得有點過頭:實際只是「保留一份實驗紀錄給 proposer 看」,並沒有計算每個修改各自的貢獻。

幾個疑點與限制:

  • 綁在一起的修改,功勞沒有被真正分開。 R0-A 的兩個修改(把它讀成兩個修改是我的解讀)會各有一筆 +3.93 的紀錄,看起來像各自進步 3.93,實際只是合起來進步 3.93。這使 B 的品質綁在 A 上。
  • ai=0 a_i = 0 混了兩種意思:「規則擋下」與「輸給更好的同輪候選」。後者不代表點子失敗。R0-B 就是例子:假設方向和 R0-A 相同,被拒絕是因為只進步 +1.69、又多花 26.1%,意思是「這個版本不划算」,不是「驗證提醒沒用」。論文沒說 proposer 怎麼區分。
  • 論文沒說 proposer 怎麼「條件在這份歷史上」(整份放進 prompt,還是先做摘要),也沒說 ℓi \ell_i 與 hi h_i 兩個標籤由誰標。
  • 被 critic 在評分前擋掉的候選沒有量測值,可能不在紀錄裡(概念八)。
  • 「把歷史給 proposer 看」不是新東西。Appendix B 描述的基線 Meta-Harness 與 AHE 已經在做類似的事,B 的差別只剩格式更結構化,論文沒有單獨量這個差別,表 2 也沒有單獨拿掉 B。

C 是一條防偏食規則:搜尋連續幾輪沒有進展時,把停滯訊號與「這次進化裡還沒碰過的元件類別」清單交給 proposer,並保留一個候選名額給探索。論文舉的例子是 proposer 一直改寫 prompt,agent 的結構性機制(工具、記憶、subagent)都沒動過。B 讓 proposer 看到歷史,但歷史本身不保證它會去試新方向。

機制在論文 Eq. 13 與 Appendix C.2:

σt=1[S^t−S^t−w≤δ],Ut=K∖Tt,Et=(σt, Ut, mdraft)\sigma_t = \mathbb{1}\big[\hat S_t - \hat S_{t-w} \le \delta\big], \qquad U_t = \mathcal{K} \setminus \mathcal{T}_t, \qquad \mathcal{E}_t = (\sigma_t,\ U_t,\ m_{\text{draft}})
  • S^t \hat S_t :第 t t 輪在位 harness 的評分。w w :停滯偵測的視窗大小,看最近 w w 輪。
  • δ \delta :雜訊帶(概念四)。進步不超過它,就當作跟雜訊分不開。
  • 1[⋅] \mathbb{1}[\cdot] :括號裡成立就是 1,否則是 0。σt=1 \sigma_t = 1 表示「停滯中」。
  • K \mathcal{K} :元件類別的全集,共 9 類:prompt、control_flow、config、output_plumbing、context_mgmt、client_tool、skill、memory、subagent。
  • Tt \mathcal{T}_t :到目前為止,至少有一筆被量測過的修改所屬的類別。Ut U_t 是 K \mathcal{K} 減去 Tt \mathcal{T}_t ,也就是還沒碰過的類別。
  • mdraft m_{\text{draft}} :停滯時保留給探索的候選名額數。

用表 5 的 coding 設定(w=3 w = 3 、δ=0.017 \delta = 0.017 、mdraft=1 m_{\text{draft}} = 1 )走一次,分數是自編的:S^5=0.780 \hat S_5 = 0.780 、S^8=0.792 \hat S_8 = 0.792 ,差 0.012,不超過 0.017,所以 σ8=1 \sigma_8 = 1 ,判定停滯。若 S^8=0.805 \hat S_8 = 0.805 ,差 0.025 大於 0.017,σ8=0 \sigma_8 = 0 ,不觸發。假設前 8 輪碰過 prompt、control_flow、context_mgmt 三類,則 U8 U_8 是其餘 6 類,proposer 會拿到這份清單,並被要求留 1 個候選名額給它們。

疑點與限制:

  • 論文沒有描述怎麼確保 proposer 照做,用詞只有 reserved、redirect,沒有任何強制機制(概念七)。
  • 「沒碰過」的判定很粗:碰過 prompt 一次就算試過,不管改的是哪一段,被拒絕的修改也算數。
  • 推論:K \mathcal{K} 只有 9 類,每輪又有好幾個候選,Ut U_t 可能很快變空,論文沒說變空時怎麼處理。
  • 元件標籤由誰標(proposer、程式或另一個分析 LLM),論文未說明,而 C 的判定完全依賴這些標籤。
  • 表 6 的案例也沒有停滯觸發的例子,沒有證據顯示它有作用。

A、B、C 是三份給 LLM 的軟性指示,只有 bt b_t 是明確的數字。方向都合理,工程上也容易實作,但論文沒有證明每一個各自有效。整個提案端唯一的證據是表 2 的一列 “w/o proposal regularizers”。我的推論是 B 最可能有用,因為把過去的結果給 proposer 看,是所有基線都在做的事,A 和 C 的效果最不確定。

篩選端是一串各擋不同東西的關卡,候選必須依序全部通過,最後在倖存者裡挑分數最高的。每一關的設計都合理,但沒有任何一關有單獨的驗證。

在候選被拿去評分之前,先由一個 critic(專門負責審查的 LLM)讀它的程式碼差異(diff),把「寫死題目資訊」的修改擋在門外。論文明講的部分(Section 3.3、4.1、Appendix C.3):

  • 擋的東西:明確寫進任務名稱、實體名稱、任務特定數值、答案,或其他只對 evolve benchmark 成立的邏輯。另外也擋 “inert machinery”(加了但沒有作用的程式)。
  • 管的是內容,不是元件類別:通用的 prompt 或工具說明改進仍然可以通過。
  • 時機在評分之前。理由是被擋的候選永遠拿不到那個會讓它顯得有吸引力的 evolve set 高分。
  • 執行者是 Claude Opus 4.8,和 proposer、analyst 同一個模型。

leakage 出自機器學習的 data leakage,指測試資料的資訊漏進訓練過程,讓評估失真。這裡用得貼切,不是包裝:如果候選把 evolve 題目的答案寫進 harness,就等於評分標準漏進了被評分的對象,evolve 分數會被灌水。

自編例子:候選 P 在 prompt 加一句「遇到 Acme 公司的併購合約,違約金條款固定寫 15%」,被擋(寫死實體名稱與數值)。候選 R 新增一個從沒被呼叫的輔助函式,被擋(inert machinery)。放行的真實例子是表 6 的 Engineering R2:針對「workdir must be an existing directory」這個反覆出現的工具錯誤,加一個有界的復原提示。它不含任何題目資訊,被接受了(122/244 到 128/244 passes,token 只多 1.6%),論文拿它當 task-agnostic 修正的代表。

疑點與限制:

  • critic 的判準與提示詞沒有公開,也沒有可調的門檻,「通用」與「針對這個 benchmark」的界線完全是 LLM 的判斷。
  • 只擋明確寫死的內容。沒有寫死名稱卻恰好貼合 evolve 題目分布的修改(例如假設每題都要附摘要表),critic 不太可能抓到(推論)。
  • critic 與 proposer 是同一個模型,盲點可能高度重疊(推論)。
  • 表 6 的案例裡沒有任何一個是被 critic 擋下的,也沒報告擋掉的比例。

進化開始前,先把沒改過的 H0 H_0 重複評分幾次,看分數自然會晃多大,這個幅度就是 δ \delta 。之後任何候選的分數,都不准比「歷史最高分減去 δ \delta 」還低。

論文只給方法的一句話(進化前重複評估沒改過的 base harness,估出 empirical noise band),之後 δ \delta 固定不變。論文給了三個領域的結果與對應的實際數量(表 5、Appendix D.1),我驗算過:3/178 ≈ \approx 0.0169、60/14,100 ≈ \approx 0.0043、5/244 ≈ \approx 0.0205,與表上一致。

領域δ \delta 對應的實際數量
coding0.017(1.7 分)3 個 pass,總共 89 題 × k=2 k = 2 = 178 次試驗
agentic workspace0.004(0.4 分)60 個評分項目,總共約 14,100 個
engineering design0.020(2.0 分)5 個 pass,總共 61 題 × k=4 k = 4 = 244 次試驗

表中的 k k 是每題每次評估重複跑的次數,pass 指通過的試驗數。論文沒說進化前重複評估幾次,也沒說用什麼統計量當 δ \delta (標準差、全距還是某個分位數)。

分數底線(論文 Eq. 5):

S^(H′)  ≥  S⋆−δ\hat S(H') \;\ge\; S^{\star} - \delta

S^(H′) \hat S(H') 是候選 H′ H' 在 evolve set 上實測的分數。S⋆ S^{\star} 是到目前為止,整個進化過程中觀察到的最高 evolve 分數,起點是 S^(H0) \hat S(H_0) ,每輪更新成 max⁡(S⋆,S^(Ht+1)) \max(S^{\star}, \hat S(H_{t+1})) 。它是接受候選的必要條件,而且不能被其他項目抵銷(論文稱 non-compensatory)。表 6 的 Coding R8-B 是唯一實例:把原始任務指令釘進完成關卡,分數 −2.81 -2.81 、成本 −13.6% -13.6\% ,coding 的 δ \delta 是 1.7 分,退步超過了,省成本也救不回來。

底線綁在歷史最高分,而不是在位 harness,是為了防止搜尋「連續走下坡」:每一步的退步都小到可以當作雜訊,累積起來卻很多。數字例子見概念四。

這一關有個容易忽略的事實:它防的其實不是「假進步」。 論文 Section 3.3 用 noise chasing 來描述 E,但 Eq. 5 只設了下限,擋的是連續小退步。一個靠運氣多量到 0.3 分的候選,不會被它擋住。若要真的擋掉運氣造成的假進步,統計上更合理的是要求 S^(H′)≥S⋆+δ \hat S(H') \ge S^{\star} + \delta ,代價是會誤殺運氣差的真進步。兩種做法的取捨在概念四。

其他疑點:

  • δ \delta 只在 H0 H_0 上量過一次,之後套用到所有候選,論文沒驗證這個假設。進化後的 harness 步驟更多(圖 4(b):21.2 步增加到 26.3 步),雜訊未必和 H0 H_0 一樣(推論)。
  • S⋆ S^{\star} 記錄的是被選中候選的實測分數,而被選中的是最高的那個,所以可能被運氣墊高(贏家詛咒:從有雜訊的分數挑最高的,那個高分通常被運氣墊高,詳見概念二)。
  • Algorithm 2 沒說在位 harness 的分數 S^t \hat S_t 是沿用當初選中時的量測,還是每輪重量。

F 的原則是:多花的 token 要用分數進步來換,進步越多,允許多花越多。先定義兩個量(論文 Eq. 6),再看規則(Eq. 7):

ΔS=S^(H′)−S^(Ht),ΔC=C^(H′)−C^(Ht)C^(Ht)\Delta S = \hat S(H') - \hat S(H_t), \qquad \Delta C = \frac{\hat C(H') - \hat C(H_t)}{\hat C(H_t)}ΔC≤β0+β1×ΔS(只在 ΔS>δ 時使用)\Delta C \le \beta_0 + \beta_1 \times \Delta S \qquad (\text{只在 } \Delta S > \delta \text{ 時使用})
  • ΔS \Delta S :候選比目前在位的 harness 多拿了幾分(用比例表示,多過 7 題 / 178 題 = 0.039)。注意是跟在位 harness 比,不是跟歷史最高分比。
  • ΔC \Delta C :每次試驗平均 policy tokens 的相對變化。1.0M 變 1.5M 就是 0.5,變省則是負數。
  • β0 \beta_0 :基本額度,不管進步多少都先給這麼多(coding 是 0.10,即 10%)。
  • β1 \beta_1 :換算率,每進步一單位,額外允許多少成本增加(coding 是 44.5)。

白話:允許增加的成本 = 基本額度 + 換算率 × 分數進步。實際增加的成本沒超過這個額度就通過,超過就拒絕。

自編例子,用 coding 的設定(β0=0.10 \beta_0 = 0.10 、β1=44.5 \beta_1 = 44.5 ):

候選 A候選 B
多過幾題7 題4 題
ΔS \Delta S 7/178 = 0.0394/178 = 0.022
允許增加的成本0.10 + 44.5 × 0.039 = 1.85(185%)0.10 + 44.5 × 0.022 = 1.10(110%)
實際增加的成本50%150%
結果50% ≤ \le 185%,通過150% > > 110%,拒絕

進步 7 題,多花 50% 划得來。進步 4 題,多花 150% 就不划算。

β \beta 的實際意思(Appendix D.1,我驗算過):coding 的 β1=44.5 \beta_1 = 44.5 相當於每多過 1 題允許多 25% token。agentic 的 β1=35.4 \beta_1 = 35.4 是每多 100 個評分項目多 25%。engineering 的 β1=24.4 \beta_1 = 24.4 是每多過 1 題多 10%。β0 \beta_0 分別是 0.10、0.10、0.15。

疑點與限制:額度很寬,而且是相對在位版本算的,沒有對 H0 H_0 的絕對上限。連續接受三次各多 30% 的候選,累計是 1.33 1.3^3 ,約 2.2 倍(算術)。β \beta 的選法沒有敏感度分析。

進步沒超過 δ \delta 的候選(包含小幅退步),不看成本上限,改用一個加減分數的算式決定要不要收:

ws ΔS  −  wc ΔC  +  wn ν  >  0w_s\,\Delta S \;-\; w_c\,\Delta C \;+\; w_n\,\nu \;>\; 0
  • ΔS \Delta S 、ΔC \Delta C :同上。ΔS \Delta S 進步為正,ΔC \Delta C 變貴為正、變省為負。
  • ν \nu :這個候選碰到的結構性元件(client_tool、skill、memory、subagent 四類)裡,有幾類從來沒出現在「被採用的修改」中。
  • ws w_s 、wc w_c 、wn w_n :三項各自的權重。

白話:進步加分、變貴扣分、試了沒人成功過的新結構加分,加總大於 0 就通過。coding 設 ws=0 w_s = 0 ,分數變化在這條規則裡完全不算分,算式只剩 −wcΔC+wnν>0 -w_c \Delta C + w_n \nu > 0 。

自編例子,三個 coding 候選,都在雜訊帶內、都通過分數底線:

分數成本碰新結構算式結果
P+3 題+26%沒有−wc×0.26 -w_c \times 0.26 拒絕,不管權重多少
Q持平−10% -10\% 沒有+wc×0.10 +w_c \times 0.10 通過(只要 wc>0 w_c > 0 )
R持平+5%首次加 memory−wc×0.05+wn -w_c \times 0.05 + w_n wn>0.05 wc w_n > 0.05\,w_c 才通過

P 就是表 6 的 Coding R0-B(+1.69 分、+26.1% 成本,被拒絕)。R0-B 進步 3 題,coding 的 δ \delta 約 3 題(1.7 分),不算「超過」,所以走的是這條規則。這是我用數字對出來的,論文沒有明寫。

疑點與限制:

  • 論文說 ws w_s 、wc w_c 、wn w_n 列在表 5,實際的表 5 沒有這三個,所以新奇加分到底多強無從得知。
  • 分支邊界是一個懸崖。 coding 裡多過 3 題、多花 26% 被拒。多過 4 題(ΔS \Delta S 超過 δ \delta ,改走 Eq. 7)允許多花約 110%,多花 80% 也能過。3 題和 4 題只差 0.56 分,遠小於雜訊帶本身。
  • 這條規則是論文裡比 C 更硬的探索推力,因為它直接改變誰能被收。但它只管雜訊帶內的候選,也只對四類結構性元件有效。
  • 為什麼 coding 的 ws=0 w_s = 0 ,以及它是不是為了讓小進步過關,見概念九。

如果某類元件最近幾輪的修改都沒有帶來進步,就把它列為刪除目標,交給 proposer,請它提出「把這類東西拿掉」的修改。

gt(ℓ)=max⁡{ΔSi:ℓi=ℓ,  t−ti≤nprune},Bt={ℓ∈Tt:gt(ℓ)≤0}g_t(\ell) = \max\{\Delta S_i : \ell_i = \ell,\; t - t_i \le n_{\text{prune}}\}, \qquad \mathcal{B}_t = \{\ell \in \mathcal{T}_t : g_t(\ell) \le 0\}
  • ℓ \ell :元件類別,共 9 類。ΔSi \Delta S_i :第 i i 筆紀錄的分數變化(紀錄格式見 B)。
  • t−ti≤nprune t - t_i \le n_{\text{prune}} :只看最近 nprune n_{\text{prune}} 輪的紀錄(coding 是 4,engineering 是 5)。
  • gt(ℓ) g_t(\ell) :這類元件最近幾輪裡,最好的一次分數變化。
  • Tt \mathcal{T}_t :到目前為止至少被修改過一次的類別。Bt \mathcal{B}_t 是 gt(ℓ)≤0 g_t(\ell) \le 0 的那些類別,即剪枝目標。

白話:最近 4 輪裡,這類元件最好的一次也沒有進步(小於等於 0),就列入刪除目標。自編例子,第 8 輪、nprune=4 n_{\text{prune}} = 4 ,只看第 4 輪以後的紀錄:

元件類別紀錄(輪次:分數變化)窗口內最好的一次結果
memory第 3 輪 +0.02、第 5 輪 −0.01 -0.01 、第 6 輪 0.000.00(第 3 輪已超出窗口)列為刪除目標
skill第 6 輪 +0.01+0.01保留

它只是建議,不是強制刪除。 每一輪開始時,程式用歷史紀錄算出 Bt \mathcal{B}_t 放進 proposer 的輸入,Appendix C.2 說 proposer 被指示要移除沒有產出的機制。程式不會直接刪任何東西,proposer 提出刪除的候選之後,還是要走完全部關卡。所以誤列的代價只是 proposer 白白花了一個提案名額:如果那個元件其實有用,刪掉後分數會掉,被 E 擋下。如果刪掉沒影響又省了成本,這個候選在成本規則裡反而加分。

疑點與限制:

  • 公式規定空集合的最大值是負無限大,所以「以前試過、但窗口內完全沒紀錄」的類別按字面也會被列入。而 Appendix C.2 的文字說的是「最近有被動過但沒進步」,論文未判定是哪一種。
  • 「元件」在這裡是 9 個大類別,論文沒說實際刪的是整類,還是類別底下的某一段。
  • G 在圖 2 與 Section 3.3 被放在篩選端,但 Algorithm 1 是在提案端算出剪枝目標,靠 proposer 執行。

coding 與 agentic 沒有 guard,這一關等於直接放行。engineering 的候選只要符合下面任一條就被拒絕,而且不能被分數抵銷(Appendix C.3):

  • 有效輸出率(valid-output rate)比在位版本掉了超過 0.03。
  • 沒有提交率(no-submission rate)比在位版本升了超過 0.02。

用意是避免「通過率上升,但基本執行有效性大幅變差」的候選被收進來。自編例子:在位版本有效輸出率 0.95,候選的通過率進步了,但有效輸出率掉到 0.90,掉了 0.05,超過 0.03,被拒絕。兩個門檻(0.03、0.02)不在表 5,論文沒說怎麼選,兩個比率也只有名稱,沒有定義。

候選要被收,依序要過這幾關(Algorithm 2):

  1. D:critic 檢查(評分之前)。
  2. 在 evolve set 上評分,得到 ΔS \Delta S 、ΔC \Delta C 。
  3. E:分數不能比歷史最高分低超過 δ \delta 。
  4. ΔS>δ \Delta S > \delta 走 F(Eq. 7),否則走雜訊帶內規則(Eq. 17)。
  5. 領域 guard(只有 engineering)。
  6. 全部通過的候選裡,挑分數最高的當 Ht+1 H_{t+1} ,並更新 S⋆ S^{\star} 。沒有任何候選通過,Ht+1=Ht H_{t+1} = H_t 。

最後一步仍然是「挑分數最高的」,所以贏家詛咒(概念二)並沒有被完全消除,只是前面的關卡先把明顯有問題的濾掉了。

代號零件什麼時候檢查檢查什麼對付的問題
Dleakage screening評分前critic 讀 diff,擋寫死題目資訊、擋沒作用的程式針對特定 benchmark 的擬合
E分數底線評分後分數 ≥ \ge 歷史最高分 − δ -\ \delta 論文說是追逐雜訊,實際擋的是連續小退步
F成本規則(Eq. 7)評分後,進步 >δ > \delta 多花的成本 ≤β0+β1ΔS \le \beta_0 + \beta_1 \Delta S 複雜度累積
-雜訊帶內規則(Eq. 17)評分後,進步 ≤δ \le \delta wsΔS−wcΔC+wnν>0 w_s \Delta S - w_c \Delta C + w_n \nu > 0 不把小波動當證據
G結構剪枝每輪開始(在提案端)最近沒進步的元件,建議 proposer 刪除複雜度累積
-領域 guard評分後(只有 engineering)有效輸出率、沒提交率不能明顯變差防止基本品質被破壞
-最終選擇最後倖存者挑分數最高,沒人倖存就維持原樣-

最扎實的證據是 agentic 領域的表 1 與表 2:RRSI 在進化用題目上進步最小,在沒看過的 benchmark 上進步最大,而且拿掉正則化後這個優勢就消失。其餘實驗都是補強,方向一致,但每個都只有一個數字、沒有變異數。

論文在三個領域、八個 benchmark 上實驗。每個領域只在一個 benchmark 上進化,然後把 harness 原封不動拿去跑其他 benchmark。

領域Benchmark角色內容與分數
codingTerminal-Bench 2.1evolve89 個容器化終端機任務,該任務自己的單元測試通過才算解出
codingSWE-bench VerifiedOOD真實 GitHub issue 的修復率,patch 要讓 fail-to-pass 測試轉為通過、pass-to-pass 測試仍通過
agenticHarvey LABevolve(120 題)與 ID held-out(40 題)法律工作,25 個 practice area。每題有 20 到 100 條評分準則,由 LLM judge 逐條判定,分數是通過的準則比例
agenticJobBenchOOD真實職場工作流程,加權評分表分數。評審是 Gemini-3.5-Flash 與 Claude Opus 4.8 的平均
agenticGDPvalOOD交付物與人類專家的交付物並排比較,三個評審模型多數決。分數是贏過人類專家的比例(185 題)
agenticAPEX-AgentsOOD480 題,沙盒環境裡有多種 MCP 工具,pass@1(單次執行即成功)
engineeringEngDesignevolve61 題設計任務,各自由模擬器或 testbench 評分,結果確定,沒有評審模型
engineeringFrontier-EngOOD26 個領域的工程最佳化。Medal Score 依結果達到金、銀、銅門檻給 1、0.67、0.33 分後取平均,47 題中 38 題有得分

其他設定:policy 固定為 Claude Opus 4.8,proposer、analyst(寫失敗回饋的)、critic 也都是 Opus 4.8。起點 H0 H_0 是 Terminus-2(coding)與 ReAct 迴圈加 MCP 工具與 ReSum 式 context 管理(agentic、engineering)。四個基線 Meta-Harness、AHE、TTHE、HarnessX 都從同一個 H0 H_0 出發,共用 policy、evolve set 與候選預算。超參數見前面的表 5。

表 1:RRSI 與四個既有 harness 進化方法在 agentic workspace 任務上的比較,欄位包含 Harvey LAB 的 evolve 與 ID held-out,以及 JobBench、GDPval、APEX-Agents。
表 1 — 與既有 harness 進化方法在 agentic workspace 任務上的比較。(來源:原始論文。)

只有 agentic 這個領域有逐一對手的數字,coding 與 engineering 只在圖 1(b)、(d)有「四個對手的平均」。欄位的意思:Harvey LAB (Evolve) 是進化用的 120 題,Harvey LAB (ID Held-out) 是同 benchmark 沒用過的 40 題,JobBench、GDPval、APEX-Agents 是完全沒看過的三個 benchmark。三個 OOD 分數的意思不同(加權評分表、勝率、任務成功率),所以 OOD 平均只是方便的摘要,沒有單一含義。

下表是用表 1 算出的對照,每個數字是相對沒進化的 H0 H_0 進步多少。OOD 平均欄是我自己算的,論文只在表 2 與圖 1 給 H0 H_0 與 RRSI 的平均:

方法Evolve 進步ID held-out 進步OOD 平均OOD 平均進步
H0 H_0 (沒進化)--39.7-
Meta-Harness+3.6+2.340.6+0.9
HarnessX+2.4+2.239.70.0
AHE+1.3+1.839.2−0.5 -0.5
TTHE+1.7+1.638.0−1.7 -1.7
RRSI+1.1+2.343.6+3.9

這張表說三件事。在進化用的題目上,RRSI 進步最小(+1.1),Meta-Harness 最大(+3.6)。在同一個 benchmark 沒用過的題上,大家差不多,RRSI 與 Meta-Harness 並列最高(+2.3)。差距出現在完全沒看過的 benchmark:RRSI 平均進步 +3.9,比最強對手 Meta-Harness 高 3.0 分,另外兩個對手掉到 H0 H_0 以下。三個 benchmark 上 RRSI 都是第一,比各自最強的對手高 3.5(JobBench)、3.2(GDPval)、2.2(APEX-Agents)分。換句話說,進化時進步越多的方法,換題目後越不穩,RRSI 刻意用 evolve 分數換取轉移能力。

疑點與限制:

  • 論文沒說每個方法重跑幾次進化,也沒有標準差。推論:三個 benchmark 全部第一,而且差距比對手彼此的差距(最好 40.6 對最差 38.0)還大,比較不像單純運氣,但這不是統計檢定。
  • 這裡的「OOD」只是同一個領域內的換題:用 Harvey LAB(法律)進化,測其他職場任務 benchmark。沒有測跨領域,例如拿 coding 進化的 harness 去測 workspace 任務。
  • 對手是作者自己重跑的,論文沒說對手有沒有調參,也沒說它們的 proposer 是不是同一個模型。
圖 3:RRSI 在 coding、agentic workspace、engineering design 三個領域的主要結果,以柱狀圖比較未進化的 H0 與 RRSI 在進化用 benchmark 與沒看過的 benchmark 上的分數。
圖 3 — 三個領域的主要結果。每個數字都是相對同一時段量測的未進化 H0 H_0 。(來源:原始論文。)

圖 3 的數字整理如下:

領域進化用的 benchmark進步完全沒看過的 benchmark進步
codingTerminal-Bench 2.1:74.2 到 80.2+6.0SWE-bench Verified:82.0 到 83.8+1.8
agenticHarvey LAB:89.4 到 90.5+1.1JobBench、GDPval、APEX-Agents+3.5 到 +4.7
engineeringEngDesign:50.0 到 54.9+4.9Frontier-Eng:17.7 到 22.0+4.3
  • coding 的 OOD 進步很小:SWE-bench 的 +1.8 分,與 coding 的雜訊帶 1.7 分差不多大。兩者是不同的 benchmark,不能直接當檢定,但這個進步很難跟雜訊分開(推論)。
  • Frontier-Eng 的 +4.3 來自很小的基期:4.3% 大約是 1.6 到 2 個金牌的分量(分母取 38 或 47 題),所以論文摘要那個「相對進步 24.3%」聽起來很大,底下只是少數幾題的差別。
表 2:agentic workspace 任務上的 ablation,列出 H0、無正則化的進化、拿掉提案端、拿掉接受端與完整 RRSI 在 evolve、ID held-out、OOD 平均與每次試驗 token 數上的結果。
表 2 — 正則化的 ablation(agentic workspace)。OOD 平均是 JobBench、GDPval、APEX-Agents 的平均,Tokens/trial 是每次試驗平均消耗的 policy tokens(百萬)。(來源:原始論文。)

這是論文唯一能看出正則化本身貢獻的地方。最乾淨的對照是「沒有任何正則化」對「RRSI」(下表由表 2 計算,論文沒有直接列):

對照EvolveID held-outOOD 平均Tokens/trial
H0 H_0 到 Unregularized(只靠進化)+3.4+2.0+0.61.56M 到 3.80M(+144%)
Unregularized 到 RRSI(正則化的貢獻)−2.3 -2.3 +0.3+3.33.80M 到 2.42M(−36% -36\% )
H0 H_0 到 RRSI(總進步)+1.1+2.3+3.91.56M 到 2.42M(+55%)

沒有正則化的進化,evolve 分數漲最多,但換到沒看過的題目幾乎沒進步(只有 +0.6),還多花了一倍多的 token。加上正則化後,evolve 分數少拿 2.3 分,OOD 多拿 3.3 分,token 省了三分之一,ID held-out 只差 0.3。

把正則化一組一組拿掉的四列:

變體EvolveID held-outOOD 平均Tokens/trial
RRSI(全部都有)90.589.243.62.42M
拿掉 proposal 端(A、B、C)90.788.841.92.69M
拿掉 acceptance 端(D、E、F)91.588.741.03.59M
全部拿掉92.888.940.33.80M

規律很整齊:拿掉的正則化越多,evolve 分數越高(90.5、90.7、91.5、92.8),OOD 越低(43.6、41.9、41.0、40.3)。這正是論文要證明的取捨。

疑點與限制:

  • 每一列都只有一個數字,沒有標準差,3.3 分的 OOD 差距有多穩無從判斷。
  • 只在 agentic 一個領域做了 ablation,coding 與 engineering 沒有。
  • 仍然沒有單一零件的 ablation,只有兩大組。G 屬於哪一組,論文的說法前後不一,表 2 也沒交代。
  • 「Unregularized」沒說是否包含 analyst 回饋和歷史紀錄,只是拿掉了 A 到 G。論文摘要寫「少 30% token」,這個對照我算出來是少 36%,論文沒說 30% 拿什麼比。
  • 論文摘要的數字是挑最好看的:「最多進步 14.1 分」是表 3 較弱模型在進化用題目上的進步,「OOD 最多 4.7 分」是三個 benchmark 裡最好的一個,「比既有方法高 22.9%」是 Frontier-Eng 的 17.9 到 22.0(圖 1(d)),基期很小,相對百分比被放大。這裡的基期 17.9 與圖 3 的 17.7 略有出入,論文沒說明差在哪。

這幾個實驗都是補強,不是證據核心,因此只放結果與一句話保留。

表 3:coding 領域的 policy 穩健度,分別以 Claude Opus 4.8 與 Gemini 3.5 Flash 為固定 policy 進化,列出 Terminal-Bench 2.1 與 SWE-bench Verified 上 H0 與 RRSI 的分數和進步幅度。
表 3 — coding 領域的 policy 穩健度:各 policy 獨立進化,harness 原封不動拿去跑 SWE-bench Verified。(來源:原始論文。)

表 3 要驗證的是換一個不同家族的模型重新進化,效果是否仍在。結果如下:

PolicyTerminal-Bench 2.1(evolve)SWE-bench Verified(OOD)
Claude Opus 4.874.2 到 80.2(+6.0)82.0 到 83.8(+1.8)
Gemini 3.5 Flash64.6 到 78.7(+14.1)76.8 到 79.0(+2.2)

疑點:論文摘要的「14.1」就是這一列(進化用題目、較弱模型)。SWE-bench 的進步都只有 +2 左右,與 coding 雜訊帶同量級。只測兩個模型,沒有標準差。

表 4:以 Gemini 3.5 Flash 進化出的 harness 原封不動用在較弱的 Gemini 3.1 Flash Lite 上,Terminal-Bench 2.1 的分數從 11.2 到 14.6。
表 4 — 跨模型轉移:進化好的 harness 搬到沒參與搜尋的較弱模型。(來源:原始論文。)

表 4 要看進化好的 harness 搬到沒參與進化的較弱模型,還有沒有幫助。Gemini 3.1 Flash Lite 從 11.2 到 14.6(+3.4)。論文寫相對進步 30.4%,但絕對進步只有 +3.4,約保留進化用模型 +14.1 的四分之一。疑點:測的是進化用的同一批題目,只驗證了換模型,沒驗證換題目。Flash Lite 與進化用的 Flash 同屬 Gemini,不是跨家族。只有一個弱模型,且只測往弱的方向。

圖 4:各進化方法最終 harness 的成本,(a)為每次試驗的 policy tokens 對 OOD 平均的散佈圖,陰影區是 RRSI 完全勝過的區域,(b)為每次試驗的步數。
圖 4 — 各進化方法最終 harness 的成本(agentic workspace 的 evolve split)。(a)的陰影區是 RRSI 完全勝過的區域:花更多 token,OOD 平均卻更低。(來源:原始論文。)

圖 4 要說的是 RRSI 是所有進化方法裡花得最少的。RRSI 每次試驗 2.42M tokens、26.3 步,對手是 27.3 到 34.6 步。AHE 最貴,3.82M tokens(多 58%),OOD 還少 4.4 分。疑點:RRSI 仍比沒進化的 H0 H_0 (1.56M、21.2 步)貴 55%。TTHE 與 RRSI 差距不大,優勢主要被 AHE 拉開。這裡只量最後 harness 跑一次的成本,進化過程本身(20 輪、每輪多個候選、三個 LLM)花多少,論文沒報。

最後是 Section 4.2 後半的 deterministic grading:EngDesign 與 Frontier-Eng 由模擬器確定性評分,進步仍在(+4.9、+4.3),用來說明進步不是靠迎合 LLM judge 的口味。疑點:這只證明工程領域。JobBench 的評審之一與 policy 同為 Opus 4.8,GDPval 評審之一同為 Claude 家族,論文未討論評審偏好自家模型的可能。

這篇的價值在於提醒「harness 自動進化很容易過擬合,要加護欄」,而不在於護欄本身有多新。我的判斷是研究價值偏低,工程參考價值中等偏上。

最乾淨的對照就是前面 ablation 那一節算出來的「沒有任何正則化的進化」對「RRSI」:加上護欄後,進化用的題目少拿 2.3 分(92.8 到 90.5),沒看過的題目多拿 3.3 分(40.3 到 43.6),每次試驗的 token 從 3.80M 降到 2.42M,省了三分之一。這是這篇最扎實的證據。論文摘要裡其他數字都是挑最好看的那個,真正穩的只有這一組,而且只在 agentic 一個領域。

研究價值偏低:研究貢獻接近「一個好的問題定義加上一組合理的工程規則」,沒有新的演算法或理論。論文也沒有推導任何泛化保證,「正則化搜尋軌跡」是設計上的框架加類比,效果靠實驗支持,不是靠理論。工程參考價值中等偏上:規則具體、可以照著實作,而且設計原則脫離這篇論文也成立。

面向優點缺點
研究把「harness 進化會過擬合」講清楚,並指出三個具體行為。反覆用同一批題目評分的風險本身是真實的問題各個零件大多是常見做法的組合:評分前審查、雜訊底線、成本換分數、保留歷史紀錄(這是判斷)。L0、L1、L2 只是命名(概念三)
研究有整組 ablation,方向與論文的說法一致。有換 policy、換模型、換評分方式的補強實驗沒有單一零件的 ablation,不知道哪個零件真的有用。所有比較都沒有標準差,跨方法比較只有一個領域
工程規則都很具體,可以直接照著實作。程式碼與完整的逐輪紀錄有公開(Appendix E 說在專案網站,含 proposal、critic 決定、接受決定與完整 diff)關鍵超參數有的沒交代、有的沒列出(β \beta 怎麼選、δ \delta 怎麼量、guard 門檻、w w 權重)。進化本身花多少錢沒報,只報了最後 harness 的成本
工程每個護欄各自對應一個明確的失敗模式,出問題時比較好排查critic 與 proposer 是同一個 LLM,盲點可能重疊(推論)
  1. 沒有變異數。 每個數字都是一次進化的結果,沒說重跑幾次。3.3 分的 OOD 差距有多穩,無法判斷。
  2. 「泛化」只是同類任務之間換題。 沒有測跨領域,例如用 coding 進化的 harness 去測 workspace 任務。
  3. 每個零件都沒有單獨的證據。 論文的核心賣點是「這一整包護欄有效」,不是「這個零件有效」。
耐久度內容判斷
中把「harness 自動進化會過擬合」講清楚,並歸納出三個行為:擬合特定 benchmark、追逐雜訊、複雜度累積問題定義本身有價值,是這篇最實在的貢獻
中低一整組護欄的工程配方(A 到 G 加 guard),在 agentic 上有整組 ablation 支持每個零件都是常見做法的組合,沒有任何單一零件的證據
低具體數字(OOD +3.3、省 36% token)與 L0 / L1 / L2 的命名數字只在一個領域、沒有變異數,會隨新模型過期。命名只是比喻,可以忽略

一句話:這篇接近一個好的問題定義,加上一組合理但沒被拆開驗證的工程規則。真正耐久的是後面「延伸」裡概念一到四、六那幾個通用觀念。

以下九段是讀這篇論文時最容易卡住、也最容易忘記的觀念,概念一到四、六是通用的觀念,脫離這篇論文也成立。概念五、七、八、九是這篇論文留下的疑點,會引用前半的方法與公式,建議讀完對應的方法章節再看。

先看最簡單的情境:你有 100 題可以評估一個系統。只評估一次,再用這個分數當成「這個系統的水準」,這是沒有偏差的估計,最多有隨機雜訊。問題出在你不只評估一次:你看了結果,根據結果改了系統,再用同一批題目評估,再改,如此反覆。

第二次修改的方向,是根據第一次在這批題目上的結果決定的,所以修改內容已經帶著「這批題目的特徵」。等到第三次評估時,你量到的分數有一部分是「我針對這批題目調整過」的成果,不是真的變強。這批題目已經不再是獨立的檢驗資料,統計上叫 adaptive data reuse,相關的研究領域叫 adaptive data analysis(Dwork 等人 2015 年是代表性的一篇,這篇論文引用它來說明問題存在,沒有自己推導)。

以下是統計的一般知識,不是論文內容。有兩個放大器:

  1. 每次評分帶隨機雜訊,而每一輪都是「從一堆候選挑最高分」。取最大值會系統性地挑出被雜訊墊高的那個(見概念二)。以每個候選的真實效果都是 0、雜訊標準差為 σ \sigma 為例:4 個候選挑最好的,期望值約 +1.03σ +1.03\sigma 。100 次評分挑最好的,期望值約 +2.51σ +2.51\sigma 。什麼都沒改進,看起來也會進步,而且看的次數越多,假進步越大。
  2. 空間越大、越靈活,越容易找到「恰好貼合這批題目」的修改。harness 進化的搜尋空間是「改任意原始碼」,屬於表達力異常大的空間,所以論文說它是 adaptive empirical optimization over an unusually expressive search space,也就是在表達力異常大的空間裡做適應性的經驗最佳化。

實際做法只有一個:進化用的題目和最後檢驗用的題目要分開,而且檢驗用的題目不能參與任何決策,包括調超參數。這篇論文的超參數就只用 evolve 環境選定,沒有參考 held-out 或 OOD(表 5 的 caption)。

有問題的寫法是進化與檢驗用同一批題目:

for t in range(T):
    candidates = propose(current, feedback(current, tasks))
    current = max(candidates + [current], key=lambda h: score(h, tasks))
final_score = score(current, tasks)   # 這個數字被搜尋過程「看過」,偏高

較好的寫法是讓檢驗題目不參與任何決策:

evolve_tasks, holdout_tasks = split(tasks)
for t in range(T):
    candidates = propose(current, feedback(current, evolve_tasks))
    current = max(candidates + [current], key=lambda h: score(h, evolve_tasks))
final_score = score(current, holdout_tasks)   # 只在最後量一次

RRSI 沒有做到「進化中完全不重用同一批題目」(它做不到,evolve set 就是要被反覆評分的),而是用一組護欄降低重用造成的傷害。論文沒有推導任何泛化保證,「正則化搜尋軌跡」是一個設計框架加類比。

這也是這組觀念裡最耐久的一條:任何「自動改進、自動評估」的系統(prompt 優化、skill 進化、agent 進化)都有這個結構。

另外,沒有任何正則化的進化在表 2 裡是個有價值的負面結果:進化分數最高(92.8),沒看過的題目卻只進步 0.6(39.7 到 40.3),token 還多了 144%。評估任何自動進化系統,不要只看它在進化用題目上的分數,要看沒參與決策的題目,也要看成本。

從一堆帶有運氣成分的分數裡挑最高的,被挑中的那個,分數幾乎一定被運氣墊高了,所以它的真實水準比看到的分數低。

用一個例子看:4 個候選,真實實力完全一樣,都是 90.0 分。但每次評分都有隨機波動(LLM 每次跑結果不同,每題也只跑幾次),所以量到的分數會在 90.0 上下晃:

候選真實實力這次量到的分數
A90.089.7
B90.090.4
C90.089.9
D90.090.1

挑最高分,選中 B(90.4)。看起來 B 進步了 0.4 分,但 B 其實跟其他人一樣是 90.0,多出來的 0.4 純粹是這次運氣好。這個 0.4 就是「詛咒」:你選中它,是因為它運氣好,但下一次重新評分時,運氣不會跟著它走,分數會掉回 90.0 附近。

import random

def measure(true_score=90.0, noise=0.4):
    return random.gauss(true_score, noise)   # 每次評分帶隨機雜訊

scores = [measure() for _ in range(4)]       # 4 個真實實力相同的候選
best = max(scores)                           # 「贏家」

這裡的 best 平均會比 90.0 高約 1.03 倍的 noise,這個差距是運氣,不是實力。

這個詞最早來自拍賣:得標者往往是對物品估價最樂觀的人,付的價錢通常高過物品的真實價值。「贏」的人贏的原因有一部分是運氣,所以贏得的東西(那個高分)不能當真。候選越多,被墊高的幅度越大:4 個候選挑最高,期望被墊高約 1.03 個雜訊標準差,100 個約 2.51 個。

跟這篇論文的關係:

  • 每一輪 RRSI 都是「一堆候選挑分數最高」,所以每一輪都有這個問題。
  • 被選中候選的分數會被記成歷史最高分 S⋆ S^{\star} ,這個被墊高的數字會影響之後的分數底線判斷(概念四)。
  • 前面的關卡(critic、分數底線、成本規則)把明顯有問題的候選濾掉,但最後仍是在倖存者裡挑最高分,所以贏家詛咒沒有被消除,只是被減輕。

實務上的通則是:只要流程裡有「一堆候選挑最高分」這一步,就要假設那個最高分偏高,不要當成真實水準。

訓練資料只有有限的 n n 筆,模型太靈活的話,會連資料裡的雜訊都背起來,訓練誤差很低,換一批資料就很差。正則化的做法是在最佳化目標裡多加一項複雜度懲罰:

min⁡θ    1n∑i=1nℓ(fθ(xi), yi)  +  λ R(θ)\min_{\theta}\;\; \frac{1}{n}\sum_{i=1}^{n}\ell\big(f_\theta(x_i),\,y_i\big)\;+\;\lambda\,R(\theta)
  • θ \theta :模型的參數,可以想成一排旋鈕。
  • fθ(xi) f_\theta(x_i) :模型對第 i i 筆輸入 xi x_i 的預測。yi y_i :第 i i 筆的正確答案。
  • ℓ \ell :單筆預測的誤差。1n \frac{1}{n} 乘上加總,就是對 n n 筆誤差取平均,也就是訓練誤差。
  • R(θ) R(\theta) :複雜度懲罰,例如「旋鈕總共轉多大」。
  • λ \lambda (大於等於 0):懲罰強度,越大越偏好簡單的模型。

自編數字例子:λ=0.1 \lambda = 0.1 。模型 A 的訓練誤差 0.0、複雜度 R=10 R = 10 ,總分 0.0+0.1×10=1.0 0.0 + 0.1 \times 10 = 1.0 。模型 B 的訓練誤差 0.5、複雜度 R=3 R = 3 ,總分 0.5+0.1×3=0.8 0.5 + 0.1 \times 3 = 0.8 。總分越低越好,所以選 B:A 雖然把訓練資料背得滿分,但太複雜,被懲罰扣掉了。

注意兩個關鍵:懲罰的對象是「模型本身的參數 θ \theta 」,作用的位置是「最佳化的目標函數」。這就是「限制假設空間」,假設空間(hypothesis space)指所有可能的模型的集合。

範數(norm)是「量一個向量有多大」的方法。設 θ=(θ1,…,θd) \theta = (\theta_1, \dots, \theta_d) :

∥θ∥0=#{ j:θj≠0 },∥θ∥1=∑j=1d∣θj∣,∥θ∥22=∑j=1dθj2\|\theta\|_0 = \#\{\, j : \theta_j \neq 0 \,\}, \qquad \|\theta\|_1 = \sum_{j=1}^{d} \lvert\theta_j\rvert, \qquad \|\theta\|_2^2 = \sum_{j=1}^{d} \theta_j^2

第一式是不等於零的參數有幾個,第二式是每個參數的絕對值加總,第三式是每個參數的平方加總。自編例子:θ=(3,0,−1,0) \theta = (3, 0, -1, 0) 。L0 是 2(兩個非零),L1 是 3+0+1+0=4 3 + 0 + 1 + 0 = 4 ,L2 的平方是 9+0+1+0=10 9 + 0 + 1 + 0 = 10 。把它們放進懲罰項 λR(θ) \lambda R(\theta) ,就得到三種正則化:

R R 取什麼名稱效果備註
L0 範數L0 正則化直接數「開了幾個旋鈕」,限制非零參數的個數「數個數」沒辦法用梯度下降,最佳化困難,實務少見
L1 範數Lasso(Least Absolute Shrinkage and Selection Operator,最小絕對值收縮與選擇算子)把不重要的參數壓到剛好 0,得到稀疏的模型兼具選擇變數的效果
L2 範數的平方Ridge(嶺迴歸)讓所有參數一起縮小,但很少變成剛好 0在 ML 裡最常見,weight decay 本質上就是它

為什麼 Lasso 會歸零,Ridge 不會?看斜率。把一個參數從 0.1 降到 0,L1 的懲罰少掉 0.1,L2 的懲罰只少掉 0.1 的平方,也就是 0.01。∣θ∣ \lvert\theta\rvert 的斜率永遠是 1,所以一路把參數推到 0。θ2 \theta^2 的斜率是 2θ 2\theta ,越靠近 0 推力越小,到不了 0。

這篇論文怎麼借用這三個名字,其實只是比喻:

論文的名稱RRSI 實際在做的事對應程度
L0:退火式編輯預算(A)一個候選最多綁 bt b_t 個修改,形式上是個數上限形式對得上,但它是硬性上限不是懲罰項,把「L0」拿掉資訊沒有損失
L1:結構剪枝(G)近期沒有正增益的元件,列為刪除目標只有「稀疏化」的意圖相同,機制更接近神經網路壓縮裡的 pruning
L2:複雜度感知接受(F)多花的 token 要有分數增益來抵是一個成本效益門檻,沒有平方、沒有收縮,對應最弱

論文在 Appendix C 也承認這是功能上的類比,不是最佳化任何範數懲罰的目標函數。所以這些名詞不會讓 RRSI 繼承 L1 的稀疏性或 L2 的收縮性,看到「L1 風格」時,只需要理解成「剪掉沒貢獻的東西」。另外,圖 2 把 F 標成 L1、G 標成 L0,與正文(A 是 L0、G 是 L1、F 是 L2)不一致,我判斷是筆誤(推論,論文沒有明說)。

一個系統重複評分,每次的分數都不會完全一樣(LLM 每次執行結果不同,每題只跑有限次)。把「完全沒改過的版本」重複評分幾次,分數自然晃動的幅度,就是雜訊帶 δ \delta 。分數的差距如果小於 δ \delta ,就分不清是真的差異還是雜訊。做法本身很通用:進化前先把沒改過的版本重複評分,量出波動幅度,再決定什麼算進步。

scores = [evaluate(H0, tasks) for _ in range(R)]   # 進化前:重複評估沒改過的版本
delta = spread(scores)                             # 自然波動幅度,統計量要自己選

lenient = score >= best_so_far - delta   # 只擋連續小退步,放行運氣好的假進步(論文的做法)
strict  = score >= best_so_far + delta   # 擋假進步,但會誤殺運氣差的真進步

分數底線(論文 Eq. 5)是 S^(H′)≥S⋆−δ \hat S(H') \ge S^{\star} - \delta :候選分數不能比歷史最高分低超過 δ \delta 。

為什麼底線綁在歷史最高分,而不是在位版本? 防止搜尋連續走下坡。自編例子,用 coding 的 H0=74.2 H_0 = 74.2 、δ=1.7 \delta = 1.7 分:

輪次底線綁在「在位版本」底線綁在「歷史最高分」(Eq. 5)
起點在位 74.2,底線 72.5S⋆=74.2 S^{\star} = 74.2 ,底線 72.5
第 1 輪,候選 72.6通過。在位變成 72.6,底線降到 70.9通過。底線仍是 72.5
第 2 輪,候選 71.0通過。在位變成 71.0,底線降到 69.3拒絕(71.0 < < 72.5)
第 3 輪,候選 69.4通過。累計已退步 4.8 分不會發生

每一步的退步(1.6、1.6、1.6)都在 δ \delta 內,但累積起來很多。綁在歷史最高分,底線只會隨最高分上升,不會下降,所以整個進化過程最多比最高分低 δ \delta 。

Eq. 5 只設下限,不擋「運氣好的假進步」。 論文用 noise chasing 來描述這個零件,但一個真實水準沒變、只是這次評分多量到 0.3 分的候選,會輕鬆通過 Eq. 5。要擋掉這種假進步,統計上合理的做法是同時設上限:要求候選比歷史最高分高出至少 δ \delta 。兩種規則的取捨如下(數字自編,設 S⋆=78.0 S^{\star} = 78.0 、δ=1.7 \delta = 1.7 ):

情況寬鬆版(論文,S^≥S⋆−δ=76.3 \hat S \ge S^{\star} - \delta = 76.3 )嚴格版(S^≥S⋆+δ=79.7 \hat S \ge S^{\star} + \delta = 79.7 )
真實水準與現在打平,但這次運氣好量到 79.5通過。若這輪它最高就會被選中,成為假進步不通過(79.5 < < 79.7),假進步被擋下
真實水準高 1 分(真進步),但這次運氣差量到 77.5通過,但低於 S⋆ S^{\star} 所以不會刷新 S⋆ S^{\star} 不通過(77.5 < < 79.7),真進步被誤殺

寬鬆版的代價是 false positive(放行雜訊撐出來的假進步),嚴格版的代價是 false negative(擋掉運氣差的真進步)。兩者解決的是不同的問題:寬鬆版防連續小退步,嚴格版防假進步,論文只做了前者。我的推論是論文可能怕門檻設太嚴,20 輪下來幾乎沒有候選能通過,搜尋會卡住,但這只是猜測,論文沒有為這個選擇辯護。

選哪個,看你更怕哪種錯:搜尋預算充裕、假進步代價高,就選嚴格。預算緊、怕搜尋停滯,就選寬鬆。

另外兩個要記得的限制:δ \delta 是在原始版本上量的,進化後的版本雜訊未必一樣。而且 S⋆ S^{\star} 記錄的是被選中候選的實測分數,被選中的是最高的那個,所以 S⋆ S^{\star} 本身可能被運氣墊高(概念二),之後的底線也跟著偏高,實力相同的候選可能被誤擋。

Ft \mathcal{F}_t 是每一輪交給 proposer 的「目前這版 harness 哪裡失敗」的整理,論文只說了它是誰寫的、從什麼來的,沒有說內容長什麼樣。論文明講的三件事:

內容出處
目前的 harness 在 evolve set 上跑完,產生 trajectories(一次完整的任務執行紀錄),再整理成 Ft \mathcal{F}_t Section 2
負責整理的是一個獨立的 analyst(分析員)LLM,模型是 Claude Opus 4.8Section 4.1
在演算法裡是 Analyze(Ht H_t , Devolve \mathcal{D}_{\text{evolve}} ) 這一步,輸出 Ft \mathcal{F}_t Algorithm 1 第 1 行

流程是:Ht H_t 在 evolve set 上跑,得到 trajectories。analyst LLM 讀 trajectories,寫出失敗回饋 Ft \mathcal{F}_t 。Ft \mathcal{F}_t 交給 proposer,作為提案分布(Eq. 8)的條件之一。

論文沒說明的部分:Ft \mathcal{F}_t 的格式(自由文字、條列,還是結構化欄位)、有沒有帶每題的分數與失敗原因、analyst 讀的是全部 trajectories 還是抽樣、proposer 除了 Ft \mathcal{F}_t 能不能另外看原始 trajectories。Appendix B 說基線 Meta-Harness 的 proposer 可以看執行軌跡,RRSI 有沒有這個權限,文字沒交代。

還有一個前後不一致的地方:Section 4.1 寫 analyst 產出的是 “cross-round failure feedback”(跨輪的失敗回饋),但 Appendix C.1 寫 Ft \mathcal{F}_t 是 “feedback from the current round”(本輪的回饋)。兩種讀法的差別:

讀法一:只看本輪讀法二:跨輪彙整
Ft \mathcal{F}_t 的內容只分析 Ht H_t 這一輪的表現還會把過去幾輪的失敗模式綜合進來
後果Ft \mathcal{F}_t 與歷史紀錄 Lt \mathcal{L}_t 分工清楚:Ft \mathcal{F}_t 講現況,Lt \mathcal{L}_t 講歷史Ft \mathcal{F}_t 與 Lt \mathcal{L}_t 的功能有重疊

論文文字無法判定是哪一種。以下是我的推論,論文沒這樣寫:

  1. Ft \mathcal{F}_t 內容大概是失敗模式的摘要。線索是表 6 的 Engineering R2:候選針對「workdir must be an existing directory」這個反覆出現的工具錯誤加了復原提示。要能針對它提案,回饋很可能已經把「這個錯誤重複出現」整理出來。
  2. 不可能是原始紀錄全文。agentic 每輪要評估 120 題 × k=2 k = 2 = 240 次執行,表 2 顯示 H0 H_0 每次執行消耗 1.56M policy tokens(可能含每一步重複讀入的 context),整批遠超一個 context window,所以 analyst 必然是壓縮過的,怎麼壓論文沒寫。
  3. Ft \mathcal{F}_t 是題目特定資訊進入搜尋的入口。失敗回饋必然提到具體任務與具體錯誤,proposer 最省事的修法就是把這些細節寫死進 harness,這正是 D 要擋的東西,也解釋了為什麼 critic 要讀程式碼差異,而不是只看分數。

Ft \mathcal{F}_t 與 Lt \mathcal{L}_t (零件 B)的分別:

Ft \mathcal{F}_t Lt \mathcal{L}_t (零件 B)
記錄什麼現在這版 harness 哪裡失敗過去每個修改的結果
誰產生analyst LLM 整理程式記錄,標籤由誰標未說明
內容形式論文未說明七元組(見 B 一節)

退火預算是一個「前期放寬、後期收緊」的數值排程,本質就是 learning rate scheduler,只是被排程的對象是「一個候選一次最多能綁幾個修改」。

名詞來歷(一般知識,不是論文內容):

  • 「退火」原本是冶金:金屬加熱後慢慢降溫,讓內部結構穩定。
  • 進入最佳化領域後有了模擬退火(simulated annealing):用一個「溫度」隨時間下降的排程,前期允許大幅度亂走,後期只允許小幅度微調。
  • 餘弦退火(cosine annealing):2016 年 SGDR 論文把餘弦形狀用在深度學習的學習率排程,現在訓練 LLM 很常見。
  • 這篇論文借的只有「前期放寬、後期收緊」的形狀,沒有用到溫度或機率式接受的機制。

公式(論文 Eq. 4,符號見 A 一節)可以拆成四步:

  1. πt/T \pi t / T 是一個角度,隨 t t 從 0 走到 π \pi ,也就是從 0 度走到 180 度。
  2. cos⁡ \cos 隨之從 1 降到 −1 -1 。
  3. (1+cos⁡)/2 (1 + \cos) / 2 把它變成一個從 1 降到 0 的係數,形狀是起頭平、中段陡、尾巴又平的 S 形,不是一條直線。
  4. bt=⌈bmin⁡+(bmax⁡−bmin⁡)×係數⌉ b_t = \lceil b_{\min} + (b_{\max} - b_{\min}) \times \text{係數} \rceil ,也就是起點 bmax⁡ b_{\max} 與終點 bmin⁡ b_{\min} 之間依係數內插,最後向上取整成整數(因為是「幾個修改」)。

用 coding 的設定(T=20 T = 20 、bmax⁡=4 b_{\max} = 4 、bmin⁡=1 b_{\min} = 1 )走三個點:

t t 角度cos⁡ \cos 係數bt b_t
00 度11⌈1+3×1⌉=4 \lceil 1 + 3 \times 1 \rceil = 4
872 度約 0.309約 0.6545⌈1+3×0.6545⌉=⌈2.96⌉=3 \lceil 1 + 3 \times 0.6545 \rceil = \lceil 2.96 \rceil = 3
19171 度約 −0.988 -0.988 約 0.006⌈1+3×0.006⌉=⌈1.018⌉=2 \lceil 1 + 3 \times 0.006 \rceil = \lceil 1.018 \rceil = 2

取整帶來兩個後果(用公式推出來的,論文沒有討論)。第一,係數要到 t=T t = T 才會是 0,但一次進化只跑 t=0 t = 0 到 T−1 T - 1 ,所以預算永遠到不了 bmin⁡ b_{\min} ,最小停在 2。第二,取整之後整個排程只剩 4、3、2 三個台階(完整的 20 輪表格在 A 一節)。餘弦形狀只決定台階在哪一輪切換,與學習率排程不同:學習率是連續值,形狀真的影響訓練。這裡是整數,餘弦與直線遞減會得到幾乎一樣的結果。

這個排程背後還有一條更通用的設計教訓:把多個修改綁在同一個候選裡,它們共用同一組量測結果,紀錄看起來像各自貢獻,其實只是合起來的貢獻。所以每次變更盡量單一、可歸因。不得不綁時,別把共用的分數當成各自的分數。如何在不得不綁定時把功勞分給各個修改,是另一個獨立的主題,這裡沒有展開。

先分清楚「探索的數量」指的是哪一個:

數量怎麼決定過程中會變嗎
bt b_t :每個候選最多綁幾個修改由 Eq. 4 的公式決定只降不升(4 到 3 到 2)
mdraft m_{\text{draft}} :停滯時保留的探索名額表 5 的超參數,三個領域都是 1固定不變,只有偵測到停滯時才啟用
Ut U_t 的大小:還沒碰過的元件類別數全集 K \mathcal{K} (9 類)減掉已碰過的只減不增,起點是 9
  • mdraft m_{\text{draft}} :Appendix D.1 只說所有超參數都用 evolve 環境和實務上的考量(operational considerations)選定,沒有敏感度分析,為什麼是 1,論文沒有交代。
  • Ut U_t :全集 K \mathcal{K} 是寫死的 9 類,而已碰過的類別是累積的(碰過就一直算),所以 Ut U_t 只會縮小。元件被剪枝刪除後會不會回到 Ut U_t ,論文沒說。
  • 每輪總共有幾個候選,論文裡找不到具體數字,所以「保留 1 個名額」佔全部候選的多少比例,無法判斷。

「強制探索」其實沒有被強制。 論文的用詞只有 reserved(保留)、redirect(導向),沒有寫任何強制機制。論文實際給了什麼:

  1. 檢查 σt \sigma_t :最近 w w 輪的進步有沒有超過雜訊帶 δ \delta 。
  2. 算出 Ut U_t :還沒碰過的元件類別。
  3. 打包成 Et=(σt,Ut,mdraft) \mathcal{E}_t = (\sigma_t, U_t, m_{\text{draft}}) ,作為 proposer 的輸入之一(Eq. 8、Algorithm 1 第 6、8 行)。
  4. proposer LLM 產生候選,論文沒說它如何使用 Et \mathcal{E}_t 。
  5. 候選照常通過 critic 與 selection。沒有任何一步檢查 proposer 有沒有照做(critic 擋的是洩漏,不是探索)。

自編例子:假設 E8 \mathcal{E}_8 被寫成一段文字放進 proposer 的提示:「最近 3 輪進步在雜訊內。請至少提出 1 個候選,修改下列尚未嘗試過的元件之一:skill、memory、subagent、client_tool。」proposer 是否照做,完全靠 LLM 遵守提示。論文的文字有兩種讀法:

讀法一:只是提示裡的一句指示讀法二:程式層面另外處理
意思LLM 自己決定要不要遵守例如專門開一次只准改 Ut U_t 的提案呼叫
後果探索效果不保證,proposer 可以忽略探索名額一定會產生

論文無法判定。推論:讀法一比較可能,因為 Appendix C 全部用 Et \mathcal{E}_t 這種「輸入條件」的語言在描述。

論文裡比較硬的探索推力在篩選端:Eq. 17 中的 ν \nu 項,讓「嘗試了從來沒有出現在獲勝修改裡的結構性元件」的候選多拿一份加分,比較容易被接受。這才是真正偏袒新嘗試的規則,但有三個限制:只在分數落在雜訊帶內時才用。只對 client_tool、skill、memory、subagent 四類結構性元件有效。「新」的定義與 C 不同(C 看「有沒有被量測過」,加分看「有沒有贏過」)。而且論文說權重 wn w_n 列在表 5,實際沒有,所以這個加分有多強從論文無法得知。

被 critic 在評分前擋掉的候選沒有分數,而歷史紀錄的每一筆都需要分數,所以它們大概不在歷史紀錄裡,proposer 也就看不到「哪些點子因為洩漏被擋」。

一個候選經過的順序(論文 Section 3.3 與 Appendix C.3 都寫 critic 在完整評估之前執行):

  1. proposer 提出候選。
  2. critic 讀程式碼差異,判斷有沒有寫死題目資訊。被擋就到此為止,不會被拿去跑 evolve set。
  3. 通過的候選在 evolve set 上完整評分,得到 ΔS \Delta S 、ΔC \Delta C 。
  4. 寫進歷史紀錄 Lt \mathcal{L}_t 。

分數(ΔS \Delta S 、ΔC \Delta C )是第 3 步跑完才會產生的。被擋的候選停在第 2 步,從來沒被執行過,所以沒有分數。歷史紀錄的每一筆是七元組,ΔS \Delta S 與 ΔC \Delta C 是必填欄位,沒有分數就填不完。論文 Appendix C.2 在寫出紀錄公式之前有半句 “Ignoring candidates that fail before a valid measurement is obtained”,意思是先不考慮那些還沒拿到有效量測就失敗的候選。

後果是 proposer 讀 Lt \mathcal{L}_t 來調整提案,被擋的候選不在裡面,它就不知道有哪些點子曾經被擋過。自編例子:某一輪候選 W 在 prompt 裡加了一句「遇到 Acme 公司的報表要用 YY 格式」,被 critic 擋掉。下一輪 proposer 讀 Lt \mathcal{L}_t ,完全沒有 W 的痕跡,可能再提出類似的東西,critic 又擋一次。代價是浪費一個提案名額加一次 critic 呼叫。推論:不會浪費 evolve set 的評分預算,因為被擋的候選不會被評分。

這裡有個不確定。上面那半句是寫公式時的記法,沒有明說「critic 擋掉的候選一定不進紀錄」。論文文字有兩種讀法:

讀法一讀法二
“fail before a valid measurement” 指什麼包含被 critic 擋掉的候選只指執行失敗、環境壞掉這類,沒有包含被 critic 擋掉的
後果proposer 看不到洩漏被擋的紀錄,可能重複提出被擋的紀錄可能透過別的管道(例如本輪的 Ft \mathcal{F}_t )傳給 proposer

論文文字無法判定。旁證是 Appendix E 說專案網站公開完整的逐輪紀錄,包含 critic 的決定,所以 critic 的決定有被記錄下來,但記到哪裡、proposer 有沒有讀到,論文沒有寫。

這件事背後有個通則:能在拿到誘因之前擋掉的東西,不要等拿到之後再處理。critic 先審查,被擋的候選就永遠拿不到那個會讓它顯得有吸引力的高分,後續輪次也不會被它的高分誤導。代價就是上面說的:被擋的候選沒有量測值,不能寫進「每個修改附上分數」的紀錄。

if critic_flags(diff):
    reject(candidate)               # 先審查,沒有分數可以偏袒它
else:
    score = evaluate(candidate)     # 通過審查才拿去評分

這裡的規則指 Eq. 17:候選進步沒超過雜訊帶 δ \delta 時,用 wsΔS−wcΔC+wnν>0 w_s \Delta S - w_c \Delta C + w_n \nu > 0 決定要不要收。

疑問一:coding 為什麼把 ws w_s 設成 0? 論文沒有說原因,只寫了結果:coding 的 ws=0 w_s = 0 ,所以雜訊帶內的分數進步不能單獨讓候選通過,要靠省成本或試新結構。agentic 與 engineering 用正的 ws w_s ,也沒解釋為什麼三個領域不一樣。

推論(論文沒這樣寫):這條規則的目的是「不要把小幅的分數波動當成足夠的證據」(Appendix C.3),ws=0 w_s = 0 是把這個原則做到最徹底,雜訊帶內的分數變化完全不算數。但這個推論有個破洞:coding 的 δ \delta 是 0.017,engineering 的 δ \delta 是 0.020,比 coding 還大,engineering 卻用正的 ws w_s 。所以「δ \delta 大,所以不信分數」不能解釋三個領域的差異,找不到一致的理由。

疑問二:這條規則是為了讓小幅進步的修改也有機會被接受嗎? 只對一半。

說法判斷
論文寫的目的避免把小幅分數波動當成充分證據目的偏向防守,不是幫小進步開門
這條規則的角色雜訊帶內的候選不受 Eq. 7 的成本上限約束,需要另一套規則決定收不收它處理的是「分不出是真進步還是雜訊」的灰色地帶
小進步能不能被收可以,但走的路不是靠進步對的部分

小進步的候選確實有機會被收,但在 coding 裡,被收的原因是「省成本」或「試了新結構」,分數進步本身不算分。用兩個自編候選看(coding,都在雜訊帶內):

候選分數成本結果
S多 1 題省 10%通過,因為省成本(只要 wc>0 w_c > 0 )
T多 1 題多 26%拒絕

兩個候選的分數進步一樣,結果不同,決定因素完全是成本。所以在 coding 裡,這條規則更像是「雜訊帶內的候選,只有更便宜或更新奇才留」。agentic 與 engineering 因為 ws w_s 是正的,小進步才真的有加分。

這條規則還留下一個設計教訓:兩個分支(進步超過雜訊帶走 Eq. 7、沒超過走 Eq. 17)在邊界兩側寬鬆度差很多,才會有前面那個 3 題與 4 題的懸崖。設計門檻規則時,要檢查邊界兩側是不是差太多。

RRSI 點出了 harness 自動進化的一個真實問題:每一輪都用同一批題目評分,進化分數會漲,換題目後的進步卻會縮水。它用提案端(A、B、C)加篩選端(D、E、F、G)一整包護欄來管,在 agentic 領域的 ablation 裡,加上護欄後進化用題目少拿 2.3 分,OOD 多拿 3.3 分,token 省 36%。

我的判斷是研究價值偏低、工程參考價值中等偏上,因為這篇論文本身的證據有限:所有數字沒有變異數,「泛化」只是同類任務之間換題,每個零件都沒有單獨的 ablation。比較值得借用的是設計原則:進化與驗證用的題目要分開、先量評分雜訊再決定什麼算進步、成本要用分數來換、每個修改都留紀錄,以及評估自動進化系統時,要看沒參與決策的題目和成本,不能只看它自己的分數。