# 图执行逻辑 > 版本:2025-12-16 本文档详细说明 DevAll 后端如何解析和执行工作流图,特别是对于包含循环结构的复杂图的处理机制。 ## 1. 执行引擎概述 DevAll 工作流执行引擎支持两类图结构: | 图类型 | 特征 | 执行策略 | |--------|------|----------| | **DAG(有向无环图)** | 节点间无循环依赖 | 拓扑排序 + 同层并发执行 | | **含环有向图** | 存在一个或多个循环结构 | 递归式超级节点调度 | 执行引擎会自动检测图结构,选择合适的执行策略。 ## 2. DAG 执行流程 对于不包含循环的工作流图,执行引擎采用标准的 DAG 调度策略: 1. **构建前驱/后继关系**:解析边定义,为每个节点建立 `predecessors` 和 `successors` 列表 2. **计算入度**:统计每个节点的前驱数量 3. **拓扑排序**:将入度为 0 的节点放入第一层,执行后将后继节点入度减 1,新的入度为 0 节点进入下一层 4. **同层并发**:同一层内的节点无依赖关系,可以并行执行 ```mermaid flowchart LR subgraph Layer1["执行层 1"] A["节点 A"] B["节点 B"] end subgraph Layer2["执行层 2"] C["节点 C"] end subgraph Layer3["执行层 3"] D["节点 D"] end A --> C B --> C C --> D ``` ## 3. 循环图执行流程 ### 3.1 Tarjan 强连通分量检测 当图中存在循环结构时,执行引擎首先使用 **Tarjan 算法** 检测所有强连通分量(Strongly Connected Components, SCC)。Tarjan 算法通过深度优先搜索,在 O(|V|+|E|) 时间复杂度内识别图中的所有环路。 包含多于一个节点的 SCC 即为环路结构。 ### 3.2 超级节点构建 检测到环路后,执行引擎将每个环路抽象为一个"超级节点"(Super Node): - 环路内部的所有节点被封装在超级节点中 - 超级节点之间的依赖关系来源于原始节点间的跨环边 - 封装后的超级节点图一定是 DAG,可以进行拓扑排序 ```mermaid flowchart TB subgraph Original["原始图"] direction TB A1["A"] --> B1["B"] B1 --> C1["C"] C1 --> B1 C1 --> D1["D"] end subgraph Abstracted["超级节点图"] direction TB A2["节点 A"] --> S1["超级节点
(B, C 环路)"] S1 --> D2["节点 D"] end Original -.->|"抽象"| Abstracted ``` ### 3.3 递归式环路执行策略 对于环路超级节点,系统采用递归式执行策略: #### 步骤 1:唯一初始节点识别 分析环路边界,识别当前被唯一触发的入口节点作为"初始节点"。该节点必须满足: - 被环路外部的前驱节点通过满足条件的边触发 - 有且仅有一个节点满足此条件 #### 步骤 2:构建作用域子图 以当前环路的所有节点为作用域,**逻辑上移除初始节点的所有入边**。这一操作打破外层环的边界,使后续的环路检测仅针对环内部的嵌套结构进行。 #### 步骤 3:嵌套环路检测 对构建的子图再次应用 Tarjan 算法,检测作用域内的嵌套环路。由于初始节点的入边已被移除,检测到的强连通分量仅为真正的内层嵌套环。 #### 步骤 4:内层超级节点构建与拓扑排序 若检测到嵌套环路: - 将每个内层环路抽象为超级节点 - 构建作用域内的超级节点依赖图 - 对该超级节点图执行拓扑排序 若未检测到嵌套环路,则直接进行 DAG 拓扑排序。 #### 步骤 5:分层执行 按拓扑排序得到的执行层次依次执行: - **普通节点**:检查触发状态后执行,首轮迭代时初始节点强制执行 - **内层环路超级节点**:**递归调用步骤 1-6**,形成嵌套执行结构 #### 步骤 6:退出条件检查 每完成一轮环内执行后,系统检查以下退出条件: - **出口边触发**:若任一环内节点触发了环外节点的边,则退出环路 - **最大迭代次数**:若达到配置的最大迭代次数(默认 100),强制终止 - **初始节点未被重触发**:若初始节点未被环内前驱节点重新触发,环路自然终止 若条件均不满足,则返回步骤 2 开始下一轮迭代。 ### 3.4 环路执行流程图 ```mermaid flowchart TB A["环路超级节点被调度"] --> B["识别唯一触发的初始节点"] B --> C{"是否有有效初始节点?"} C -->|"无"| D["跳过该环路"] C -->|"有多个"| E["报告配置错误"] C -->|"唯一"| F["构建作用域子图
移除初始节点入边"] F --> G["Tarjan算法检测嵌套环路"] G --> H{"存在内层嵌套环?"} H -->|"否"| I["DAG拓扑排序"] H -->|"是"| J["构建内层超级节点
执行拓扑排序"] I --> K["分层执行"] J --> K K --> L["执行普通节点"] K --> M["递归执行内层环路"] L --> N{"检查退出条件"} M --> N N -->|"出口边被触发"| O["退出环路"] N -->|"达到最大迭代次数"| O N -->|"初始节点未被重触发"| O N -->|"继续迭代"| F ``` ## 4. 边条件与触发机制 ### 4.1 边触发(trigger) 每条边有一个 `trigger` 属性,决定该边是否参与执行顺序计算: | trigger 值 | 行为 | |------------|------| | `true`(默认) | 该边参与拓扑排序,目标节点等待源节点完成 | | `false` | 该边不参与拓扑排序,仅用于数据传递 | ### 4.2 边条件(condition) 边条件决定数据是否沿该边流动: - `true`(默认):总是传递 - `keyword`:检查上游输出是否包含/不包含特定关键词 - `function`:调用自定义函数判断 - 其他自定义条件类型 只有当条件满足时,目标节点才会被触发执行。 ## 5. 典型循环场景示例 ### 5.1 人工审阅循环 ```yaml nodes: - id: Writer type: agent config: name: gpt-4o role: 你是一位专业的技术作家 - id: Reviewer type: human config: description: 请审阅文章,满意请输入 ACCEPT edges: - from: Writer to: Reviewer - from: Reviewer to: Writer condition: type: keyword config: none: [ACCEPT] # 不包含 ACCEPT 时继续循环 ``` 执行流程: 1. Writer 生成文章 2. Reviewer 人工审阅 3. 若输入不包含 "ACCEPT",返回 Writer 修改 4. 若输入包含 "ACCEPT",退出循环 ### 5.2 嵌套循环 系统支持任意深度的嵌套循环。例如,一个外层"审阅-修订"循环内部可以包含一个"生成-验证"循环: ``` 外层循环 (Writer -> Reviewer -> Writer) └── 内层循环 (Generator -> Validator -> Generator) ``` 递归式执行策略会自动处理这种嵌套结构。 ## 6. 关键代码模块 | 模块 | 功能 | |------|------| | `workflow/cycle_manager.py` | Tarjan 算法实现、环路信息管理 | | `workflow/topology_builder.py` | 超级节点图构建、拓扑排序 | | `workflow/executor/cycle_executor.py` | 递归式环路执行器 | | `workflow/graph.py` | 图执行主入口 | ## 7. 变更记录 - **2025-12-16**:新增图执行逻辑文档,详细说明 DAG 与循环图的执行策略。