Lecture 10 · 时序与约束规划——日程、旅行、多约束与运行时重规划(含 MACI) · Temporal & Constraint Planning

Advanced Large Language Models Research Seminar · Lecture 10。个人学习讲义与配套实验,按主题整理并持续修订。

课程源码 ZIP ↓

个人整理的学习笔记,非官方讲义;课程来源与整理说明见课程介绍。配套示例未逐一运行验证。

本篇目录

对应 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

学完这一讲,你应该能够:

  1. 说出真实规划比积木世界多了什么:时间(时长、先后、时间窗)、资源(同一时间只能做一件事)、很多条约束同时成立、执行中的变故。
  2. 解释”每条约束大概率满足”和”所有约束同时满足”之间的指数鸿沟,用它读懂 TravelPlanner 的 micro / macro 通过率,并知道为什么只报告一个数不够。
  3. 用简单时序网络(STN)精确地推理时间约束:最早 / 最晚时间、松弛、一致性;知道负环就是”哪几条约束冲突”的解释。
  4. 区分不完备的”草稿 + 逐条修补”(LLM-Modulo 式)和完备的求解器:谁能找到解、谁能证明无解、谁能解释无解。
  5. 复述 MACI 的设计主张(元规划器、依赖图、规划与验证分开、最小上下文、运行时监控),并用受控实验检验”最小上下文”这一条:它在什么条件下成立、代价是什么。
  6. 在运行时重规划中权衡”从头重规划”和”局部修补”(计划稳定性),理解监控器发现变故的早晚意味着什么。

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 讲的积木世界只有一种约束:动作的前提(要搬的积木必须在最上面)。真实的规划问题多了四样东西:

  1. 时间:动作有时长(火鸡要烤 4 小时),有先后(先接到人才能开饭),有时间窗(航班 14:30 落地、18:00 开饭),有截止时间。
  2. 资源:一个人同一时间只能在一个地方,一个烤箱同一时间只能烤一样东西。资源约束是”二选一”的(谁先谁后),正是它们让调度问题变成 NP 难。
  3. 很多条约束同时成立:一份旅行计划要满足预算、住宿天数、餐厅不重复、交通不冲突、用户的偏好……任何一条不满足,这份计划就不能用。
  4. 执行中的变故:航班延误、某件事比预想的久、有人临时有事。计划要在执行过程中被监控、被修改。

这一讲按这四样东西组织:§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 条全部满足的概率是 pmp^m(演示 1):

pm = 1m = 5m = 10m = 20m = 50
0.9999.0%95.1%90.4%81.8%60.5%
0.9595.0%77.4%59.9%35.8%7.7%
0.9090.0%59.0%34.9%12.2%0.5%

一个”大部分约束都满足”的计划和一个”能用”的计划之间,隔着一道指数鸿沟。这和第 9 讲世界模型的误差累积(一步准确率的 k 次方)是同一个算术,也是第 11 讲长程智能体的核心问题。

2.3 用 TravelPlanner 的数字检验

演示 2 把 TravelPlanner 公布的常识约束通过率(GPT-4-Turbo)代进 p8p^8:

设置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% 提到 0.51/8≈91.7%0.5^{1/8} \approx 91.7\%。

2.4 只报告一个数不够

约束的失败往往不独立:一份糟糕的计划常常同时违反好几条。演示 3 固定 micro = 80%、m = 8,让计划之间的”质量”有不同的离散程度:

离散程度micromacro
0(独立)79.9%16.7%
0.0580.0%22.6%
0.280.0%36.1%
0.580.1%56.1%

同样的 micro,macro 可以从 17% 到 56%。正相关让失败集中在少数糟糕的计划上,macro 更高;负相关(例如修好一条约束常常弄坏另一条——预算和舒适度就是这样)让它更低。比较两个系统时,要同时报告 micro、macro,最好还有每条约束各自的通过率。


3. 时间约束:简单时序网络 · Simple Temporal Networks

3.1 定义

简单时序网络(Simple Temporal Network,STN,Dechter, Meiri & Pearl 1991)由若干时间点和形如

lo≤tv−tu≤hi\text{lo} \le t_v - t_u \le \text{hi}

的约束组成:两个事件之间的时间差在某个区间里。时长(火鸡烤 240 分钟:240≤t出炉−t入炉≤240240 \le t_{出炉} - t_{入炉} \le 240)、先后(t开饭−t到家≥10t_{开饭} - t_{到家} \ge 10)、时间窗(t落地−tZ=870t_{落地} - t_Z = 870,即 14:30)都可以写成这种形式。

