04 — RLM 子系统:持久化 REPL 与辅助函数体系
RLM 子系统:持久化 REPL 与辅助函数体系
学习目标
理解 CodeWhale 的 RLM(Recursive Language Model)子系统:持久化 Python REPL 设计、辅助函数体系与四种处理模式(CHUNK/BATCH/SEQUENCE/单查询)。
前置知识
- 上下文压缩与 Token 优化 — 上下文压缩通用策略
下文假设你已理解上述概念,直接聚焦 CodeWhale 的具体实现。
项目实践
生命周期
四个核心工具:
rlm_open— 打开命名 REPL 会话,加载源数据rlm_eval— 执行 Python 代码,返回结果rlm_configure— 调整 REPL 反馈设置rlm_close— 关闭完成的会话
源数据加载
rlm_open 可以加载多种源:
- 文件内容(大文件 > 50K tokens)
- 长文本(日志、转记、语料)
session://引用(v0.8.45 引入:加载当前提示、历史和会话数据)
加载的源在 REPL 内作为 _context 可用,_ctx 和 content 是兼容别名。
REPL 内辅助函数体系
| 函数 | 用途 | 处理模式 |
|---|---|---|
peek | 有界检查(开头/结尾/摘要) | 所有模式 |
search | 语义搜索 | CHUNK/BATCH |
chunk | 分块处理 | CHUNK |
context_meta | 元数据提取 | 所有模式 |
sub_query | 单个子查询 | SEQUENCE |
sub_query_batch | 并行批量查询(需声明 independence) | BATCH |
sub_query_sequence | 顺序依赖查询 | SEQUENCE |
sub_query_map | 映射式查询 | BATCH |
sub_query_sequence | 序列式查询 | SEQUENCE |
sub_rlm | 嵌套 RLM 调用 | 所有模式 |
finalize | 最终合成 | 所有模式 |
evaluate_progress | 进度评估 | 所有模式 |
四种处理模式
CHUNK — 真正的超大输入(整个文件 > 50K tokens、长转记、多文档语料)。分块处理,每块独立处理,最后合成。
BATCH — 多个独立项需要 LLM 关注(分类 20 个条目、从 30 个文档提取字段、评分 15 个候选)。使用 sub_query_batch(..., dependency_mode="independent") 并行执行——它 fan-out 到同一个 DeepSeek 客户端,在一轮中完成 15 次顺序读取的工作量。批量助手拒绝运行,除非显式声明独立性。
SEQUENCE — 数据依赖工作,其中 A 的输出是 B 的输入。使用 sub_query_sequence(...) 或显式 Python for 循环。中间状态存储在变量中,每步检查结果再继续下一步。
符号状态设计
RLM 的核心设计是符号状态:
- 长输入和中间值留在 REPL 环境中
- 不复制到根模型上下文
- 用有界切片检查(
peek),不用全量输出 - 用 Python 变换,不用语言描述
- 大中间字符串存储在变量或
var_handle中 - 不要将整个 body 粘贴回 prompt 中
var_handle 输出支持
当 RLM 返回大对象时,不直接返回完整内容,而是返回 var_handle:
- 父 Agent 通过
handle_read按需查询 - 支持切片、行范围、JSONPath 投影
- 保持父上下文精简,但不丢失对细节的访问
问题与规避
陷阱:BATCH 模式用于依赖工作
如果项之间有依赖关系(B 依赖 A 的输出),使用 sub_query_batch 会导致错误结果。
规避:批量助手拒绝运行,除非显式声明 dependency_mode="independent"。对于依赖工作,使用 SEQUENCE 模式或 Python 显式 for 循环。
陷阱:RLM 返回大对象膨胀父上下文
RLM 处理的结果可能很大(如分类 100 个条目的完整结果)。如果直接返回,会膨胀父上下文。
规避:使用 var_handle 返回大对象。父 Agent 通过 handle_read 按需读取关键部分。
陷阱:REPL 状态泄漏
关闭 RLM 会话后,REPL 环境中的变量和状态可能被新会话误用。
规避:每个 rlm_open 创建新的独立 REPL 环境。rlm_close 清理环境。会话之间不共享状态。
设计取舍
为什么选择 Python REPL
- Python 是数据处理的通用语言——大部分文本处理、JSON 操作、统计分析都可以用 Python 单行完成
- REPL 提供了交互式探索的能力——先
peek了解数据结构,再决定处理策略 - Python 的标准库足以处理大多数上下文操作,不需要额外依赖
RLM vs 上下文压缩
| 维度 | RLM | 上下文压缩 |
|---|---|---|
| 目的 | 处理超出窗口的长文本 | 释放上下文空间 |
| 方法 | Python REPL + 辅助函数 | 摘要/截断 |
| 保留信息 | 按需查询(完整保留) | 有损(摘要丢失细节) |
| 适用场景 | 需要精确分析大文件 | 长对话需要腾出空间 |
| 成本 | RLM 子调用成本 | 压缩调用成本 |
两者互补:RLM 处理数据,压缩释放空间。
为什么批量助手需要独立性声明
这是安全设计——防止模型无意中将依赖任务并行化导致竞争条件或错误结果。显式声明 dependency_mode="independent" 强制模型思考任务之间的依赖关系。
参考来源
crates/tui/src/tools/rlm.rs— RLM 工具实现prompts/base.md中 “RLM — How to Use It” 章节- v0.8.45 CHANGELOG: RLM session objects