一个 Windows 桌面小组件:从看 CPU、内存,到盯住线上服务
6 月 10 日,我们用 AI 编程工具 Claude Code 写了一个只显示 CPU 和内存的桌面小组件。十天里它长成了线上服务的状态台和企业微信推送,8 月又加了温度。本文按真实经过写这个自用小工具:两台机器之间的漂移、被静默吞掉的推送、打包之后才出现的崩溃,以及读不到的温度为什么不显示。
先说结论
- 这个自用的 Windows 桌面小组件,6 月 10 日第一版只显示 CPU 和内存;十天里长成了线上服务的状态台和企业微信推送,8 月又加了温度。
- 6 月是 Claude Code、8 月加温度的是 Codex,都在我们的对话里直接完成,那时 APSer-Atelier 还没有组织这个组件;今天这类工作分三个角色:我们提需求、拍板和真机验收,AI 编程工具作为执行器写代码,APSer-Atelier 作为主控负责组织,执行器换了,事情也能在原来的记录上接着做。
- 最费时间的是没有任何报错的失败:推送被吞掉、IP 变了之后的拒绝、一秒就被冲掉的提示;让失败留下痕迹,比多加一个功能更要紧。
- 跨机器、打包后的程序,验收只能在它真正运行的机器和环境里做;温度只显示能从公开接口如实读到的 ACPI 温区和硬盘,读不到的显示「--」。
我们日常开着一台 Windows 笔记本,屏幕角落里常驻着一个小窗口:上面是本机的 CPU、内存,下面是官网、论坛、格友搭子服务和公司那台 Mac 的在线状态,有新帖、新注册时,手机上的企业微信会收到一条消息。
这个小组件是自用的,不对外发布。它的第一版写于 6 月 10 日上午 11:20,只有 223 行代码,只做一件事:显示 CPU 和内存。到今天,它是一个 1680 行的单文件 Python 程序,一共 44 次提交:6 月 37 次(其中 6 月 16 日一天 18 次),8 月 5 次,9 月 2 次。
先交代分工。6 月 10 日的第一版和 6 月的几十次改动,是我们在和 Claude Code 的对话里直接做的;8 月加温度的是 Codex,同样在对话里完成。那时我们自研的工作平台 APSer-Atelier 还在搭建,没有组织这个组件;8 月 22 日,它的自动链路第一次在这个组件的代码仓里做了一次改动。今天我们做类似的事,分三个角色:我们负责提需求、拍板和在真机上验收;AI 编程工具作为执行器,负责写代码;APSer-Atelier 作为主控,负责组织:建项目、登记、把每件事从提出到验收串成一条记录、决定交给哪个执行器、挂起待拍板的问题、记下每一条要求,并用钩子在出错的当下拦住;执行器换了,事情也能在原来的记录上接着做。主控只做组织,代码由执行器写。平台的来历见《APSer-Atelier 的场景锚定与价值定位,以及实践总结》,钩子的做法见《从记忆、规则到钩子》。
这里说的 APSer-Atelier 主控包括两部分:面对我们的主控会话(一段 Claude Code 或 Codex 对话),负责组织和派出;Atelier 平台,负责登记每一件事、挂起待拍板、记下要求、按规矩放行并留下记录。
本文按时间写这个小工具的经过,以及其中的体会,不讲怎么做。

