# Recursive Language Models (RLMs) 論文筆記 ###### tags: `論文筆記` `LLM` `Long Context` `Agent` ## 論文資訊 - **標題**:Recursive Language Models - **作者**:Alex L. Zhang, Tim Kraska, Omar Khattab(MIT CSAIL) - **連結**:[arXiv:2512.24601](https://arxiv.org/abs/2512.24601) - **GitHub**:[alexzhang13/rlm](https://github.com/alexzhang13/rlm) --- ## 寫在前面 > 不要把超長的資料直接塞進 LLM,而是讓 LLM 用程式碼去「操作」資料。 ## 要解決什麼問題? LLM 有兩個根本限制: 1. **Context window 有上限**:塞不進去就是塞不進去 2. **Context rot**:即使塞得進去,越長效能越爛 下面這張圖很明顯,GPT-5 在複雜任務上,隨著輸入變長,效能直接崩掉: ![Screenshot 2026-01-21 at 23.59.38](https://hackmd.io/_uploads/SyueuOArbx.png =500x) 左邊是 GPT-5,右邊是套用 RLM 的 GPT-5。可以看到: - S-NIAH(簡單任務):GPT-5 本來就還行 - OOLONG(線性複雜度):GPT-5 開始掉,RLM 穩住 - OOLONG-Pairs(二次複雜度):GPT-5 直接趴,RLM 維持住 --- ## RLM 核心概念 ### 傳統做法 vs RLM | | 傳統 LLM | RLM | |--|---------|-----| | Prompt 在哪 | 直接進 context window | 存成外部 Python 變數 | | LLM 看到什麼 | 完整內容 | 只知道「有個變數,長度是 X」 | | 處理方式 | 一次讀完 | 寫程式去存取需要的部分 | ### 打個比方 傳統 LLM 像是要你把整本 1000 頁的書背下來再回答問題。 RLM 像是給你一本書放在桌上,你可以翻目錄、搜關鍵字、看特定章節,不用整本背。 ### 機制圖解 ![image](https://hackmd.io/_uploads/rJLRduArbl.png) Figure 2 說明 1. **紅色 X**:Prompt 不會直接進 LLM 2. **prompt loaded as variable**:資料變成 Python 變數 3. **In[1], In[2]...**:LLM 在 REPL 環境裡寫程式操作資料 4. **llm_query()**:可以呼叫子 LLM 處理子問題 5. **最後整合輸出**:把子 LLM 的結果拼起來 --- ## 運作流程詳解 ### Step 1:外部化 用戶的 prompt(問題 + 大量資料)被載入成 Python 變數。 LLM 只被告知: ``` 你有一個變數 prompt,長度是 10,000,000 字元 ``` ### Step 2:探索 LLM 不知道內容是什麼,所以先 peek: ```python print(prompt[:500]) # 看開頭 print(prompt[5000:5500]) # 看中間某段 ``` 從輸出推斷資料結構,例如發現有 `Chapter 1`, `Chapter 2`... ### Step 3:分解與遞迴 根據探索結果決定分割策略: ```python part1, part2 = prompt.split("Chapter 2") result1 = llm_query(f"分析這段:{part1}") result2 = llm_query(f"分析這段:{part2}") ``` 子 LLM 收到的是較小片段,可以直接處理或繼續遞迴。 ### Step 4:整合輸出 收集所有子 LLM 的回應,整合成最終答案。 --- ## 實驗設計 ### 任務介紹 作者設計了不同「複雜度」的任務來測試: | 任務 | 輸入規模 | 複雜度 | 說明 | |------|---------|--------|------| | S-NIAH | 8K-1M | O(1) | 在大量文字中找一個特定答案 | | BrowseComp+ | 6-11M | O(1) | 從 1000 份文件中找資訊回答問題 | | OOLONG | 131K | O(N) | 對每一行做語義分類再聚合 | | OOLONG-Pairs | 32K | O(N²) | 對每一對做語義判斷 | 複雜度的意思是「需要處理多少資訊才能回答」: - O(1):找到關鍵幾份就好 - O(N):要看過全部 - O(N²):要看過全部的兩兩配對 ### 比較方法 所有方法都是基於同一個底層模型(GPT-5 或 Qwen3-Coder),只是處理長 context 的策略不同: | 方法 | 怎麼處理長 context | |------|-------------------| | Base Model | 不處理,直接塞 | | Summary Agent | 超過就摘要壓縮 | | CodeAct + BM25 | 用檢索找相關部分 | | RLM | 外部化成變數,LLM 寫程式存取 | | RLM (no sub-calls) | 同上但不能呼叫子 LLM | --- ## 實驗結果 ![image](https://hackmd.io/_uploads/H15rFOASbx.png) 格式是 `效能分數 (平均成本 ± 標準差)` 例如 `56.00 ($0.92 ± $1.23)` = 正確率 56%,平均每個 query 花 $0.92 ### 重點數據 **1. OOLONG-Pairs 的戲劇性差距** | 模型 | Base Model | RLM | |------|------------|-----| | GPT-5 | 0.04% | 58.00% | | Qwen3-Coder | 0.06% | 23.11% | Base model 幾乎是 0%,RLM 直接拉到 58%。這是因為這個任務需要對每一對做語義判斷,Base model 根本處理不來。 **2. 超長輸入(BrowseComp+ 6-11M tokens)** | 方法 | 效能 | 成本 | |------|------|------| | GPT-5 Base | 0%(塞不進) | N/A | | Summary Agent | 70.47% | $0.57 | | RLM | 91.33% | $0.99 | Base model 直接爆炸,RLM 達到 91%。 **3. 有時候不需要遞迴** 在 CodeQA 上(Qwen3-Coder): - RLM:56.00% - RLM (no sub-calls):66.00% 不用子呼叫反而更好!因為這個任務用程式碼過濾就夠了,子呼叫反而引入錯誤。 ### 五個核心觀察 1. **RLM 可以擴展到 10M+ tokens**,效能達 base model 的 2 倍 2. **REPL 環境是必要的**,光是外部化就能突破 context limit 3. **遞迴子呼叫在 information-dense 任務上很重要**,提升 10%-59% 4. **成本跟 base model 相當**,中位數甚至更便宜,但有高變異 5. **不同模型行為不同**,Qwen3-Coder 傾向過度使用子呼叫 --- ## 湧現行為 ![image](https://hackmd.io/_uploads/S1k_tOAB-g.png) 沒有人教 LLM 這樣做,但它自己發展出這些策略: ### 1. 用先驗知識過濾 LLM 會根據它對世界的了解,主動用 regex 搜尋: ```python # 知道 "La Union" 是地名,主動搜尋 results = re.findall(r'.*La Union.*', context) ``` ### 2. 分塊遞迴 自己決定怎麼切割,對每塊呼叫子 LLM: ```python for chunk in context.split('\n'): result = llm_query(f"分類這行:{chunk}") ``` ### 3. 答案驗證 會呼叫子 LLM 來 double check ==( 但有時過度驗證反而出錯 )== ### 4. 用變數累積長輸出 把子 LLM 的結果存在變數裡,最後一次輸出 --- ## 缺點與限制 ### 論文明確提到的 | 缺點 | 說明 | |------|------| | 依賴 coding 能力 | 小模型效果很差 | | 同步呼叫慢 | 沒有平行化 | | 小 context 反而更差 | 輸入短的時候直接用 base model 更好 | | 成本高變異 | 中位數便宜但 outlier 很貴 | | 過度驗證 | 有時反覆確認最後反而選錯 | | 遞迴深度只有 1 | 子呼叫是普通 LLM 不是 RLM | ### 可以推論的 | 缺點 | 說明 | |------|------| | 安全風險 | 讓 LLM 執行任意程式碼 | | 錯誤累積 | 子呼叫越多錯誤越多 | | 探索策略不穩定 | LLM 自己決定怎麼切,品質不一定 | --- ## 什麼時候該用? | 情況 | 建議 | |------|------| | 資料短 + 簡單任務 | 直接 base model | | 資料長 + 只需找特定資訊 | RLM 或 RAG 都行 | | 資料長 + 需要遍歷全部 | **RLM 最適合** | | 需要對每筆做語義轉換 | RLM with sub-calls | | 模型 coding 能力弱 | 別用 RLM | --- ## 個人想法 這篇的 idea 其實很簡單——「==資料不要塞進去,讓 LLM 用程式存取==」。但就是這麼簡單的想法,之前沒人系統性地做過。 幾個值得注意的點: 1. **不是取代 RAG,而是互補**:RAG 適合「找相關的幾份」,RLM 適合「需要看全部」 2. **模型要夠強**:這不是讓小模型變強的方法,而是讓強模型能處理更大的輸入 3. **成本不一定更貴**:因為可以選擇性存取,有時反而比直接塞便宜 4. **未來可能會有專門訓練的 RLM 模型**:目前是用現成模型,沒有針對這個場景優化 --- ## 相關連結 - 論文:https://arxiv.org/abs/2512.24601 - GitHub:https://github.com/alexzhang13/rlm - 精簡版實作:https://github.com/alexzhang13/rlm-minimal