把每条约束拆成距离图里的两条边:u→vu \to v 权重 hi,v→uv \to u 权重 −lo。于是:

  • 网络一致(存在满足所有约束的时间安排)⇔ 距离图里没有负环;
  • 最短距离 d(u,v)d(u, v) 是 tv−tut_v - t_u 的最紧上界;以零点 Z 为原点,事件 v 的最晚时间是 d(Z,v)d(Z, v),最早时间是 −d(v,Z)-d(v, Z);
  • 最晚减最早就是这个事件的松弛(slack):还能推迟多少。

这些都是最短路计算(Floyd–Warshall,O(n3)O(n^3)),对几十个事件瞬间完成。

3.2 一个家庭聚餐

演示 4 的场景(灵感来自 MACI 论文里的感恩节晚餐案例,细节是本讲义自己设定的):18:00 开饭;火鸡要烤 4 小时,厨房 10:00 之后可用,出炉后静置 15 分钟;配菜 90 分钟,14:00 之后才能开始;航班 14:30 落地,取行李 20 分钟、开车 45 分钟,到家后至少 10 分钟再开饭;奶奶 13:00 之后才准备好,接她往返 60 分钟,开饭前 30 分钟到家。

事件最早最晚松弛
火鸡入炉10:0013:45225 分钟
配菜开始14:0016:30150 分钟
离开机场14:5017:05135 分钟
出发接奶奶13:0016:30210 分钟

“火鸡最晚 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 有解的比例:相变

H6789101214
有解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有解的题草稿就对修补(列出全部冲突)修补(只说第一条)二值反馈(整个重写)求解器
7440%75%91%0%100%
91200%92%92%2%100%
141910%99%96%7%100%

(每道题最多 300 轮。)草稿几乎从来不对;修补循环在宽松的题上几乎都能修好,紧的时候更难;列出全部冲突还是只说第一条,差别不大也不一致(H = 7 时只说第一条反而更好,44 道题的样本很小);二值反馈几乎没用——和第 7、8 讲一致,反馈至少要指出错在哪里。

练习 3 把轮数加到 1000、3000:H = 7 时从 33/44 到 36/44,然后不再提高——修补循环会卡在”局部最优”(每一步都没法再减少冲突,但冲突没有消失),预算再多也没用。

5.4 无解的题上:修补循环不会说”不可能”

H无解的题草稿的冲突数修补 300 轮后求解器:平均尝试次数其中传播直接判定
618210.23.51165
71568.32.32139
81407.11.45106

修补循环在无解的题上把冲突从 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 在多约束的时序规划上缺乏深思熟虑的推理、时间意识和一致的约束处理。它的三个组件:

  1. 元规划器(meta-planner):分析任务,识别角色(厨师、司机、监督者)和约束,构建一张依赖图——节点是角色 / 任务,边是时间、空间或资源上的依赖;加入常识,让约束更符合现实。
  2. 智能体:通用的和任务专用的智能体,按依赖图执行规划。
  3. 运行时监控器:在执行中监视偏离,必要时激活应急智能体修改依赖、重新分配角色、调整约束,并把更新通知受影响的智能体。

论文主张的几条设计原则:把规划和验证分开(模型能发现别人计划里的错误,却常常发现不了自己的——第 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)
299%100%93%100%
496%100%73%98%
692%100%49%95%
892%90%38%94%
1091%80%33%92%

(合并智能体在所有 m 上都 100% 正确。)四个发现:

  1. “一次看全部”比预想的稳:从 99% 缓慢降到 91%,6–10 人都没在训练中见过。“这个时段有没有人忙”是一个与位置无关的查找,人多了只是查找范围变大。所以”上下文越长越糟”不是普遍规律——取决于任务需要模型在上下文里做什么(第 6 讲的多跳查找被干扰陈述严重破坏,这里不会)。
  2. 拆开、但下游没见过上游的输出:反而最差(10 人时 33%)。原因(演示 2):单个人的日程平均 7.7 个忙碌时段,10 个人合并后平均 14.8 个(一共只有 16 个)。按忙碌时段数分组,gap1 在 ≤ 8 个时 98–100%,≥ 12 个时只有 46%。拆分改变了下游看到的分布:每个智能体”只看最小的上下文”,但这份上下文是上游写的,不是它的训练数据。
  3. 让下游在”上游会交给它的东西”上训练,拆分就和一次看全部一样好(gapU:100% / 95% / 92%),代价是 m 次调用。
  4. 思维链在训练范围内最好、超出之后最先崩(10 人时 80%)。我原以为它败在先写的”合并后的日程”变长写错了;演示 3 说明不是:10 人时并集写对了 95%,但写对之后答案只对 80%——错在最后一步,在一份很满的日程里找空档(训练时的并集平均最多约 12 个忙碌时段)。思维链和 gap1 栽在同一个地方:中间结果落在训练分布之外。

