一个人 + AI,从 Streamlit 单文件到全栈调度运维平台

0 阅读9分钟

为什么要自己造轮子

数据中台每晚跑 391 个 ETL 任务,分布在同步、计算、质量三个模块。平台自带的调度管理界面能看单个任务状态,但回答不了运维最关心的几个问题:

  • 凌晨 2:00-3:00 到底有多少任务在并发?超限了吗?
  • 一个计算任务的上游同步有没有跑完?它们之间有没有时间重叠?
  • 某个 ETL 的 SQL 改了,下游字典文档有没有跟着更新?

平台不提供这些视角,手动排查要打开十几个页面交叉比对。作为数据团队唯一的开发,我决定自己造一个。

但我不是前端工程师,不是全栈开发者——我是写 SQL 的数仓工程师。能在三周内从零做出一个前后端分离的运维平台,核心原因是 AI 协作

调度看板 — 854个实例运行状态、并发趋势、周期完成折线


三代进化:从能用到好用

第一代:Streamlit 单文件(v1,2025-12)

动机: 想看每晚任务并发情况,判断哪些时段过载。

实现: 一个 400 行的 app_v3.py,通过 HTTP API 爬取平台数据,Plotly 画折线图。

痛点:

  • Token 手动从浏览器复制,经常过期
  • 数据靠爬虫,平台接口一改就废
  • 只能看并发折线,没有任务间依赖关系

AI 协作方式: 把需求描述给 AI,它直接生成整个 Streamlit 应用。Cron 表达式解析、时间轴坐标转换这些逻辑,说一遍需求就能拿到完整实现。

调度排布分析 — 并发时间分布与超限检测

第二代:数据库直连(v2,2026-03)

动机: Token 过期太烦了,而且发现平台底层就是 MySQL,我有 root 权限。

改动: 去掉 HTTP 爬虫,换成 SQLAlchemy 直连。同时加了 SeaTunnel 任务的 UNION 查询,覆盖面从单一同步模块扩展到全量。

收益:

  • 再也不用复制 Token
  • 数据实时,不受 API 缓存影响
  • 组织列表从硬编码 15 个变成从 sys_org 动态加载

AI 协作方式: 描述"我想把 API 数据源换成数据库直连",AI 给出 SQLAlchemy 连接池方案 + 参数化查询写法。一轮对话完成迁移。

第三代:前后端分离全栈应用(v3,2026-05)

动机: Streamlit 天花板到了——想做 DAG 拓扑图、想做可交互的节点点击、想做知识图谱联动跳转。Streamlit 做不了这些。

决策: 拆成 FastAPI 后端 + React 前端,用 AntV X6 画 DAG。

AI 协作方式转变: 不再是"给我生成一个页面"的单轮交互,而是持续对话式开发——

  1. 我描述业务需求("我想看一个调度内所有节点的上下游依赖关系")
  2. AI 提出技术方案("可以解析 ETL SQL 提取 FROM/JOIN 表名,再反查血缘表找到上游同步任务")
  3. 我补充业务约束("血缘表的 to_table_name 有空格,而且 WITH 子句里的临时别名不能算输入表")
  4. AI 迭代代码,我验证数据正确性

这不是"AI 写代码我抄",是双方各自发挥优势:我知道业务逻辑和数据里的坑,AI 擅长把想法快速变成可运行代码。

全量 DAG — 同步→生产→质量三层跨模块依赖拓扑


六个功能模块

v3 最终形成 6 个页面,每个解决一类运维问题:

模块解决什么问题技术要点
Dashboard 看板任务总览、状态分布、异常计数聚合查询 + 卡片式布局
全量 DAG跨模块依赖可视化SQL 解析 + 血缘反查 + dagre 自动布局
调度排布分析并发超限检测、时段优化建议cron 解析 + 分钟级并发计算 + 甘特图
统一任务列表全量任务检索、状态筛选多表 UNION + 动态过滤
知识图谱表级血缘追溯图数据库思路的关系查询
ETL 同步SQL 变更自动同步字典文档快照 diff + Markdown patch + Git 推送

下面展开讲两个我觉得最有价值的模块。

知识图谱 — 招采系统表级血缘拓扑,按层级着色(ODS/DWS/DWD)


全量 DAG:让隐藏的依赖关系浮出水面

问题

平台的调度编辑器只展示"计算任务"之间的先后顺序(手动连线)。但真实的数据流是:

同步任务 → 写入 ODS 表 → 计算任务读 ODS 表 → 写入 DWS 表 → 质量任务检测 DWS 表

这条链路跨了三个模块,平台里看不到全貌。如果一个同步任务凌晨跑失败了,下游计算任务照跑——产出的就是脏数据。

方案

自己建立跨模块依赖关系。核心逻辑:

  1. SQL 解析器:用正则从计算任务的 SQL 中提取输入表(FROM/JOIN)和输出表(INSERT INTO/CREATE TABLE)
  2. 血缘反查:输入表名 → 查平台血缘表 data_blood_tb → 找到对应的同步任务
  3. 质量匹配:输出表名 → 匹配 data_governance_quality_config 的 metatable → 挂载质量节点

最终每个调度生成一张完整的三层 DAG:上游同步(橙色)→ 计算任务(绿色)→ 下游质量(紫色)。

SQL 解析器的取舍

用正则而不是语法解析库(如 sqlglot),原因:

  • 391 个 ETL 的 SQL 方言混杂(Doris SQL、MySQL、标准 SQL),完整解析器兼容性反而差
  • 我只需要 FROM/JOIN 后面的表名,不需要完整语法树
  • 正则 + 几条过滤规则(排除 WITH 别名、排除 tmp_ 前缀、排除 SQL 关键字误匹配)覆盖了 95% 的场景