组件的完整显示:上半部分是本机的 CPU、内存和温度,下半部分是各项服务的在线状态。在线人数、论坛新帖和公司那台 Mac 的一段已打码。
一、第一天,组件怎样从看本机走到看线上服务?
6 月 10 日上午的第一版:CPU、内存的实时百分比,各带一条迷你折线图;没有标题栏,靠拖动移动窗口、双击折叠;右键菜单里有开机自启和退出。
当天傍晚,我们想顺便看一眼几个线上服务是否正常。18:37,组件加了「服务」一段:官网、论坛、格友搭子服务各占一行,一个状态点加一个延迟。第一次对真实生产服务器探测,三个目标全通,延迟分别是 299、340 和 137 毫秒。
这一版就定下了一条之后始终没有变的规矩:所有网络请求都放在后台线程里做,界面的刷新循环只读结果。一个请求超时,最多是那一行晚一点更新,窗口不会卡住。
还有一处和本机环境有关:本机开着的代理软件,对国内域名的判断有时不准,探测结果会被它带偏。所以组件的远程请求绕开系统代理,直接连接。
第二天,服务行下面多了一行小字:官网和论坛的在线人数、论坛最新的帖子、格友搭子最新注册的用户。这些数据要登录才能读,账号和密钥在组件里录入,用 Windows 自带的加密接口保存,只有这台机器上的这个账户能解开,磁盘上不留明文。后来又加了一条:凭证只通过 HTTPS 发送,地址一旦写成 http,就只探测可用性,不带凭证。
一天之内,这个小窗口的用途就从「看看本机忙不忙」变成了「看看线上服务好不好」。6 月 16 日凌晨,公司那台做开发和本地推理的 Mac 也加了进来:CPU、内存、磁盘,以及本地大模型服务和代理是否在线。
二、代码在 Mac、组件在 Windows,两台机器之间出了什么问题?
这个组件有一个特殊之处:代码在 Mac 上写、在 Mac 上保存,组件只能在 Windows 上运行。它用到的加密接口、开机自启、毛玻璃效果都是 Windows 独有的,在 Mac 上只能做语法检查,跑不起来。
6 月 16 日,两台机器之间出现了漂移:Mac 上改完了,没有推送到远端仓库,Windows 这边拿不到新版本,看到的还是旧的。
当天上午 10:52,组件有了自更新:右键「检查更新」,在后台比对远端,有新提交就拉取并自动重启。随后又加了两样:右下角显示当前版本号,一眼就知道跑的是哪一版;每天 12:00 自动检查一次。
这一天一共 18 次提交,其中有几次是修 Mac 上看不出来的问题:
- 点了没反应。 检查更新的结果写在界面上的一行小字里,而那行字每秒被刷新一次,提示不到一秒就被冲掉了。改成弹窗之后才看得到。
- 版本历史只显示第一行。 右键「版本更新历史」打开的窗口,在 Windows 上只显示第一行日期。第一次修完,AI 报告已经解决;随后发现这个结论建立在一个没有核实的前提上(用来判断的那段文字,未必是从组件里复制出来的),便撤回了结论,换了一种写法重做,前后改到第三次才完整显示。
- 圆角的黑角。 11:33 加的圆角,当时看起来是好的;半小时后发现四个角各有一块黑色直角。当时看不出来,是因为窗口背后的桌面恰好也是深色。改用系统自带的圆角机制后才干净。