对 MACI 式设计的启示:“每个智能体只看最小上下文”是一个合理的工程原则,但它不是免费的:(1) 一次调用变成多次,上游的错误会传给下游(这里合并智能体恰好不出错,所以没有累积;第 11 讲会看到累积的后果);(2) 下游的输入分布由上游决定,要在那个分布上训练和测试。要证明拆分有帮助,需要和”一次看全部”做受控的对比——本实验就是这样一个对比的模板。


7. 运行时重规划 · Runtime replanning

代码:03_runtime_replanning.py(只用标准库,约 1 秒)。

7.1 问题

计划很少按计划执行。运行时重规划要回答三个问题:

  1. 监控:谁、什么时候发现计划已经不成立了?
  2. 重规划的范围:从头重新规划,还是只修补受影响的部分?
  3. 什么不能改:已经发生的事不能撤销(已经出发的车、已经放进烤箱的火鸡)。

经典规划里,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.4012
到时才发现局部修补55.0%3.636
提前 4 个时段从头重规划54.0%6.2612
提前 4 个时段局部修补55.5%3.675
一早就知道从头重规划57.5%6.8416
一早就知道偏好原计划58.5%4.6215
一早就知道局部修补59.0%3.889

(“偏好原计划”= 完整地重新求解,但每个任务先试原来的安排;“局部修补”= 只放开出问题的任务,修不好再把有先后关系或可能共用一个人的邻居也放开,逐步扩大——ALAS 式的有界编辑半径。)

三个发现:

  1. 局部修补改动得少,成功率几乎一样:一早就知道时,从头重规划平均改动 6.84 个任务(共 12 个),局部修补 3.88 个。演示 3 的一个例子:任务 B 最早只能推迟 3 个时段开始,从头重规划改动了 8 个任务,局部修补只把 B 和同一个人的 G 对调了顺序。
  2. 局部修补要能”扩大”:练习 4 去掉了”修不好就扩大”这一步(只放开出问题的任务),成功率从 59.0% 掉到 25.5%。最小的改动常常不够;关键是改动的范围要按需增长,而不是固定。
  3. 早发现的好处在这里不大:从头重规划在”到时才发现”时 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 智能体里刚刚开始被系统地研究;经典规划的计划稳定性、计划修补文献是现成的起点。

研究问题:

  1. “最小上下文”在什么任务上有帮助、在什么任务上没有?能否预测——例如根据任务需要的是”全局查找”还是”多跳推理”?
  2. 拆分之后,下游智能体的输入分布由上游决定。怎样在不重新训练的情况下(例如只用提示)让下游适应上游的输出分布?
  3. LLM 把自然语言翻译成约束时出的错,怎样在交给求解器之前发现?(回译、多次翻译的一致性、在小例子上的测试?)
  4. 对无解的请求,怎样选择对用户代价最小的放松方案?冲突核告诉你哪些约束冲突,但用户更愿意放松哪一条,需要偏好模型。

9. 小结 · Summary

  1. 真实规划比积木世界多了时间、资源、很多条约束、执行中的变故。
  2. 每条约束独立地以 p 满足,m 条全部满足是 pmp^m:TravelPlanner 的常识约束 micro 80.4%、0.804⁸ ≈ 17.5%,公布的 macro 17.2%。同样的 micro,相关性不同,macro 可以从 17% 到 56%——要同时报告 micro、macro 和每条约束的通过率。
  3. 简单时序网络精确地推理时间:最早 / 最晚时间、松弛都是最短路;排不开时,负环就是”哪几条约束冲突、差多少”的解释。资源约束是析取的,需要搜索。
  4. LLM + 求解器的两条路线:LLM-Modulo(LLM 写、批评者查,GPT-4-Turbo 提高到 4.6 倍)和 LLM 翻译 + SMT(93.9%,并能解释无解)。
  5. 修补循环在有解的题上表现不错,但会卡在局部最优,而且不会说”不可能”——在无解的题上交出仍有冲突的计划;完备的求解器每道都能证明无解,并给出冲突核。
  6. MACI 的”最小上下文”不是免费的:拆分改变了下游看到的分布;在单人日程上训练的下游 10 人时只有 33%,在合并日程上训练的 92%,和一次看全部(91%)差不多。
  7. 运行时重规划:不监控时 98% 的天出问题;局部修补比从头重规划改动少(3.9 vs 6.8 个任务),成功率相同;修补范围要能按需扩大;早发现的价值取决于有多少可以挪动的余地。

