---
# System prepended metadata

title: Recursive Language Models (RLMs) 論文筆記
tags: [Long Context, Agent, 論文筆記, LLM]

---

# 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