不訓練神經網路也能打出理論最高分:Heuristic Learning 的設計邏輯
Jiayi Weng 在維護 EnvPool 的時候,想用便宜的方式驗證遊戲環境的正確性,不想每次 CI 都跑神經網路。他用 codex 寫了幾條純規則的 policy——完全沒有 NN,只有 Python 程式碼。Atari Breakout 的分數依序是:387 → 507 → 839 → 864。
864 是理論最高分。驗證做完了。
讓他困惑的是,這個「policy」已經不只是幾條 if-else,它長成了一套帶有動作偵測器、落點預測、卡住循環偵測、影片回放、回歸測試的完整軟體系統。codex 沒有訓練任何神經網路——它在維護一套還能繼續生長的程式碼系統。
Deep RL 也有辦法打出這個分數,但過程完全不同。這兩條路的根本差異是什麼?
讀完精華版(2 分鐘),你會理解:
- 為什麼 Coding Agent 讓「用程式碼作為 policy」這件事重新值得做
- HL 怎麼把 Deep RL 的「災難性遺忘」轉化成一個工程問題
- HL + NN 的最有希望的混合架構是什麼,以及它的核心挑戰
這篇不是 RL 教學,也不是 Atari 刷分攻略。它是在問:當 coding agent 強到某個程度,哪些原本不值得做的事情開始值得了?
精華版
| 維度 | Deep RL | Heuristic Learning |
|---|---|---|
| Policy | 神經網路參數 | 程式碼(規則、狀態機、MPC、宏動作) |
| 更新 | Gradient descent | Coding agent 直接修改程式碼 |
| 記憶 | Replay buffer(隱式,會被覆蓋) | 顯式記錄 trials、logs、失敗原因、版本 diff |
| 遺忘問題 | 災難性遺忘,無法根本解決 | 轉化為工程問題:舊能力固化為 regression tests |
| 可解釋性 | 幾乎沒有 | 程式碼可翻譯成人話,可以 code review |
- Deep RL:用梯度下降調整神經網路參數,透過大量樣本逼近最優策略,但學新任務時必然破壞舊能力,且策略無法被人直接讀懂。
- Heuristic Learning(HL):用程式碼作為 policy,由 coding agent 持續修改程式碼代替反向傳播,舊能力被寫進 regression tests 而不靠模型記憶,但受制於程式碼的表達能力上限。
為什麼 HL 現在才有意義? 不是 heuristic 以前沒用,而是人工維護的成本太高——加一條規則修好 case A,case B 壞了,如此反覆,最後沒人敢動這份程式碼。Coding agent 改變了這個成本曲線:同樣一次失敗,修復快 10 倍,讓原本不值得長期維護的 heuristic 系統重新值得了。
HL 的邊界在哪? 程式碼的表達能力就是上限。控制任務(Breakout、Ant)和邏輯推理,HL 表現強;複雜感知任務(ImageNet、視覺 QA)純程式碼根本寫不出來,需要神經網路。
HL + NN 怎麼結合? 最有希望的方向是 System 1/2 分工:淺層 NN 處理快速感知,Heuristic System 處理線上決策和規則維護,LLM agent 週期性分析失敗並更新兩者。核心挑戰在於 HL 產生的特定分布數據,可能在更新 LLM 時破壞其通用能力。
HL 和 AutoResearch 的差異是什麼? AutoResearch 是在固定時間窗口大量搜尋策略,有明確的 evaluation function,目標是找到當下最好的答案。HL 是持續迭代維護一個會生長的系統,沒有「結束點」,格言是「任何可以被持續迭代的,都開始能被解決」,對應 RLVR 的「任何可以被驗證的,都開始能被解決」。
以下是完整版,按需取用。
一個不應該發生的分數
EnvPool 是一個高效能的 RL 環境實作 library。Weng 在維護它的時候,需要持續驗證每個遊戲環境的正確性,但真正跑 RL training 太貴——用神經網路驗每個 CI 的成本太高。他的解法很直接:用 codex 寫一個便宜的 policy,只要能得分就好,不需要接近最優。
沒想到,codex 把 Breakout 打到了 864 分。理論最高分。
這個過程是漸進的:387 → 507 → 839 → 864。每次迭代,程式碼就長大一點。到最後,那個 policy 已經有動作偵測器、球的落點預測、卡住循環偵測、回歸測試、影片回放系統。它不再是「一個策略函數」,而是一套完整的軟體系統,有測試、有記憶、有診斷工具。
codex 做的事情,和訓練神經網路根本不同。它在持續修改程式碼,而程式碼是它唯一的 policy。
同樣的現象也出現在其他環境:MuJoCo Ant 打出 6000+,純 Python 程式策略學會了節律步態;MuJoCo HalfCheetah 5 局均值 11836.7,靠可解釋的步態規則加在線規劃;VizDoom D3 Battle 用純 cv2/NumPy 螢幕 CV,完全不訓練神經網路,mean=557.0。Atari 57 全套評測在固定環境交互步數下,中位數 HNS 在 1M steps 附近已遠高於 PPO。
什麼是 Heuristic Learning,什麼是 Heuristic System
Weng 把這個觀察整理成一個概念框架。Heuristic Learning(HL) 是一個學習過程,有六個核心特徵:
- Policy 由程式碼構成(規則、狀態機、controller、宏動作),不是神經網路參數
- 和 Deep RL 共享同樣的閉環(state → action → feedback → update),但更新對象是程式碼而不是梯度
- Feedback 可以來自環境 reward、testcase 通過/失敗、執行日誌、影片回放、人類意見——不只是一個純量 reward
- 更新不用反向傳播,由 coding agent 直接修改 policy、狀態偵測器、測試或 memory
- HL 是過程,Heuristic System(HS) 是被長期維護的對象
- HS 不只是一個 policy 函數,而是一整套系統
HS 的組成:
Heuristic System
├── 程式策略(Program Policy) ← 規則、狀態機、controller、MPC、宏動作
├── 狀態表示(State Representation) ← 變數、偵測器、快取
├── 反饋入口(Feedback Channel) ← 環境 reward、tests、logs、回放、人類反饋
├── 實驗記錄(Experiment Records) ← trials、summary、失敗原因
├── 回放/測試(Replay / Tests) ← golden trace、固定 seed 回放、regression tests
├── Memory ← 跨輪次的策略筆記
└── 更新機制(Update Mechanism) ← coding agent 執行的修改管線
判斷是不是 HS 的標準很明確:「規則 + 反饋入口 + 歷史 + 下一輪更新機制」全部接起來,才算 HS。單條規則不夠。
維護成本曲線:為什麼以前 heuristic 沒發展起來
「用程式碼作為策略」的想法在學術界叫 Programmatic RL,已討論多年。PROPEL(2019)、LEAPS(2021)、HPRL(ICML 2023)都在研究這個方向,學術共識是程式化策略的可解釋性和可形式化驗證性確實比神經策略好。
為什麼沒有大規模被採用?因為人工維護 heuristic 的死亡螺旋:
Day 1:加一條規則修 case A ✓
Day 2:發現 case B 被修壞了 ✗
Day 3:加一個 if 修 B ✓
Day 4:C 又壞了 ✗
...
Day N:沒人敢刪了,沒人搞得清楚,系統腐化
問題不在 heuristic 沒用,在沒人力養得起。這和工業革命前的手工紡紗一樣:原理沒問題,規模一大就崩。
Coding agent 改變了這個成本曲線。Weng 用的比喻是工業革命:紡織機不是發明了紡紗,而是讓同樣人力可以產出 10 倍。Coding agent 對 heuristic 系統做的事情一樣——同樣一次失敗,修復快 10 倍,讓過去那套「以前不值得長期維護的 heuristic」,現在突然值得了。
Weng 的核心貢獻正是在這裡:他論證的不是 heuristic 的原理,而是一條新的工程路徑——把 coding agent 當成可以持續澆灌 HS 的營養管道。
災難性遺忘:從 ML 問題變成工程問題
Deep RL 最難解的問題之一是災難性遺忘(Catastrophic Forgetting)——模型學了新任務之後,舊任務的能力會退化。EWC、PNN、replay buffer 都是 patch,沒有根本解決。
HL 的處理方式不是「解決」這個問題,而是把它轉化成一個工程問題:
Deep RL 的處理方式:
用正則化(EWC、dropout)防止模型參數漂移
→ 但模型記住能力的方式是不透明的,退化是靜默的
HL 的處理方式:
舊能力直接寫成 regression tests + golden traces + replay
→ 能力存在哪裡是明確的;能力壞掉了,test 會告訴你
Breakout 策略的演進軌跡說明了這個機制如何運作:
初始版本:「球在左邊就往左,球在右邊就往右」
↓ 遇到球速過快失敗
加入落點預測
↓ 遇到卡住循環
加入卡住偵測 + 跳出邏輯
↓ 加了新功能但舊場景壞掉
加入 regression tests
↓ 有了測試後可以安全繼續迭代
球偵測 + 擋板偵測 + 落點預測 + 卡住偵測 + tests + video replay
↓
864 分(理論最高分)
每次「舊能力壞掉」,不是在找模型為什麼遺忘,而是在把失敗模式寫進測試。工程師熟悉這個流程——這就是維護一個有測試的軟體系統的標準做法。把 ML 問題轉化成工程問題,是 HL 的核心機制之一。
Heuristic System 為什麼需要同時吸收反饋和壓縮歷史?
健康的 Heuristic System 需要兩件事同時在做:
操作一:吸收反饋(Absorb Feedback) 把新失敗、新日誌、新 reward 寫回系統。每次迭代之後,把觀察到的模式記錄下來。這是 HS 的「學習」。
操作二:壓縮歷史(Compress History) 把一堆局部補丁折回更簡單、更可維護的表示。把多個 patch 重構成一個更簡潔的模組;把舊的失敗模式提升為統一的偵測邏輯;而不是堆積 if-else。這是 HS 的「泛化」。
只做第一個操作,不做第二個:
只增長不壓縮的 HS ← Big Ball of Mud(大泥球)
特徵:記住了很多東西,但記住方式太差
後果:沒人敢動,腐化速度越來越快
和神經網路的過擬合不同,HS 的過擬合也有工程解法——簡化 + 回歸 + multi-seed 驗證形成一種工程正則化。但這需要 coding agent 有能力做「重構」而不只是「添加」。這對 agent 的能力要求比單純的功能添加高得多。
範式演進:HL 在哪個位置
Weng 把 HL 放在這個脈絡裡理解:
Pretraining
↓ 知道很多,但不聽話
RLHF
↓ 聽話了,但只能靠人類偏好訊號
Large-scale RL / RLVR
↓ 可驗證的問題都開始能被解決
格言:Anything verifiable becomes solvable
Heuristic Learning(?)
格言:Anything continuously iterable becomes solvable
RLVR 的邊界是:問題必須有明確的 verifier(數學答案對不對、程式碼能不能執行)。HL 的邊界更寬鬆:系統只需要有持續迭代的環境,不需要知道「正確答案」,只需要知道「好不好」。
「任何可以被持續迭代的,都開始能被解決」——這是 HL 的核心賭注。
這個格言不是在主張 HL 比 Deep RL 強,而是在描述一條平行的路徑:深度學習是把能力固化進參數(offline learning),HL 是把能力固化進可持續更新的程式碼系統(online + continual)。兩條路解決不同的問題,也有不同的邊界。
Heuristic Learning 的邊界在哪裡?
作者自己說得很清楚:「我想不出有個 agent 能搓出一個純 Python code、不用神經網路去解決 ImageNet。」
HL 受制於程式碼的表達能力:
| 任務類型 | HL 適用性 |
|---|---|
| 明確規則可表達的控制任務(Ant, Breakout) | 強 |
| 邏輯推理 + 搜索 | 強 |
| 感知 + 規則組合(VizDoom, cv2 trick) | 中等 |
| 複雜感知任務(ImageNet, 視覺 QA) | 不適用,純程式碼表達不了 |
| 長程語言理解 | 不適用,需要 NN |
Atari 57 的評測結果也有反例:Montezuma 只到 400 分,靠 86 個宏動作基本開環執行。有些環境需要更強的程式形態——可組合的宏動作、可恢復的搜索狀態、長期 memory。普通 if-else 解決不了所有問題,HL 有表達能力的天花板。
另一個上限是 Coupling Complexity:HS 的複雜度受 coding agent 的能力制約。Agent 能理解多複雜的程式碼,HS 才能長到多複雜。這讓 HL 的進展和 coding agent 本身的能力曲線直接掛鉤。
HL + NN Hybrid:System 1/2 分工
最有希望的方向不是「HL 取代 NN」,而是兩者分工:
三方角色各司其職:淺層 NN 處理感知這件 HL 做不好的事,HS 處理線上決策和規則維護,LLM agent 做慢思考的反饋分析。
以機器人為例,這個分工可以按時間尺度分層:
任務級 HL(Task-level) ← 目標分解、任務恢復、長期記憶
全身平衡 HL(Whole-body) ← 平衡控制、整體協調
肢體級 HL(Limb-level) ← 步態、接觸處理
關節級 HL(Joint-level) ← 安全控制、低延遲響應(最接近硬體)
低層負責安全和低延遲(不能等 LLM),高層負責任務和長期記憶(可以慢一點)。Coding agent 在這裡不需要「懂得走路」,而是作為更新管線:失敗影片 + 感測器數據 → coding agent 分析 → 改寫程式碼和參數 → 下一輪。
核心挑戰是 LLM 的更新問題:HL 持續在線生成特定任務的數據,如果週期性用這些數據更新 LLM,特定分布可能破壞 LLM 的通用能力——也就是說,災難性遺忘這次發生在 LLM 側。這是經典的 post-training 問題,有成熟的工程解法(課程學習、數據比例控制、EWC),但在 HL+NN 場景中還沒有標準答案。
Heuristic Learning 怎麼實作:HL Benchmark 的三個關鍵設計
Weng 做了一個最小化的參考實作(learning-beyond-gradients),可以直接看到 HL 理論的每一個概念怎麼對應成程式碼。
Structural vs Scalar 區分
HS 的修改分兩種:Structural(改邏輯結構,加偵測器、加 guard、改狀態機)和 Scalar(只調數值參數,改 gain、改閾值)。兩種修改分開記錄,因為如果混在一起,無法判斷是哪個因素讓分數提升。search.py 只做 scalar search;coding agent 只做 structural improvement。這個設計讓「到底是結構改對了還是數字調對了」變成可以獨立回答的問題。
Append-Only Ledger
results/trials.jsonl 是 HS 的 memory,只能 append,永不刪除。每條記錄強制包含 failure_analysis 和 next_hypothesis——失敗的試驗也要留,不能偷偷刪掉。Ledger 不再只是分數記錄,而是診斷日誌 + 假設記錄,下一輪的 coding agent 可以直接讀。
三段 Seed Split
dev seeds 用於日常迭代,holdout seeds 凍結用於比較,audit seeds 最終只跑一次。search.py 有硬性守門,不允許在 holdout/audit seeds 上做搜索——對應理論中「固定 seed 回放作為不可污染的 golden traces」。
這個設計哲學和系列裡提過的 SkillOpt Skill Contract (P,O,A,V,F) 很接近:已知失敗方向(F)被顯式列出,不是靠模型「記住」,而是寫進系統結構裡。
Agentic coding 不只改變了寫程式碼的速度,也改寫了哪些程式碼值得被長期擁有。HL 的核心主張是:規則、測試、日誌、memory 和補丁,從散落的工程材料,可以被組織成持續自我更新的 Heuristic System——前提是有 coding agent 作為不間斷的維護管線。RLVR 說「任何可以被驗證的都開始能被解決」,HL 說「任何可以被持續迭代的都開始能被解決」。這是同一個方向的兩條平行推進。