# 输入表提取:FROM/JOIN 后的表名
INPUT_PATTERN = re.compile(
    r'\b(?:FROM|JOIN)\s+(?:`?(\w+)`?\.)?`?([a-zA-Z_][\w]*)`?',
    re.IGNORECASE,
)

剩下 5% 的 edge case(动态 SQL、多层子查询嵌套),手动在血缘表里补录就行。工具不需要完美,够用比完美重要。

前端渲染

用 AntV X6 + dagre 自动布局。节点按模块分色,边支持点击高亮上下游。选中一个计算节点时,自动高亮它的所有上游同步(橙色连线)和下游质量(蓝色连线),其余边降为浅灰。

比起盯着平台里十几个页面来回翻,一张图看清全貌。


ETL 同步:字典文档自动跟 SQL 走

问题

数仓项目有 53 个字典 Markdown 文件,记录每张表的字段含义和编码对照。每次改 ETL SQL 里的 CASE WHEN 映射(比如状态码从 3 种变 4 种),都要手动找到对应字典文件去改编码表。

改 SQL 不改文档是常态,改文档不改 SQL 也有——口径漂移就是这么来的。

方案

做一个自动同步服务,周期性轮询 ETL 变更并 patch 字典:

运维库 ETL SQL → hash 对比快照 → 提取 CASE 映射 → diff 新旧映射 
→ 定位字典文件 → patch Markdown 编码表 → Git commit + push

核心链路:

  1. 快照对比:每个 ETL 任务的 SQL 存一份 hash,变了才处理
  2. 映射提取:正则提取 CASE WHEN 中的编码→中文对照关系
  3. Markdown Patch:找到字典文件中对应字段的编码表,增量更新行
  4. Git 推送:自动 commit 带语义化消息,推到远程仓库

这套机制跑起来后,ETL SQL 改了映射 → 5 分钟内字典文档自动更新 → 下游消费者看到的永远是最新口径。


AI 协作的真实体感

三代开发下来,AI 在不同阶段扮演的角色不同:

阶段AI 角色我的角色
v1 原型代码生成器(说需求→出代码)需求描述者
v2 迁移方案顾问(给技术选型建议)决策者
v3 全栈结对程序员(持续对话迭代)架构师 + 业务专家

几个具体的协作场景:

场景 1:dagre 布局不收敛

我发现节点超过 30 个时,dagre 布局出来的图挤成一团。告诉 AI 这个现象,它建议调整 nodesepranksep 参数,并加了一个 fallback:如果 dagre 对半数以上节点没生成坐标,就回退到按模块分层的手动排列逻辑。

场景 2:血缘表脏数据

血缘表 data_blood_tbto_table_name 字段有前导空格和大小写混乱。我发现这个问题后告诉 AI,它在查询层统一加了 LOWER(TRIM(...)),而不是在应用层逐条处理——这是正确的做法,但如果我不告诉它数据里有坑,它生成的代码不会主动加。

场景 3:前端我不会,但我能描述交互

我不懂 React,但我能精确描述"点击节点高亮上下游、点击空白恢复、模块按颜色区分"。AI 把这些交互需求翻译成 X6 的事件绑定代码。我验证效果,提修改意见,再迭代。

核心体会:AI 不能替代你对业务数据的理解。 它不知道血缘表有脏数据、不知道 WITH 子句的别名不能算输入表、不知道 SeaTunnel 和传统同步是两套表要 UNION。这些业务知识必须你喂给它,它才能写出正确的代码。


技术栈选型回顾

选型为什么选
后端框架FastAPI异步、自带 OpenAPI 文档、Python 生态熟悉
ORMSQLAlchemy(raw text)查询都是复杂 JOIN,ORM 反而碍事
前端框架React + TypeScriptAI 生成 React 代码质量最稳定
UI 库Ant Design中后台组件齐全,Table/Select/Tabs 开箱即用
DAG 渲染AntV X6 + dagreX6 交互能力强,dagre 自动布局省手动排
定时任务APScheduler轻量,不需要引入 Celery 那套
本地存储SQLiteETL 快照存储,不依赖外部服务

没有用 Next.js、没有用 GraphQL、没有上 K8s——工具是给 5 个人的数据团队用的,overengineering 是浪费。


部署:一个 bat 文件的事

start_prod.bat:
1. npm run build(前端打包到 dist/)
2. uvicorn backend.main:app --host 0.0.0.0 --port 8000
3. FastAPI 托管前端静态文件,单端口 8000 对外

局域网内任何人浏览器打开 http://我的IP:8000 即可使用,不需要装任何东西。

目前跑在我的开发机上,数据团队 5 个人日常使用。如果将来需要稳定运行,扔到 Linux 服务器 nohup 跑就行。


总结

维度v1 → v3 变化
代码量400 行 → 3000+ 行(后端)+ 2000+ 行(前端)
功能1 个并发图 → 6 个模块
架构单文件脚本 → 前后端分离 + 定时服务
数据来源API 爬虫 → 数据库直连
用户只有自己 → 团队 5 人
开发周期3 周(业余时间)
AI 参与度~70% 代码由 AI 生成,我负责架构、业务逻辑、数据验证

一个数仓工程师,不会前端,不会 React,用 AI 协作三周做出一个能用的全栈运维工具。这不是炫技——是数据团队资源有限时的现实选择。平台不提供的视角,自己造。

任务总览 — 854个任务统一检索,来源/状态/耗时一目了然