kermt-monitor 是任何以分离方式运行的 KERMT 工作流的配套技能,适用于三个预训练技能(kermt-continue-pretrain、kermt-pretrain-scratch、kermt-add-cmim-pretrain)以及 kermt-finetune。kermt-infer 和 kermt-embed 默认以阻塞方式运行,不需要此技能;但如果用户有意以分离方式启动它们,监控仍然可用(工作流分发在步骤 4 中通过跟踪运行目录中最近修改的日志文件来处理未知工作流)。该技能读取运行目录的 run.json,查询 Docker 获取容器状态,展示最新进度,并跟踪或跟随日志。
硬件要求
无。此技能仅读取磁盘并查询 Docker,不涉及 GPU 计算。
输入
以下之一:
<run-dir> — 位置参数,指向包含 run.json 的目录(例如 runs/continue-pretrain_2026-05-17T10-23Z)。首选方式。
--container <name-or-id> — 直接引用容器;如果可用,技能仍会从容器 inspect 输出中引用的运行目录读取 run.json,但在没有它的情况下以降级模式工作。
可选参数:
--lines N — 要打印的末尾日志行数(默认 50)。
--follow — 流式输出 docker logs -f 直到 ^C。适用于“观察 loss”。没有它时,技能为一次性执行并退出。
--json — 输出结构化状态报告而非人类可读文本。当父智能体想要采取下游操作时有用。
工作流
令 RUN_DIR=$1(或用户提供的任何路径)。
定位清单文件。
MANIFEST=$RUN_DIR/run.json
如果不存在则拒绝继续;给出有帮助的消息,指向运行目录约定(runs/<workflow>_<ts>/)。
解析清单(Python 辅助):
workflow=$(jq -r .workflow $MANIFEST) container_name=... # 目前 run.json 中不直接包含;启动的技能在启动期间将其存储在 run.json 的 container.name 下(见下方注释)。 logs_dir=$(jq -r .logs_dir $MANIFEST) image_tag=$(jq -r .container.image_tag $MANIFEST) started_at=$(jq -r .started_at $MANIFEST)
查询 Docker 获取容器状态。
docker ps --filter "name=$container_name" --format
'{{.ID}}\t{{.Status}}\t{{.CreatedAt}}'
如果不存在,回退到 docker inspect $container_name --format '{{.State.Status}} (exit {{.State.ExitCode}})' 以查看容器是已退出(正常或失败)还是已被移除(退出后 --rm)。
查找实时日志文件。
case "$workflow" in continue-pretrain|pretrain-scratch) LOG=$logs_dir/pretrain_ddp.log ;; finetune) LOG=$logs_dir/finetune.log ;; ) LOG=$(ls -1t $logs_dir/.log 2>/dev/null | head -n 1) ;; esac
清单的 workflow 字段区分预训练(pretrain_ddp.log)与微调(finetune.log)。其他工作流回退到 $logs_dir 中最近修改的 .log 文件。
显示最新进度。
tail -n $LINES $LOG 获取原始近期输出。
解析最后几行进度并展示人类友好的摘要。格式因工作流而异:
预训练:epoch / step / val_loss
Current epoch: 12/100 step: 4523/9000 val_loss: 0.832 (best 0.821 @ step 4100)
微调:fold / epoch / val_(例如回归的 val_mae,分类的 val_auc — 从 run.json 读取 args_applied.metric)
Fold 0 epoch 12/30 val_mae 0.187 (best 0.182 @ epoch 9)
墙钟时间:自 started_at 起 1h 23m;预计剩余约 6h。
最终测试指标块(微调,完成时)。如果工作流为 finetune 且容器已干净退出(State.Status=exited,ExitCode=0)且 $RUN_DIR/ckpt/fold_*/test_result.csv 存在,解析它并输出每个任务的指标表:
Final test metrics (per task): Target MAE HLM_clearance 0.187 RLM_clearance 0.213 MDR1-MDCK_efflux 0.241 solubility_pH6.8 0.156
指标列与 args_applied.metric 匹配(回归为 mae,分类为 auc 等)。对于多折或集成运行,跨折/模型取平均,如果 std > 0 则注明 ± std。如果没有 test_result.csv 则静默跳过(运行未完成或未生成测试集)。
如果 --follow,流式输出实时日志。
docker logs -f $container_name
包装直到 ^C。
停止/清理提示(一次性模式结束时打印):
To stop: docker stop $container_name
To remove: docker rm $container_name
To re-run: $(jq -r .cmd_replay $MANIFEST)
硬性规则
对用户数据只读。绝不修改 run.json,绝不触碰容器的检查点目录。监控仅进行检查。
未经用户明确指示,不要杀死容器。如果用户要求停止,运行 docker stop;如果他们要求放弃,保持运行并直接退出。
不要拉取或修改 kermt 镜像。监控仅读取。
JSON 输出模式为非交互式。跳过“按 ^C 退出”提示,输出单个 JSON 文档,以便父智能体可以管道处理。
关于 container_name 接线的说明
当前编写的 run.json 模式尚未包含启动的容器名称 — kermt_run_detached 将其打印到 stdout,但运行脚本未将其捕获到 run.json。监控回退到基于文件系统的查找:列出 runs/<workflow>_*/ 目录并按 mtime 匹配;或显式接受 --container <name>。后续:让启动技能在退出前将容器名称记录到 run.json。
输出(文本模式,默认)
KERMT continue-pretrain · runs/continue-pretrain_2026-05-17T10-23Z Container : kermt-continue-pretrain-… (Up 1 hour, status: running) Image : kermt:latest@sha256:… Repo : 2fe00f9 (clean) Started : 2026-05-17T10:23:14Z (1h 23m ago) Workflow : continue-pretrain, pretrain_mode=hybrid, world_size=2
Latest log (last 50 lines from $LOG): [Epoch 12/100] step 4523/9000 loss 0.832 lr 1.2e-4 [val] step 4100 val_loss 0.821 (new best) ...
Progress: epoch 12/100, ~12% done. ETA ~6h. TensorBoard: tensorboard --logdir $RUN_DIR/logs/tb Replay command: $(jq -r .cmd_replay $RUN_DIR/run.json)