AI Agent 任务规划的 DAG 设计:从理论到工程实践
当 LLM 学会了”思考”,谁来教它”编排”?
答案是:DAG(有向无环图)。
引言:为什么 Agent 需要任务规划
大语言模型让 AI 具备了”单步推理”的能力——给它一个问题,它能给出回答。但现实世界的任务从来不是单步的:
- 写一篇技术报告:调研 → 大纲 → 撰写 → 审校 → 发布
- 部署一个服务:编译 → 测试 → 打包 → 部署 → 验证
- 处理一个客户工单:分类 → 检索历史 → 生成方案 → 确认 → 执行
这些任务有一个共同特征:步骤之间存在依赖关系,某些步骤可以并行,某些必须串行,某些步骤的输出是另一些步骤的输入。
这正是 DAG(Directed Acyclic Graph,有向无环图)的天然领地。
本文将从理论到工程,系统性地分析 AI Agent 任务规划的 DAG 设计——为什么选 DAG、DAG 的数学模型、核心算法、与 LLM 的集成模式、工业级实现方案,以及前沿的动态 DAG 演化。
一、DAG 的数学基础与表达力
1.1 什么是 DAG
DAG(有向无环图)是一个满足以下两个条件的有向图:
- 有向性:每条边有明确的方向(从 A 到 B,而非 A-B)
- 无环性:不存在从某个节点出发沿着有向边能回到自身的路径
1 | [A] A: 获取数据 |
无环性的重要性:如果存在环(A→B→C→A),系统就会陷入死锁——A 等 B 完成,B 等 C 完成,C 等 A 完成,谁也动不了。
1.2 DAG 的形式化定义
一个任务 DAG 定义为四元组:
$$G = (V, E, w, d)$$
其中:
- $V = {v_1, v_2, …, v_n}$:任务节点集合
- $E \subseteq V \times V$:有向边集合,表示依赖关系
- $w: V \rightarrow \mathbb{R}^+$:节点权重函数(估计执行时间)
- $d: E \rightarrow D$:边上的数据传递描述
关键约束:
- 无环性:$\nexists$ 路径 $v_i \xrightarrow{+} v_i$
- 依赖完备:$\forall v_i \in V$,如果 $v_i$ 有前驱,则所有前驱完成才能执行 $v_i$
- 数据一致性:$v_i$ 的输入数据类型与所有前驱 $(v_j, v_i) \in E$ 的输出数据类型匹配
1.3 DAG vs 其他任务表达模型
| 模型 | 并行表达 | 条件分支 | 循环 | 动态性 | 适用场景 |
|---|---|---|---|---|---|
| 线性链 (Chain) | ❌ | ❌ | ❌ | ❌ | 简单管道 |
| 状态机 (FSM) | ❌ | ✅ | ✅ | 部分 | 游戏AI、对话系统 |
| 行为树 (BT) | ✅(并行节点) | ✅ | ✅ | 部分 | 机器人控制 |
| Petri 网 | ✅ | ✅ | ✅ | ✅ | 并发系统建模 |
| DAG | ✅ | ✅(条件边) | ❌(本质无环) | ✅(动态构建) | 任务编排 |
| 工作流 (BPMN) | ✅ | ✅ | ✅ | ✅ | 业务流程 |
DAG 的核心优势:
- 天然并行:无依赖的节点可以立即并行执行
- 拓扑排序:有明确的执行顺序保证
- 可组合:子 DAG 可以作为大 DAG 的节点
- 可验证:环检测、依赖完备性都是多项式时间可解
DAG 的局限:
- 无法原生表达循环:迭代/重试需要外层控制
- 静态结构:运行前必须确定完整的图结构(但可通过动态 DAG 缓解)
二、Agent 任务规划的核心问题
2.1 从自然语言到 DAG:任务分解
这是 Agent 任务规划的核心挑战——将用户的一句话转化为一个可执行的 DAG。
问题定义:
给定自然语言任务描述 $T$,生成任务 DAG $G = (V, E, w, d)$,使得执行 $G$ 的结果满足 $T$ 的要求。
子问题拆解:
- 任务识别:$T$ 包含哪些原子任务?($V$ 的确定)
- 依赖推断:哪些任务必须先于哪些任务?($E$ 的确定)
- 资源估算:每个任务需要多少时间/资源?($w$ 的确定)
- 数据流设计:任务之间传递什么数据?($d$ 的确定)
2.2 任务粒度问题
DAG 设计中最关键的决策之一是粒度选择——每个节点应该代表多”大”的任务?
1 | 粒度过粗: 粒度过细: |
粒度选择原则:
| 原则 | 描述 | 示例 |
|---|---|---|
| 独立性 | 节点应该有明确的输入/输出,不依赖内部状态 | “获取用户数据” 是好的节点,”处理一半数据” 不是 |
| 可重试 | 节点失败后可以独立重试,不需要从头开始 | API 调用、文件写入 |
| 可并行 | 不同节点可以分配给不同的执行器 | 数据获取可以并行 |
| 有意义 | 节点对应一个人类可以理解的逻辑步骤 | 而非”调用第3行代码” |
经验法则:一个 DAG 节点应该对应”一个 API 调用”或”一次 LLM 推理”或”一个确定性的数据处理步骤”。
2.3 依赖类型与建模
DAG 中的依赖不只是简单的”A 完成才能做 B”。实际场景中的依赖类型更丰富:
| 依赖类型 | 含义 | DAG 表达 | 示例 |
|---|---|---|---|
| 硬依赖 | A 必须成功完成后 B 才能开始 | 有向边 A→B | 编译 → 测试 |
| 软依赖 | A 完成后 B 可以开始,但 B 不一定需要 A 的输出 | 有向边(可选标记) | 建议参考 → 生成方案 |
| 条件依赖 | A 的结果决定 B 是否执行 | 条件边 | 检查 → [如果失败] → 修复 |
| 数据依赖 | B 需要 A 的输出作为输入 | 有向边 + 数据标注 | 查询DB → 格式化结果 |
| 资源依赖 | A 和 B 不能同时使用同一资源 | 互斥约束(DAG 外) | 写同一文件 |
条件依赖的 DAG 建模:
条件依赖是最复杂的——它意味着 DAG 的结构在运行时才能确定。
1 | [检查输入] |
实现方案有两种:
- 静态 DAG + 条件边:运行前确定完整的图,条件边标记执行谓词
- 动态 DAG:运行时根据中间结果动态添加/删除节点和边
三、DAG 调度算法深度分析
3.1 拓扑排序与执行顺序
DAG 的执行顺序由拓扑排序(Topological Sort)确定。一个 DAG 可能有多种合法的拓扑排序,选择哪一种直接影响执行效率。
Kahn 算法(BFS 式拓扑排序):
1 | def topological_sort_kahn(graph): |
关键洞察:Kahn 算法天然揭示了最大并行度——同一时刻所有入度为 0 的节点都可以并行执行。
3.2 关键路径分析
关键路径(Critical Path)是 DAG 中最长的路径,决定了任务的最短完成时间(无并行约束下)。
$$CP(G) = \max_{p \in \text{paths}(G)} \sum_{v \in p} w(v)$$
1 | def critical_path(graph, weights): |
对 Agent 调度的意义:
- 关键路径上的任务应分配最高优先级和最多资源
- 非关键路径上的任务有”浮动时间”(slack),可以延迟而不影响总完成时间
- 优化关键路径上的任务是最有效的性能提升手段
3.3 并行调度策略
3.3.1 最小完成时间调度
目标:最小化 DAG 的总完成时间(makespan)。
这是一个 NP-hard 问题(等价于带依赖约束的作业车间调度),但有多种近似算法:
HEFT 算法(Heterogeneous Earliest Finish Time):
1 | def heft_schedule(graph, weights, processors): |
3.3.2 Agent 场景下的调度策略
Agent 任务调度与传统的 HPC 调度有本质区别:
| 维度 | HPC 调度 | Agent 调度 |
|---|---|---|
| 任务执行时间 | 可预测(秒级) | 不可预测(LLM 调用 1-30 秒) |
| 任务失败率 | 极低 | 较高(LLM 幻觉、API 故障) |
| 资源异构 | CPU/GPU | LLM/API/本地工具 |
| 优先级 | 固定 | 动态(用户反馈可能改变优先级) |
| 数据传递 | 文件/消息 | Token 上下文/JSON |
Agent 适配的调度策略:
1 | class AgentDAGScheduler: |
四、LLM 驱动的 DAG 构建
4.1 从自然语言到 DAG 的转换
这是 Agent 任务规划最具挑战性的环节——让 LLM 理解任务并生成结构化的 DAG。
4.1.1 单步生成 vs 渐进生成
单步生成:直接让 LLM 输出完整的 DAG
1 | SINGLE_STEP_PROMPT = """ |
渐进生成:先分解为子任务,再逐步细化依赖
1 | PROGRESSIVE_PROMPTS = [ |
渐进生成的优势:
| 维度 | 单步生成 | 渐进生成 |
|---|---|---|
| 准确性 | 低(复杂任务容易遗漏) | 高(逐步验证) |
| 可控性 | 低 | 高(每步可人工干预) |
| 成本 | 低(1 次 LLM 调用) | 高(4+ 次 LLM 调用) |
| 复杂度 | 简单 | 需要编排逻辑 |
| 适用场景 | 简单任务(< 5 步) | 复杂任务(5+ 步) |
4.1.2 DAG 验证与修正
LLM 生成的 DAG 不一定合法,需要验证和修正:
1 | class DAGValidator: |
4.2 动态 DAG:运行时演化
静态 DAG 要求执行前确定完整的图结构,但 Agent 面对的任务往往需要运行时动态调整:
- 某个步骤的结果决定了后续步骤的数量(如:查询返回 N 条记录,每条需要处理)
- 某个步骤的失败需要插入修复步骤
- 用户中途修改了需求
动态 DAG 的三种实现模式:
模式一:条件边
1 | class ConditionalEdge: |
模式二:扇出/扇入(Map-Reduce)
1 | class MapReduceNode: |
模式三:自适应 DAG(最灵活)
1 | class AdaptiveDAG: |
4.3 Plan-then-Execute vs ReAct
当前 Agent 的两种主流执行模式与 DAG 有不同的关系:
Plan-then-Execute(先规划后执行):
1 | 用户请求 → LLM 生成 DAG → 调度器执行 DAG → 返回结果 |
- 优势:全局最优规划,可并行,可预估时间
- 劣势:规划可能与实际不符,无法灵活应对意外
ReAct(推理-行动交替):
1 | 用户请求 → [思考 → 行动 → 观察] 循环 → 返回结果 |
- 优势:灵活,可实时调整
- 劣势:线性执行,无法并行,容易陷入局部最优
DAG 增强的混合模式:
1 | 用户请求 → LLM 生成初始 DAG → 执行 DAG(支持并行) |
1 | class HybridPlanner: |
关键洞察:DAG 提供了结构化的并行能力,ReAct 提供了灵活的异常处理。两者结合,既有全局规划的高效,又有局部应变的灵活。
五、DAG 设计模式
5.1 线性管道(Pipeline)
最简单的 DAG——一条线性链。
1 | [A] → [B] → [C] → [D] |
适用:步骤间严格串行,无并行可能。
Agent 示例:文本处理管道
- 接收文本 → 分句 → 翻译 → 校对 → 返回
5.2 扇出-聚合(Fan-out / MapReduce)
1 | [A] |
适用:一个数据源需要多种并行处理,结果需要合并。
Agent 示例:多源调研
- 确定主题 → [搜索论文 / 搜索新闻 / 搜索GitHub] → 整合报告
5.3 钻石依赖(Diamond)
1 | [A] |
适用:两个独立任务都需要同一输入,且都需要完成才能继续。
Agent 示例:代码部署
- 拉取代码 → [单元测试 / 代码扫描] → 合并报告 → 部署
5.4 条件分支(Conditional)
1 | [A] |
适用:根据中间结果走不同分支。
Agent 示例:客服处理
- 分类工单 → [技术问题 → 技术支持 / 账单问题 → 财务处理] → 发送回复
5.5 递归子图(SubDAG)
1 | [外层DAG] |
适用:复杂任务的层次化组织。子 DAG 封装了内部细节,对外只暴露输入输出。
Agent 示例:研究报告生成
- 主 DAG:大纲 → [子DAG: 各章节撰写] → 整合 → 审校
- 每个章节的子 DAG:收集素材 → 撰写初稿 → 自审 → 定稿
5.6 动态扇出(Dynamic Fan-out)
1 | [A: 查询] → ??? → [B: 聚合] |
适用:子任务数量在运行时才确定。
Agent 示例:批量邮件处理
- 获取邮件列表 → [处理邮件1 / 处理邮件2 / … / 处理邮件N] → 汇总
5.7 模式选择决策树
1 | 任务是否有并行步骤? |
六、工业级 DAG 引擎分析
6.1 主流 DAG 引擎对比
| 引擎 | 领域 | DAG 定义方式 | 动态性 | 容错 | 生态 |
|---|---|---|---|---|---|
| Apache Airflow | 数据工程 | Python 代码 | 低 | 重试 + 回填 | 极丰富 |
| Prefect | 数据工程 | Python + API | 中 | 自动重试 | 中等 |
| Dagster | 数据工程 | Python + 类型系统 | 中 | 级别化容错 | 中等 |
| Temporal | 微服务编排 | 代码 + 状态机 | 高 | 持久化执行 | 中等 |
| Argo Workflows | Kubernetes | YAML | 中 | 重试 + 继续 | K8s 生态 |
| LangGraph | AI Agent | Python + 图 | 高 | 检查点 | LLM 生态 |
| CrewAI | AI Agent | Python + 角色 | 中 | 有限 | LLM 生态 |
| AutoGen | AI Agent | 代码 + 对话 | 高 | 有限 | LLM 生态 |
6.2 Airflow 的 DAG 模型
Airflow 是最成熟的 DAG 引擎,其核心抽象值得深入分析:
1 | from airflow import DAG |
Airflow 的核心设计理念:
- DAG 即代码:用 Python 代码定义,可版本控制
- 静态优先:DAG 结构在解析时确定,运行时不可变
- 重试与回填:失败任务自动重试,支持历史回填
- 传感器(Sensor):等待外部条件的特殊节点
对 Agent DAG 的启示:
- “DAG 即代码” 的理念适合 Agent——LLM 生成的 DAG 可以序列化为可审查的代码
- 传感器模式适合 Agent 等待用户输入或外部事件
- 重试和回填机制是 Agent 容错的基础
6.3 LangGraph 的状态图模型
LangGraph 是专门为 LLM Agent 设计的图引擎,其核心创新是将状态引入 DAG:
1 | from langgraph.graph import StateGraph, END |
LangGraph vs Airflow 的关键区别:
| 维度 | Airflow | LangGraph |
|---|---|---|
| 执行粒度 | 任务级(分钟-小时) | 步骤级(秒-分钟) |
| 状态管理 | 数据库持久化 | 内存 + 检查点 |
| 动态性 | 静态 DAG | 条件边 + 循环 |
| 循环支持 | ❌ | ✅(状态图而非严格 DAG) |
| 人工介入 | 手动触发 | 人工节点 |
| 适用场景 | 数据管道 | Agent 工作流 |
**LangGraph 的”伪 DAG”**:严格来说 LangGraph 支持循环边(reviewer → writer),因此不是真正的 DAG。但从设计意图上看,它用状态图扩展了 DAG 的表达力——循环不再是”结构性循环”,而是”迭代性循环”,每次循环的状态不同。
6.4 Temporal 的持久化执行
Temporal 采用了完全不同的范式——持久化执行(Durable Execution):
1 |
|
Temporal 的关键优势:
- 执行不丢失:即使进程崩溃,重启后从上次完成的状态继续
- 天然支持长时间任务:一个工作流可以运行数天
- 内置重试和超时:声明式配置
对 Agent DAG 的启示:Agent 任务经常涉及长时间运行的 LLM 调用和外部 API,持久化执行是刚需。
七、Agent DAG 的完整工程实现
7.1 核心数据结构
1 | from dataclasses import dataclass, field |
7.2 LLM 驱动的 DAG 构建器
1 | class LLMDAGBuilder: |
7.3 执行引擎
1 | class DAGExecutionEngine: |
7.4 检查点与恢复
长时间运行的 Agent DAG 需要检查点机制,以便崩溃后恢复:
1 | class CheckpointManager: |
八、高级话题
8.1 DAG 的代价模型
在选择 DAG 策略时,需要考虑 LLM 调用的代价:
单次 LLM 调用成本:
$$C_{llm} = \frac{T_{input} \times P_{input} + T_{output} \times P_{output}}{1000}$$
其中 $T$ 是 token 数,$P$ 是每千 token 价格。
DAG 执行总成本:
$$C_{total} = \sum_{v \in V} C_{llm}(v) + C_{coordination}$$
$$C_{coordination} = \sum_{v \in V} (R_v \times C_{retry}) + C_{context_propagation}$$
关键优化:
- 减少不必要的 LLM 调用(用确定性步骤替代)
- 压缩上下文传播(不要把整个中间结果都传给下游)
- 增加并行度以减少时间成本(但可能增加 token 成本)
8.2 多 Agent DAG 协作
当 DAG 的节点由不同角色的 Agent 执行时,协作模式成为关键:
1 | class MultiAgentDAG: |
8.3 DAG 可观测性
生产环境的 DAG 需要完整的可观测性:
1 | class DAGTelemetry: |
8.4 DAG 的测试策略
1 | class DAGTester: |
九、前端可视化与交互
9.1 DAG 可视化
DAG 的可视化对于理解和调试至关重要:
1 | ┌─────────────────────────────────────────────┐ |
9.2 交互式 DAG 编辑
允许用户在 LLM 生成 DAG 后进行微调:
- 拖拽调整节点顺序
- 点击节点编辑参数
- 右键添加/删除/禁用节点
- 切换边的条件
十、总结与展望
10.1 核心要点回顾
| 要点 | 说明 |
|---|---|
| DAG 是 Agent 并行的基石 | 有向无环图天然表达任务依赖和并行关系 |
| 粒度选择是关键 | 太粗无法并行,太细调度开销大 |
| 动态 DAG 是 Agent 的刚需 | 运行时才能确定完整结构的场景很常见 |
| Plan + ReAct 是最佳组合 | DAG 提供结构化并行,ReAct 提供灵活应变 |
| LLM 生成 DAG 需要验证 | 幻觉可能产生非法图结构 |
| 关键路径决定性能瓶颈 | 优化关键路径上的任务最有效 |
10.2 开放问题
- LLM 生成的 DAG 质量如何保证?——需要更强的结构化输出约束
- 动态 DAG 的可验证性——运行时修改图结构后如何保证安全性?
- DAG 与循环的统一——LangGraph 用状态图扩展了 DAG,但理论模型还不清晰
- 跨 Agent 的 DAG 编排——不同 Agent 的 DAG 如何组合和协调?
- 自适应粒度——DAG 的粒度能否根据运行情况自动调整?
10.3 未来趋势
- 声明式 DAG:用户只需描述”做什么”,”怎么编排”由系统自动决定
- DAG 编译优化:类似数据库查询优化器,自动合并、重排、并行化 DAG
- DAG 市场:可复用的 DAG 模板库,类似 GitHub Actions marketplace
- 可验证 DAG:形式化方法保证 DAG 的安全性和正确性
- 神经 DAG:用神经网络学习最优的 DAG 结构
参考文献
- Li, Y., et al. (2026). Beyond Entangled Planning: Task-Decoupled Planning for Long-Horizon Agents. arXiv preprint.
- Jafari, A.A., et al. (2026). A Lightweight Modular Framework for Constructing Autonomous Agents: AgentForge. arXiv preprint.
- Moslemi, Z., et al. (2026). POLARIS: Typed Planning and Governed Execution for Agentic AI. arXiv preprint.
- Del Rosario, R.F., et al. (2025). Architecting Resilient LLM Agents: A Guide to Secure Plan-then-Execute. arXiv preprint.
- Ye, Y. (2025). Task Memory Engine: Spatial Memory for Robust Multi-Step LLM Agents. arXiv preprint.
- Topcuoglu, H., et al. (2002). Performance-effective and low-complexity task scheduling for heterogeneous computing. IEEE TPDS.
- Kahn, A.B. (1962). Topological sorting of large networks. Communications of the ACM.
- Dean, J., & Ghemawat, S. (2004). MapReduce: Simplified data processing on large clusters. OSDI.
- Airflow documentation. https://airflow.apache.org
- LangGraph documentation. https://langchain-ai.github.io/langgraph/
- Temporal documentation. https://docs.temporal.io
- Prefect documentation. https://docs.prefect.io
- Dagster documentation. https://docs.dagster.io
- Argo Workflows documentation. https://argoproj.github.io/argo-workflows/
DAG 不是目的,而是手段。
目标是让 Agent 像人类一样高效地组织工作——哪些先做、哪些并行、哪些可以跳过、失败了怎么办。DAG 是我们目前找到的最优雅的形式化工具。
撰写日期:2026-05-14
字数:~15,000 字