【论文速读】ReCAP: 递归上下文感知——解决 LLM 长时序规划迷失的通用框架
论文标题: ReCAP: Recursive Context-Aware Reasoning and Planning for Large Language Model Agents
作者: Zhenyu Zhang 1 ∗ † ^{1*\dagger} 1∗†, Tianyi Chen 1 ∗ ^{1*} 1∗, Weiran Xu 1 ∗ ^{1*} 1∗, Alex Pentland 2 , 3 ^{2,3} 2,3, Jiaxin Pei 2 ^{2} 2 (Stanford University, MIT Media Lab)
代码: https://github.com/ReCAP-Stanford/ReCAP
5. 总结
核心结论:针对长时序任务(Long-horizon tasks)中 LLM 容易迷失目标或上下文过载的问题,本文提出了一种名为 ReCAP 的递归推理与规划框架。不同于传统的扁平化思考链(CoT/ReAct)或割裂的层级规划,ReCAP 通过共享的滑动窗口上下文和**结构化的父级计划重注入(Re-injection)**机制,在保持高层意图连贯性的同时,实现了对底层执行细节的动态修正。
前瞻展望:在严格的 Pass@1 设置下,ReCAP 在复杂烹饪任务 Robotouille 中将成功率提升了 32%(相比 ReAct),并在 SWE-bench Verified 中表现优异。该方法证明了:如何组织和重用上下文(Structure)比单纯增加上下文长度(Length)更为关键。通过将线性对话历史重构为动态展开的递归树,为构建更高效、更鲁棒的 Agent 记忆机制提供了新的范式。
1. 思想
当前 LLM Agent 在处理复杂现实任务时面临着严重的“遗忘”与“迷失”困境。
-
大问题:
- 上下文漂移 (Context Drift):在扁平的顺序提示(如 ReAct)中,随着步骤增加,早期的长远计划会被大量的中间观察淹没或截断,导致模型忘记最初目标,陷入死循环。
- 层级割裂 (Hierarchical Fragmentation):现有的层级方法(如 THREAD, ADaPT)通常为每个子任务分配独立的上下文。这虽然隔离了干扰,但也切断了信息流,使得底层执行无法有效感知高层约束,或无法利用其他分支的经验。
-
小问题:
- 如何在递归分解任务时,既能让 LLM 专注于当前的原子动作,又能随时回溯并修正未完成的高层计划?
- 如何在有限的上下文窗口内,以线性增长的成本处理深度递归的任务树?
-
核心思想: 递归上下文感知与结构化重注入 (Recursive Context-Awareness with Structured Re-injection)。
- 预规划分解 (Plan-ahead Decomposition):模型一次性生成完整的子任务列表,但仅执行头部任务,其余作为“待办”保留。
- 共享上下文树 (Shared Context Tree):所有的递归调用发生在同一个物理 LLM 会话(Session)中,而非通过独立的 API 调用隔离。
- 结构化重注入 (Structured Re-injection):当从子任务递归返回(Backtracking)时,系统显式地将父级的剩余计划和最新的观察摘要重新注入到当前的上下文末端。这相当于在“遗忘”发生前,主动“提醒”模型接下来的高层目标。

Figure 1: (a) 顺序提示(ReAct)容易导致早期目标丢失;层级提示导致信息碎片化。

