应用开发:DimLight节能项目
文章目录
摘要:本文记录了一个车间电脑批量管理系统的完整开发过程——从需求分析到离线服务器部署上线,全程通过 AI 对话式开发完成。包含整体架构设计、AI 辅助开发的实际工作流、自动化升级链路的设计取舍,以及一路踩过的坑。
背景
工厂车间里散布着大量产线电脑,长期存在几个痛点:
- 下班后电脑忘记关机,整夜空转浪费电
- 批量开关机、重启靠人跑到现场逐台操作
- 客户端程序更新需要逐台拷贝安装
- 产线环境完全离线,很多现成的云方案直接出局
于是有了 DimLight 项目:一个部署在客户内网 Windows Server 上的 Web 管理系统,管理员在浏览器里按「客户 / 线体 / 段别」的树形结构批量下发关机、休眠、重启、升级命令,电脑上的 Agent 负责接收执行。从第一行代码到上线,全程用 AI 结对完成。
整体架构
技术选型的第一约束是离线:所有依赖必须在一台联网开发机上装好、打包、拷进内网。因此刻意压低了复杂度:
|
|
几个关键决策:
1. Agent 用 HTTP 轮询,而不是长连接
产线电脑数量多但网络环境差,WebSocket 断线重连的复杂度不值得。Agent 每 10 秒 GET /api/agent/commands,轮询即心跳——顺带上报版本号、刷新在线状态,一个接口解决三件事。离线判定就是"超过 30 秒没轮询"。
2. 命令管道设计成"先取走、后回报"
命令生命周期是 pending → dispatched → done/failed。轮询时立即标记 dispatched,防止休眠唤醒后重复执行同一条关机命令(这是真实发生过的问题:电脑唤醒 → 又收到休眠命令 → 无限休眠)。
3. 数据库用 SQLite,但计划任务必须落库
SQLite 对这种单服务器小规模场景完全够用。唯一的坑是定时关机功能——如果计划存在内存里,服务器一重启就丢,所以计划配置必须存表,配合 last_run_date 字段做当天防重。
AI 结对开发的实际工作流
这个项目最值得分享的不是最终代码,而是和 AI 协作的过程。它不是"一句话生成整个系统",而是一个持续几周的迭代循环:
第一轮:需求 → 初版骨架
我先写了一份 README,把需求分析、技术栈建议、实施路径都列清楚,然后让 AI 按文档生成三端代码。产出的是能跑的最小系统:登录、树形结构、命令下发。这一轮的意义在于让 AI 和我对齐边界——比如它把 frontend 放进了 backend 目录,我一句"可以放同级目录吗"就纠正了。
中间若干轮:小步快跑 + 报错回贴
之后的每一轮对话基本都是这个模式:
|
|
印象最深的几个修复都是这么完成的:
- cp1252 编码崩溃:Agent 以 Windows 服务运行时 stdout 是管道,打印中文直接抛
UnicodeEncodeError,服务反复重启进入 Paused 状态。把日志贴给 AI,加了两行reconfigure(encoding="utf-8")解决 - Vue 自闭合标签:DOM 模板模式下
<el-button />会让后面的按钮全部消失,页面上按钮"无故失踪"——这种前端诡异现象靠人肉调试可能要半天,贴现象描述给 AI 一次到位
升级链路:三轮对话磨出来的方案
客户端自动升级是这个项目里最"工程"的部分,前后迭代了三轮:
- 第一版:后端 HTTP 下载 + version.txt 版本标记。能跑,但 exe 要在 FTP 和后端各放一份,维护别扭
- 第二版:改走 FTP 单一来源——服务器上本来就有 FTP 服务,新 exe 只上传一个地方。version.txt 也被质疑"我就升级个 exe 还要维护 txt?",于是改成版本号在打包时由脚本自动写入 exe 的版本资源,Agent 用 FTP 的
SIZE命令比对文件大小判断新版本,连版本文件都不用下载 - 第三版:静默自动升级落地。Agent 每 5 分钟检查一次,发现新版本就触发升级脚本:FTP 下载 → 计划任务脱离进程树 → 停服务 → 备份 .bak → 替换 → 重启 → 失败回滚
这轮迭代里 AI 的价值在排障。比如升级时计划任务创建一直报:
|
|
这类 Windows 冷知识(服务会话里 schtasks 必须显式 /ru SYSTEM),靠搜索引擎要翻很久,AI 直接给出了标准解法。同样解决的还有 ftp.exe 脚本模式不认裸用户名密码行、bat 文件含 UTF-8 中文注释导致 cmd 解析碎裂、NSSM 重定向日志后 Python 块缓冲造成日志乱序延迟(每行强制 flush)等等。
定时关机:一次说清需求的示范
功能成熟后的需求提法已经非常结构化了:
- 对应客户的账号可以执行对应客户的定时关机,不限于管理员
- 命令除了关机/重启,还要加上休眠
- 指定线体里需要定义到段别,不选段别则针对整条线
- 对应账号不可以定时操作其他客户的电脑
四条需求一轮对话完成实现 + 测试 + 部署说明。而且第 4 条权限约束 AI 直接做在了后端(403 拦截),而不是只在前端隐藏按钮——这种安全意识如果没有提前对齐,是容易被忽略的。
部署方案
最终交付形态是三个 NSSM 注册的 Windows 服务:
| 服务 | 内容 |
|---|---|
| DimLightBackend | uvicorn 跑 FastAPI |
| DimLightNginx | nginx 托管前端静态文件并反代 API |
| DimLightAgent | 各产线电脑上的 exe,开机自启 |
升级流程简化到极致:新 exe 打包后扔进 FTP 的 agent 目录,所有电脑 5 分钟内自动升级,Web 端树形结构里直接显示每台电脑的版本号和"升级OK"状态。
踩坑清单
按"每条一句话"列出来,都是真金白银换来的:
- Windows 服务重定向 stdout 后默认 cp1252 编码,打印中文必崩,
sys.stdout.reconfigure(encoding="utf-8")是保命符 - Vue3 DOM 模板模式不支持自闭合组件标签,
<el-button />会吞掉后面的兄弟节点 - cmd 执行含 UTF-8 中文注释的 bat 会解析碎裂,部署用脚本一律纯 ASCII
- 服务会话里
schtasks /create必须显式/ru SYSTEM,否则报"account names and security IDs"错误 - NSSM 停服务会杀整个进程树,升级脚本必须通过计划任务脱离进程树执行
- Python 日志写入文件默认块缓冲,重定向场景必须逐行 flush,否则日志乱序延迟
- 计划任务的同一天防重用日期字段判断而不是时间比较,否则修改执行时间会导致当天重复触发
- 升级只替换 exe 不动 config.ini,用户配置天然跨版本保留
后记
回头看,这个项目如果是传统开发方式,前后端加客户端三端 + 离线部署 + 自动升级链路,至少是一个小团队几周的活。AI 结对模式下,一个人通过二十来轮对话完成了全部工作——但前提是每一步都有明确的需求描述和验证反馈。
AI 没有替代掉的东西:对产线现场的理解(为什么离线电脑不能补发关机命令、为什么休眠唤醒不能重复执行)、对方案的取舍判断(FTP 还是 HTTP、轮询还是长连接、手动还是静默升级)。AI 负责实现和排障,人负责定义"什么是对的"。
下一步计划
- 集成 TightVNC 实现 Web 端一键远程协助(走现有 FTP 升级渠道静默部署)
- PostgreSQL 迁移(数据量上来之后)
- 命令执行结果的统计报表
文章作者
上次更新 2026-11-03