
用 Codex 这类 AI 编程工具做服务器监控面板是我经常拿来试 AI 能力的一个真实案例。表面看只是显示 CPU、内存、磁盘三个指标真正做下来会发现难点根本不在于画几张卡片而在于需求怎么拆、数据从哪里来、刷新频率怎么定、部署后能不能长期跑。这篇文章把一个完整流程拆开让 Codex 从零生成一个浏览器可访问的监控面板负责数据采集、JSON 接口和前端展示同时把每一步的验证方法、参数边界和常见坑写出来。适合刚接触 AI 编程、又经常要处理服务器运维或业务系统监控的读者。你不需要先会完整的 Web 项目但最好懂基本的 Linux 命令和 Python 语法。1. 难点不是让 Codex 画界面而是把监控需求拆成它能执行的任务1.1 一个看似简单的需求里藏着多少没说清楚的口径很多人拿到题目后第一句话会直接给 AI 发需求“帮我做一个服务器监控面板显示 CPU、内存、磁盘。”如果 Codex 只负责写代码它大概率会先给你一个能跑的界面但很多关键口径它根本不知道你只看当前值还是需要历史曲线CPU 是所有核平均还是每个核单独展示内存要看 used 百分比还是 available 可用量磁盘只看根分区还是所有挂载点页面多久刷一次1 秒还是 5 秒面板给谁看开发自己还是整个运维组页面要不要告警色阈值是多少数据要保留多久重启服务后要不要续上这些不写清楚Codex 第一版出来你一定会觉得“少了点东西”。但问题不在 Codex而在需求本身太模糊。真实项目里监控面板通常不是给电脑看的花哨大屏而是要解决“服务器现在到底行不行”的判断问题。判断标准不同采集和展示的逻辑完全不同。所以我给出的第一份提示词不应该只是“做监控面板”而应是一份带约束的任务说明。1.2 建议先拆成“采集、指标、接口、展示”四层这一层是整篇案例的地基。如果让 Codex 一个文件把所有事都干完后面遇到问题会很痛苦刷新慢了不知道是前端调用太频繁还是后端采集阻塞磁盘数据不对不确定是脚本读错分区还是浏览器换算错误。更稳妥的做法是先按链路拆开采集层读取系统里的 CPU、内存、磁盘数据。指标层统一字段名、单位、百分比和更新时间。接口层用 HTTP 返回 JSON网页只负责消费数据。展示层渲染卡片、进度条和最近更新时间。这样分层Codex 每次只需要在一个明确的小任务里改代码。测试时也能单独验证某一层而不是整条链路一起猜。另外这套分层可以复用到很多场景。今天监控 CPU、内存、磁盘明天想加网络流量、IO、进程列表结构不用推翻只需要在采集层加新函数在接口层加一个路由在展示层加一张卡片。1.3 开工之前先把验收标准写出来我给 Codex 下任务时不只写功能还会写“怎么算成功”启动后能在本机通过浏览器访问页面。/api/metrics返回 JSON字段名稳定。页面每 5 秒自动刷新一次不会出现明显卡顿和重复请求堆积。CPU、内存、磁盘三个指标能动态变化。数值可以和系统里的top、free -m、df -h对照差异在合理范围内。这些验收标准也方便后面做回归测试。Codex 改一版后直接按清单检查不用每次都重新想。2. 跑面板不需要高配机器但需要一个不骗人的数据来源2.1 为什么优先选 psutil而不是让 AI 自己读系统文件服务器监控面板最重要的不是页面好看而是数据准确。操作系统本身提供了大量统计信息比如 Linux 下的/proc/stat、/proc/meminfo、/proc/diskstats。但直接让 Codex 去解析这些文件很容易踩坑CPU 使用率需要两次采样时间差第一次容易得到 0。内存的 used、available、free 在不同内核版本上含义不完全一样。磁盘分区可能包含只读挂载、swap、伪文件系统过滤条件复杂。所以我在案例里让 Codex 使用psutil。它是一个跨平台的 Python 库把系统计数器封装成了稳定的函数。对 AI 编程工具来说用成熟封装比自己解析/proc更少出错代码也更短。反过来想如果 AI 生成的代码要读一堆底层文件表面看很“硬核”但后续维护成本很高。监控面板要的是稳定、可复用不是炫技。2.2 先准备一个最小可运行环境下面是以 Linux 服务器为例。如果是 CentOS、Ubuntu、Debian 这类常见发行版确认 Python 3 环境后安装两个依赖即可。python3 --version pip install psutil flask如果我是在临时环境里做测试会新建一个目录避免文件散落mkdir -p /tmp/server-monitor cd /tmp/server-monitor如果之后要长期部署就把目录放到/opt/server-monitor这类固定位置再考虑用户权限和 systemd 服务。Codex 的实际安装方式不同版本、不同发布渠道差别不小。最常见的路径是先装 Codex CLI再完成账号认证。具体怎么装请以你那个版本的官方文档为准。我不建议在项目里凭记忆乱猜安装命令否则后面很容易遇到“命令找不到”“certificate 问题”等干扰项。2.3 Codex 开始写代码前先确认三件事很多项目在 Codex 环节卡住不是代码问题而是使用环境没准备好。我一般会先确认Codex 命令能在当前终端里正常调用。当前目录是项目目录Codex 有权限读取和写入文件。允许 Codex 运行 shell 命令因为生成完代码后它可能要执行验证。如果担心 Codex 误改目录那就单独建一个测试目录别直接在正式项目根目录里乱放。等代码稳定了再手动搬到项目结构里。3. 采集模块让 Codex 生成能被手工验证的 CPU、内存、磁盘数据3.1 给 Codex 的第一份提示词进入正题。下面是我在这个案例里比较常用的一份提示词你可以直接复制到 Codex 对话里再根据自己环境改动请帮我创建一个服务器监控采集脚本 metrics.py满足以下要求 1. 使用 psutil 获取 CPU 总占用率、内存总量/已用/可用/使用率、根分区磁盘总量/已用/使用率。 2. 返回结构是字典并且所有数值都可以被 JSON 序列化。 3. 内存和磁盘大小单位保持字节bytes不要在函数里转成人类可读文本。 4. CPU 使用率用 interval1不要用 intervalNone避免第一次返回 0。 5. 增加一个“server_time”字段表示本次采集时间。 6. 不要使用额外的私有库只依赖 psutil。要求 3 很容易被忽略。让采集层只返回字节展示层再做格式化是因为前端需要看到原始数据。如果采集层就把单位换算成“GB”字面没问题但后续做阈值判断、历史记录时会很别扭。3.2 一个可运行的采集脚本长什么样下面这段是经过我验证后比较稳的一版。你让 Codex 生成的结果可能不完全一样但结构上可以对照参考。# metrics.py import time import psutil def collect_metrics(): cpu_percent psutil.cpu_percent(interval1) mem psutil.virtual_memory() disk psutil.disk_usage(/) return { server_time: time.time(), cpu_percent: cpu_percent, memory_total: mem.total, memory_available: mem.available, memory_used: mem.used, memory_percent: mem.percent, disk_total: disk.total, disk_used: disk.used, disk_percent: disk.percent, }这里有几个值得注意的细节。第一返回了memory_available而不是只返回memory_used。Linux 系统里内存被 page cache 占掉一部分是正常的很多时候free里的 used 很高但系统并不缺可用内存。available 更接近“还能再分配多少”的真实感受。第二所有字段都没有转成字符串。百分比是浮点数容量是整数。前端拿到后可以自己算也可以做格式化以后存历史数据也方便。第三CPU 采集使用interval1表示采集前先等 1 秒再统计这 1 秒内的 CPU 使用率。代价是这个函数每次调用会阻塞 1 秒。对单个请求来说还好但如果你设置了几百毫秒的定时器请求就会排队。3.3 采集模块的验证方法采集模块不要直接扔给接口层。先在命令行手工跑一次python3 -c import metrics; print(metrics.collect_metrics())成功时你会看到类似下面这样的输出{ server_time: 1710000000.123, cpu_percent: 4.2, memory_total: 16759728128, memory_available: 9346301952, memory_used: 7013744640, memory_percent: 41.8, disk_total: 107269324800, disk_used: 53687091200, disk_percent: 50.0 }然后拿这个结果和系统命令对照top free -m df -h比例不需要完全一样因为top、free的计算口径和 psutil 存在细微差异。但如果内存百分比差了 20 个百分点或者磁盘容量完全不是一个量级就要先停下来不要继续往后做接口。4. 把监控数据变成 JSON 接口前端不直接碰系统状态4.1 为什么不能在前端直接调用 psutil前端页面跑在浏览器里没有权限读取服务器操作系统的 CPU、内存、磁盘数据。就算能用一些浏览器 API 拿到浏览器的内存占用那也代表不了服务器本身。所以必须有后端接口这一层。后端启动一个 HTTP 服务提供/api/metrics接口。前端每隔几秒请求一次拿到 JSON 后更新页面。这个设计也为以后接入自动化告警、历史记录、外部监控系统留了路。4.2 用 Flask 写一个最小接口在项目目录创建app.pyimport time from pathlib import Path from flask import Flask, jsonify, send_from_directory import metrics BASE_DIR Path(__file__).resolve().parent app Flask(__name__) app.get(/api/metrics) def api_metrics(): data metrics.collect_metrics() data[server_time] time.time() return jsonify(data) app.get(/) def index(): return send_from_directory(BASE_DIR, index.html) if __name__ __main__: app.run(host127.0.0.1, port5000, debugFalse)测试时先启动python3 app.py然后在另一个终端请求接口curl -s http://127.0.0.1:5000/api/metrics能返回 JSON说明接口层通了。这里绑定的是127.0.0.1意思是只允许本机访问。如果你在远程服务器上调试不要急着改成0.0.0.0。先确认服务能在本机跑起来再考虑怎么安全地暴露给你自己或团队。4.3 接口刷新频率和 CPU 采集阻塞之间的关系前端如果想让页面刷新得很快比如 1 秒一次而这个接口内部 CPU 采集还要interval1就会出问题。原因很简单采集函数本身阻塞 1 秒。如果 1 秒轮询一次上一个请求还没处理完下一个请求又进来了。Flask 开发服务器虽然能并行处理一点请求但长任务堆积起来会让页面假死。更合理的方案是让前端 5 秒请求一次采集间隔仍是 1 秒。这样每次请求都有足够时间完成不会重叠加塞。如果你确实需要 1 秒内的实时更新正确做法不是把interval1改小而是把