ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

用Flask+AI自研工厂BI,替代帆软报表的实战指南

用Flask+AI自研工厂BI,替代帆软报表的实战指南 用过帆软的同学都懂它的做表能力确实成熟但每当工厂里冒出一个新需求——比如车间想看“按班组、按工单、按小时颗粒度”的产量趋势或者要在一张大屏上同时塞下 OEE、废品率、设备状态——你大概率会经历一轮漫长的提需求、排期、改模板、再测试的循环运气好一周上线运气不好拖一个月。更现实的问题是授权费用一个中小型工厂如果每个车间都上帆软一年下来的预算足够再招一个初级开发了。所以我花了大概一个月晚上和周末的时间用 Flask AI 辅助编程的方式自己搭了一套面向工厂车间的 BI 平台替代掉了原来挂在帆软上的大部分报表。这篇文章把我整个过程的思路、步骤、踩坑记录以及我给 AI 用的提示词全部整理出来给正在纠结“要不要脱帆软”“怎么低成本自研 BI”的朋友一个参考。这篇文章适合懂一点 Python、想用开源技术栈做企业数据可视化的开发也适合正在评估自研方案的信息化负责人。1. 先说结论自研 BI 到底比帆软好在哪1.1 帆软的三个痛点帆软FineReport 和 FineBI在企业报表领域确实能打尤其是财务三大表、复杂分组报表、填报流程这些功能几行脚本就搞定了。但落到工厂这个场景里我遇到的痛点特别具体不是功能不够而是功能和实际管理方式对不上。第一个痛点是需求响应太慢。工厂车间的管理报表往往不是一成不变的今天想看设备综合效率明天想按产品线拆分不良率后天想把晨会看板改成三班倒视图。帆软的模板是配置好的想改动需要熟悉 FineReport 设计器的人来改或者提交给服务商实施。对工厂内部的小需求来说这个链路非常重。第二个痛点是数据口径和维护成本。帆软连接工厂数据库之后报表逻辑通常写死在模板里多人维护时很容易出现同一张“产量表”在不同模板里面统计口径不一致。时间一长管理层发现问题了再去排查是哪张模板的过滤条件写错了那是不折不扣的考古工作。第三个痛点是钱。帆软的授权是按模块、按年、按用户数叠加的另外如果需要技术支持、定制开发成本还会更高。对于预算本身就不宽裕的中小工厂来说这笔开销是很肉疼的。而且要扩展一个用户还得联系商务加授权这在信息化快速试错阶段是很别扭的。1.2 自研适合什么工厂不适合什么工厂我不建议所有人都去照着这篇文章自研因为自研是有前提条件的。先说适合的情况你的报表主要是内部看板、日常管理报表、车间大屏数据量在千万条以内并且你手里至少有一个能写 Python、能折腾服务器的开发人员。这种情况下自研的投入产出比是很高的。不适合自研的情况也很明显如果你需要大量填报报表、复杂工作流审批、用户自助拖拽分析、或者给几十个业务部门每人开通不同的精细权限那还是老老实实用商业 BI 或者像 Superset、Metabase 这类开源 BI 更适合。这里不是说 Flask 做不到而是这些能力要做好做稳研发成本远超预期。有一点要清楚自研 BI 的目标不是“全面对标帆软”而是在你实际用得最多的几个场景里做到够用、好用、快速迭代。我做的时候砍掉了自助分析、数据填报、复杂权限矩阵只保留了数据连接、指标计算、报表展示、定时刷新、大屏展示这样开发的复杂度就一下子降下来了。1.3 选型对比Flask 不是唯一解为什么我选它如果你决定自研技术选型其实很宽。开源 BI 方案里Superset 和 Metabase 都是现成的但定制起来还是绕不过去改样式、改交互、嵌入现有系统都得熟悉它本身的插件机制和后端架构学习成本一点也不低。Power BI 免费版虽然好用但数据源、刷新频率、云服务这些约束在工厂内网环境里也很麻烦。最后我选了 Flask理由很简单团队对 Python 最熟Flask 足够轻量可以完全控制接口和页面从数据库读取到 JSON 输出再到前端图表渲染整条链路都是自己的。Flask 不像 Django 那样自带一堆东西但做 BI 后端我们本来就不需要复杂的 ORM、Admin 后台反而轻一点更好扩展。这里也要顺便说一下Flask 在并发方面有一些限制如果你直接用它处理上万人的并发访问那就得考虑加一层异步框架或者加服务实例。但工厂 BI 的使用场景是车间几十个看板、几个部门轮换看并发往往只是个位数或几十Flask 完全扛得住。部署上用 gunicorn 或 waitress 起多进程就行我在后面会详细写。2. 整体架构设计一个工业车间的数据监控系统怎么搭2.1 三层架构数据库层、服务层、展示层自研 BI 的核心不是代码多漂亮而是架构清晰。我做的时候把系统拆成三层层和层之间用 JSON 接口通信这样可以保证以后任何一层替换掉都不影响另外两层。数据库层负责存储源数据。对工厂来说数据通常已经在 MES、ERP 或 PLC 采集系统里了BI 平台不一定要重复存一份全量数据只需要把报表需要的明细数据或者轻度汇总数据同步过来。我这边是直接从 MySQL 生产库里读取订单和报工表为了不拖累生产库特意加了一个只读账号并限制它只能访问特定的几张业务表。服务层就是 Flask 后端。它负责接收前端请求、调 SQL 查询、做二次计算、返回统一的 JSON 结构。对于 BI 来说最好在服务层就把所有指标口径固定下来而不是让每个前端页面自己重新写过滤逻辑。这样当管理员问“为什么两张图产量不一样”的时候答案很简单因为前后端算的是同一个聚合函数。展示层是浏览器里的页面用 ECharts 渲染图表用原生 HTML/CSS 或轻量框架搭布局。大屏、看板、列表页都只是数据的最终呈现形式核心逻辑全部在服务层所以前端可以做得比较薄以后就算换 Vue 或 React 重写前端后端接口完全不用动。2.2 数据库表设计用生产订单表举个例不管做什么 BI表设计都是地基。我们以最常见的“订单产量统计”为例在数据库中通常会有一张类似production_order的表它的字段大概长这样字段名类型说明idbigint主键order_novarchar工单号product_codevarchar产品编码line_codevarchar产线编码shift_codevarchar班次比如 D / Nplan_qtyint计划数量actual_qtyint实际完成数量qualified_qtyint合格数量statustinyint工单状态create_timedatetime开工时间finish_timedatetime完工时间这张表其实已经能覆盖工厂 80% 的基础统计需求了。比如按天统计产量就用create_time字段做日期分组按产线统计就用line_code按班次统计就用shift_code。从这张表派生出来的日产量、班次产量、计划达成率、合格率就是典型的 BI 指标。在设计时有一个非常实用的建议不需要一开始就把所有统计维度建模成雪花模型直接把业务明细表同步过来然后在查询时用聚合函数做维度分析就行。工厂的数据量级通常在几千万以下几百万条记录做 GROUP BY 在现代数据库上毫秒级就出来了完全不用上数据仓库那套复杂建模。2.3 数据接入方式MES/ERP 数据怎么进 BI数据接入是自研 BI 最容易卡住的环节。工厂的数据源五花八门有 MySQL 的有 SQL Server 的有直接读 PLC 存到 PostgreSQL 的还有一部分数据是 Excel 导出再导进来的。我这边统一采用的方式是“只读视图 定时拉取”用 Flask 的定时任务每天凌晨把源库数据同步到 BI 库的明细表中。这样有两个好处一是 BI 查询不会影响源系统性能二是可以自主控制刷新频率比如大屏需要每 5 分钟刷新一次那就对某几张关键表单独做短周期同步。如果你的工厂数据源比较复杂可以在服务层加一个统一的数据接入模块支持导入 CSV、调用第三方 API、直连 ERP 数据库。我自己没有做太复杂的适配因为工厂的几套系统都支持 MySQL 只读账号这已经足够了。如果你要接的是 REST API实践上也不难在服务层写一个定时拉取任务就行主要注意幂等性和增量判断避免每次全量覆盖。3. 实操从空目录到第一个看板完整步骤3.1 环境准备与项目初始化开发环境建议使用 Python 3.10 或 3.11 版本我这边用的是 Python 3.11Flask 2.3 以上版本。先建一个虚拟环境再把依赖装上mkdir factory_bi cd factory_bi python -m venv venv source venv/bin/activate # Windows 上是 venv\Scripts\activate pip install flask flask-sqlalchemy flask-cors pymysql pandas gunicorn我一般习惯把项目结构分成app.py、models.py、api/和templates/四个部分。这样文件不会全部堆在一个文件里面以后加接口、改样式都好找。factory_bi/ ├── app.py # Flask 入口 ├── config.py # 配置数据库连接等 ├── models.py # SQLAlchemy 模型 ├── api/ │ ├── __init__.py │ ├── report.py # 报表接口 │ └── auth.py # 登录权限 ├── templates/ │ └── dashboard.html # 看板页面 └── static/ ├── css/ └── js/这里有一个细节要提醒数据库连接尽量用 SQLAlchemy 连接池不要每次请求都新建连接。在生产环境数据库连接频繁断开重连是导致接口偶发超时的最大原因之一。配置上设置pool_size10、pool_recycle3600就够用了。3.2 用 AI 提示词生成 Flask 报表接口我写代码不是一行行手打的大部分重复性的接口代码都是让 AI 直接生成我再做检查和修改。给 AI 的提示词最关键的一点是“给它足够的上下文”要包含表结构、字段含义、想要的返回格式、甚至已经定义好的数据模型。一个实用提示词模板长这样你是一名 Python Flask 后端工程师请帮我写一个报表统计接口。 项目使用 Flask SQLAlchemy PyMySQL连接 MySQL 数据库。 已有数据模型 production_order 的字段如下 - order_no: 工单号 - product_code: 产品编码 - line_code: 产线编码 - shift_code: 班次D 表示白班N 表示夜班 - actual_qty: 实际完成数量 - qualified_qty: 合格数量 - create_time: 开工时间 请实现 GET /api/report/production 接口参数 start_date 和 end_date 返回 JSON 格式如下 { code: 0, data: [ {date: 2025-01-01, total_qty: 100, qualified_qty: 95, line_code: A线} ] } 要求按日期、产线分组统计支持日期范围过滤按日期升序排列。把这个提示词交给 AI 之后它基本能在几秒内生成一个可运行的接口代码。我拿到后再根据项目里的模型做一点点调整比如字段名不一致、时区问题几分钟就能跑通。生成之后我通常会再追加一个提示词来做代码检查和防御性处理请再帮我优化这个接口 1. 如果 start_date 大于 end_date返回参数错误。 2. 查询时增加索引提示。 3. 避免把 null 字段直接传给 JSON转成 0。 4. 增加简单的耗时日志输出。这里要特别提醒AI 生成的代码不一定符合你的数据库规范尤其是表名、列名、权限校验一定要自己过一遍不能直接上线。我在实际项目中把 AI 当作“高级代码生成器”所有代码都要经过 review 和测试。3.3 用 AI 提示词生成 ECharts 前端看板后端接口跑通之后前端做一个工厂看板其实不难。我的页面选择用 ECharts通过 CDN 引入不需要构建前端工程保持简单直接。核心是一个 HTML 页面里面有若干图表容器和一个定时刷新脚本。前端最花时间的其实是 ECharts 配置项。如果只做一个柱状图那确实没难度但要做成大屏风格的“产量趋势 设备状态 班组达成率”组合配色、图例、tooltip、自适应逻辑都挺烦的。我建议用 AI 来生成配置提示词模板如下你是 ECharts 可视化专家。 我现在有一个 JSON 数据格式如下 [ {date: 2025-01-01, total_qty: 100, qualified_qty: 95}, {date: 2025-01-02, total_qty: 120, qualified_qty: 113} ] 请生成一个 ECharts 配置要求 1. 使用柱状图显示 total_qty。 2. 使用折线图显示 qualified_qty放在同一个 x 轴上。 3. 配色使用深色背景大屏风格主色 #00d4ff折线颜色 #ffd700。 4. 柱状图圆角 4tooltip 显示日期、产量、合格数。 5. x 轴日期过长时倾斜 45 度。这样生成的配置基本就能直接用了。如果觉得某些细节不对比如网格间距、字体大小、动画效果可以继续追加描述让 AI 改。把 AI 当同事使唤哪里不对改哪里效率比自己在文档里查 API 高太多了。3.4 权限控制怎么做工厂 BI 必然涉及权限问题。车间主任看自己车间的数据厂长看全厂数据质检员只看不良统计这些如果全靠一套通用查询是管不住的。我在自研版里把权限控制做成了一套非常轻量的 token 机制没有上 Flask-Login 全家桶。实现思路是用户在登录页面提交账号密码后端校验后生成一个包含用户角色和过期时间 token前端每次请求在 Header 里带Authorization: Bearer token。后端用一个装饰器校验 token 并解析出用户角色在查询数据时根据角色追加过滤条件。提示词示例帮我用 Flask 写一个登录接口和权限校验装饰器。 用户表 user 有字段 id, username, password_hash, role。 role 有三种admin 可以看全部数据manager 可以看指定 line_code 的数据viewer 只读。 token 使用 itsdangerous 生成有效期 12 小时。 请写一个 require_role(manager) 的装饰器并将用户的 line_code 注入到请求上下文。对于中小工厂这种程度已经够用。要说清楚的是这不替代帆软那种精细到单元格级的数据权限但如果只是做到“车间的人只能看见车间的数据”百万级用户以下的场景完全没有问题。3.5 大屏适配与定时刷新工厂看板经常是挂在车间墙上的电视或者 LED 大屏上所以前端必须解决两个问题分辨率适配和自动刷新。分辨率适配我用了 ECharts 的resize事件加上 CSS 的百分比定位。核心逻辑是监听窗口变化所有图表实例统一调用chart.resize()。如果你对细节有要求还可以让 AI 帮你写一个initChart工厂函数。定时刷新用 JavaScript 的setInterval来做每隔 30 秒或 5 分钟调一次后端接口然后用setOption更新图表数据。注意在更新时设置notMerge: true避免旧的配置项残留在图表里。async function refreshDashboard() { const res await fetch(/api/report/production?start_date2025-01-01end_date2025-01-07); const result await res.json(); const dates result.data.map(item item.date); const qty result.data.map(item item.total_qty); myChart.setOption({ xAxis: { data: dates }, series: [{ data: qty }] }, true); } setInterval(refreshDashboard, 30000);这段逻辑很简单就不需要 AI 提示词了自己写更快。如果你要在这个基础上增加“首次加载动画”“加载失败重试”这些体验优化再丢给 AI 补充也不迟。4. 常见问题与排查技巧实录4.1 接口返回慢先查索引再想缓存刚开始我遇到一个特别典型的问题产量报表的查询参数跨度大一点比如查一年的数据接口要跑四五秒才返回。一开始我以为是 Flask 的问题后来排查下来发现是数据库查询没走索引create_time和line_code都没有索引全表扫描了几百万行。解决方式是给数据库表加联合索引ALTER TABLE production_order ADD INDEX idx_time_line (create_time, line_code); ALTER TABLE production_order ADD INDEX idx_status (status);加完索引后接口直接从 4 秒多降到了 300 毫秒以内。这个教训给我提了个醒自研 BI 的性能瓶颈几乎都在数据库层不要在 Flask 代码里瞎优化缓存。如果加完索引还是很慢再考虑加 Redis 缓存做 5 分钟级别的快照而不是每次实时查库。4.2 图表数据对不上口径统一才是核心做 BI 最容易翻车的问题就是两个图表数字对不上。比如“昨日产量”在晨会看板上是 9800到了月度汇总表里变成 9600。问题基本上出在统计口径上常见的原因有日期范围不统一一个用create_time一个用finish_time。过滤条件不一致一个只看status 1已完工一个把所有工单都算进去。时区问题数据库存储的是 UTC 时间前端展示用的是北京时间。我的解决方案是在服务层把口径集中定义不要在页面里乱加过滤条件。比如服务层定义一个dashboardService.py里面所有查询都走统一的date_field参数这样任何一个新报表只需要复用同一个服务函数就不会出现口径分叉。另外建议你在前端页面显著位置标注“统计口径按开工日期含已完工与生产中工单”这样业务部门也能理解数据差异。4.3 部署上线的坑gunicorn nginx 进程守护开发环境跑flask run没问题真正上线用 Flask 自带的开发服务器是不行的并发一高就卡住。我最终用的是 gunicorn 来跑 Flask 应用nginx 做反向代理。部署步骤也很直接pip install gunicorn gunicorn -w 4 -b 127.0.0.1:8000 app:app --timeout 60nginx 配置里把/反向代理到127.0.0.1:8000再设置几个静态文件的缓存策略。server { listen 80; server_name your-server-ip; location / { proxy_pass http://127.0.0.1:8000; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; } location /static/ { alias /opt/factory_bi/static/; expires 1d; } }还有一个坑是 Flask 里的if __name__ __main__: app.run()在 gunicorn 下不会生效所以入口文件要写得干净不要在里面带 9999 端口这种测试配置。最后用 systemd 或者 supervisor 把 gunicorn 守护起来否则服务器一重启服务就没了车间大屏直接雪花这个责任你肯定不想背。4.4 边缘情况工单跨天、时区、扫码数据延迟工厂数据还有一个特别常见又麻烦的情况——夜班跨天。假设夜班是晚上 20:00 到第二天早上 8:00如果按自然日统计产量会把 24 号夜班和 25 号日班混在一起导致管理层永远看不到正确的“单日班次产量”。我的处理方式是在数据库里加一个shift_date字段这个字段在数据同步时根据班次规则计算好比如 20:00 到次日 8:00 的工单统一归到开工日。这个逻辑看似简单却是工厂 BI 和通用 BI 最大的区别之一。扫码数据延迟也是工厂的老大难。产线工人晚扫码、漏扫码导致实时看板上的产量比实际偏低。我的做法是在看板页面显眼位置标注“数据采集时间”和“统计截止时间”同时允许按工单维度做一次人工数据修正接口这样管理层看到波动时会先判断是不是数据延迟而不是误以为生产出了大问题。4.5 快速排查速查表现象可能原因优先排查方式接口超时SQL 没走索引 / 数据量过大EXPLAIN分析执行计划补索引图表长时间空白前端请求异常 / token 过期打开浏览器 F12 看 Network 请求数字对不上日期口径不同 / 状态过滤条件不一致对比两个查询条件统一走服务层函数大屏显示变形缩放布局写死用百分比定位 ECharts resize部署后页面 502gunicorn 挂了 / nginx 没启动systemctl status gunicorn看日志定时任务不执行没有设置时区 / 进程未加载检查 cron 或 APScheduler 的时区配置我还建议大家写接口时统一返回结构{ code: 0, message: success, data: ... }前端统一判断code这样排查接口问题时能快速定位是后端报错还是前端没调对。这个习惯在自研项目里越早统一越好后面接口超过 10 个的时候体会会特别深。写在后面回到最初的问题用 AI Flask 自研替代帆软到底值不值我的答案是看场景。对我们厂来说日常生产看板、晨会日报、月度产量汇总这些需求占了 80%过去依赖帆软的模板和外包实施现在完全是内部团队当天提需求、当天上线这个响应速度是商业 BI 给不了的。我个人实际操作的体会是一套轻量 BI 的代码量并没有想象中那么大核心可能就几千行 Python 和几个 HTML 页面真正的难点在于“你对业务指标的理解”以及“你敢不敢砍掉 80% 的伪需求只保留最有价值的那几个报表”。AI 辅助编程在这个过程中把写代码的门槛压低了很多但千万不要把 AI 当作万能工具它生成的代码只能算初稿每一个聚合字段、每一条过滤条件都需要你来为数据的准确性兜底。最后再分享一个我后来才体会到的小技巧自研 BI 一定不要把“做报表”当成终点而是要把“指标口径固定下来”这件事做好。当整个工厂都是同一个数据源、同一个计算函数、同一个权限模型的时候你会发现不再需要出一本厚厚的报表说明文档因为所有看板上的数字天然就是一致且可追溯的。这才是我认为自研 BI 真正值钱的地方。
返回列表