计划赶不上变化,这句话在项目管理里几乎是公理。一个在启动会上被所有人认可的甘特图,往往在项目进行到 30% 的时候就已经面目全非。任务延期、需求插入、人员变动、外部依赖未就绪------每一类变更都可能引发连锁反应,影响远比直觉判断的要深。
传统的应对方式是 PM 人工重排甘特图,这个过程既耗时又高度依赖个人经验。AI Agent 在这里能做的,不是替 PM 做决策,而是把变更的影响链路快速算清楚,让 PM 用更少的时间做出更有据可查的判断。
一、甘特计划变更的四类场景
要设计 Agent 的动态响应逻辑,首先需要对变更场景做一个清晰的分类。不同类型的变更,影响传播的方向和烈度完全不同。
场景一:任务延期。某个任务的完成时间晚于计划。影响方向:沿依赖链向下传播,所有后置任务的最早开始时间可能都需要后移。
场景二:新任务插入。在已有计划中间插入一个新任务。影响方向:新任务抢占资源,且如果它处于关键路径上,下游任务全部受影响。
场景三:资源变动。某个执行者的可用工时发生变化(请假、调岗、离职)。影响方向:该执行者名下的所有未完成任务都需要重新评估可行性。
场景四:里程碑时间调整。客户要求提前或推迟某个里程碑节点。影响方向:需要反向从里程碑往前推,判断哪些任务需要压缩工期或并行执行。
Agent 的动态响应,需要针对这四类场景设计不同的影响传播算法,而不是用一套通用逻辑硬套。
二、关键路径的动态维护
所有变更响应的核心计算,都依赖一个实时准确的关键路径。关键路径(Critical Path)是决定项目最早完成时间的那条任务链,任何关键路径上的延迟都会直接推迟项目终点。
工程上,关键路径不能只在项目启动时计算一次,而必须随着每次变更实时重算。一个轻量但有效的实现:
python
import networkx as nx
from datetime import timedelta
class CriticalPathCalculator:
def __init__(self, tasks: list):
self.graph = self._build_dag(tasks)
def _build_dag(self, tasks: list) -> nx.DiGraph:
G = nx.DiGraph()
for task in tasks:
G.add_node(task.id, duration=task.estimated_days,
earliest_start=None, latest_start=None)
for dep in task.dependencies:
G.add_edge(dep, task.id)
return G
def calculate(self) -> dict:
# 前向遍历:计算最早开始时间(ES)
for node in nx.topological_sort(self.graph):
preds = list(self.graph.predecessors(node))
if not preds:
self.graph.nodes[node]['es'] = 0
else:
self.graph.nodes[node]['es'] = max(
self.graph.nodes[p]['es'] + self.graph.nodes[p]['duration']
for p in preds
)
project_duration = max(
self.graph.nodes[n]['es'] + self.graph.nodes[n]['duration']
for n in self.graph.nodes
)
# 后向遍历:计算最晚开始时间(LS)
for node in reversed(list(nx.topological_sort(self.graph))):
succs = list(self.graph.successors(node))
if not succs:
self.graph.nodes[node]['ls'] = project_duration - self.graph.nodes[node]['duration']
else:
self.graph.nodes[node]['ls'] = min(
self.graph.nodes[s]['ls'] for s in succs
) - self.graph.nodes[node]['duration']
# 浮动时间为0的节点即为关键路径节点
critical_path = [
n for n in self.graph.nodes
if self.graph.nodes[n]['ls'] - self.graph.nodes[n]['es'] == 0
]
return {"critical_path": critical_path, "project_duration": project_duration}
def recalculate_after_change(self, changed_task_id: str, new_duration: int):
self.graph.nodes[changed_task_id]['duration'] = new_duration
return self.calculate()
每次变更发生时,Agent 调用 recalculate_after_change,得到新的关键路径和项目总工期,再把这两个结果作为上下文传给 LLM 做影响分析。
三、影响链路的自动推算
关键路径之外,Agent 还需要计算"这次变更具体影响了哪些任务、影响幅度各是多少"。这个推算逻辑按变更类型不同而不同:
3.1 任务延期的影响推算
python
def propagate_delay(graph: nx.DiGraph, task_id: str, delay_days: int) -> list:
"""
从变更任务出发,沿依赖边向下传播延迟影响
返回受影响的任务列表,按影响程度排序
"""
affected = []
# BFS 遍历所有下游节点
queue = [(task_id, delay_days)]
visited = set()
while queue:
current_id, current_delay = queue.pop(0)
if current_id in visited:
continue
visited.add(current_id)
for successor in graph.successors(current_id):
node_data = graph.nodes[successor]
# 只有当延迟超过后继任务的浮动时间时,才会实际影响
float_time = node_data['ls'] - node_data['es']
actual_impact = max(0, current_delay - float_time)
if actual_impact > 0:
affected.append({
"task_id": successor,
"delay_impact_days": actual_impact,
"is_critical": float_time == 0
})
queue.append((successor, actual_impact))
return sorted(affected, key=lambda x: x['delay_impact_days'], reverse=True)
得到影响列表之后,Agent 将其格式化为结构化的上下文,传给 LLM 生成自然语言的影响摘要和应对建议。
3.2 资源变动的影响推算
资源变动的影响推算稍微复杂一些,需要知道被影响执行者承担的任务、这些任务的当前进度,以及其他人是否有能力接手:
python
def assess_resource_change(person_id: str, available_days_change: int,
tasks: list, team_capacity: dict) -> dict:
person_tasks = [t for t in tasks if t.owner == person_id
and t.status != "DONE"]
total_remaining_days = sum(t.remaining_days for t in person_tasks)
current_capacity = team_capacity.get(person_id, 0)
new_capacity = current_capacity + available_days_change
if new_capacity >= total_remaining_days:
return {"impact": "LOW", "detail": "容量变化未超出剩余工作量"}
shortfall = total_remaining_days - new_capacity
transferable_tasks = [t for t in person_tasks
if not t.requires_specific_skill]
return {
"impact": "HIGH" if shortfall > 5 else "MEDIUM",
"shortfall_days": shortfall,
"affected_tasks": [t.id for t in person_tasks],
"transferable_tasks": [t.id for t in transferable_tasks],
"suggested_actions": ["考虑将可转交任务重新分配", "评估是否需要外部资源补充"]
}
四、Agent 响应的时机控制
不是每次甘特图变更都需要 Agent 立即介入。如果任务A延期半天但它有足够的浮动时间,Agent 的介入反而是噪声。
一个合理的介入门槛:
-
变更影响到关键路径 → 立即响应
-
变更导致里程碑时间推迟 → 立即响应,附带里程碑影响摘要
-
变更影响超过 3 个下游任务 → 响应
-
变更仅影响非关键路径任务且延迟 < 2 天 → 记录但不主动推送
这些阈值应该可以按项目类型和 PM 偏好进行配置,不能写死在代码里。
五、计划重排建议的生成
在分析完影响之后,Agent 还可以进一步生成计划重排的建议。这里 LLM 的作用是把结构化的计算结果转化为可读的建议,而不是替代调度算法本身做计算。
一个典型的 prompt 结构:
plaintext
你是一个项目管理顾问。以下是当前项目的变更情况和影响分析:
变更:[变更描述]
受影响任务:[影响列表]
当前关键路径:[关键路径]
资源状况:[资源摘要]
请基于以上信息,给出 2-3 个可行的计划调整建议。
每个建议需要说明:
1. 具体操作(调整哪些任务的排期或资源)
2. 预期效果(能否挽回延期,代价是什么)
3. 主要风险(这个方案可能带来的新问题)
不要凭空假设资源,只使用上述已知信息。
这个 prompt 的关键约束是"不要凭空假设资源"------LLM 容易在建议里虚构不存在的人力或时间余量,必须通过 prompt 明确禁止。
六、工程落地要点
甘特变更响应的工程落地,有几个容易被忽视的前置条件:
任务依赖关系的完整录入:如果任务依赖关系在系统里是残缺的,关键路径计算就是错误的,Agent 的所有下游分析都没有意义。这是数据质量的问题,比算法问题更根本。
变更的原子性:一次人工操作可能同时触发多个任务变更,Agent 需要把这些变更作为一个整体来分析影响,而不是逐条独立响应,否则会产生重复或矛盾的分析结论。
历史基线的保留:Agent 在分析影响时,需要对比"当前状态"和"变更前的基线"。这要求系统支持快照功能,能随时回溯到变更发生之前的计划状态。Bizfocus ADP 等国产项目管理平台的基线与版本管理功能,正是为这类需求提供的底层数据支撑,使得 Agent 有可靠的比对基准可用。
七、小结
甘特计划变更场景的 AI Agent 响应,本质上是一个计算密集 + 语言生成的两阶段任务。计算部分------关键路径、影响传播、资源缺口------应该用确定性算法来做,保证结果精确可复现;语言生成部分------影响摘要、调整建议------则是 LLM 真正发挥价值的地方。把这两个阶段清晰地分开,是这个场景工程落地成功的关键。