右键「版本更新历史」打开的窗口,现在每一条记录都完整显示。
中午 12:42 到 13:22 的五次提交都是文档核对:拿代码逐项对照说明文件,改正了几处已经落后于代码的描述,包括监控类型数写错、右键菜单漏列两项、代码注释没跟上新加的功能。
这一天的体会:Mac 上编译通过,只说明语法没错;组件能不能用,只有在它真正运行的那台机器上看过才算数。一个「看起来好了」的结果,也可能只是背景恰好遮住了问题。
三、推送到手机,遇到了哪些坑?
6 月 17 日晚上,我们想在论坛有新帖、格友搭子有新注册时,手机上能收到通知。
22:24 的第一版,推送走企业微信的群机器人。第一次见到的帖子和注册只记下来作为起点,不补推历史,免得刚装好就刷屏;之后每出现一条更新的,推一次。
不到一个小时就发现走不通:我们是一人公司,企业微信的通讯录里只有自己,而建群至少要两个人,建不了群,也就用不了群机器人。23:20,推送改走企业微信的「自建应用」,消息直接发到个人。
改完之后又遇到一个坑:自建应用发消息,要求把运行机器的公网出口 IP 加进后台的「可信 IP」名单,否则会被拒绝。把 IP 补进去之后,23:28,论坛新帖和新注册都在手机上收到了。这个坑写进了说明文件:公网 IP 一变,推送就会失败。
第二天早上,我们发现有一条新注册没有收到通知。查下来,最可能的原因是:组件在推送之前就把「已推送到哪一条」的记录往前挪了,而且没有检查推送的结果。推送一旦失败,这条消息就被跳过了,界面上没有任何提示,事后也查不到。
08:07 的修复改了三处:
- 送达之后,才把记录往前挪;失败了就在下一轮(15 秒后)重试,直到送达;
- 每次自动推送的结果写一行日志,成功还是失败、错误码是什么;同一个错误只记一次,免得每 15 秒刷一行;
- 右键菜单加「查看推送日志」。这样收不到消息时,能分清是「没有触发」还是「推了但失败」。
后来群建起来了,08:41,群机器人重新作为主通道,自建应用保留为备用。群机器人不需要可信 IP 名单,公网 IP 变化导致的那类静默失败也就没有了。
这一段的体会:最费时间的是没有任何报错的失败。推送被吞掉、IP 变了之后的拒绝、一秒就被冲掉的提示,都属于这一类。让失败留下痕迹,比多加一个功能更要紧。
四、打包成单个程序之后,冒出了哪些新问题?
代码开发只在 Mac 上进行,我们不想在那台 Windows 笔记本上保留项目目录。6 月 19 日,我们把组件打包成一个单独的可执行程序,双击就能运行。这一步只能在 Windows 上做,Mac 上打不出 Windows 程序。
打包之后,组件的运行环境变了,问题也跟着变了:
- 自更新要关掉。 打包后的程序旁边没有代码仓库,原来的「检查更新」会直接报错。打包模式下,这两个菜单项不再显示,换新版靠重新打包。
- 开机自启要指向程序本身,原来写的是「用 Python 运行脚本」。
- 「查看推送日志」一点,整个程序直接退出。 打包成不带控制台窗口的程序后,调用系统默认程序打开文件,会在底层触发一次运行库的强制中止。这种崩溃发生在 Python 之外,代码里的异常捕获兜不住,只能从 Windows 事件日志里找到出错的模块和异常码。修法是不再调用外部程序,改在组件内置的窗口里显示日志。顺着同一个原因往下查,单击服务名打开浏览器用的也是同一类调用,在打包版里有同样的崩溃隐患,也一并改掉。
- 版本历史读不到变更记录。 打包后的程序运行时解压到临时目录,变更记录文件没有打进去。构建命令加上这个文件,并固定成一个构建脚本,免得下次用旧命令重打。
这些问题在源码直接运行时都不存在。同一份代码,源码运行和打包运行,是两种环境,要分别验。
五、8 月加温度,为什么只显示能如实读到的?
8 月中旬,我们想在组件上看到温度。
先动手的是另一款 AI 编程工具,它写了五个独立的草稿文件,留在 Mac 的工作目录里,没有提交。Windows 那边自然拉不到新版本。8 月 13 日早上,我们把这件事交给 Codex 接手。那时我们的主要工作已经转到 Codex,经过见《Claude Code、Codex 与 APSer-Atelier》。
Codex 先读了项目里的说明文件,再审草稿,结论是不能原样合入:草稿调用的温度接口,在 Windows 上的这个库里并不提供;它还引入了两个新依赖,和这个组件「单文件、只依赖一个库」的约定不符;草稿也没有接进主程序。
Codex 没有直接改代码,先在那台 Windows 笔记本上做了一次只读探测:系统自带的 ACPI 温区读数是 3010(单位是十分之一开尔文),即 27.85°C,和系统性能计数器里的数值一致。
这个读数来自主板固件划定的温区,不等于 CPU 核心温度。所以界面上写的是「ACPI 温区」。提交前的最后一轮复核还发现,标签一度只写了「温区」两个字,仍然可能被当成 CPU 温度,于是补全了。
我们接着问:CPU、主板、硬盘、显卡、内存的温度,还有风扇,是不是都缺了?
Codex 在真机上逐项核对后的答复是:
- 硬盘可以补。 固态硬盘的温度能从 Windows 标准的存储接口读到,验收时是 59 到 65°C,于是加上了,悬停时逐块显示硬盘名称和温度。
- 其余几类没有标准读数。 CPU、主板、显卡、内存的温度和风扇转速,在这台机器的系统标准接口里都没有分类的读数。系统里有 29 路动态温度值,但没有标明哪一路对应哪个部件,猜一个对应关系,就可能显示错的数。
- 要补全,需要外部的硬件监控程序。 这类程序要么要开启共享内存,要么要装驱动,都会改变这台机器的配置。Codex 没有替我们做这个决定,把选项和代价列了出来,交由我们定。

