
把 YOLO 训练平台做成 Windows 双击即用pathlib psutil 跨平台规矩与 PyInstaller 打包实战系列第 5 篇内部 AI 工具的现实是公司有闲置的 Windows 台式机还带显卡没有专职运维申请一台 Linux 服务器要走流程安装这事最终要落到不会敲命令的同事手里。这篇讲怎么把一个 FastAPI YOLO 的训练管理平台做成Windows 就是主战场双击安装、双击启动、关窗即停。写给同样要给非技术用户交付内部工具的人。为什么敢把 Windows 定为主环境Web 项目的默认假设几乎都是 Linux 服务器Windows 是二等公民。但内部工具的验收标准不是架构漂亮是离你最远的那个人能不能自己用起来。公司的机器是 Windows使用者和维护者都不是专业运维——与其和环境较劲不如把 Windows 支持做扎实。关键是从第一天就定死规矩而不是写完再移植——移植一个写满了 POSIX 假设的项目比重写还痛苦。一、代码层的跨平台规矩1. 全程 pathlib禁手拼路径、禁 os.system# 禁止pathdata/name os.system(fyolo train data{yaml_path})# 必须pathDATA_DIR/datasets/str(dataset_id)subprocess.Popen([exe,detect,train,fdata{yaml_path},...])subprocess 一律用参数列表形式、不经过 shell既是跨平台要求也顺带杜绝了命令注入。2. 启动脚本第一行chcp 65001Windows 控制台默认 GBK 代码页Python 输出中文直接乱码。start.bat第一行切 UTF-8一行解决。别小看这一行——没它的话日志里的中文类别名全是问号排查问题时痛不欲生。3. zip 中文文件名cp437→GBK 兜底解码同事在 Windows 上打的数据集 zip中文文件名按 GBK 存但标记位常常没设置Python 解出来是 cp437 乱码def_decode_member_name(raw:str)-str:try:returnraw.encode(cp437).decode(gbk)# Windows 打包的中文名except(UnicodeEncodeError,UnicodeDecodeError):returnraw# 本来就是正常 UTF-8 名4. 程序生成的路径保持纯 ASCII中文用户名 中文安装路径 深度学习框架是 Windows 上的经典翻车组合。对策是隔离用户数据爱叫什么叫什么程序自己生成的路径一律纯 ASCII——data/runs/task_123/、data/datasets/456/。文件下载 URL 用记录 id/api/images/123/file不把中文文件名放进 URL。5. 进程管理交给 psutil训练是用 subprocess 调 yolo CLI 跑的。Windows 上terminate()杀不掉整棵进程树——yolo CLI 自己还会再 fork 子进程只杀直接子进程会留下占着显存的孤儿。用 psutil 递归杀Windows/Linux 行为一致importpsutildefkill_tree(pid:int):try:procpsutil.Process(pid)exceptpsutil.NoSuchProcess:returnprocsproc.children(recursiveTrue)[proc]forpinprocs:try:p.terminate()exceptpsutil.Error:pass_,alivepsutil.wait_procs(procs,timeout1)forpinalive:# 1 秒还没退的补一刀try:p.kill()exceptpsutil.Error:pass同理不用killpg、start_new_session这类 POSIX 专属 API系统差异全用 psutil 抹平。6..gitattributes统一行尾仓库根加.gitattributes*.py text eollf等。踩过的同类坑shell 脚本在 Windows 上 checkout 变成 CRLF拷回 Linux 直接无法执行。二、GPU 策略默认 CPU 版 torch按需换轮子深度学习项目装环境最大的坑是 torch 的 CUDA 版本。我们的策略requirements.txt默认锁CPU 版 torch——谁都能装永远装得上要用 GPU 训练README 给一行替换命令按nvidia-smi右上角显示的 CUDA Version 选轮子# nvidia-smi 显示 12.8 → pip install torch --index-url https://download.pytorch.org/whl/cu128代码里deviceauto有 CUDA 用 GPU没有就 CPU训练照常能跑只是慢这个默认 CPU、按需升级的决定让安装成功率接近 100%GPU 从安装前置条件变成了性能增强选项。三、安装向导让不会敲命令的人也能装内部工具的真正验收标准不是能跑是**“非技术同事能自己装上”**。为此写了一个图形安装向导installer.pytkinter 实现Python 自带无额外依赖环境自检检测 Python 版本、磁盘剩余空间、显卡型号和 CUDA 版本有 N 卡就自动选对应的 GPU 版 torch 轮子选安装目录默认给一个可自定义自动完成复制程序 → 创建虚拟环境 → 安装依赖 → 建桌面快捷方式也提供命令行/静默模式python installer.py --cli 安装目录 [--no-shortcut]给会敲命令的人用几个细节装依赖显示实时进度日志失败了把 pip 输出原样展示——内部工具的傻瓜化是简化操作不是隐藏信息桌面快捷方式指向图形启动器而不是命令行窗口下节讲PowerShell 创建快捷方式时安装路径要转义单引号再拼进命令——路径含会让命令断裂四、打包与启动双击图标关窗即停日常使用的入口是一个 PyInstaller 打包的图形启动器launcher.pyw它做了四件事后台拉起 uvicorn 服务参数列表形式的 subprocess日志重定向到data/tmp/uvicorn.log窗口里显示服务日志启动过程可见出问题不用翻日志文件轮询健康检查就绪后自动打开浏览器到http://localhost:8788关闭窗口 停掉服务不留后台进程核心逻辑就几行去掉 GUI 部分长这样defport_open(port,timeout0.5):try:withsocket.create_connection((127.0.0.1,port),timeouttimeout):returnTrueexceptOSError:returnFalseprocsubprocess.Popen([str(venv_python),-m,uvicorn,backend.main:app,--port,8788],stdoutlog_file,stderrsubprocess.STDOUT,creationflagssubprocess.CREATE_NO_WINDOW,# Windows不弹黑窗口)whilenotport_open(8788):# 每 0.5 秒试连一次端口超时 120 秒time.sleep(0.5)os.startfile(http://localhost:8788)# 就绪后用系统默认浏览器打开这套组合下来同事的使用体验是双击桌面图标 → 等几秒 → 浏览器自动打开 → 用完关窗。从头到尾不需要知道什么是 uvicorn、什么是端口。五、验收清单里的 Windows 条目PLAN.md 里的验收标准专门为 Windows 留了几条每次发版前过一遍全新 Windows 机器上按 README 三步venv → pip → start.bat能跑起来GPU 训练在 Windows 上真实生效任务管理器/nvidia-smi 可见占用代码无 POSIX-only 调用pathlib、psutil、无 os.system中文路径、中文文件名、中文类别名全流程不乱码这套清单不是纸面文章系统目前由 5 名同事日常使用已导入 10 个数据集、上万张图片数据还在持续导入全部按上面的方式装在 Windows 机器上跑。投入产出也算得过来安装向导installer.py413 行、图形启动器launcher.pyw383 行、启动脚本start.bat60 行三个文件加起来不到 900 行换来的是部署这件事从需要我到场变成同事自己点几下。要诚实交代的局限是这套安装/启动链路没有自动化测试覆盖——仓库里 13 个 pytest 用例测的是认证、数据集、训练接口安装向导和启动器全靠上面那张人工验收清单每次发版前过一遍。没有可靠数字证明它在所有 Windows 环境上的成功率原因是样本只有公司这几台机器接近 100%只是这几台上的经验值。什么时候不需要这么做这套打法的前提是Windows 就是主战场、安装要落到非技术同事手里换个环境很多内容就是过度设计有专职运维和现成 Linux 服务器直接按 Linux 部署做扎实安装向导、图形启动器、cp437 兜底这些都不用写使用者本身就是开发者README pip 就够tkinter 向导和 PyInstaller 启动器的维护成本收不回来项目明确只跑单平台、没有分发性跨平台规矩里仍值得保留的是 pathlib 和 subprocess 参数列表后者顺带防命令注入其余可以从简边界说清楚CPU 版 torch 训练只是能跑速度没法和 GPU 比——默认 CPU保的是安装成功率不是训练性能。小结Windows 优先不是找罪受是尊重部署环境的现实机器是 Windows就没有资格假设 Linux跨平台规矩就几条——pathlib、psutil、纯 ASCII 路径、UTF-8 控制台、cp437 兜底——不难难的是从第一天就坚持事后移植比重写痛苦默认 CPU 版 torch 把 GPU 从安装前置条件降级成性能增强选项装机再没被 CUDA 版本卡住过内部工具做得好不好不看技术多漂亮看的是离你最远的那个人能不能自己装上、自己用起来。FAQQ为什么不直接要求装 GPU 版 torchCUDA 版本和 torch 轮子必须对上是装环境最大的坑。默认锁 CPU 版保证永远装得上要用 GPU 再按nvidia-smi显示的 CUDA Version 换一行安装命令代码里deviceauto自动适配。QWindows 上杀训练进程有什么坑terminate()杀不掉整棵进程树。训练是 subprocess 调 yolo CLI 起的用 psutil 递归遍历子进程再杀Windows 和 Linux 行为一致也顺带避开了killpg这类 POSIX 专属 API。Q快捷方式为什么不直接指向 start.batbat 会留下一个命令行黑窗口使用者容易误关或不敢关。快捷方式指向 PyInstaller 打包的图形启动器窗口里直接看服务日志、就绪后自动开浏览器、关窗即停服务体验上就是一个普通桌面软件。Q中文安装路径为什么不直接支持中文用户名 中文路径 深度学习框架是 Windows 经典翻车组合与其逐个框架修兼容不如隔离程序自己生成的路径一律纯 ASCII用户数据随意下载 URL 用记录 id 而不是文件名。QPyInstaller 启动器和 uvicorn 服务是什么关系启动器只是个壳用 subprocess 拉起 uvicorn把日志重定向到文件并在窗口里显示轮询健康检查通过后自动打开浏览器窗口关闭时负责把服务停掉不留后台进程。技术栈FastAPI · SQLite · Vue 3 · ultralytics · PyInstaller · tkinter系列导航系列第 1 篇开发总览——23 个实践教训系列第 2 篇需求设计与技术选型系列第 3 篇subprocess 训练进程管理系列第 4 篇标注数据一致性的 4 个设计系列第 5 篇Windows 双击即用与 PyInstaller 打包本篇系列第 6 篇业余时间做内部工具不烂尾的心得有问题欢迎评论区交流。