从 0 构建 AI Workload Platform(二):工作流、DAG、状态机与可靠执行基础 摘要我正在从零开发的 AI Workload Platform需要把多步骤 AI 和数据任务变成可校验、可追踪、可恢复的后台工作。工作流、DAGDirected Acyclic Graph有向无环图、状态机和可靠执行分别解决任务如何组织、依赖如何表达、生命周期如何记录以及失败后如何继续的问题。本文从一个文档处理例子出发解释工作流、任务、依赖、DAG、状态机、持久化、重试、幂等、控制面、执行节点和智能代理Agent等概念并说明这些技术在本项目中如何协作以及为什么先选择 Go、本地进程、Mock Executor模拟执行器和接口隔离。本文面向没有工作流平台背景的读者内容是概念和方案设计不代表工作流内核已经实现。阅读定位本文记录模块 0 阶段建立的概念基线因此“如何验证”一节保留了当时的验证计划。这些计划后来是否成立应继续查看系列第三篇的单机内核证据、第四篇的控制面故障实验、第五篇的 Agent 边界验证和第六篇的多 Worker 故障恢复实验不能根据本文的方案说明推导出已实现结论。目录本章要解决的问题前置知识一句话定义核心术语先看一次完整流转最小示例不使用统一平台时会发生什么在本项目中的位置DAG、状态机与调度器如何协作方案选择与替代方案常见错误和失败场景如何验证这些行为进一步思考当前实现边界本章总结与限制1. 本章要解决的问题以“把新文档加入搜索系统”为例任务可能依次完成读取文档、清洗内容、生成向量、更新索引。前一步没有成功后一步就不能开始某一步失败后还要决定是否重试。单个脚本可以描述正常路径却通常不会统一记录每一步的状态也不会自动判断重试是否会重复写数据。任务运行时间变长、执行节点变多后日志散落、状态丢失和重复执行都会增加排查成本。本项目关注的问题是怎样统一管理普通程序、模型调用和 Agent 的执行状态让多步骤后台工作在失败后仍有可解释、可恢复的处理路径。2. 前置知识本文不要求读者了解容器或分布式系统只需要知道程序一组可以被计算机执行的指令进程Process程序的一次运行实例数据库Database用于长期保存和查询数据的系统。分布式系统Distributed System由多个通过网络协作的计算机或进程组成。网络可能延迟或中断进程也可能独立崩溃因此系统需要保存足够状态才能在故障后判断下一步该做什么。本项目先验证单机内核再处理多节点问题。3. 一句话定义工作流平台是一套保存执行状态、检查步骤依赖、安排任务运行并处理失败的系统让由多个步骤组成的后台工作能够可靠完成。4. 核心术语4.1 工作流、任务和依赖工作流Workflow为完成一个目标而组织起来的一组任务及其关系。任务Task可以单独执行和记录结果的工作流步骤。依赖Dependency任务开始前必须满足的条件。例如“生成向量”依赖“清洗文档”。编排Orchestration根据依赖、状态和策略决定任务何时运行、在哪里运行以及失败后怎么办。4.2 DAGDAG 是 Directed Acyclic Graph 的缩写中文是有向无环图。有向表示关系有方向例如 A - B 表示 B 依赖 A无环表示不能沿依赖关系绕一圈回到原任务。如果 A 依赖 B同时 B 又依赖 A两个任务都会等待工作流也就没有可以开始的任务。因此提交工作流时需要检查依赖环。DAG 也可以表达并行关系。例如 A 完成后B 和 C 互不依赖就可以同时运行最后由 D 等待 B、C 都成功- B -\ A - - D - C -/调度器通常会维护每个任务尚未满足的前置任务数量。A 完成后B 和 C 的计数变为零它们进入“可运行”B、C 都完成后D 才被解锁。这种逐步减少未满足依赖数量的过程是拓扑排序Topological Sort在调度场景中的直观应用。拓扑排序可以给出合法的先后顺序但不能单独决定任务是否已经成功、是否正在重试或是否被取消。4.3 状态、持久化和恢复状态State任务当前所处的阶段例如等待依赖、可运行、运行中、成功、失败或已取消。状态机State Machine规定允许出现哪些状态以及状态之间可以怎样转换的模型。持久化Persistence把状态保存到进程退出后仍可读取的存储介质而不是只放在内存中。故障恢复Failure Recovery进程或节点故障后根据保存的状态继续处理尚未完成的工作。状态机的价值在于把“现在是什么状态”和“下一步允许做什么”明确写下来。例如等待依赖的任务不能直接标记为成功已成功的任务也不能因为重复收到失败消息而退回运行中。每个状态转换都应有明确的触发事件、前置状态和结果。4.4 重试、超时、取消和幂等重试Retry任务失败后按规则再次执行超时Timeout任务超过允许时间仍未结束时采取终止、重试或人工处理取消Cancellation用户或系统要求不再继续当前工作流幂等Idempotency同一个操作执行一次或重复执行多次最终业务结果相同。例如“把订单状态设为已完成”容易设计成幂等操作“给余额增加 100 元”如果没有唯一请求编号重复执行通常会产生不同结果。重试机制必须与幂等写入或补偿策略一起设计。4.5 Agent 与 Mock ExecutorAgent智能代理根据目标和上下文选择模型、工具或操作步骤并返回结果的软件执行单元其输出可能受到模型和外部工具影响。Mock Executor模拟执行器不调用真实模型或工具而是按测试预设返回成功、失败、超时或指定结果的替代实现。它模拟的是工作流内核需要的执行接口不代表 Agent 的决策能力。普通程序任务Program Task按确定代码执行的任务例如解析文件或计算校验和。API 是 Application Programming Interface 的缩写中文是应用程序编程接口用于让不同程序交换请求和结果。API Key 是接口访问凭证。多个逻辑 Agent 是否可以共享一个凭证取决于供应商条款、速率限制和并发限制。4.6 控制面和执行节点控制面Control Plane接收工作流、校验依赖、保存状态、判断可执行任务并处理重试和取消的管理部分。执行节点Worker Node真正启动普通程序或 Agent、收集日志并上报结果的执行部分。调度器Scheduler控制面中选择接下来运行哪个任务的组件。控制面决定做什么执行节点负责实际去做。两者分开后未来才能让多个执行节点共享同一套状态和调度规则。5. 先看一次完整流转把前面的文档处理流程写成数据流可以直接看到各组件的职责工作流定义 - 校验器检查任务和依赖 - 调度器根据状态选择可运行任务 - 执行节点运行任务并返回结果 - 控制面保存状态变化 - 成功状态解锁下游任务失败状态触发重试或终止这条流程先回答“数据依次经过谁”第 9 节再回答“DAG、状态机和调度器分别决定什么”。最关键的不是组件名称而是状态变化顺序只有任务结果已经可靠保存为成功调度器才可以解锁下游任务只有取消请求被执行器确认运行中的任务才可以从“取消中”进入“已取消”。6. 最小示例T1 读取文档 - T2 清洗内容 - T3 生成向量 - T4 更新索引向量Vector是用一组数字表示文本特征的数据结构索引Index是为了更快查找数据而建立的结构。本文只用它们说明任务关系不讨论具体算法。任务输入输出失败示例T1 读取文档文档位置原始文本文件不存在T2 清洗内容原始文本规范化文本格式无法解析T3 生成向量规范化文本数字向量模型服务超时T4 更新索引文档编号和向量索引版本存储暂时不可用正常情况下T1 成功后才解锁 T2T2 成功后才解锁 T3最后 T4 成功工作流标记为成功。如果 T3 超时平台应记录本次尝试失败保持 T4 等待并根据重试策略决定是否再次执行 T3。达到最大重试次数后工作流进入失败或等待人工处理状态。7. 不使用统一平台时会发生什么直接串联脚本在任务很少时成本最低但随着数量和风险增加常见问题包括每个脚本分别实现日志、重试和超时规则不一致进程重启后不知道哪个步骤已完成人工重跑整个脚本导致已成功步骤重复写数据两台机器同时执行同一批任务前置步骤失败后后续步骤仍被错误启动Agent 获得过多文件、网络或工具权限。统一平台也有代价需要维护状态模型、存储、调度和监控。对于一次性、失败后可以直接人工重跑的小脚本完整平台反而会增加复杂度。8. 在本项目中的位置项目按模块逐步引入复杂度定义价值、边界和术语 - 实现单机可靠工作流内核 - 建立控制面、事务持久化和故障恢复 - 增加 Agent Runtime、自然语言草稿与校验 - 验证多 Worker 执行与故障恢复 - 增加可观测性、受限执行和 Kubernetes - 用真实场景、最小控制台和开源文档完成交付完整的模块递进关系见项目总览中的“技术路线和推进顺序”。本文只解释为什么概念基线之后必须先进入单机内核。模块 0 只能定义“合法状态应该怎样变化”却不能证明并发完成、持久化失败、超时和取消同时发生时实现仍会遵守这些规则。模块 1 因而先用 Go 写出可运行内核用 Mock Executor 稳定制造成功和失败用 FileStore把 Run 快照保存为本地 JSON 文件的存储实现保存最小快照再通过自动化测试验证状态顺序。只有先确定这套语义后续网络控制面、关系数据库、Agent 运行时和多执行节点才有可以共同继承的规则。这里没有直接进入控制面、真实模型或多节点是因为它们会同时引入网络、数据库、供应商协议和执行所有权问题。若此时测试失败很难判断根因来自基础状态模型还是新增基础设施。单机内核的代价是不能证明多客户端和多节点正确但它能先把最核心的调度问题隔离出来。学习目标分为三层理解术语、理解实现顺序、能够说明方案取舍与失败边界。后文先解释 DAG、状态机和调度器如何协作再说明当前阶段为什么选择 Go、本地进程、Mock Executor 和接口隔离。9. DAG、状态机与调度器如何协作9.1 三者的职责边界DAG 和状态机解决的是两个不同问题DAG 描述“任务之间的先后关系”状态机描述“某个任务此刻处于什么生命周期阶段”。调度器把两者结合起来只有当任务的依赖都处于成功状态且任务自身处于可运行状态时才会把它交给执行节点。可以用下面这张表观察一个任务的典型生命周期状态含义常见进入条件后续可能状态等待依赖前置任务尚未全部成功工作流创建或前置任务运行中可运行、已取消可运行依赖已满足等待调度所有前置任务成功运行中、已取消运行中执行节点正在处理调度器领取任务成功、失败、超时、取消中重试中本次失败等待下一次尝试错误可重试且未达到上限可运行、失败取消中已收到取消请求等待执行停止运行中任务收到取消已取消、成功或失败成功任务结果已确认执行结果成功且状态保存完成终态失败不再自动继续不可重试或重试次数耗尽终态或人工恢复已取消任务确认不再执行取消完成终态“取消中”不能简单省略为“已取消”因为控制面发出取消请求时执行节点可能仍在运行。类似地“超时”只说明控制面在规定时间内没有收到结果不等于远端一定没有产生副作用。9.2 一个任务如何推进第 5 节的系统数据流到达调度器后单个任务的最小状态变化可以表示为等待依赖 - 可运行 - 运行中 - 成功 | - 失败 - 等待重试 - 可运行 | - 已取消 - 已取消网络延迟、进程崩溃和重复消息会打断这个过程因此实现需要保留唯一运行标识、状态转换规则和持久化记录。例如只有先可靠保存成功结果才应解锁后续任务如果结果已经写入外部系统平台却没有保存成功状态恢复时就可能重复执行这是后续必须用幂等或去重处理的边界。10. 方案选择与替代方案10.1 为什么选择 GoGo 是一种静态类型、编译型编程语言。静态类型表示许多类型错误可以在运行前检查编译型表示源代码先转换成可执行程序。选择 Go 的原因当前开发环境已安装 Go用户有相关经验标准库适合网络服务、并发任务和测试编译后的单个程序便于后续部署控制面。为什么不选择其他语言作为当前控制面实现Python生态丰富、原型快也适合模型和数据处理它不会自动在运行前检查所有接口类型错误但可以用类型标注和静态分析工具补充约束。Node.js处理大量输入输出请求方便但当前学习主线和已有经验不以 JavaScript 服务端为中心。Rust内存安全和底层控制能力强但当前单机控制面不需要先承担更高学习成本受限执行节点阶段再单独评审。Go 的代价是需要编译部分业务原型代码比 Python 更长。如果未来主要工作转为模型实验或数据科学可以让 Python 承担对应任务而不必重写控制面。10.2 为什么选择本地进程本地进程是直接在一台开发机器上启动的程序实例。它启动快、调试路径短适合先验证依赖、状态和恢复逻辑。为什么不选择其他运行环境作为当前起点Docker Compose 适合集成多个容器服务但单机内核尚不需要这些服务Kubernetes 适合多节点容器编排但会增加排查层级虚拟机隔离边界较强但启动和资源开销更大。本地进程不能提供可靠安全隔离也不能证明多节点故障恢复正确。进入资源限制、节点选择或容器生命周期验证时才需要容器和本地 Kubernetes 集群。10.3 为什么选择 Mock ExecutorMock Executor 能按测试要求稳定返回结果不消耗模型费用也不依赖网络适合验证平台如何处理成功、失败、超时和取消。它与真实 Agent Runtime 的边界不同前者验证通用执行协议后者还要处理模型、工具、权限和预算。为什么不选择其他 Agent 实现作为当前起点真实云模型会引入费用、网络、速率限制和凭证管理本地模型会引入模型文件、内存和推理资源固定脚本不能表达 Agent 的非确定输出和工具调用。Mock Executor 的代价是不能证明真实模型接入可用。进入 Agent Runtime 模块后仍需保留 Mock 测试并增加少量人工触发的真实接口测试。10.4 为什么选择接口隔离接口隔离是让调度器依赖稳定操作例如“执行任务并返回结果”而不直接绑定某个模型供应商或存储客户端。直接调用供应商 SDK 初期代码少但更换供应商或离线测试时需要修改调度逻辑通过全局变量共享外部客户端会让测试相互影响一开始引入消息队列会增加消息重复、确认和部署问题。接口会增加少量类型和适配代码但本项目已批准同时支持 Mock、云模型、本地模型和普通程序任务因此当前需要这个边界。11. 常见错误和失败场景11.1 依赖形成环A 等 BB 又等 A所有任务都无法运行。工作流提交时就应执行环检测。11.2 失败后无限重试参数本身错误时重试不会成功反而持续消耗资源。重试策略需要最大次数、间隔和不可重试错误分类。11.3 重试非幂等操作执行节点完成写入后在成功上报前崩溃控制面可能认为任务失败并重新执行。业务操作必须使用唯一请求编号、幂等写入或补偿策略。11.4 只在内存保存状态控制面重启后失去运行信息无法区分“从未运行”和“已经成功但尚未上报”。实现需要通过存储接口验证恢复逻辑。11.5 把超时等同于任务没有成功调用方超时只表示没有按时收到结果远端操作可能已经完成。不能仅凭超时直接重复执行有副作用的操作。11.6 把容器当作绝对安全边界容器隔离进程和资源但错误配置、操作系统安全漏洞或过宽权限仍可能造成风险。不应宣称容器能安全运行任意恶意代码。11.7 让多 Agent 成为默认方案多个 Agent 会增加上下文传递、结果合并、修改冲突和模型成本。只有任务能够独立并行或确实需要不同能力和独立审查时多 Agent 才可能带来收益。12. 如何验证这些行为本文写作时还没有工作流业务代码因此当时不能验证任务状态机本身。后续实现需要用可重复的测试和故障实验验证实验操作期望观察依赖测试构造 A - B - CA 成功前 B、C 不运行环检测构造 A - B - A工作流在创建时被拒绝重试测试Mock Executor 前两次失败、第三次成功尝试次数和最终状态正确幂等测试对同一任务结果重复提交业务结果只生效一次超时测试Mock Executor 故意阻塞任务按策略超时不解锁后续任务取消测试任务运行中发起取消不再启动新的后续任务恢复实验保存状态后重启控制面已成功任务不被无条件重跑离线测试断开外部网络运行测试Mock 和核心单元测试仍可运行测试结果需要记录环境、命令、原始输出和限制。没有实测数据时不写任务吞吐量、恢复时间或资源开销数字。13. 进一步思考下面的问题是作者基于本文内容提出的后续思考不是预设的读者提问。13.1 为什么 DAG 不能代替状态机DAG 只能说明任务的依赖关系无法表达任务已经执行过几次、当前是否超时或用户是否要求取消。状态机补充了时间维度和生命周期约束两者缺一不可。13.2 “至少一次”和“至多一次”执行有什么区别“至少一次”优先保证任务不要被漏掉但可能重复执行因此需要幂等或去重“至多一次”尽量避免重复却可能在故障时丢失任务。工作流平台通常要根据任务副作用和业务价值选择执行语义不能只用一个口号覆盖所有场景。13.3 如果任务只有一步还需要工作流平台吗通常不需要。一次性脚本或简单定时任务更直接。只有当任务需要统一状态、权限、资源限制、审计或后续扩展为多步骤流程时平台化才有明显价值。13.4 为什么先做单机内核而不是先做多节点单机内核可以先验证任务定义、状态转换、依赖解锁、重试和取消。多节点会同时引入心跳、租约、重复领取和网络故障如果单机状态模型本身不正确多节点只会让问题更难定位。13.5 平台重试能保证只执行一次吗不能。网络超时和进程故障可能让平台无法确认远端是否已经成功。一种常见设计是“至少执行一次并通过幂等去重”在参与者、存储和协议都受控时也可以实现更强的执行语义但需要单独证明。13.6 为什么控制面和执行节点要分开控制面维护全局状态执行节点运行资源消耗更大的任务。分开后可以独立扩缩、限制权限和处理节点故障。13.7 为什么不一开始使用 KubernetesKubernetes 能解决部署、资源和容器生命周期问题但不能替代工作流状态机。先验证状态和调度逻辑再引入 Kubernetes故障定位更清晰。13.8 Mock 测试通过能证明真实 Agent 可用吗不能。Mock 只证明平台对预设行为的处理符合预期。真实接口还需要验证鉴权、速率限制、流式响应、输出变化、成本和供应商错误。14. 当前实现边界本文写作时项目只完成了概念、产品范围、高层架构和文档基线没有工作流业务代码。Go、本地进程、Mock Executor 和接口隔离是后续单机内核的建议起点不是当时已经运行的实现。后续证据与本文的关系是系列第三篇实现并验证了单机状态、调度、重试、取消和恢复第四篇将同一内核接入 HTTP 控制面和 PostgreSQL并记录了真实停库恢复实验第五篇建立了 Agent Runtime、工具权限、草稿校验和人工确认边界第六篇把任务执行拆到独立 Worker并验证了租约续期、节点崩溃接管和迟到结果拒绝。这些是对本文问题的后续回答不改变本文写作时尚无业务实现的事实。15. 本章总结与限制可靠工作流平台通过保存状态、检查依赖、安排执行和处理失败管理跨多个步骤的后台工作。DAG 描述无环依赖控制面负责决策执行节点负责运行重试解决临时失败但必须结合幂等、超时和故障恢复。本文介绍的是模块 0 当时的概念、示例和方案取舍不代表工作流内核在当时已经实现。任务状态转换、重试、取消和恢复等行为必须在后续代码实现中通过自动化测试和可重复的故障实验验证。模块 0 当时也没有性能测试数据因此本文不提供吞吐量、恢复时间或资源开销结论后续已产生的性能证据在对应模块文章和实验报告中单独记录。参考资料Apache Airflow 官方文档What is Airflow?Prefect 官方文档IntroductionTemporal 官方文档Argo Workflows 官方文档Kubernetes 官方文档JobsLangGraph 官方文档Overview项目源码本文对应模块 0 的工作流基础。完整源码、验证报告和后续模块见 AI Workload Platform GitHub 仓库。

