首页 / 资讯中心 / 文章详情

一个人业余时间做内部 AI 工具,怎么才能不烂尾?FastAPI + SQLite 的 YOLO 训练平台实践心得

一个人业余时间做内部 AI 工具,怎么才能不烂尾?FastAPI + SQLite 的 YOLO 训练平台实践心得 ★ FEATURED ARTICLE
一个人业余时间做内部 AI 工具怎么才能不烂尾FastAPI SQLite 的 YOLO 训练平台实践心得系列第 6 篇一个人、业余时间、给公司内部用的工具怎么做才能做完、能用、活得久这是我用 FastAPI SQLite 从零做完一个 YOLO 训练管理平台后总结的方法论。没有 deadline、没有需求评审的项目反而最容易烂尾——没人逼你做也没人拦着你加需求。适合正在一个人维护内部工具、或者正打算动手的人。先交代结果系统最终的形态FastAPI SQLite 单进程后端Vue 3 前端用 subprocess 调 yolo CLI 调度训练Windows 优先部署图形安装向导 桌面快捷方式。覆盖数据集导入 → 在线标注 → 版本快照 → 训练 → 模型入库 → 试模型整条链路公司同事双击图标就能用。目前 5 名同事日常使用已管理 10 个数据集、上万张图片规模还在随数据持续导入继续涨。下面这些心得一半是技术一半是自我管理。一、PLAN.md 驱动开发先写文档再写代码这个项目做得最对的一件事是动手前先写了一份PLAN.md而且一直维护它。里面有几样东西需求细节每条需求写到没有歧义为止。比如 train/val 划分写清楚发起训练时选用自带划分或按比例随机分默认 9:1——不写清楚写到一半就要停下来想一想就岔技术选型和理由为什么用 SQLite 单文件而不是 MySQL、为什么用 subprocess 直接调 yolo CLI 而不是上 Celery——每条选型都写下理由三个月后自己回看也接得上避坑清单开发中每踩一个坑补一条进去最后攒了二十多条——后来整理成文章的踩坑合集基本就是它的公开版明确不做清单这个下面单独说这份文档不需要什么格式我的骨架就四节可以直接抄# PLAN.md ## 需求细节 —— 每条写到没有歧义例train/val 默认 9:1 随机分 ## 技术选型 —— 每个选择附一句为什么例SQLite 单文件 → 备份 拷目录 ## 明确不做 —— 写出诱惑和拒绝的理由例不上 Docker用户只会双击图标 ## 避坑清单 —— 每踩一个坑补一条写文档不是走形式。一个人开发没有同事帮你 review 想法文档就是你的 review 对象——把设计写清楚的过程中一半的错误自己就暴露了。二、明确不做清单和需求清单一样重要PLAN.md 里专门有一节明确不做不做Docker 化、nginx、多项目工作区、细粒度权限、审计日志、强制改密、数据挖掘二期候选每条不做都对应一个真实的诱惑“都写 Web 了不上 Docker 吗”“权限就两级是不是太糙了”——每忍住一次项目就早完成一周。内部工具最大的死因不是功能少是过度设计拖到烂尾。判断标准很简单这个功能解决的是今天真实存在的痛点还是以后可能有用后者一律进不做清单真到了需要的那天再加——那时候你对需求的理解也比现在深。三、每一步都要可独立验证实施步骤是按依赖排序、每步可独立验证的先登录权限再导入再标注再训练再版本快照……每完成一步系统都是一个能用的东西只是功能少点。验证手段也不用重我到现在一共就 13 个 pytest 用例覆盖登录、数据集、训练三条主链路跑一遍十几秒够挡住大部分低级回归。这个节奏对业余项目至关重要。业余时间是被打碎的今晚一小时、周末一下午如果项目处于再写三小时才能跑起来的状态捡起来先要回忆上下文几次之后就再也不想打开了。让项目永远处于跑得起来的状态是维持开发动力最实际的办法。四、诚实地做安全取舍安全这块我的原则分层看待该省的省该硬的一分不让。省掉的部分系统跑在公司内网用户是可信的同事所以登录限速、token 吊销、强制改密这些对外部攻击者的防御明确不做——默认账号 admin/admin123 写在 README 里也无所谓内网工具够用就好。不让的部分数据层的规则一条不放松——类别只能追加、训练必须引用版本快照、被引用的版本禁删、上传解压拦../路径。因为这些防的不是恶意是误操作和静默出错而误操作在内网天天发生删错数据集、传错 zip、双击两次保存版本。以拦../路径为例实现就三行任何要解压用户上传 zip 的系统都能直接抄frompathlibimportPurePosixPathdefis_evil_name(name:str)-bool:zip 条目名含绝对路径或 .. 一律拒绝防解压穿越pPurePosixPath(name)returnp.is_absolute()orany(part..forpartinp.parts)# 用法extractall 之前先过一遍# for info in zf.infolist():# if is_evil_name(info.filename):# raise ValueError(f非法路径: {info.filename})一句话对攻击者的防御可以按环境裁剪对手滑的防御永远要在。五、可维护性藏在无聊的决定里回头看几个最无聊的决定反而是长期收益最大的整个data/目录就是全部数据备份 打包它迁移 拷走。没有数据库导出导入没有多组件状态同步所有记录带谁、何时、备注数据集、版本、模型、任务、标注全部有 created_by 和时间。出了问题不用猜这是谁干的、什么时候干的训练参数只暴露四个参数越少用户乱调的空间越小出问题排查范围越小错误信息写清楚原因训练完成但未产生 best.pt可能是标注全空比一屏 traceback 有用得多这些决定没有任何技术含量但它们决定了半年后这个系统是还在稳定服役还是没人敢动了。六、给也想做内部工具的人几条建议先写 PLAN.md写完再放三天三天后还觉得这个设计对再动手需求砍到原来的三分之一砍完你会发现真正重要的就那几件部署方式是第一优先级需求不是最后一步——给谁用、谁来装决定了整个技术选型踩坑清单从第一天开始记它是这个项目最值钱的副产品还能变成文章验收标准是离你最远的人能用起来不是我觉得好用什么时候这套方法不适用公允地说上面这些心得有它的适用前提换几个场景就不成立了对外的商业产品第四节的安全取舍只在内网 可信用户下成立。面向公网的产品登录限速、token 吊销、强制改密一条都不能省默认密码更是事故多人协作的项目PLAN.md 能替代自己 review 自己替代不了团队里的沟通和代码评审一个人砍需求是果断团队里单方面砍需求是事故有明确 deadline 和 KPI 的项目“写完放三天”砍到三分之一是有无限时间预算时的奢侈。有硬性交付节点时该堆人堆人、该加需求加需求节奏完全不同用户量大的工具SQLite 单文件、单进程这套架构前提就是内网低频使用并发上去了老老实实换数据库和任务队列小结一个人开发文档就是你的 review 对象——先写 PLAN.md写到没有歧义再动手明确不做清单和需求清单一样重要内部工具最大的死因是过度设计拖到烂尾业余项目要永远处于跑得起来的状态每一步可独立验证对攻击者的防御按环境裁剪对手滑的防御永远要在验收标准是离你最远的人能用起来不是我觉得好用FAQQ1内部工具一定要做成 Web 吗不一定。判断标准是给谁用、谁来装——部署方式是第一优先级需求。如果使用者就是你自己或身边两三个懂技术的同事命令行脚本更省我们做成 Web是因为最终用户是双击图标的同事。Q2一个人项目用 SQLite 够吗内网、单进程、低并发的场景完全够。换来的是整个data/目录就是全部数据备份 打包迁移 拷走运维成本几乎为零。Q3业余时间不够文档能不能省恰恰不能省。一个人没有同事帮你 review文档就是 review 对象需求写不清楚代码写到一半必然停下来返工更费时间。PLAN.md 写完放三天再看能过滤掉一半冲动设计。Q4默认密码 admin/admin123 写在 README 里不怕安全问题吗前提是系统跑在公司内网、用户是可信同事——对攻击者的防御可以按环境裁剪。但注意另一半数据层的规则版本禁删、拦../路径这些防的是误操作一条都不能松。Q5怎么防止业余项目烂尾两条最实际一是明确不做清单忍住不加需求二是让项目每一步都可独立验证、永远跑得起来这样碎片化时间也捡得起来。系列导航系列第 1 篇开发总览——23 个实践教训系列第 2 篇需求设计与技术选型系列第 3 篇subprocess 训练进程管理系列第 4 篇标注数据一致性的 4 个设计系列第 5 篇Windows 双击即用与 PyInstaller 打包系列第 6 篇业余时间做内部工具不烂尾的心得本篇技术栈FastAPI · SQLite · Vue 3 · ultralytics · PyInstaller有问题欢迎评论区交流。
阅读完成 · 觉得有帮助?
咨询建站