高级规划策略【选修】
本节定位
上一节的 Plan-and-Execute 已经把长任务拆成了顺序步骤。
但真实复杂任务往往不是一条直线,而更像一张图:
- 有些步骤必须先做
- 有些步骤可以并行
- 有些步骤失败后要回滚或重规划
所以这节会再往前走一步:
高级规划不是把清单写得更长,而是把任务关系建成图。
学习目标
- 理解为什么复杂任务需要依赖图,而不只是线性步骤
- 理解并行、关键路径、资源限制在规划中的作用
- 通过可运行示例看懂一个最小 DAG 调度器
- 理解高级规划和普通 Plan-and-Execute 的差别
一、为什么线性计划有时不够?
1.1 因为现实任务里很多步骤并不是“先 A 再 B 再 C”
例如做一份调研报告时,
你可能需要:
- 收集产品资料
- 收集用户反馈
- 读取历史数据
这些步骤并不一定要严格串行。
如果硬写成直线,
计划会显得:
- 冗长
- 低效
- 难以表达真实依赖
1.2 高级规划最核心的问题
不是“列多少步骤”,
而是:
- 哪些步骤依赖哪些前置条件
- 哪些可以并行
- 哪些是关键路径
也就是说,高级规划的对象更像:
- 任务图
1.3 一个类比:施工图而不是办事清单
普通计划像待办清单。
高级规划更像施工图:
- 哪 些工序能同时开工
- 哪些工序必须等验收
- 哪些工序拖慢会影响全局
二、高级规划里最常见的三个概念
2.1 依赖关系
如果任务 B 必须等待任务 A 产出结果,
那就有:
A -> B
例如:
- 先抓取数据,再清洗数据
- 先完成统计,再写报告
2.2 并行性
如果两个任务互不依赖,
它们理论上可以同时做。
这意味着:
- 总耗时可能缩短
- 但调度会更复杂
2.3 关键路径
关键路径指的是:
- 决定总耗时的那条最长依赖链
很多任务不是所有步骤都同样重要。
真正拖慢整体进度的,往往是关键路径上的节点。
三、先跑一个真正的 DAG 调度示例
下面这段代码会做一件很有代表性的事:
- 给定任务依赖和持续时间
- 在 2 个 worker 限制下做调度
- 输出每个时间点在跑什么
这会帮助你建立高级规划最重要的直觉:
- 计划不只是顺序,还是资源和依赖的组合
tasks = {
"collect_policy_docs": {"deps": [], "duration": 2},
"collect_user_cases": {"deps": [], "duration": 3},
"summarize_policy": {"deps": ["collect_policy_docs"], "duration": 2},
"analyze_cases": {"deps": ["collect_user_cases"], "duration": 2},
"draft_report": {"deps": ["summarize_policy", "analyze_cases"], "duration": 2},
}
def schedule(task_graph, workers=2):
completed = set()
running = []
timeline = []
time = 0
while len(completed) < len(task_graph):
# 先完成这一时刻结束的任务
just_finished = [task for task, end_time in running if end_time == time]
if just_finished:
for task in just_finished:
completed.add(task)
running = [(task, end_time) for task, end_time in running if end_time != time]
# 找出当前可执行任务
available = []
for task, meta in task_graph.items():
if task in completed:
continue
if any(task == running_task for running_task, _ in running):
continue
if all(dep in completed for dep in meta["deps"]):
available.append(task)
# 分配空闲 worker
free_slots = workers - len(running)
for task in available[:free_slots]:
end_time = time + task_graph[task]["duration"]
running.append((task, end_time))
timeline.append(
{
"time": time,
"running": [task for task, _ in running],
"completed": sorted(completed),
}
)
if len(completed) == len(task_graph):
break
time += 1
return timeline
timeline = schedule(tasks, workers=2)
for item in timeline:
print(item)
3.1 这段代码最该看什么?
重点不是细节语法,
而是这三件事:
- 任务不是线性列表,而是
deps图 - 只有依赖满足的任务才能进入
available - worker 数量会限制并发度
这三件事合在一起,
就是高级规划最核心的现实约束。