悬停在温度那一行上:逐项写明读数的来源,也写明还没有接入的部分。服务区的在线人数、论坛新帖和公司那台 Mac 的一段已打码。
同一轮里还修了一处真机上才看得出的问题:那台笔记本上保存的窗口宽度只有 231 像素,温度和原有的文字挤在一行,左边的字被截断了。温度单独成一行后,源码运行和打包运行都截图核对过,连续跨过两次 30 秒的采样,程序没有退出,也没有残留的后台进程。
当天早上,我们又问了一句:电脑上自带的管理软件能显示 CPU 温度,为什么组件不行?Codex 接着查了下去:那个软件通过自家的驱动读取硬件,对外只有没有文档的私有通道,没有公开接口;私有协议里可能还包含调节性能模式、风扇的命令,盲目试探有副作用。随后它又尝试只读地读取那个软件窗口里显示的温度数字,发现窗口没有把这个数字开放给辅助功能读取。到这里,Codex 停了下来,没有做这个对接。
中间还有一处 Codex 判断错了:它把管理软件内部的文件版本号当成了产品版本号,得出「需要先升级」的结论。我们截图给它看了真实的产品版本,它核对后撤回了这个判断。
最后留在组件上的温度只有两项:ACPI 温区和硬盘。读不到的,显示「--」。
六、9 月为什么要让不同的工具读同一份说明?
9 月的两次提交只改了文档:让项目的规则放在一份不同 AI 编程工具都会读的说明文件里,换一家工具接手,读到的是同一份规矩。这件事的来由,前面提到的那篇文章里写过。
这个组件的历次提交里,Claude Code 参与了 39 次,Codex 4 次;另有 1 次是 Atelier 的自动链路完成的:在隔离的写入环境里整理了变更记录的格式,核对后并入。
还有哪些没做?
- CPU、主板、显卡、内存的温度和风扇:需要外部的硬件监控程序,接不接、接哪一个,我们还没定。
- 打包版的更新:靠手动重新打包替换,没有自动更新。
- 备用推送通道:走自建应用时,公网 IP 一变仍需手动补名单;主通道没有这个问题。
以下是我们的看法
小工具的用途是用出来的。 第一版只看 CPU 和内存;服务状态、在线人数、手机推送、Mac 的状态、温度,没有一项是动手前想到的。先做出一个能用的版本放在眼前,下一步要什么,用着用着就清楚了。
跨机器的东西,验收只能在运行它的那台机器上做。 这个组件的变更记录里,反复出现「Mac 上编译通过,待 Windows 真机验证」这句话。编译通过、代码看起来合理,都不能代替在真机上看一眼;看的时候,也要想想眼前的「好了」会不会只是恰好。
读不到的,就不显示。 温度这件事,最省事的做法是挑一个看起来像 CPU 温度的数字显示出来。组件最后只显示能从公开接口如实读到的两项,读不到的写「--」。一个自己每天看的数字,如果不知道它到底代表什么,不如不显示。
写下来的记录,让换工具之后接得上。 6 月由 Claude Code 写,两个月后我们把它交给 Codex 接手加温度。Codex 能很快接上,靠的是项目里留下的说明文件:「单文件、只依赖一个库」「网络请求只在后台线程」这些约定,打包后踩过的坑和根因,都写在里面。变更记录里,每次改动也写了改什么、为什么、在哪台机器上验过。
如果您也想让 AI 帮您做一个每天用的小工具,可以先想两件事:它最终在哪台机器上运行,谁在那台机器上验收?出了问题,您从哪里能看到?