对应 Maps to:CS486 课程描述的 “enhance LLM planning” 与 “multi-agent collaboration”——规划部分(第 8–11 讲)的第三讲:从只有”动作前提”的积木世界,走向有时间、资源、很多条约束、执行中会出变故的真实规划;以及多智能体框架(MACI、ALAS)在这类问题上的设计主张。 依据说明:CS486 没有公开的日程或讲义。本讲依据约束满足与时序推理的经典内容(简单时序网络、回溯与约束传播、min-conflicts、计划稳定性),真实场景规划的基准(TravelPlanner、NATURAL PLAN、REALM-Bench),LLM 与求解器结合的工作(Gundawar et al. 2024 的 LLM-Modulo 旅行规划、Hao et al. 2024 的 SMT 方法),以及 Edward Y. Chang 等人的 MACI 与 ALAS。§2–§7 的实验是本讲义自己设计的,数字全部来自配套代码的实际输出。 配套代码 Code:
code/lecture10/(代码 01–03 只用标准库,几秒到 20 秒;代码 04 用 PyTorch,第一次约 1.5 分钟——并行训练 5 个小模型) 预计阅读时间:3.5 小时(含运行代码)
0. 本讲导航 · How to read this lecture
0.1 学习目标 Learning goals
学完这一讲,你应该能够:
- 说出真实规划比积木世界多了什么:时间(时长、先后、时间窗)、资源(同一时间只能做一件事)、很多条约束同时成立、执行中的变故。
- 解释”每条约束大概率满足”和”所有约束同时满足”之间的指数鸿沟,用它读懂 TravelPlanner 的 micro / macro 通过率,并知道为什么只报告一个数不够。
- 用简单时序网络(STN)精确地推理时间约束:最早 / 最晚时间、松弛、一致性;知道负环就是”哪几条约束冲突”的解释。
- 区分不完备的”草稿 + 逐条修补”(LLM-Modulo 式)和完备的求解器:谁能找到解、谁能证明无解、谁能解释无解。
- 复述 MACI 的设计主张(元规划器、依赖图、规划与验证分开、最小上下文、运行时监控),并用受控实验检验”最小上下文”这一条:它在什么条件下成立、代价是什么。
- 在运行时重规划中权衡”从头重规划”和”局部修补”(计划稳定性),理解监控器发现变故的早晚意味着什么。
0.2 先修与本讲范围 Prerequisites & scope
| 默认你已经会 Assumed | 本讲不展开 Not covered |
|---|---|
| 第 6 讲:干扰陈述与长度泛化;无解的题 | 调度理论的复杂性证明(只给结论) |
| 第 7 讲:外部反馈 vs 内在反馈;定位反馈 | SAT / SMT 求解器的内部算法(CDCL 等) |
| 第 8 讲:验证器、LLM-Modulo、LLM+P | 运筹学的整数规划方法 |
| 第 9 讲:搜索、完备性、MPC 闭环 | 多智能体系统的一般架构(第 14 讲) |
0.3 本讲地图 Map
§1 从积木到日程:真实规划多了什么
§2 很多约束同时成立:指数鸿沟;TravelPlanner 的 micro / macro ← 代码 01 演示 1–3
§3 时间约束:简单时序网络;最早 / 最晚时间;负环就是解释 ← 代码 01 演示 4–5
§4 LLM + 求解器:LLM-Modulo 的旅行规划;把需求翻译成约束交给 SMT
§5 实验:草稿 + 逐条修补 vs 完备的求解器——谁能说"这不可能" ← 代码 02
§6 MACI:元规划器、依赖图、最小上下文;实验:一次看全部 vs 拆开 ← 代码 04
§7 运行时重规划:监控、从头再来 vs 局部修补、计划稳定性、ALAS ← 代码 03
§8 现状与开放问题
§9–13 小结、常见误区、练习、延伸阅读、下一讲预告
1. 从积木到日程 · From blocks to schedules
第 8、9 讲的积木世界只有一种约束:动作的前提(要搬的积木必须在最上面)。真实的规划问题多了四样东西:
- 时间:动作有时长(火鸡要烤 4 小时),有先后(先接到人才能开饭),有时间窗(航班 14:30 落地、18:00 开饭),有截止时间。
- 资源:一个人同一时间只能在一个地方,一个烤箱同一时间只能烤一样东西。资源约束是”二选一”的(谁先谁后),正是它们让调度问题变成 NP 难。
- 很多条约束同时成立:一份旅行计划要满足预算、住宿天数、餐厅不重复、交通不冲突、用户的偏好……任何一条不满足,这份计划就不能用。
- 执行中的变故:航班延误、某件事比预想的久、有人临时有事。计划要在执行过程中被监控、被修改。
这一讲按这四样东西组织:§2 讲”很多约束”,§3 讲”时间”,§5 讲”资源 + 很多约束”下的求解,§7 讲”变故”。§4 和 §6 讲 LLM 和多智能体框架在其中扮演什么角色。
2. 很多约束同时成立 · Many constraints at once
代码:01_constraints_and_time.py(只用标准库,约 1 秒)。
2.1 基准
- TravelPlanner(Xie et al. 2024,ICML):1,225 个旅行规划请求,一个可以查询近 400 万条记录(航班、餐厅、住宿、景点)的沙盒。计划要满足常识约束(8 条:信息在沙盒内、信息完整、在当前城市活动、路线合理、餐厅不重复、景点不重复、交通方式不冲突、满足最少入住天数)和硬约束(预算、房型、菜系等用户要求)。GPT-4-Turbo 在”自己用工具查信息再规划”的两阶段模式下,只有 0.6% 的计划满足全部约束;把需要的信息直接给它(只规划模式),也只有 4.4%。
- NATURAL PLAN(Zheng et al. 2024):三类任务——旅行规划(多城市行程、航班衔接)、会议规划(在城市里见尽量多的朋友,考虑交通时间)、日程安排(找所有人都有空的时段)。工具的输出(航班、地图、日历)直接放进上下文,只考察规划本身。旅行规划上 GPT-4 31.1%、Gemini 1.5 Pro 34.8%,而且随城市数增加急剧下降。
- REALM-Bench(Geng & Chang 2025):面向多智能体系统的真实规划与调度问题(最初 11 个,后来的版本扩展到 14 个),可以沿三个维度加难度:并行的规划线程数、相互依赖的复杂度、执行中变故的频率。
2.2 指数鸿沟
TravelPlanner 报告两种通过率:micro——所有适用约束中被满足的比例;macro——所有约束都满足的计划的比例。如果每条约束独立地以概率 p 被满足,m 条全部满足的概率是 (演示 1):
| p | m = 1 | m = 5 | m = 10 | m = 20 | m = 50 |
|---|---|---|---|---|---|
| 0.99 | 99.0% | 95.1% | 90.4% | 81.8% | 60.5% |
| 0.95 | 95.0% | 77.4% | 59.9% | 35.8% | 7.7% |
| 0.90 | 90.0% | 59.0% | 34.9% | 12.2% | 0.5% |
一个”大部分约束都满足”的计划和一个”能用”的计划之间,隔着一道指数鸿沟。这和第 9 讲世界模型的误差累积(一步准确率的 k 次方)是同一个算术,也是第 11 讲长程智能体的核心问题。
2.3 用 TravelPlanner 的数字检验
演示 2 把 TravelPlanner 公布的常识约束通过率(GPT-4-Turbo)代进 :
| 设置 | micro(公布) | macro(公布) | micro⁸ |
|---|---|---|---|
| 两阶段 · 验证集 | 61.1% | 2.8% | 1.9% |
| 两阶段 · 测试集 | 63.3% | 2.0% | 2.6% |
| 只规划 · 验证集 | 80.4% | 17.2% | 17.5% |
| 只规划 · 测试集 | 80.6% | 15.2% | 17.8% |
数量级对得上,但不完全吻合。这只是一个粗略的检验(8 条常识约束不一定对每个计划都同样适用),但它说明了一件事:macro 的低迷主要是约束数目的算术,而不一定是某一条约束特别难。要把 macro 从 17% 提到 50%,每条约束的满足率要从 80% 提到 。
2.4 只报告一个数不够
约束的失败往往不独立:一份糟糕的计划常常同时违反好几条。演示 3 固定 micro = 80%、m = 8,让计划之间的”质量”有不同的离散程度:
| 离散程度 | micro | macro |
|---|---|---|
| 0(独立) | 79.9% | 16.7% |
| 0.05 | 80.0% | 22.6% |
| 0.2 | 80.0% | 36.1% |
| 0.5 | 80.1% | 56.1% |
同样的 micro,macro 可以从 17% 到 56%。正相关让失败集中在少数糟糕的计划上,macro 更高;负相关(例如修好一条约束常常弄坏另一条——预算和舒适度就是这样)让它更低。比较两个系统时,要同时报告 micro、macro,最好还有每条约束各自的通过率。
3. 时间约束:简单时序网络 · Simple Temporal Networks
3.1 定义
简单时序网络(Simple Temporal Network,STN,Dechter, Meiri & Pearl 1991)由若干时间点和形如
的约束组成:两个事件之间的时间差在某个区间里。时长(火鸡烤 240 分钟:)、先后()、时间窗(,即 14:30)都可以写成这种形式。
把每条约束拆成距离图里的两条边: 权重 hi, 权重 −lo。于是:
- 网络一致(存在满足所有约束的时间安排)⇔ 距离图里没有负环;
- 最短距离 是 的最紧上界;以零点 Z 为原点,事件 v 的最晚时间是 ,最早时间是 ;
- 最晚减最早就是这个事件的松弛(slack):还能推迟多少。
这些都是最短路计算(Floyd–Warshall,),对几十个事件瞬间完成。
3.2 一个家庭聚餐
演示 4 的场景(灵感来自 MACI 论文里的感恩节晚餐案例,细节是本讲义自己设定的):18:00 开饭;火鸡要烤 4 小时,厨房 10:00 之后可用,出炉后静置 15 分钟;配菜 90 分钟,14:00 之后才能开始;航班 14:30 落地,取行李 20 分钟、开车 45 分钟,到家后至少 10 分钟再开饭;奶奶 13:00 之后才准备好,接她往返 60 分钟,开饭前 30 分钟到家。
| 事件 | 最早 | 最晚 | 松弛 |
|---|---|---|---|
| 火鸡入炉 | 10:00 | 13:45 | 225 分钟 |
| 配菜开始 | 14:00 | 16:30 | 150 分钟 |
| 离开机场 | 14:50 | 17:05 | 135 分钟 |
| 出发接奶奶 | 13:00 | 16:30 | 210 分钟 |
“火鸡最晚 13:45 入炉”是一条依赖链(开饭 → 静置 15 分钟 → 烤 240 分钟)上的逐项相减。对 LLM 来说,这种推理要一步步做——链有多长,就要串行地做多少次(第 1、3 讲的串行深度);对 STN 来说,它是一次最短路计算。
3.3 负环就是解释
航班延误时(演示 5):延误 ≤ 135 分钟(正好是”离开机场”的松弛)都排得开;延误 150 分钟就排不开了。此时距离图里出现一个负环,环上的约束是:
航班 17:00 落地(延误 150 分钟)→ 取行李至少 20 分钟 → 机场开车到家 45 分钟 → 到家后至少 10 分钟再开饭 → 开饭定在 18:00
这五条合起来要求的时间比可用的多 15 分钟(延误 180 分钟时多 45 分钟)。这不只是”不行”,而是解释:是哪几条要求合在一起做不到,差多少。用户可以据此决定放松哪一条(开饭推迟 15 分钟?取消”到家后 10 分钟”的缓冲?),或者改变计划的结构(让接机的人直接去餐馆)。§4 会看到,Hao et al. 用 SMT 求解器做旅行规划时,正是把这种”不可满足核”交给用户。
3.4 STN 管不了的:资源
“同一个司机不能同时去机场和接奶奶”不是 STN 的约束:它是”要么先接奶奶再去机场,要么反过来”——一个析取(disjunction)。带析取的时序网络(Disjunctive Temporal Problem)和资源受限的调度是 NP 难的,需要搜索:每一种先后的选择对应一个 STN,有一个选择一致,问题就有解。这就是 §5 的约束满足求解器做的事:搜索”谁先谁后、谁来做”,用 STN 式的推理(最早 / 最晚时间)剪枝。
4. LLM + 求解器 · LLMs with solvers
4.1 LLM-Modulo 的旅行规划
Gundawar et al.(2024,“Robust Planning with LLM-Modulo Framework: Case Study in Travel Planning”)把第 8 讲的 LLM-Modulo 框架用在 TravelPlanner 上:LLM 写计划,一组批评者分别检查各条约束(预算、交通、住宿天数……),把违反的约束反馈给 LLM,LLM 修改,循环。在只规划模式的验证集上,GPT-4-Turbo 的最终通过率提高到原来的 4.6 倍(基线 4.4%),GPT-3.5-Turbo 从 0% 提到 5%。
这是可观的提高,但绝对数仍然不高。§5 的实验会说明一个结构性的原因:修补循环是不完备的——它找不到解时,不知道是”还没找到”还是”根本没有”。
4.2 把需求翻译成约束,交给 SMT
Hao et al.(2024,NAACL 2025,“Large Language Models Can Solve Real-World Planning Rigorously with Formal Verification Tools”)走了另一条路:LLM 只负责把自然语言的需求翻译成约束满足问题,由 SMT 求解器(Z3)求解。在 TravelPlanner 上通过率 93.9%(同一篇论文报告,给出全部所需信息时,o1-preview 直接规划只有 10%)。更重要的是对无解的请求:求解器给出不可满足核,说明是哪些要求冲突,LLM 据此向用户建议怎样修改,在两个数据集上分别修好并解出 81.6% 和 91.7% 的无解请求。
这和第 8 讲的 LLM+P 是同一个思路:LLM 负责翻译和常识,求解器负责正确性。代价是翻译本身可能出错(第 8 讲练习 5)——求解器会”正确地”解出一个翻译错了的问题。
4.3 什么时候用哪一种
| LLM-Modulo(LLM 写 + 批评者查) | LLM 翻译 + 求解器 | |
|---|---|---|
| 正确性 | 通过所有批评者的计划满足那些约束 | 求解器保证(在翻译正确的前提下) |
| 无解时 | 循环跑完预算,交出一个仍有冲突的计划 | 证明无解,并给出冲突核 |
| 约束能否形式化 | 批评者可以是”软”的(LLM 当批评者检查风格) | 约束必须能写成求解器的语言 |
| 主要风险 | 循环不收敛、修好一条弄坏另一条 | 翻译错误 |
5. 实验:草稿 + 逐条修补 vs 完备的求解器 · Repair vs solve
代码:02_repair_vs_solve.py(只用标准库,约 20 秒)。
5.1 设置
一族随机的调度问题:8 个任务(时长 1–4 个时段,每个任务可以由 1–3 个人中的某些人做)、3 个人、6 条先后约束,所有任务必须在时间范围 H 内完成。H 从 6(很紧)到 14(很松)。
- 完备的求解器(
schedule_lab.solve):回溯搜索 + 前向检查 + 先后约束的边界传播(就是 §3 的最早 / 最晚时间推理用在还没安排的任务上)。有解一定找到,无解一定能证明。 - 修补循环(
repair_loop):从一份”草稿”出发(按顺序把每个任务放在前置任务结束之后的最早时刻,交给第一个能做它的人——照顾了先后,没照顾人手冲突);批评者列出违反的约束;每轮把一个涉及冲突的任务挪到”冲突最少”的位置(min-conflicts,Minton et al. 1992)。这是 LLM-Modulo 式修补的算法替身:它不是 LLM,但有同样的结构——看着反馈逐条修改,没有系统的搜索。 - 二值反馈:批评者只说”不行”,于是整个重写一份(随机取值)。
5.2 有解的比例:相变
| H | 6 | 7 | 8 | 9 | 10 | 12 | 14 |
|---|---|---|---|---|---|---|---|
| 有解 | 9% | 22% | 30% | 60% | 78% | 94% | 96% |
有解的比例随 H 陡峭地变化——约束满足问题的”相变”现象(Cheeseman et al. 1991;Mitchell, Selman & Levesque 1992 在随机 3-SAT 上的经典结果)。做复杂度扫描时要知道题落在哪一段:H = 7 时 78% 的题根本无解,一个不会说”不可能”的方法在这些题上只会被记成”失败”——第 6 讲”思考的幻觉”之争里,复杂度扫描混进了无解题,正是这个问题。
求解器的工作量:有边界传播时,每道题最多尝试 198 次取值(中位数 0–8 次,很多题靠传播直接判定);没有传播时中位数也只有十几次,但最多要 17,183 次——工作量有很长的尾巴。好的求解器靠推理,而不是靠蛮力。
5.3 有解的题上:修补循环表现不错,但不是 100%
| H | 有解的题 | 草稿就对 | 修补(列出全部冲突) | 修补(只说第一条) | 二值反馈(整个重写) | 求解器 |
|---|---|---|---|---|---|---|
| 7 | 44 | 0% | 75% | 91% | 0% | 100% |
| 9 | 120 | 0% | 92% | 92% | 2% | 100% |
| 14 | 191 | 0% | 99% | 96% | 7% | 100% |
(每道题最多 300 轮。)草稿几乎从来不对;修补循环在宽松的题上几乎都能修好,紧的时候更难;列出全部冲突还是只说第一条,差别不大也不一致(H = 7 时只说第一条反而更好,44 道题的样本很小);二值反馈几乎没用——和第 7、8 讲一致,反馈至少要指出错在哪里。
练习 3 把轮数加到 1000、3000:H = 7 时从 33/44 到 36/44,然后不再提高——修补循环会卡在”局部最优”(每一步都没法再减少冲突,但冲突没有消失),预算再多也没用。
5.4 无解的题上:修补循环不会说”不可能”
| H | 无解的题 | 草稿的冲突数 | 修补 300 轮后 | 求解器:平均尝试次数 | 其中传播直接判定 |
|---|---|---|---|---|---|
| 6 | 182 | 10.2 | 3.5 | 1 | 165 |
| 7 | 156 | 8.3 | 2.3 | 2 | 139 |
| 8 | 140 | 7.1 | 1.4 | 5 | 106 |
修补循环在无解的题上把冲突从 8.3 条修到 2.3 条(H = 7),然后在预算用完时交出这个仍有冲突的计划。它没有办法区分”还没找到”和”根本没有”——这正是 LLM 在无解题上的表现(第 6 讲的无解谜题、第 8 讲 o1 在无解积木题上的表现)。完备的求解器每道都给出无解的证明,平均只尝试 1–5 次取值。
5.5 无解时的解释:冲突核
unsat_core 用删除法找一个极小的先后约束子集:只保留它们(加上全部任务、人手和时间范围),问题仍然无解;删掉其中任何一条,问题就变得有解。H = 8 的 140 道无解题里:
- 77 道是一条时长链超过了时间范围(例:C → D → F → G,时长 1 + 4 + 1 + 3 = 9 > 8);
- 31 道是先后关系和人手合起来冲突(人手无限时放得下,加上”同一个人同一时间只能做一件事”就放不下);
- 32 道去掉所有先后约束仍然无解——人手和时间根本不够。
三种原因需要用户做三种不同的让步(拆开一条依赖链?加一个人?延长时间?)。把冲突核交给用户——“这几条要求不能同时满足,你愿意放松哪一条?“——比交出一个悄悄违反约束的计划好得多。
6. MACI:多智能体的时序规划 · MACI
6.1 框架
MACI(Multi-Agent Collaborative Intelligence,Chang 2025,Stanford InfoLab 技术报告)针对的问题正是本讲的主题:LLM 在多约束的时序规划上缺乏深思熟虑的推理、时间意识和一致的约束处理。它的三个组件:
- 元规划器(meta-planner):分析任务,识别角色(厨师、司机、监督者)和约束,构建一张依赖图——节点是角色 / 任务,边是时间、空间或资源上的依赖;加入常识,让约束更符合现实。
- 智能体:通用的和任务专用的智能体,按依赖图执行规划。
- 运行时监控器:在执行中监视偏离,必要时激活应急智能体修改依赖、重新分配角色、调整约束,并把更新通知受影响的智能体。
论文主张的几条设计原则:把规划和验证分开(模型能发现别人计划里的错误,却常常发现不了自己的——第 7 讲);每个智能体只保留最小的上下文(作者观察到 LLM 在长上下文里偏重最近的信息、忽略早先的约束,称为 attention narrowing,主张每个智能体的上下文控制在约 1k token);加入常识。
证据:论文的主要实验是两个案例——感恩节晚餐(多人从不同城市到达、接机、租车、火鸡要烤 4 小时且需要有人在家、接奶奶)和校园旅行商问题——以及一个”航班延误 3 小时”的反应式变体。没有元规划器时,几个 LLM 在晚餐案例里出现了推迟晚餐(违反 18:00)、让烤箱无人看管、算错往返时间等错误;在延误变体里,得到预警的模型提前改派人去机场。这些是有价值的定性观察,但论文没有报告成功率或受控的对比实验——“最小上下文”等主张是从案例中得出的诊断。
ALAS(Geng & Chang 2025)是同一研究组的后续:一个有状态的、面向变故的多智能体规划框架。验证器独立于规划的 LLM(避免”自己检查自己”);用版本化的执行日志记录已经发生的事,能恢复到之前的状态;出现变故时只修补计划中受影响的最小区域(“有界的编辑半径”),按重试、超时、补偿等明确的策略处理,工作流可以映射到 Amazon States Language 和 Argo Workflows。在作业车间调度(DMU、TA 基准)上报告 83.7% 的成功率,token 用量减少 60%,速度快 1.82 倍;局部修补比全局重算的完工时间退化更小。
6.2 实验:一次看全部 vs 拆成只看最小上下文的几次调用
代码:04_context_and_decomposition.py(第一次约 1.5 分钟)。
“最小上下文”是一个可以做受控实验的主张。第 6 讲已经看到它的一半证据:无关的陈述会让小模型的多跳查找失败。这里换一个更贴近日程规划的任务——NATURAL PLAN 日程安排的缩小版:m 个人各有一份忙碌时段(16 个半小时时段),找所有人都有空、连续 d 个时段的最早开始时刻。四种做法,模型都是 2 层 TinyReasoner:
- 一次看全部,直接回答(只在 2–4 人的题上训练);
- 一次看全部 + 思维链:先写出合并后的忙碌时段,再回答(2–4 人);
- 拆开(gap1):一个”合并”智能体每次只看两份日程、写出并集(链式调用 m − 1 次),再交给一个”找空档”智能体——它在单个人的日程上训练;
- 拆开(gapU):同上,但找空档的智能体在 1–10 个人合并后的日程上训练。
| 人数 m | 一次看全部 | 一次看全部 + 思维链 | 拆开(gap1) | 拆开(gapU) |
|---|---|---|---|---|
| 2 | 99% | 100% | 93% | 100% |
| 4 | 96% | 100% | 73% | 98% |
| 6 | 92% | 100% | 49% | 95% |
| 8 | 92% | 90% | 38% | 94% |
| 10 | 91% | 80% | 33% | 92% |
(合并智能体在所有 m 上都 100% 正确。)四个发现:
- “一次看全部”比预想的稳:从 99% 缓慢降到 91%,6–10 人都没在训练中见过。“这个时段有没有人忙”是一个与位置无关的查找,人多了只是查找范围变大。所以”上下文越长越糟”不是普遍规律——取决于任务需要模型在上下文里做什么(第 6 讲的多跳查找被干扰陈述严重破坏,这里不会)。
- 拆开、但下游没见过上游的输出:反而最差(10 人时 33%)。原因(演示 2):单个人的日程平均 7.7 个忙碌时段,10 个人合并后平均 14.8 个(一共只有 16 个)。按忙碌时段数分组,gap1 在 ≤ 8 个时 98–100%,≥ 12 个时只有 46%。拆分改变了下游看到的分布:每个智能体”只看最小的上下文”,但这份上下文是上游写的,不是它的训练数据。
- 让下游在”上游会交给它的东西”上训练,拆分就和一次看全部一样好(gapU:100% / 95% / 92%),代价是 m 次调用。
- 思维链在训练范围内最好、超出之后最先崩(10 人时 80%)。我原以为它败在先写的”合并后的日程”变长写错了;演示 3 说明不是:10 人时并集写对了 95%,但写对之后答案只对 80%——错在最后一步,在一份很满的日程里找空档(训练时的并集平均最多约 12 个忙碌时段)。思维链和 gap1 栽在同一个地方:中间结果落在训练分布之外。
对 MACI 式设计的启示:“每个智能体只看最小上下文”是一个合理的工程原则,但它不是免费的:(1) 一次调用变成多次,上游的错误会传给下游(这里合并智能体恰好不出错,所以没有累积;第 11 讲会看到累积的后果);(2) 下游的输入分布由上游决定,要在那个分布上训练和测试。要证明拆分有帮助,需要和”一次看全部”做受控的对比——本实验就是这样一个对比的模板。
7. 运行时重规划 · Runtime replanning
代码:03_runtime_replanning.py(只用标准库,约 1 秒)。
7.1 问题
计划很少按计划执行。运行时重规划要回答三个问题:
- 监控:谁、什么时候发现计划已经不成立了?
- 重规划的范围:从头重新规划,还是只修补受影响的部分?
- 什么不能改:已经发生的事不能撤销(已经出发的车、已经放进烤箱的火鸡)。
经典规划里,Fox et al.(2006,ICAPS,“Plan Stability: Replanning versus Plan Repair”)提出计划稳定性:修补后的计划和原计划越像越好——每改一处,就要通知一个人”你的安排变了”,还可能引起新的连锁反应。他们的实验发现,修补原计划比从头重规划更快,而且保留了更多原计划。
7.2 实验
200 个”有解的一天”:12 个任务、4 个人、10 条先后约束,时间范围 11 个时段(比较紧)。每天发生 2 个随机变故:某个任务超时 1–3 个时段,或者某个任务比当前计划晚 1–3 个时段才能开始。已经开始的任务不能再改。
不监控(照原计划执行):只有 2.0% 的天里原计划还能用;平均每天结束时违反 2.23 条约束(一个任务超时,会挤占同一个人的下一个任务、推迟依赖它的任务,冲突会传播)。
监控 + 重规划(三种做法 × 四种发现时机):
| 监控器发现变故 | 做法 | 成功 | 平均改动的任务数 | 求解器尝试次数 |
|---|---|---|---|---|
| 到时才发现 | 从头重规划 | 54.5% | 5.40 | 12 |
| 到时才发现 | 局部修补 | 55.0% | 3.63 | 6 |
| 提前 4 个时段 | 从头重规划 | 54.0% | 6.26 | 12 |
| 提前 4 个时段 | 局部修补 | 55.5% | 3.67 | 5 |
| 一早就知道 | 从头重规划 | 57.5% | 6.84 | 16 |
| 一早就知道 | 偏好原计划 | 58.5% | 4.62 | 15 |
| 一早就知道 | 局部修补 | 59.0% | 3.88 | 9 |
(“偏好原计划”= 完整地重新求解,但每个任务先试原来的安排;“局部修补”= 只放开出问题的任务,修不好再把有先后关系或可能共用一个人的邻居也放开,逐步扩大——ALAS 式的有界编辑半径。)
三个发现:
- 局部修补改动得少,成功率几乎一样:一早就知道时,从头重规划平均改动 6.84 个任务(共 12 个),局部修补 3.88 个。演示 3 的一个例子:任务 B 最早只能推迟 3 个时段开始,从头重规划改动了 8 个任务,局部修补只把 B 和同一个人的 G 对调了顺序。
- 局部修补要能”扩大”:练习 4 去掉了”修不好就扩大”这一步(只放开出问题的任务),成功率从 59.0% 掉到 25.5%。最小的改动常常不够;关键是改动的范围要按需增长,而不是固定。
- 早发现的好处在这里不大:从头重规划在”到时才发现”时 54.5%,“一早就知道”时 57.5%。剩下 40% 多的天,变故让问题本身无解了(时间范围很紧),早发现也救不回来——这时该做的是告诉用户哪条约束必须放松(§3.3、§5.5 的冲突解释)。早发现值多少,取决于问题里有多少可以提前挪动的余地。
一个反直觉的细节:发现得越早,从头重规划改动得越多(到时才发现 5.40 → 一早就知道 6.84),局部修补几乎不变(3.63 → 3.88)。越早,还没开始、可以挪动的任务越多;从头重规划会把它们全部重新排一遍,哪怕它们和变故毫无关系。LLM 被要求”根据新情况重新写一份计划”时,行为更像从头重规划——这是 ALAS 主张局部修补、版本化日志的原因。
7.3 对 LLM 系统的启示
这些做法都需要两样东西:一个能接受”固定一部分”的求解器(已经发生的不能改、没受影响的尽量不改),和一个独立于规划者的监控器。MACI 把规划和验证分开、用运行时监控触发重规划;ALAS 用版本化的执行日志知道”哪些已经发生、不能再改”。让同一个 LLM 一边执行、一边自己发现问题、再从头重写计划,三个环节都可能出错(第 7 讲的自我纠错)。第 9 讲的 MPC 闭环是这一节的最简单版本;第 11 讲会把它放进长程的智能体任务里。
8. 现状与开放问题 · State of the field
- 真实场景规划基准(TravelPlanner、NATURAL PLAN、REALM-Bench)上,LLM 直接规划的成功率仍然很低;主要的提高来自和求解器结合(Hao et al. 的 93.9%)或外部批评者(LLM-Modulo)。推理模型提高了直接规划的成绩,但无解请求和大规模问题仍然困难。
- 多智能体框架(MACI、ALAS)提出了有价值的设计原则——规划与验证分开、最小上下文、运行时监控、局部修补——但多数证据是案例研究,受控的消融实验还很少。
- 运行时重规划在 LLM 智能体里刚刚开始被系统地研究;经典规划的计划稳定性、计划修补文献是现成的起点。
研究问题:
- “最小上下文”在什么任务上有帮助、在什么任务上没有?能否预测——例如根据任务需要的是”全局查找”还是”多跳推理”?
- 拆分之后,下游智能体的输入分布由上游决定。怎样在不重新训练的情况下(例如只用提示)让下游适应上游的输出分布?
- LLM 把自然语言翻译成约束时出的错,怎样在交给求解器之前发现?(回译、多次翻译的一致性、在小例子上的测试?)
- 对无解的请求,怎样选择对用户代价最小的放松方案?冲突核告诉你哪些约束冲突,但用户更愿意放松哪一条,需要偏好模型。
9. 小结 · Summary
- 真实规划比积木世界多了时间、资源、很多条约束、执行中的变故。
- 每条约束独立地以 p 满足,m 条全部满足是 :TravelPlanner 的常识约束 micro 80.4%、0.804⁸ ≈ 17.5%,公布的 macro 17.2%。同样的 micro,相关性不同,macro 可以从 17% 到 56%——要同时报告 micro、macro 和每条约束的通过率。
- 简单时序网络精确地推理时间:最早 / 最晚时间、松弛都是最短路;排不开时,负环就是”哪几条约束冲突、差多少”的解释。资源约束是析取的,需要搜索。
- LLM + 求解器的两条路线:LLM-Modulo(LLM 写、批评者查,GPT-4-Turbo 提高到 4.6 倍)和 LLM 翻译 + SMT(93.9%,并能解释无解)。
- 修补循环在有解的题上表现不错,但会卡在局部最优,而且不会说”不可能”——在无解的题上交出仍有冲突的计划;完备的求解器每道都能证明无解,并给出冲突核。
- MACI 的”最小上下文”不是免费的:拆分改变了下游看到的分布;在单人日程上训练的下游 10 人时只有 33%,在合并日程上训练的 92%,和一次看全部(91%)差不多。
- 运行时重规划:不监控时 98% 的天出问题;局部修补比从头重规划改动少(3.9 vs 6.8 个任务),成功率相同;修补范围要能按需扩大;早发现的价值取决于有多少可以挪动的余地。
10. 常见误区 · Common pitfalls
- “每条约束都满足了 90%,计划大致可用。” 10 条约束全部满足只有 35%;可用要求的是全部。
- “micro 一样,两个系统就一样好。” 相关性不同,macro 可以差好几倍。
- “让 LLM 多修几轮,总能修好。” 修补会卡在局部最优;问题无解时,修多少轮都不会收敛,而且它不会告诉你。
- “复杂度越高,模型越差,说明它推理能力有限。” 先检查高复杂度的题里有多少是无解的(§5.2、第 6 讲)。
- “把任务拆给多个只看最小上下文的智能体,一定更可靠。” 拆分改变了每个智能体看到的输入分布,还会让错误在调用之间传递;需要受控对比。
- “出了变故就让 LLM 重新写一份计划。” 从头重写会改动大量没受影响的安排;局部修补更稳定,而且要有独立的监控器和”已经发生的事”的记录。
- “有了求解器就不需要 LLM 了。” 求解器需要形式化的约束;把自然语言的需求、常识(“奶奶需要休息一下”)变成约束,是 LLM 擅长的事——也是新的错误来源。
11. 练习 · Exercises
练习 1(指数鸿沟)。TravelPlanner 只规划模式下常识约束的 micro 是 80.4%。(a) 在独立的假设下,micro 要到多少,macro 才能到 50%?到 90% 呢?(b) 硬约束的 micro 是 47.1%、macro 是 22.2%。如果独立,平均每个请求有几条硬约束?
参考答案:(a) ;。从 80% 到 99%,每条约束的错误率要降低约 15 倍。(b) :平均约 2 条。(TravelPlanner 的请求按难度有不同数量的硬约束;这只是一个粗略的反推。)
练习 2(析取约束)。§3.2 的家庭聚餐里,假设只有一个司机,既要接机又要接奶奶。(a) 为什么这不能直接写成 STN?(b) 怎样用两个 STN 判断它是否排得开?(c) 在不延误的情况下,你预期哪种顺序可行?
参考答案要点:(a) “同一个人不能同时做两件事”是”接奶奶在接机之前完成,或者在接机之后开始”——析取,STN 只能表达合取(所有约束同时成立)。(b) 枚举两种顺序:每种顺序加上一条普通的先后约束(例如”奶奶到家 ≤ 出发去机场”),得到两个 STN,分别检查一致性;有一个一致就排得开。k 个这样的二选一就是 个 STN——这就是资源约束让问题变难的原因,也是求解器要搜索的东西。(c) 先接奶奶:13:00 出发、14:00 到家,再出发去机场(需要 14:30 左右到机场,模型里取行李后 14:50 离开)——时间上可行。先接机:最早 15:35 到家,再去接奶奶 60 分钟、16:35 到家,也早于”开饭前 30 分钟”(17:30)。两种都可行;航班延误时,“先接奶奶”的顺序给接机留出的松弛更多。(要精确回答,需要把”从家出发去机场”的时间点加进模型。)
练习 3(修补循环的预算)。§5.3 的修补循环在 H = 7 时 300 轮修好 75%(33/44)。如果把轮数加到 1000、3000 会怎样?为什么?
参考答案(草稿目录里实际运行):33/44 → 36/44 → 36/44。增加预算最初有一点帮助,然后完全停止:min-conflicts 每一步只做”让冲突最少”的局部修改,会卡在一个局部最优——任何单个任务的移动都不能减少冲突,但冲突没有消失。经典的补救是随机重启或允许”变差”的移动(模拟退火、禁忌搜索);对 LLM 修补循环,对应的是”换一份全新的草稿重来”,或者给反馈加上”之前试过但失败的修改”(第 9 讲的记忆)。
练习 4(局部修补的范围)。local_repair 在只放开出问题的任务修不好时,会把邻居也放开、逐步扩大。如果不扩大会怎样?
参考答案(草稿目录里实际运行,“一早就知道”的设置):不扩大时成功率从 59.0% 掉到 25.5%,成功的天里平均改动 1.51 个任务(扩大时 3.88 个)。只动出问题的任务常常不够——一个任务被推迟,可能需要和同一个人的另一个任务对调顺序,而那个任务本身并没有冲突。“有界的编辑半径”的界要能按需增长;固定一个很小的半径,等于放弃很多本可以修好的情况。
练习 5(拆分的受控实验设计)。§6.2 的实验里合并智能体 100% 正确,所以拆分没有出现误差累积。设计一个实验,研究”每次调用的准确率”和”拆分的层数”之间的权衡:在什么条件下,拆分会比一次看全部更差?
参考答案要点:控制合并智能体的准确率(例如训练更少的步数,或者在它的输出上以概率 ε 随机删掉 / 加上一个时段),让拆分的成功率约为 ;对比一次看全部的准确率曲线 。拆分更差的条件是 ——ε 不够小、m 很大、或者一次看全部本来就很稳(就像本实验)。一个好的报告应该画出这两条曲线,并说明交叉点在哪里。这正是第 11 讲”误差累积”的问题。
练习 6(重规划时什么不能改)。§7 的模拟里,“已经开始的任务不能改”。在真实的 LLM 智能体里,“已经发生的事”可能包括什么?智能体怎样才能知道哪些事已经发生了?
参考答案要点:已经发出的邮件和日程邀请、已经下的订单、已经付的定金、已经告诉某人的时间、已经出发的车。智能体需要一份外部的、可靠的执行记录(ALAS 的版本化执行日志;数据库里的事务记录),而不是依赖自己上下文里的记忆——上下文会被截断、会被摘要改写、会出错。而且不可逆的动作在执行前就要谨慎(第 11 讲):一旦发出,就进入了”不能改”的集合。
12. 延伸阅读 · Further reading
基准
- J. Xie et al. TravelPlanner: A Benchmark for Real-World Planning with Language Agents. ICML 2024.
- H. S. Zheng et al. NATURAL PLAN: Benchmarking LLMs on Natural Language Planning. 2024.
- L. Geng, E. Y. Chang. REALM-Bench: A Benchmark for Evaluating Multi-Agent Systems on Real-world, Dynamic Planning and Scheduling Tasks. 2025.
LLM 与求解器
- A. Gundawar et al. Robust Planning with LLM-Modulo Framework: Case Study in Travel Planning. 2024.
- Y. Hao, Y. Chen, Y. Zhang, C. Fan. Large Language Models Can Solve Real-World Planning Rigorously with Formal Verification Tools. NAACL 2025.
多智能体的时序规划
- E. Y. Chang. MACI: Multi-Agent Collaborative Intelligence for Adaptive Reasoning and Temporal Planning. 2025.
- L. Geng, E. Y. Chang. ALAS: Transactional and Dynamic Multi-Agent LLM Planning. 2025.
约束与时序推理
- R. Dechter, I. Meiri, J. Pearl. Temporal Constraint Networks. Artificial Intelligence, 1991.
- S. Minton et al. Minimizing Conflicts: A Heuristic Repair Method for Constraint Satisfaction and Scheduling Problems. Artificial Intelligence, 1992.
- P. Cheeseman, B. Kanefsky, W. Taylor. Where the Really Hard Problems Are. IJCAI 1991.
- M. Fox, A. Gerevini, D. Long, I. Serina. Plan Stability: Replanning versus Plan Repair. ICAPS 2006.
- S. Russell, P. Norvig. Artificial Intelligence: A Modern Approach(第 6 章,约束满足问题).
13. 下一讲预告 · Next lecture
第 11 讲:长程智能体——在环境里规划与行动。 这一讲的计划都是”先排好、再执行”。智能体不一样:它在环境里一步步行动,每一步都看到新的观察(网页、终端输出、文件),一个任务可能要几十到几百步。第 2 节的指数鸿沟在这里变成了”时间跨度”:每步 99% 正确,100 步之后只剩 37%。METR 发现前沿模型能以 50% 概率完成的任务长度每约 7 个月翻一番;τ-bench 发现同一个任务重复跑 8 次全部成功的比例,比只跑一次低得多。我们会在一个文本环境里研究:每步的可靠性和任务长度的关系、出错之后能不能恢复、检查点与回溯、不可逆的动作,以及怎样可靠地评测一个智能体。