Slide 1 · 开场
大家好,我是 電源线PowerAdapter。"从零到一,基于 WorkBuddy 构建一个训练工具链" 做一下自己的技术分享——,也是为了参加wb的超级个体大赛,不过,用德勒兹的话来说应该是“生成-超级组装体”。
具体来说是两个东西:一个是wb积分消耗的看板,另外一个就是训练远程日志监控的小工具。不算特别复杂,算是拿 wb 做的两个非常甜点的项目,既满足日常需求,也是一个不错的实践。
如果你是一个 Python 开发者的话——那么对于这些工具都会更容易上手一些,但也会吐槽wb会往你基础解释器里塞一堆的包,而不是用虚拟环境。如果是非开放的话,也能够快速构建想要实现的功能,满足日常的需求。
Slide 2 · 我们遇到了什么问题?
先讲痛点,也是需求的诞生
无论是在ML/DL 的训练当中,基本都是训练在跑,人在等。一次训练 4 到 5 个小时或者更多,然后电脑GPU99满载状态,也干不了其他的什么。凌晨启动,早上起来看结果。崩了就直接接着睡就像可以了。
第二个问题就是实验记录散落。对 ML/DL 开发来说,留日志是基操——但跑多了模型之后,每次的 IC 多少?参数什么配置?全散落在终端输出或者临时笔记里,根本回溯不到哪一次表现最好。日志本身的意义之一,就是让你能及时看到、或者随时回顾想要看到的信息。
第三个问题就更简单了:无论是躺在床上,还是服务器在房间另一头,又或是出门在外的情况之下,想用手机看一眼进度。虽然wb有提供通过Claw链接电脑的选项,但是基本都需要等待任务结束之后才会回复你,或者你主动打断。
三个问题指向同一个方向:我需要一个工具链,让我能记录、监控、远程查看。
Slide 3 · 先解决监控问题:Log Monitor 的起点
刚才说了第三个痛点,远程查看的需求是最急的。补充一个细节:tqdm 进度条只输出到终端,你关了 PyCharm 或其他 IDE,就什么都看不见了。
所以需求很明确:远程实时看到训练日志和进度条。
Slide 4 · Log Monitor 的构建过程
这个功能也不是一步到位的,而是经历了四次迭代。
v1 双路输出:核心思路很简单——tqdm 输出到 stderr,只需要 tee stderr 进行分流,然后捕获进度条。所以写了一个 TeeFile 类,同时输出到终端和 .log 文件。一行正则表达式就能解析 tqdm 的进度信息。
v2 HTTP 服务:然后现在日志有了,但要远程看。这里有个关键问题:怎么让手机访问到电脑上的服务?最开始想了三条路。第一条是手机直连电脑,但这需要暴露端口到公网,信息不安全。第二条是走云服务器中转,数据多跳一次,延迟高还要维护服务器。第三条就是用 Tailscale 这类 VPN 组网,相当于在手机和电脑之间拉了一条加密的私有网络,安全且直连。最后选了第三条,Tailscale 装上就能用,手机浏览器直接访问电脑的 18888 端口。服务端就是 Python 原生 HTTP Server,通过 /api/logs 列出日志文件,/api/log 用 SSE 推送实时内容。
顺便说下为什么选 18888 这个端口。一是比较冷门,不容易跟其他服务撞。二是 WB 在测试过程中如果要 kill 掉这个进程的话,它就不会弹警告,然后让你手动允许——这点在日常使用中挺重要的,不然每次重启都要手动确认一遍,这和自动办公的需求相悖了。
v3 tqdm 解析:虽然我们能够看到日志了,但是还不够美观,因为只有纯终端的文本。所以我们可以加入一些可视化。正则提取 tqdm 的进度信息,在浏览器里渲染成进度条。然后是多进度条自动去重,显示 一些关键指标信息之类的细节。
v4 智能增强:再进一步就是体验上的进一步优化迭代,比如说添加日志标题自动提取、大文件 末尾N行的tail-N 截断、wb工作空间的监控等功能。
Slide 5 · Credits 的起点:作为 Monitor 的附属面板
Monitor 跑起来之后我们意识到,完全可以把积分消耗看板也加进来,作为 Monitor 的一个附属面板,同时也可以远程查看积分的消耗。
首先是,做 Credits积分消耗看板 的原因:WB 官方没有提供一个类似 API Token 消耗看板那样的功能。你消耗了多少积分、花在哪个模型上、什么时候花的——官方页面只能看一个列表,没有汇总、没有趋势、也没有可视化。
既然没有,那完全可以自己去做。不是单纯的造轮子,而是这些信息能给你一个大概的反馈,无论是成就感,还是实现一个功能会需要多少积分,成本是多少,看板会给你这样的一个基本概念。
从官网 usage 的表格我们可以很简单的就想到表格是什么样的,如果不简单也可以截图发给 wb 帮你分析。
需要记录的字段不复杂:RequestID、积分消耗、模型、客户端以及时间。关键是要足够轻量级——不能比手动翻页面还麻烦
需要注意的是之前的表格里是没有 User Prompt 的,也就是你发给 wb 的提示词。
Slide 6 · Credits v1:单文件全栈
Credits 最初就是一个网页,所以你甚至只需要一个 HTML 文件。纯 HTML、CSS和JavaScript,没有任何依赖,连 npm install 都不用。浏览器直接打开文件就能用。
数据存在本地里,刷新也不会丢。用 Chart.js 画了趋势图和模型占比饼图。数据支持 JSON 和 Excel 导入导出,简单的迁移。
一开始可能没有那么美观,但能用比好看重要。
(点击链接可以打开初版 Dashboard 看看)
Slide 7 · Credits v3:从单机到多端
v1 能用了,但数据锁在浏览器里。换台电脑就没了,手机上也打不开。
而 Monitor 已经有了 HTTP 服务,所以 Credits 的迭代方向很自然成为了:直接复用 Monitor 的服务端,多端同步。
服务端用 JSON 文件存储,零数据库依赖——不想为一个积分看板装个 MySQL。前端拉取数据用 GET 请求,同步用 POST,不复杂。本地缓存做兜底,服务器挂了也能用。手机浏览器直接访问,响应式布局适配。
Credits 作为 Monitor 的附属面板接入,同一个端口、同一套基础设施。下班地铁上随手记一笔,回家电脑上自动同步。数据再也不会锁在单一设备里了。
Slide 8 · 重构:1293 行 → 5 个文件
代码写到 1293 行的时候,单文件已经很难维护了。不是炫技式重构——是不改就改不动了。
拆成了 5 个模块:config.py 负责常量和配置,db.py 是数据查询层,handlers.py 处理 HTTP 路由和 SSE 流,server.py 是入口,static 下面的 HTML 文件是前端展示层。
关键是 log_writer——它是整个体系里最可复用的模块。用 with 语法,自动把标准输出和标准错误同时写到终端和文件,tqdm 原生兼容,已经封装成 Skill 可以跨项目复用。
训练到日志到 HTTP SSE 推送到手机,积分到 JSON 到 API 到多端同步。一个端口 18888 承载全部。
Slide 9 · 整体架构
最后看一眼完整架构。数据流非常清晰:
训练脚本跑起来,log_writer 做双路输出,日志写到 logs 目录下的 .log 文件,Python HTTP Server 在 18888 端口提供服务,手机和电脑浏览器同时访问。
左边是 Monitor 实时日志,右边是 Credits 积分看板。同一套基础设施,两个完全不同的功能,共享一个端口。
Slide 10 · 三条原则
结尾我们简单的总结一下。从最初一个 HTML 文件,到现在一个端口跑两个功能,这个过程里其实没有什么难的东西,全是被实际需求与功能的一步步实现。
做这个项目中,我们可以总结出三条生成限定,或者说生成原则:
第一,小步迭代。 每次解决一个真实需求或痛点。v1 可以不美观,但要能跑起来。不追求一步到位,优化是后面的事。
第二,工具链思维。 每个模块都可独立复用。log_writer 封装成 Skill,新项目一行 import 就能接入。直接让wb总结重复性的工作,以及确实会长期使用或复用的东西,都可以成为一个SKILL。
第三,先有后优。 最开始的 monitor 一千多行的py代码不够优雅,完全没有关系,功能稳定后再拆成多个模块。重构不是目的,可维护才是。
虽然说是整个项目基本都是围绕 Python 的原生栈,但 日志远程 加 SSE 推流这套模式适用于任何语言和框架,或者说再进一步,可以扩展到不单单是训练日志的查看这一目的。
展望
下一步我们甚至可以引入 htmx。同样的轻量级,不需要前端构建工具,但能带来体验上的质变——比如日志列表的局部刷新、Credits 数据的实时更新,不用再手写 fetch 和 DOM 操作。用最小的改动换最大的体验提升,这跟整个项目"先有后优"的思路一脉相承。
如果你有所收获的话,点赞三连支持一下。
愿代码之美,与精神秩序并行。
这里是電源线PowerAdapter;我在生成的路上;我将往千高原去,那里有建设中的神椿市和世界末日的花海。
评论仅对已登录账号开放,不再接受匿名昵称。
登录后评论