# Agent 规划器防震荡指南:从 NOAH 1975 到 LLMCompiler,50 年的轮回
> 面试官问:"你的 Agent 规划器怎么避免路径震荡?"如果你只答"LangGraph 的 state machine 加 retry",那这道题你可能只拿了 30 分。因为这道题考的不是框架熟练度,而是你能不能看出一个事实:LLM Agent 圈这两年的"新论文",本质上是把控制论、强化学习、经典 AI 规划 30~50 年前的东西换了个名字重做。
## 什么是路径震荡?
先定义问题。Agent 在执行任务时,不是走一条从起点到终点的直线,而是在几个状态之间反复横跳:
```
搜索文件 → 读文件 → 搜索文件 → 读文件 → 搜索文件 → ...
修改代码 → 运行测试 → 修改代码 → 运行测试 → 修改代码 → ...
```
这不是 bug,这是 Agent 规划器的**结构性缺陷**。2026 年 4 月 UIUC 和 IBM 联合发表的论文 "From Plan to Action"(分析了 16,991 条 SWE-agent 轨迹)给出了量化证据:
- **DeepSeek-R1** 在没有 plan 提醒时,plan compliance 最低,且频繁产生 malformed tool calls(349/500 实例)
- **GPT-5 mini** 在简单问题上跳过 Reproduction 直接 patch,在难题上又回到 plan——策略不一致本身就是一种震荡
- **所有模型**在 SWE-bench Pro(低污染数据集)上的 plan compliance 平均下降 13%
更关键的是 Finding 12:**周期性 plan 提醒(每 5 步重新注入 plan)是唯一一致有效的防震荡手段**。这说明震荡的根本原因是**上下文窗口压力**——plan 被越来越多的 tool output、error message、file content 淹没了。
## 50 年轮回:经典规划 → LLM Agent
让我们把时间线拉长,看看这个问题被解决过多少次。
### 第一幕:经典 AI 规划(1975-1996)
**NOAH (Sacerdoti, 1975)**——非线性规划的开山之作。
Sacerdoti 观察到:人类规划不是线性的 A→B→C→D,而是**层次化的**。你先规划高层目标("修 bug"),再逐步展开细节("找到文件"→"读代码"→"定位 bug"→"写测试"→"改代码"→"验证")。NOAH 引入了**procedural net**——一个有向图,节点是动作,边是时序约束(before/after),但允许并行执行。
这解决了一个核心问题:**线性 plan 太脆弱**。如果步骤 3 失败,线性 plan 要么从头来,要么跳过。而 NOAH 的非线性 plan 可以只回退到受影响的子图。
**Tsuneto et al. (1996)**——在不确定性下的规划。
Tsuneto 引入了**规划-执行-监控-重规划**循环(plan-execute-monitor-replan),这和今天 LLM Agent 的 reason-act-observe 循环**完全同构**。他们的关键洞察是:监控步骤不是"检查是否完成",而是"检测是否偏离 plan",偏离时触发重规划而非盲目重试。
**Fox et al. (2006)**——POMDP 中的策略回归。
Fox 指出:在部分可观测环境下(POMDP),最优策略不是一条固定路径,而是一个**从信念状态到动作的映射**。当 Agent 对环境的信念更新后,最优动作可能完全改变。这解释了为什么 LLM Agent 会"震荡"——它不是在犯错,而是在信念更新后选择了不同的动作,但缺乏一个全局一致性检查来防止反复切换。
### 第二幕:强化学习的层次化(1999-2020)
**Sutton et al. (1999)**——Options 框架。
Sutton 提出了**时间抽象**(temporal abstraction):一个 "option" 是一个"元动作",它本身包含一个策略、一个终止条件和一个持续时间的分布。比如"搜索文件"不是一个原子动作,而是一个 option——它可能需要多次调用搜索工具,直到找到目标或超时。
Options 框架直接对应了 LLM Agent 中的**子任务分解**。ReAct 的 "Thought: I need to search for the file" 就是在启动一个 option。但 ReAct 的问题在于:**它没有显式的终止条件**。option 什么时候结束?ReAct 靠 LLM 自己判断,而 LLM 经常判断错——这就是震荡的根源。
**FeUdal Networks (Vezhnevets et al., 2017)**——Manager-Worker 分层。
FeUdal 把 RL Agent 分成两层:
- **Manager**:在低时间分辨率上设定抽象目标("找到 bug 的位置")
- **Worker**:在高时间分辨率上执行具体动作("打开文件 X,读第 Y 行")
关键设计:**Manager 和 Worker 之间没有梯度传播**。Manager 的学习信号完全来自环境奖励,而不是 Worker 的反馈。这避免了"Worker 的短期失败导致 Manager 频繁改变目标"的问题——而这正是 LLM Agent 震荡的典型模式。
**Dabney et al. (2020)**——Successor Features 和奖励分解。
Dabney 提出了一个深刻的问题:如果 Agent 面对的是一个多目标任务(既要修 bug,又要保证不引入新 bug,还要通过测试),它应该怎么平衡?答案是:**把总奖励分解为多个独立的 successor features**,每个 feature 对应一个子目标。Agent 可以独立评估每个子目标的进展,而不是被一个混合奖励信号反复拉扯。
这直接对应了 LLM Agent 中的**plan phase compliance**问题。"From Plan to Action" 论文定义了三个维度:
- **PPC(Phase Coverage)**:是否覆盖了所有 plan 阶段?
- **POC(Order Compliance)**:是否按正确顺序执行?
- **PPF(Phase Fidelity)**:是否只执行 plan 中的阶段,没有多余动作?
Dabney 的 successor features 可以理解为这三个维度的 RL 版本。
### 第三幕:LLM Agent 的范式演化(2022-2026)
现在让我们看 LLM Agent 圈怎么"重新发明"了这些概念。
**ReAct (Yao et al., 2023)**——reason-act-observe 交错执行。
ReAct 的核心思想是:LLM 交替生成推理链(Thought)和动作(Action),观察环境反馈(Observation)后继续。这本质上是**把 Sutton 的 Options 框架用 LLM prompt 实现了**——每个 Thought-Action-Observation 三元组就是一个 option。
ReAct 的震荡问题:没有显式的 plan,LLM 在每一步都重新决定下一步做什么。如果上下文窗口被 error message 填满,LLM 就会忘记之前的推理,反复尝试相同的失败动作。
**Plan-and-Solve (Wang et al., 2023)**——先规划再执行。
Plan-and-Solve 把 ReAct 的单步决策变成了两阶段:
1. **Plan 阶段**:LLM 生成完整的步骤列表
2. **Solve 阶段**:逐步执行每个步骤
这本质上是**NOAH 1975 的层次化规划**——先生成高层 plan,再逐步展开。但 Plan-and-Solve 有一个致命缺陷:**plan 是一次性的**。如果步骤 3 失败,整个 plan 可能需要重写,但 Plan-and-Solve 没有重规划机制。
**ReWOO (Xu et al., 2023)**——推理与观察解耦。
ReWOO 的核心创新:把 plan 分成三部分——**Plan、Worker、Output**。Plan 阶段生成所有步骤的占位符(`#E1`, `#E2`, ...),Worker 阶段并行执行所有步骤(不依赖中间结果),Output 阶段汇总结果。
这解决了 ReAct 的一个核心问题:**观察结果污染推理**。在 ReAct 中,每一步的观察结果都会进入下一步的 prompt,导致上下文膨胀和注意力分散。ReWOO 通过解耦,让每一步只看到自己需要的信息。
但 ReWOO 也有问题:**如果步骤之间有依赖关系,并行执行会导致错误**。而且 ReWOO 没有处理执行失败的情况——如果 `#E2` 失败了,`#E3`(依赖 `#E2` 的结果)怎么办?
**LLMCompiler (Kim et al., 2024)**——依赖图 + 并行调度。
LLMCompiler 在 ReWOO 的基础上引入了**依赖图(DAG)**:
1. LLM 生成任务列表
2. 自动分析任务间的依赖关系,构建 DAG
3. 拓扑排序 + 并行调度——无依赖的任务并行执行,有依赖的串行执行
这本质上是**NOAH 的 procedural net + 现代编译器的指令调度**。LLMCompiler 还引入了**反馈循环**:如果某个任务失败,可以只重执行受影响的子图,而不是从头来。
2026 年 4 月发表的 "A Scheduler-Theoretic Framework for LLM Agent Execution"(arXiv:2604.11378)更进一步,直接把经典调度理论(scheduling theory)应用到 LLM Agent 执行上,证明了 LLM Agent 的执行问题可以形式化为**带优先级约束的调度问题**。
**OpAgent (2026)**——在线强化学习的 Web Agent。
OpAgent 把 Web 导航建模为一个**在线 RL 问题**:Agent 通过与真实网站交互来优化策略,而不是依赖预训练的 LLM。这回到了 Fox 2006 的 POMDP 框架——在部分可观测环境下,策略应该基于当前信念而非固定 plan。
## 四招防震荡 Checklist
基于以上分析,我给出一个**从经典理论到工程实践**的防震荡 checklist。
### 招一:层次化规划(来自 NOAH 1975 + Sutton 1999)
**原理**:不要让 LLM 在每一步都做全局决策。把任务分解为层次化的子目标,每个子目标有明确的终止条件。
**工程实现**:
```
Level 0: "修 bug #1234"(目标)
Level 1: ["定位 bug", "写复现测试", "修改代码", "验证修复"](plan phases)
Level 2: "定位 bug" → ["搜索相关文件", "阅读代码", "确认 bug 位置"](子任务)
```
**防震荡机制**:
- 每个 Level 1 阶段有**明确的进入/退出条件**(不是靠 LLM 判断)
- Level 2 的子任务有**最大重试次数**(来自 Tsuneto 1996 的监控机制)
- 阶段间有**状态检查点**——如果 Level 2 失败,回退到 Level 1 重规划,而不是在 Level 2 内反复重试
### 招二:Plan 提醒 + 上下文管理(来自 "From Plan to Action" 2026)
**原理**:震荡的根本原因是 plan 被上下文淹没。周期性重新注入 plan 是最简单有效的防震荡手段。
**工程实现**:
- 每 N 步(N=5 是论文验证的有效值)在 system prompt 中重新注入当前 plan
- 用 **Langutory 表示**(N→R→P→V)跟踪当前阶段,而不是完整的历史
- 上下文窗口管理:**压缩已完成的阶段**,只保留当前阶段和未来阶段的详细信息
**关键数据**:论文发现 plan 提醒对所有模型一致有效,但对 DeepSeek-V3 效果最显著(plan compliance 从低到接近完美)。
### 招三:依赖图 + 选择性重规划(来自 LLMCompiler 2024 + NOAH 1975)
**原理**:不是所有失败都需要从头来。构建任务依赖图,失败时只重执行受影响的子图。
**工程实现**:
```
任务 DAG:
搜索文件 ──→ 读代码 ──→ 定位 bug ──→ 写测试 ──→ 修改代码 ──→ 验证
↑ │
└────────────────────┘
```
- 如果"写测试"失败,只需要重执行"写测试"→"修改代码"→"验证"这条路径
- 如果"修改代码"导致新 bug,触发**重规划**:回到"定位 bug"阶段,但保留之前的搜索结果(来自 Dabney 2020 的 successor features——独立评估每个子目标的进展)
### 招四:退火式探索 + 终止检测(来自 FeUdal 2017 + SpecRA 2025)
**原理**:震荡的另一个表现是 Agent 在两个状态间反复切换(A→B→A→B)。这需要两个机制:**检测震荡**和**打破震荡**。
**检测震荡**(来自 SpecRA 2025):
- SpecRA 用**傅里叶分析**检测 Agent 轨迹中的周期性模式
- 工程简化版:维护一个**最近 N 步的动作序列**,如果检测到长度 ≥ 2 的重复子序列(如 [search, read, search, read]),判定为震荡
**打破震荡**(来自 FeUdal 2017):
- Manager-Worker 分离:Worker 的失败不应该导致 Manager 改变目标
- 工程实现:维护一个**目标栈**(goal stack),当前目标失败时,不是切换到另一个目标,而是:
1. 先尝试降低当前目标的精度(比如从"精确定位 bug"降到"缩小搜索范围")
2. 如果仍然失败,再考虑切换目标
3. 切换目标时,记录切换原因,防止反复切换回同一个失败目标
## 一张图总结
```
50 年轮回:
NOAH 1975 (层次化规划) ──────────────────→ Plan-and-Solve 2023
Tsuneto 1996 (监控+重规划) ──────────────→ ReAct 的 observe 循环
Sutton 1999 (Options/时间抽象) ───────────→ ReAct 的 Thought-Action
Fox 2006 (POMDP 策略回归) ─────────────→ OpAgent 2026
FeUdal 2017 (Manager-Worker) ───────────→ Plan-and-Execute 模式
Dabney 2020 (Successor Features) ───────→ Plan Phase Compliance 指标
NOAH procedural net ─────────────────────→ LLMCompiler DAG 调度
经典调度理论 ───────────────────────────→ Scheduler-Theoretic Framework 2026
```
## 面试怎么答?
回到原题。如果面试官问"Agent 规划器怎么避免路径震荡",一个满分回答应该是:
> "路径震荡有三个根本原因:上下文窗口压力导致 plan 被遗忘、缺乏显式的终止条件导致 option 无法结束、失败后缺乏选择性重规划导致全局重试。
>
> 我的防震荡方案分四层:
> 1. **层次化规划**(NOAH 1975):把任务分解为有明确进入/退出条件的子目标,避免 LLM 在每一步做全局决策
> 2. **Plan 提醒**(From Plan to Action 2026):每 5 步重新注入 plan,用 Langutory 表示压缩上下文
> 3. **依赖图调度**(LLMCompiler 2024):构建任务 DAG,失败时只重执行受影响的子图
> 4. **退火式探索**(FeUdal 2017 + SpecRA 2025):用周期检测识别震荡,用目标栈+精度降级打破震荡
>
> 本质上,这些问题在经典 AI 规划、控制论和强化学习中都有对应解决方案。LLM Agent 的贡献不是发明了新方法,而是把这些方法用自然语言接口重新包装了。"
---
**参考文献**
| 年份 | 论文 | 核心贡献 | 对应的 LLM Agent 概念 |
|------|------|---------|---------------------|
| 1975 | Sacerdoti, NOAH | 非线性层次化规划 | Plan-and-Solve |
| 1996 | Tsuneto et al. | 规划-执行-监控-重规划循环 | ReAct 的 observe 循环 |
| 1999 | Sutton et al., Options | 时间抽象、元动作 | ReAct 的 Thought-Action |
| 2006 | Fox et al., POMDP | 信念状态到动作的映射 | OpAgent |
| 2017 | Vezhnevets et al., FeUdal | Manager-Worker 分层 | Plan-and-Execute |
| 2020 | Dabney et al., Successor Features | 奖励分解、多目标评估 | Plan Phase Compliance |
| 2023 | Yao et al., ReAct | reason-act-observe 交错 | — |
| 2023 | Wang et al., Plan-and-Solve | 先规划再执行 | — |
| 2023 | Xu et al., ReWOO | 推理与观察解耦 | — |
| 2024 | Kim et al., LLMCompiler | DAG 依赖图 + 并行调度 | — |
| 2025 | SpecRA | 傅里叶分析检测退化重复 | — |
| 2026 | OpAgent | 在线 RL Web Agent | — |
| 2026 | Liu et al., From Plan to Action | Plan Compliance 指标体系 | — |
| 2026 | Scheduler-Theoretic Framework | 经典调度理论应用于 Agent | — |
#LLMAgent #规划 #强化学习 #经典AI #面试 #ReAct #PlanAndSolve #ReWOO #LLMCompiler #控制论
登录后可参与表态
讨论回复
0 条回复还没有人回复,快来发表你的看法吧!