# AI Workflow Platform MVP Design ## 1. MVP 目标 用最小但完整的闭环验证这个架构:管理员在后台注册节点、编排工作流并发布;普通用户只上传视频,后端动态组装节点并执行;节点无人使用后自动回收。 MVP 只做单机版本,不做 Kubernetes、多租户、计费和分布式 GPU 池。目标是在一台机器上跑通: ```text 上传视频 -> ffmpeg 提音 -> faster-whisper 转写 -> LLM 翻译 -> VR ASS 生成 -> 下载结果 ``` ## 2. 整体架构 ```mermaid flowchart LR Admin[管理后台] --> AdminAPI[FastAPI Admin API] AdminAPI --> DB[(SQLite)] AdminAPI --> Registry[节点注册中心] Registry --> Manager[节点管理器] Manager --> NodeA[ASR 节点] Manager --> NodeB[LLM 节点] Manager --> NodeC[ASS 节点] User[用户前端] --> UserAPI[FastAPI User API] UserAPI --> Scheduler[工作流调度器] Scheduler --> Registry Scheduler --> Runs[WorkflowRun] Runs --> DB Scheduler --> Manager ``` 关键原则: - 节点不是写死在应用里的函数,而是独立进程,按统一协议提供服务。 - 工作流是数据库里的版本化 DAG,不是业务代码。 - 调度器只负责编排,不直接加载模型。 - 节点实例由节点管理器统一创建、分配、回收。 ## 3. MVP 范围 ### 3.1 本期包含 - 节点注册中心,支持登记节点类型、能力、参数、启动命令、资源要求。 - 节点生命周期:COLD / STARTING / READY / BUSY / IDLE / STOPPING。 - 工作流 DAG 定义、校验、版本化、发布。 - 单机工作流执行器,按拓扑顺序调度节点。 - 用户上传接口、任务状态查询、进度事件、产物下载。 - 管理后台节点管理和工作流画布。 - 用户端工作流列表、上传页、进度页、结果页。 - 一条可运行的视频字幕示例工作流。 ### 3.2 本期不做 - Kubernetes、GPU 自动扩缩、跨机器节点池。 - 多租户、用户认证、计费、配额。 - 节点在线热部署和插件市场。 - 可视化工作流调试器。 - 分布式任务队列和 Worker 集群。 ## 4. 节点抽象 ### 4.1 节点 Manifest ```json { "id": "faster-whisper", "name": "Faster Whisper ASR", "version": "1.0.0", "capability": "asr", "command": ["python", "-m", "nodes.whisper_node"], "env": { "MODEL_PATH": "./models/faster-whisper-large-v3" }, "input_schema": { "audio_uri": "file" }, "output_schema": { "srt_uri": "file" }, "max_concurrency": 1, "idle_ttl_seconds": 300, "health_timeout_seconds": 10 } ``` 字段含义: - `capability`:节点能力类型,例如 `asr`、`llm`、`ffmpeg`、`subtitle`。 - `command`:节点进程启动命令。 - `env`:模型路径、API Key 等环境变量。 - `input_schema` / `output_schema`:用于工作流校验和节点参数检查。 - `max_concurrency`:单实例最大并发任务数。 - `idle_ttl_seconds`:空闲多久后回收。 ### 4.2 节点进程协议 每个节点是一个独立进程,对外提供两个 HTTP 接口: ```text GET /health POST /invoke ``` `POST /invoke` 请求: ```json { "run_id": "run_123", "node_instance_id": "ni_456", "inputs": { "audio_uri": "storage/runs/run_123/audio.wav" }, "params": { "language": "ja", "beam_size": 1 }, "output_dir": "storage/runs/run_123/steps/whisper" } ``` `POST /invoke` 响应: ```json { "status": "completed", "outputs": { "srt_uri": "storage/runs/run_123/steps/whisper/output.srt" } } ``` 节点执行过程中可以上报进度事件: ```json { "run_id": "run_123", "node_id": "faster-whisper", "progress": 0.45, "message": "正在转录第 120/300 段" } ``` MVP 阶段节点通过本地文件系统交换产物,未来把 `storage/...` 换成对象存储 URI 即可。 ### 4.3 节点生命周期 ```text COLD -> STARTING -> READY -> BUSY -> READY -> IDLE -> STOPPING -> STOPPED | | +---------- ERROR <------------+ ``` - `COLD`:没有进程,只有注册信息。 - `STARTING`:进程已拉起,等待 `/health` 就绪。 - `READY`:进程就绪,模型已加载,可以接收任务。 - `BUSY`:正在执行任务。 - `IDLE`:任务完成,等待下一任务或回收。 - `STOPPING`:超过 `idle_ttl_seconds`,正在优雅退出。 - `ERROR`:启动或执行失败。 节点管理器定时扫描实例状态: - 任务申请节点时,优先分配 `READY` 实例。 - 没有实例时,从 `COLD` 启动。 - `BUSY` 实例不能被回收。 - `IDLE` 超过 TTL 后先卸载模型并停止进程。 - 被调度器标记为长期热门的节点可以配置 `keep_warm=true`,不回收。 ## 5. 工作流定义 工作流是一份带版本号的 DAG JSON: ```json { "name": "video-to-vr-ass", "version": 1, "nodes": [ { "id": "extract", "node_type": "ffmpeg-extract", "params": { "sample_rate": 16000, "channels": 1 } }, { "id": "asr", "node_type": "faster-whisper", "params": { "language": "ja" } }, { "id": "translate", "node_type": "llm-translate", "params": { "target_language": "zh-CN" } }, { "id": "ass", "node_type": "srt-to-dual-eye-ass", "params": { "resolution": "3840x1920" } } ], "edges": [ {"from": "extract", "to": "asr"}, {"from": "asr", "to": "translate"}, {"from": "translate", "to": "ass"} ], "entry_inputs": { "video_uri": "file" }, "final_outputs": { "cn_srt": "translate.srt_uri", "ass": "ass.ass_uri" } } ``` 工作流校验规则: - 所有 `node_type` 必须已注册。 - 边必须引用存在的节点。 - 每个节点的输入必须有上游产物或工作流入口输入。 - 工作流必须是无环图。 - 发布前必须通过一次 dry-run 校验。 ## 6. 执行模型 用户触发工作流后: 1. 创建 `WorkflowRun`,状态为 `QUEUED`。 2. 调度器读取工作流 DAG,做拓扑排序。 3. 对每个节点调用节点管理器申请实例。 4. 节点执行完毕后,产物 URI 写入 `Artifact`。 5. 所有节点完成后,`WorkflowRun` 状态变为 `COMPLETED`。 6. 任一节点失败,按重试策略重试;超过次数后标记 `FAILED`。 MVP 的调度策略: - 只支持线性链和简单 DAG。 - 没有依赖关系的节点可以并发执行。 - 节点之间只通过产物 URI 通信,不允许共享内存。 - 每个节点执行前检查健康状态,节点不可用时重新启动。 WorkflowRun 状态: ```text QUEUED -> RUNNING -> COMPLETED | | +-> FAILED + | +-> CANCELLED ``` ## 7. 数据模型 MVP 使用 SQLite,表结构如下。 ### nodes ```text id, name, version, capability, manifest_json, status, created_at ``` ### workflows ```text id, name, slug, description, published, latest_version, created_at ``` ### workflow_versions ```text id, workflow_id, version, definition_json, created_at ``` ### workflow_runs ```text id, workflow_id, workflow_version, status, current_node_id, progress, error, input_uri, created_at, updated_at ``` ### node_instances ```text id, node_id, status, pid, address, started_at, last_used_at, busy_since, error ``` ### artifacts ```text id, run_id, node_id, name, uri, mime_type, size, created_at ``` ## 8. API 设计 ### 管理端 ```text GET /api/admin/nodes POST /api/admin/nodes GET /api/admin/nodes/{node_id} DELETE /api/admin/nodes/{node_id} GET /api/admin/node-instances POST /api/admin/node-instances/{id}/stop GET /api/admin/workflows POST /api/admin/workflows GET /api/admin/workflows/{workflow_id} PUT /api/admin/workflows/{workflow_id} POST /api/admin/workflows/{workflow_id}/validate POST /api/admin/workflows/{workflow_id}/publish ``` ### 用户端 ```text GET /api/apps POST /api/apps/{workflow_id}/runs GET /api/runs/{run_id} GET /api/runs/{run_id}/events GET /api/runs/{run_id}/artifacts/{artifact_name} ``` 上传接口使用 `multipart/form-data`: ```text POST /api/apps/{workflow_id}/runs Content-Type: multipart/form-data body: file=video.mp4 ``` 进度接口使用 SSE: ```text GET /api/runs/{run_id}/events Accept: text/event-stream ``` ## 9. 前端设计 ### 管理后台 页面: - `/admin/nodes`:节点注册列表。 - `/admin/workflows`:工作流列表。 - `/admin/workflows/{id}`:React Flow 画布。 - `/admin/workflows/{id}/publish`:发布确认。 画布能力: - 左侧节点面板,按 capability 分组。 - 拖拽节点到画布。 - 节点参数面板。 - 保存、校验、发布。 MVP 不实现节点在线调试器,只实现“保存 -> 校验 -> 发布 -> 后台试跑”。 ### 用户端 页面: - `/`:已发布工作流列表。 - `/app/{workflow_id}`:上传页。 - `/runs/{run_id}`:进度页和结果下载。 用户端不展示任何工作流细节,只展示输入表单、进度、产物。 ## 10. 示例工作流 ### 节点清单 | 节点 | capability | 作用 | | --- | --- | --- | | `ffmpeg-extract` | media | 提取 16kHz 单声道音频 | | `faster-whisper` | asr | 日语语音转写为 SRT | | `srt-normalize` | subtitle | 清洗 SRT 格式 | | `llm-translate` | llm | 调用 Ollama/OpenAI 兼容接口翻译 | | `srt-to-dual-eye-ass` | subtitle | 生成 VR 双眼 ASS | ### 验收标准 1. 管理员注册上述节点,画一条工作流并发布。 2. 用户上传一个测试视频。 3. 后端自动按 DAG 执行提音、转写、翻译、ASS 转换。 4. 用户能看到进度并能下载 `.CN.srt` 和 `_dual_eye.ass`。 5. 节点空闲超过 TTL 后进程被回收。 6. 新注册一个 ASR 节点后,编辑器中可以替换节点并重新发布,不需要改业务代码。 ## 11. 技术选型 ```text Backend: Python 3.12 + FastAPI + Pydantic + SQLite Executor: 单进程调度器 + 子进程节点 Node host: Python HTTP 服务(Uvicorn) Storage: 本地 storage/ 目录 Admin UI: React + Vite + React Flow User UI: React + Vite Deploy: Docker Compose ``` MVP 不引入 Redis 和 Celery,因为单机单调度器已经可以演示核心概念。任务状态持久化在 SQLite,节点状态由节点管理器维护。 ## 12. 实现里程碑 ### M1:节点基础能力 - 节点注册表。 - 节点管理器。 - 一个 `echo` 示例节点。 - 节点生命周期与 TTL 回收。 ### M2:工作流执行 - 工作流 CRUD 和版本化。 - DAG 校验。 - 调度器按拓扑顺序执行。 - WorkflowRun 状态机和产物管理。 ### M3:用户服务闭环 - 上传接口。 - 任务状态和 SSE 进度。 - 产物下载。 ### M4:管理后台 UI - React Flow 工作流画布。 - 节点注册页面。 - 发布流程。 ### M5:字幕演示工作流 - ffmpeg 提音。 - faster-whisper 转写。 - LLM 翻译。 - SRT 转 VR 双眼 ASS。 - 完整端到端验收。 ## 13. 后续扩展路径 - SQLite -> PostgreSQL。 - 本地文件 -> MinIO/S3。 - 单机调度器 -> Redis + Celery/Temporal。 - 子进程节点 -> 容器节点 + Kubernetes。 - 节点管理器 -> KEDA 自动扩缩和 scale-to-zero。 - 注册表 -> 插件市场。 - 单用户 -> 多租户、鉴权、配额、计费。