Figure 1: (b) ReCAP 通过在单一滑动窗口中重注入父级计划,保持了跨层级的一致性。
2. 方法
ReCAP 将 Agent 的执行过程建模为在共享语言模型上下文 C C C 上的递归函数调用。
2.1 形式化定义
设 D D D 为任务描述, O init O_{\text{init}} Oinit 为初始观察。
- 规划函数 π ( C ) \pi(C) π(C): 基于当前上下文生成思维 T T T 和有序子任务列表 S = ⟨ s 0 , s 1 , … , s m − 1 ⟩ S = \langle s_0, s_1, \dots, s_{m-1} \rangle S=⟨s0,s1,…,sm−1⟩。
- 环境/执行函数 E \mathcal{E} E: 执行原子动作并返回观察。
- 修正函数 ρ ( C ) \rho(C) ρ(C): 基于执行反馈,重新生成或调整剩余的思维 T T T 和子任务列表 S S S。
2.2 算法流程
ReCAP 的核心是一个递归过程,其伪代码逻辑如下:
-
初始化与规划:
( T , S ) ← π ( C ) (T, S) \leftarrow \pi(C) (T,S)←π(C)
模型在当前层级生成完整的计划 S S S。 -
递归执行循环:
当 S S S 不为空时,取出头部子任务 s 0 s_0 s0:-
如果: s 0 s_0 s0 是原子动作 (Primitive)
直接与环境交互:
O ← E ( s 0 ) O \leftarrow \mathcal{E}(s_0) O←E(s0)
更新上下文(追加执行记录):
C ← C ∥ ⟨ T , S , s 0 , O ⟩ C \leftarrow C \parallel \langle T, S, s_0, O \rangle C←C∥⟨T,S,s0,O⟩“ ∣ ∣ || ∣∣” 符号是表示拼接, 实际是一个对话消息的追加.
“ ⟨ ⟩ \langle\rangle ⟨⟩” 表示有序元组, 这里使用 JSON 模板:
{ "think": "The cutting board is occupied, so I need to clear it first...", // 这就是 T "subtasks": [ // 这就是 S (有序列表) "pick up lettuce", "put lettuce on table", "slice onion" ] } -
否则: s 0 s_0 s0 则是复合任务 (Composite)
递归调用 ReCAP,传入包含了 s 0 s_0 s0 意图的扩展上下文:
C ← ReCAP ( C ∥ ⟨ T , S , s 0 ⟩ ) C \leftarrow \text{ReCAP}(C \parallel \langle T, S, s_0 \rangle) C←ReCAP(C∥⟨T,S,s0⟩)
注意:这里 C C C 是共享且动态增长的。
-
-
结构化回溯与重注入 (The Critical Step):
无论 s 0 s_0 s0 执行成功与否,控制权返回当前层级后,上下文窗口可能已经发生了滑动(由于子任务执行了很长步骤)。为了防止“父级计划”被遗忘,ReCAP 强制将剩余计划 S [ 1 : ] S[1:] S[1:] 重新注入到上下文末尾:
C ← C ∥ ⟨ Parent Context Reminder , T , S [ 1 : ] ⟩ C \leftarrow C \parallel \langle \text{Parent Context Reminder}, T, S[1:] \rangle C←C∥⟨Parent Context Reminder,T,S[1:]⟩ -
计划修正:
基于最新的 C C C(包含了刚才子任务的执行结果和重注入的剩余计划),调用修正函数更新计划:
( T , S ) ← ρ ( C ) (T, S) \leftarrow \rho(C) (T,S)←ρ(C)
这一步允许模型根据子任务的反馈(如失败、资源被占用)动态调整后续步骤,而不是死板地执行旧计划。

Figure 2: ReCAP 的回溯与修正机制。子任务完成后,其观察结果被保留,父级剩余任务被重注入,模型据此生成新的推理。
# Python 伪代码
def ReCAP(context):
# pi_llm 和 rho_llm 实际是具有不同 System Prompt 的 Agent
thought, subtasks = pi_llm(context)
while subtasks:
current_task = subtasks[0]
if is_primitive(current_task):
observation = env_execute(current_task)
# 这里用 "+" 号简化了拼接和格式化, 实际需要填充 Prompt 模板
context += thought + subtasks + current_task + observation
else:
context = ReCAP(context + thought + subtasks + current_task)
context += thought + subtasks[1:]
thought, subtasks = rho_llm(context)
return context
ReCAP(task + observation_init)
2.3 内存效率与滑动窗口
传统的递归方法(如 DFS)通常需要保存整个调用栈的状态。ReCAP 利用 LLM 的滑动窗口 (Sliding Window) 特性实现了高效的内存管理:
- 线性增长: 活跃的上下文大小仅与递归深度 d d d 和单步平均长度 L ˉ \bar{L} Lˉ 成正比,即 O ( d ⋅ L ˉ ) O(d \cdot \bar{L}) O(d⋅Lˉ),而不是与整个历史轨迹长度成正比。
- 机制: 当上下文超出窗口限制时,旧的历史被截断。但由于“结构化重注入”的存在,高层的关键信息(目标、剩余计划)总是被移动到 Prompt 的最末端(最新的位置)。这保证了即使历史被截断,Agent 依然“记得”它在全局计划中的位置。
3. 优势
相较于基线方法,ReCAP 展现出明显的结构化优势:
- 对比 ReAct (Sequential): ReAct 将所有历史平铺,长序列导致早期关键信息(Goal)丢失。ReCAP 通过显式维护任务树和重注入机制,确保高层目标始终在注意力范围内(Attention Scope)。
- 对比 ADaPT/THREAD (Hierarchical): 这些方法在进入子任务时通常创建全新的隔离上下文,导致子任务无法利用父级的完整背景知识。ReCAP 使用共享上下文,子任务可以“看到”之前的对话历史(作为 Few-shot 示例或背景),增强了连贯性。
- 无需训练: 这是一个纯推理时(Inference-time)的框架,无需对模型进行微调,适用于任何遵循指令的 LLM。
4. 实验
实验设置
- 基准测试:
- Robotouille: 具身智能烹饪任务,长时序(需 10-80+ 步),具有异步和同步两种模式,极具挑战性。
- ALFWorld: 经典的文本具身基准,任务较短。
- SWE-bench Verified: 真实世界软件工程问题,代码库级操作。
- FEVER: 事实核查任务,短时序。
- 模型: GPT-4o, GPT-4.1 (preview), 以及开源模型 (Qwen, LLaMA)。
- 评估标准: Pass@1。仅允许单次尝试,无重试、无投票(Self-Consistency),这是最严格且贴近实际部署的指标。
核心结果
-
长时序任务提升显著:
在 Robotouille(同步)中,ReCAP 达到了 70.0% 的成功率,远超 ReAct 的 38.0% 和 ADaPT 的 40.0%。在更复杂的异步模式下,提升同样巨大(53.0% vs 24.0%)。Table 1: Pass@1 成功率对比 (主要结果)
Task ReCAP ADaPT ReAct CoT Robotouille (Sync) 70.0 40.0 38.0 14.0 Robotouille (Async) 53.0 14.0 24.0 5.0 ALFWorld 91.0 71.6 84.0 - SWE-bench Verified 44.8 - 39.6 - -
避免死循环:
定性分析显示,ReAct 经常陷入“拿起-放下”的无限循环(Infinite Loop),因为它忘记了为什么要拿起这个物体(例如为了切它,但切菜板被占用了)。ReCAP 能通过回溯机制检测到阻塞,修改计划(先清理切菜板),从而跳出局部最优陷阱。 -
成本分析:
虽然 ReCAP 引入了递归推理步骤,但在 Robotouille 中,平均 API 调用次数约为 75 次,成本可控(单次运行约 $7.77 USD)。考虑到成功率的倍增,性价比(Cost-per-success)实际上优于反复失败的 ReAct。 -
SWE-bench 表现:
在代码生成任务中,ReCAP 也是目前 GPT-4.1 下表现最好的单次推理方法(44.8%),证明了该递归框架在非具身、纯逻辑任务中的通用性。
结论
ReCAP 证明了在 LLM Agent 设计中,**控制流(Control Flow)**的结构优化可以带来比单纯模型能力提升更显著的收益。通过递归分解和上下文重注入,它成功地在有限的注意力窗口中“折叠”了无限增长的任务复杂度。
更多推荐



所有评论(0)