相关新闻

最新新闻

PRISM:多变量时间序列转图像表示与异常检测

PRISM:多变量时间序列转图像表示与异常检测

这次我们来看一个面向多变量时间序列异常检测的表示学习方法:PRISM。项目全称是PRISM: Powerful Time Series to Image (TS2I) Representations for Multivariate Anomaly Detection,核心思路一句话能说清:把多变量时间序列转换成图像&#x…

2026/8/28 17:50:22
电力巡检绝缘子缺陷识别数据集:YOLOv5实战落地指南

电力巡检绝缘子缺陷识别数据集:YOLOv5实战落地指南

简介:绝缘子缺陷识别是输电线路AI巡检的核心任务,其本质属于小目标、低对比度、强干扰下的工业异常检测问题。技术原理上需兼顾像素级定位精度与业务语义一致性,关键在于标注规范是否贴合《DL/T 1476-2015》等电力运维标准,而非单…

2026/8/28 17:50:22
真心安利✨2026最值得入手的AI论文神器,本硕博定稿全程无痛!

真心安利✨2026最值得入手的AI论文神器,本硕博定稿全程无痛!

写论文焦虑、改稿崩溃、定稿反复翻车的同学,真心给大家安利一款实测零短板、完全适配国内高校审核标准的专属学术AI工具——PaperXie。用过十几款主流AI写作平台,最终还是锁定了这一款,它和普通通用AI完全不是一个赛道,不搞虚头巴…