10. 常见误区 · Common pitfalls

  1. “每条约束都满足了 90%,计划大致可用。” 10 条约束全部满足只有 35%;可用要求的是全部。
  2. “micro 一样,两个系统就一样好。” 相关性不同,macro 可以差好几倍。
  3. “让 LLM 多修几轮,总能修好。” 修补会卡在局部最优;问题无解时,修多少轮都不会收敛,而且它不会告诉你。
  4. “复杂度越高,模型越差,说明它推理能力有限。” 先检查高复杂度的题里有多少是无解的(§5.2、第 6 讲)。
  5. “把任务拆给多个只看最小上下文的智能体,一定更可靠。” 拆分改变了每个智能体看到的输入分布,还会让错误在调用之间传递;需要受控对比。
  6. “出了变故就让 LLM 重新写一份计划。” 从头重写会改动大量没受影响的安排;局部修补更稳定,而且要有独立的监控器和”已经发生的事”的记录。
  7. “有了求解器就不需要 LLM 了。” 求解器需要形式化的约束;把自然语言的需求、常识(“奶奶需要休息一下”)变成约束,是 LLM 擅长的事——也是新的错误来源。

11. 练习 · Exercises

练习 1(指数鸿沟)。TravelPlanner 只规划模式下常识约束的 micro 是 80.4%。(a) 在独立的假设下,micro 要到多少,macro 才能到 50%?到 90% 呢?(b) 硬约束的 micro 是 47.1%、macro 是 22.2%。如果独立,平均每个请求有几条硬约束?

参考答案:(a) 0.51/8≈91.7%0.5^{1/8} \approx 91.7\%;0.91/8≈98.7%0.9^{1/8} \approx 98.7\%。从 80% 到 99%,每条约束的错误率要降低约 15 倍。(b) ln⁡0.222/ln⁡0.471≈(−1.505)/(−0.753)≈2.0\ln 0.222 / \ln 0.471 \approx (-1.505)/(-0.753) \approx 2.0:平均约 2 条。(TravelPlanner 的请求按难度有不同数量的硬约束;这只是一个粗略的反推。)

练习 2(析取约束)。§3.2 的家庭聚餐里,假设只有一个司机,既要接机又要接奶奶。(a) 为什么这不能直接写成 STN?(b) 怎样用两个 STN 判断它是否排得开?(c) 在不延误的情况下,你预期哪种顺序可行?

参考答案要点:(a) “同一个人不能同时做两件事”是”接奶奶在接机之前完成,或者在接机之后开始”——析取,STN 只能表达合取(所有约束同时成立)。(b) 枚举两种顺序:每种顺序加上一条普通的先后约束(例如”奶奶到家 ≤ 出发去机场”),得到两个 STN,分别检查一致性;有一个一致就排得开。k 个这样的二选一就是 2k2^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% 正确,所以拆分没有出现误差累积。设计一个实验,研究”每次调用的准确率”和”拆分的层数”之间的权衡:在什么条件下,拆分会比一次看全部更差?

参考答案要点:控制合并智能体的准确率(例如训练更少的步数,或者在它的输出上以概率 ε 随机删掉 / 加上一个时段),让拆分的成功率约为 (1−ε)m−1⋅pgap(1-\varepsilon)^{m-1} \cdot p_{\text{gap}};对比一次看全部的准确率曲线 pall(m)p_{\text{all}}(m)。拆分更差的条件是 (1−ε)m−1pgap<pall(m)(1-\varepsilon)^{m-1} p_{\text{gap}} < p_{\text{all}}(m)——ε 不够小、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 次全部成功的比例,比只跑一次低得多。我们会在一个文本环境里研究:每步的可靠性和任务长度的关系、出错之后能不能恢复、检查点与回溯、不可逆的动作,以及怎样可靠地评测一个智能体。

← 返回课程目录