把上下文当环境而不是输入:RLM 的"外存-内存"范式转移
> 深度回复《Prime Agent:一个 RLM Harness,让 Agent 自己给自己升级 skill 和 prompt》
原文介绍了 Prime Agent 这个基于 RLM 的 Harness 项目——让 Agent 自己给自己升级 skill 和 prompt。但 Prime Agent 只是 RLM 范式的一个应用。真正值得深挖的是 RLM 本身:它不是"更好的长上下文方法",而是一次范式转移——把上下文从"模型的输入"变成了"模型的环境"。
这篇回复拆解 RLM 论文(arXiv:2512.24601,Zhang/Kraska/Khattab,MIT CSAIL)的技术内核,看看这个范式转移到底意味着什么。
核心洞察:上下文不是喂给模型的,是让模型去翻的
RLM 的核心洞察一句话能说清:
> 长提示不应该直接喂给神经网络,而应该被当作模型可以符号交互的环境的一部分。
这句话听起来平淡,但它和现有所有长上下文方法的哲学根本不同。
现有方法的哲学:上下文是"输入"——要么整个塞进模型窗口(vanilla LLM),要么压缩成摘要再塞(compaction),要么用检索挑相关片段塞(RAG)。无论哪种,上下文最终都要进入模型的"内存"(context window)。
RLM 的哲学:上下文是"环境"——模型不直接"看到"整个上下文,而是在一个 Python REPL 环境里写代码去"翻"上下文的片段。模型只看到它主动请求的那部分。
这个区别就像把整本书塞进脑子 vs 把书放在书架上,需要哪页翻哪页。前者受限于脑容量(context window),后者只受限于翻书速度(推理时计算)。
外存-内存类比:来自操作系统的灵感
论文明确说灵感来自外存-内存算法(out-of-core algorithms)——小而快的主存通过巧妙管理数据流入流出,处理远超主存容量的数据集。
这个类比值得展开:
| 操作系统 | RLM |
|---|---|
| 磁盘(大、慢) | 长提示(大、不在窗口内) |
| 内存(小、快) | 上下文窗口(小、模型直接可读) |
| 页面调度算法 | 模型的"peek into P"代码 |
| 缺页中断 | 模型发现需要看新片段 |
| 预读 | 模型预判接下来需要看哪部分 |
这不是"压缩"或"检索"。压缩会丢信息(摘要不可能完美),检索会漏信息(相关性排序不可能完美)。RLM 不丢不漏——完整提示始终在环境里,模型只是按需访问。
REPL 环境:模型怎么和上下文交互
RLM 的实现出人意料地简单:
1. 把提示 P 加载为 Python REPL 环境里的一个变量 2. 给模型关于 REPL 环境的通用上下文(比如 P 的长度) 3. 让模型写代码:peek(查看片段)、decompose(分解任务)、recursively call(递归调用自己)
模型写的代码可能长这样:
# 模型写的伪代码
chunk = P[0:50000] # 看前 5 万字
relevant = extract_relevant(chunk)
if need_more:
sub_result = rlm_call(f"分析这段:{relevant}")
# 递归调用自己处理子任务
final_answer = synthesize(sub_result)
关键设计:模型可以递归调用自己。这意味着一个长任务可以被分解成树状的子任务,每个子任务只处理一个小片段,结果逐层汇总。
这个"递归自调用"是 RLM 和 CodeAct 的核心区别。CodeAct 让模型在 ReAct 循环里执行代码,但提示仍然直接喂给模型。RLM 把提示移出模型窗口,移入代码环境。
数据说话:四个任务,全面碾压
论文在四个任务上测了 RLM:
| 任务 | 长度 | 测试什么 |
|---|---|---|
| CodeQA | 23K-4.2M tokens | 代码仓库理解 |
| BrowseComp+ | 6M-11M tokens | 深度研究信息聚合 |
| OOLONG | 131K tokens | 长文档理解 |
| OOLONG-Pairs | 32K tokens | 成对推理 |
| 方法 | CodeQA | BrowseComp+ | OOLONG | OOLONG-Pairs |
|---|---|---|---|---|
| Base | 20.0* | 0.0* | 36.0 | 0.06 |
| CodeAct+BM25 | 24.0* | 12.7 | 38.0 | 0.28 |
| Summary agent | 50.0 | 38.0 | 44.1 | 0.31 |
| RLM | 56.0 | 44.7 | 48.0 | 23.1 |
关键数字:
- CodeQA:RLM 56.0 vs Base 20.0,提升 180%
- BrowseComp+:RLM 44.7 vs Summary 38.0,且成本只有其 1/10
- OOLONG:RLM 48.0 vs Base 36.0,提升 33%
- OOLONG-Pairs:RLM 23.1 vs Summary 0.31,提升 74 倍
消融实验:递归调用是关键
论文做了一个关键消融——RLM (no sub-calls):REPL 环境加载了提示,但模型不能递归调用自己。模型可以在 REPL 里和上下文交互,但不能把子任务外包给另一个"自己"。
结果很有意思:
- CodeQA:RLM 56.0 → RLM (no sub-calls) 66.0(反而更高!)
- BrowseComp+:44.7 → 46.0(略升)
- OOLONG:48.0 → 43.5(下降)
- OOLONG-Pairs:23.1 → 17.3(下降)
为什么 OOLONG-Pairs 递归调用帮助巨大? 因为成对推理需要把大问题分解成小问题分别处理,每个子任务适合用子调用解决。
这告诉我们:递归调用不是"越多越好",而是"任务结构决定收益"。复杂分解任务受益,简单浏览任务不需要。
涌现的模式:模型自己学会了管理上下文
论文最迷人的部分是 3.1 节——"RLM 轨迹中的涌现模式"。即使没有显式训练,模型在 RLM 范式下自发地发展出了上下文管理策略。
GPT-5 和 Qwen3-Coder 展现了不同的风格:
- GPT-5:保守的子调用者,倾向于自己处理大部分任务
- Qwen3-Coder:激进的子调用者,倾向于把语义变换外包给子调用
这和"分工比统一更有效"原则直接相关:RLM 让模型自己决定什么时候外包、什么时候自己做,而不是强制所有任务走同一个流程。
RLM-Qwen3-8B:小模型也能当 RLM
论文还训练了第一个围绕 RLM 范式的模型——RLM-Qwen3-8B。结果:
- 比 Qwen3-8B 基线平均提升 28.3%
- 在三个长上下文任务上接近 vanilla GPT-5
和现有方法的本质区别
| 方法 | 上下文位置 | 信息损失 | 模型角色 |
|---|---|---|---|
| Vanilla LLM | 直接输入 | 无 | 被动接收 |
| Compaction | 压缩后输入 | 有(摘要丢细节) | 被动接收 |
| RAG | 检索片段输入 | 有(检索漏片段) | 被动接收 |
| CodeAct | 直接输入+代码工具 | 无 | 主动交互 |
| RLM | 环境变量 | 无 | 主动探索+递归 |
对 Agent 工程的启示
RLM 对 Agent 工程的启示不只是"长上下文任务用 RLM"。更深层的是:
1. 上下文不是模型的负担,是模型的环境。当你把上下文从"要塞进窗口的东西"变成"可以按需翻阅的环境",上下文长度不再是瓶颈。
2. 递归是处理复杂性的通用策略。RLM 的递归自调用和操作系统里进程的 fork、函数调用栈、树形分治,是同一个原理的不同实例。
3. 模型的能力和范式的设计是互补的。RLM 让 8B 模型接近 GPT-5 的长上下文能力——好的范式可以弥补参数量的差距。
4. Harness 的核心是"让模型决定怎么用自己"。Prime Agent 的"自己给自己升级 skill 和 prompt"和 RLM 的"自己决定怎么分解任务"是同一个哲学:不要替模型做决策,让模型自己决定。
结语:从"输入"到"环境"的范式转移
RLM 的真正贡献不是"处理更长的上下文",而是重新定义了上下文和模型的关系:
- 旧范式:上下文 → 模型(单向输入)
- 新范式:上下文 ↔ 模型(双向交互)
Prime Agent 把 RLM 的哲学推到了极致——不只让模型自己管理上下文,还让模型自己管理自己的 skill 和 prompt。这是"让模型决定怎么用自己"的终极版本。
当模型能力足够强时,最好的 Harness 不是"帮模型做更多",而是"让模型自己做更多"。RLM 给了模型一个环境,剩下的,交给模型自己。