2026/8/28 17:50:22
ISO26262功能安全系列: Concept Phase工作项指南

ISO26262功能安全系列: Concept Phase工作项指南

个人主页:云纳星辰怀自在 座右铭:“所谓坚持,就是觉得还有希望!” 前言 案例:某BMS项目在功能安全审核时被退回,审核员指出:“Item Definition中没有描述与其他Item的接口依赖关系,H…

2026/8/28 17:50:22
AI Agent 电商下单的技术边界与合规设计:从平台限制到工程实践

AI Agent 电商下单的技术边界与合规设计:从平台限制到工程实践

最近有一个新闻值得所有做 AI Agent 的开发者停下来想一想:Perplexity 试图让 AI 帮你直接下单购物,结果遭到亚马逊平台方面的限制,随后又出现“反转”传闻。乍一看这是商业新闻,但往深一层看,它其实是 AI Agent 发展中…

2026/8/28 17:50:22
Spring系列学习之Spring Android

Spring系列学习之Spring Android

英文原文:https://projects.spring.io/spring-android/目录特性快速开始下载用法示例* * Spring for Android是Spring Framework的扩展,旨在简化原生Android应用程序的开发。Spring for Android是一个框架,旨在提供用于Android应用程序的Spri…

2026/8/28 17:45:22