跳转到内容

v0.3 验收记录(Agent-native Training)

环境:控制面 + agent 部署于 WSL2(RTX 5090 32G);MacBook 经 SSH tunnel(127.0.0.1:18601)驱动验收。 日期:2026-08-19。验收标准(roadmap §3):Claude Code 配置 MCP,自然语言完成“提交训练 → 盯异常 → 对比 checkpoint → 给推荐”,全程无人工平台交互

v0.3 把 GPUPlane 从“人点 Web/CLI”升级为“Agent 用自然语言驱动整个实验循环”。当前交付物 = MCP server(20 工具)+ 语义层(5 函数,纯规则无 LLM)+ 3 个 skill + 插件打包 + AGENTS.md。

端到端主链路(自然语言,全绿)

Section titled “端到端主链路(自然语言,全绿)”

Agent(claude -p,仅给 .mcp.json + 仓库 skill/AGENTS.md,无任何人工平台操作)执行下述循环:

步骤 Agent 动作 结果 证据
1. SUBMIT submit_job(command=["python3","-c","…5 步 loss…"], working_dir="/tmp", gpus=0, cpu_only=True, project="accept") ☑ QUEUED 返回 job_01M0AY8X113V1T9ZEETZ76F8GG + TaskHandle(ttlMs=86400000, pollIntervalMs=15000, next_actions 指向 get_job/get_run_summary
2. MONITOR 轮询 get_job(job_id)tail_logs ☑ SUCCEEDED exit 0 5 行日志:step 0 train/loss=1.000step 4 train/loss=0.200
3. COMPARE compare_runs(两个带 val_loss eval 的最近 run) ☑ winner run_01M0AJWY6TW6D1P9KS6FZ07BGEis_best:true 两 run 训练曲线并列 best 0.35/latest 0.45;winner 因有完成的评估胜出
4. DIAGNOSE diagnose_run(run_id=winner) ☑ SUCCEEDED,无异常/OOM/NaN/health warning best val_loss 0.35 @ step 200,latest 0.45 @ 300,improving:false
5. BEST ckpt get_best_checkpoint(run_id=winner) ckpt_01M0AJXDRDW6BKSE1RXAT69B0X step 200 value 0.31 语义层优先用评估结果(0.31)而非训练兜底值(0.35)
6. RECOMMEND 自然语言给结论 “保留 ckpt_…69B0X(step 200,eval val_loss=0.31);step 300 回退到 0.45,应早停在 200”

Agent 原话(focused compare→recommend run):

Recommendation: Keep ckpt_01M0AJXDRDW6BKSE1RXAT69B0X (step 200, evaluated val_loss=0.31) from run run_01M0AJWY6TW6D1P9KS6FZ07BGE. compare_runs picked this run as best; diagnose_run shows it finished cleanly — no OOM, NaN, or stalls — with the minimum at step 200, while step 300 regressed to ~0.45, so early-stopping at 200 is the right call. The 0.31 evaluation value is the trustworthy one (the semantic layer prefers evaluation results over the 0.35 training-run best).

tools/list 经 adapter 返回 20 工具,分三层:

工具 说明
Observe(11) list_nodes get_node_status list_jobs get_job get_run_summary query_metrics tail_logs list_events list_checkpoints list_evaluations list_metric_definitions 只读,read scope token 即可
Control(4) submit_job evaluate_checkpoint cancel_job retry_job 写域 token 才暴露;cancel_job(confirm=False) 显式拒绝
Semantic(5) diagnose_run compare_runs compare_checkpoints get_best_checkpoint explain_failure 纯 Python 规则+统计,无 LLM;每个结果带 next_actions 引导 agent 下一步

启动日志确认写域 token 解锁全部工具:

gpuctl-mcp: token 'admin' has write scope (all tools available).
gpuctl-mcp streamable-http on http://127.0.0.1:18603/mcp -> http://127.0.0.1:18601

只读 token 下 submit_job/cancel_job/retry_job/evaluate_checkpoint 返回 WriteScopeError(“requires a write-scope token”)。

验收顺带抓到并修复的真实配置问题

Section titled “验收顺带抓到并修复的真实配置问题”
# 现象 根因 处置
1 get_best_checkpoint 首跑 404 “no checkpoints with the primary metric found” 历史种子数据把 eval/acc 设为 primary,但实际 run 记录的指标名是 val_loss;语义层按 primary 名匹配,查不到 PUT /metric-definitions/val_loss {is_primary:true} + 清掉 eval/acc/eval/accuracy 的 primary;修复后 get_best_checkpoint 干净返回 ckpt-200/value 0.31

这是语义层“该暴露就暴露”的正面案例:指标名与 primary 配置错配时,get_best_checkpoint 不猜、返回明确 404 + 提示(“set a metric_definitions.is_primary and evaluate or train”),Agent 据此诊断并给出修复建议,而非静默兜底一个错误 checkpoint。

语义层(5 函数,纯规则 + 统计,无 LLM)

Section titled “语义层(5 函数,纯规则 + 统计,无 LLM)”

packages/server/src/gpuctl_server/semantics.py —— REST 与 MCP 都只是薄暴露层,核心是确定性 Python 函数:

  • diagnose_run(db, run_id) → RunDiagnosis:收敛性(best/latest/is_improving/is_stalled)、异常集(ANOMALY_TYPES)、health warnings、next_actions
  • compare_runs(db, ids, metric) → 按方向(maximize/minimize)排名 + is_best 标记
  • compare_checkpoints(db, ids, metric) → 同上,checkpoint 粒度
  • get_best_checkpoint(db, run_ids|experiment_id, metric) → 优先用 SUCCEEDED 评估的 primary,无评估时兜底训练 run 的 best 值(弱信号,结果里标 source
  • explain_failure(db, run_id|job_id) → FailureExplanation:扫日志/事件模式(CUDA OOM / NCCL / ModuleNotFoundError…)+ exit_code → likely_cause + suggested_fixes + next_actions(如 OOM 后 retry_job

每个返回都带 next_actions: [NextAction(tool, args, reason)],由平台引导 Agent 下一步。

.claude/skills/gpu-training/{run-experiment,monitor-experiment,analyze-results}/SKILL.md,6 字段 frontmatter,allowed-tools 预授权 MCP 工具,references/ 按需加载:

Skill 触发 工作流
run-experiment 提交/跑训练 list_nodes→submit_job→poll get_job→get_run_summary→交给 monitor
monitor-experiment 盯训练异常 分钟级 watch loop + 异常 runbook 表(LOSS_NAN/OOM/OVERFITTING/GPU_UNDERUTILIZED/AGENT_DISCONNECTED/DISK_LOW)+ 失败 triage(explain_failure→tail_logs,OOM 不盲目重试)
analyze-results 对比/选 ckpt compare_runs→compare_checkpoints→get_best_checkpoint→evaluate_checkpoint 补评估→keep/revert 循环
  • .claude-plugin/plugin.jsonmcpServers.gpuctl stdio 启动 gpuctl-mcp stdio,env 注入 GPUCTL_SERVER_URL + GPUCTL_MCP_TOKEN;技能与 hook 随插件分发。
  • .mcp.json(仓库根,已 gitignore 含真实 token):{"mcpServers":{"gpuctl":{"type":"http","url":"http://127.0.0.1:18603/mcp","headers":{"Authorization":"Bearer …"}}}},供 claude -p 直接发现。
  • AGENTS.md(canonical)+ CLAUDE.md(mirror):仓库级 agent 规则(裸进程+SQLite 红线、实验循环、metric/job/ckpt 约定、OOM runbook、Tailwind v4 令牌 gotcha、部署命令、“never commit ./server ./–help”)。
  • gpuctl-mcp 独立进程/独立包(design §15):packages/mcp,fastmcp 3.4.7 pinned + mcp>=1.29,<2(mcp 2.0 是硬破坏,绝不与 fastmcp3 混装);坏了不影响 server。

验收期间 adapter 以 gpuctl-mcp serve --port 18603 独立进程跑在 Mac,经 tunnel 转发到 WSL server:

claude -p ──MCP/HTTP──► gpuctl-mcp (Mac:18603) ──REST/Bearer──► server (WSL:8600 via tunnel :18601)

各模块交付清单(roadmap §3 全 6 项)

Section titled “各模块交付清单(roadmap §3 全 6 项)”
模块 状态 交付
gpuctl-mcp 包(20 工具) fastmcp 3.4.7 pinned,streamable HTTP stateless 核心;11 observe + 4 control + 5 semantic;独立进程/包
语义层(5 函数) diagnose_run/compare_runs/compare_checkpoints/get_best_checkpoint/explain_failure;纯规则+统计,无 LLM;返回结构化 JSON + next_actions
Skills(3 个) run-experiment / monitor-experiment / analyze-results;6 字段 frontmatter,allowed-tools 预授权 MCP 工具,references 按需加载
插件打包 .claude-plugin/plugin.json(stdio MCP + skills + hooks);.mcp.json(http,gitignored)
AGENTS.md 仓库级规则(canonical),CLAUDE.md 镜像
读写域分级 GET /auth/whoami 暴露 {name,scope,can_write};写域 gate submit/cancel/retry/evaluate,只读 token 返回 WriteScopeError

uv run pytest tests/ -q107 passedtests/test_mcp.py 15 例:19 工具注册、bearer 转发、查询参数、语义 JSON、错误透传、whoami、submit body+handle、写域拒绝、cancel confirm gate + result 字段回归、evaluate/retry 转发、query_metrics names CSV 回归、get_job run_id 透传;test_server_api.py 语义端点 diagnose/compare/best + explain_failure 真机场景 + 收敛 stalled/improving、job_id 过滤、单 primary、get_job run_id、retry attempt 回归)。ruff + mypy 全绿。

真机功能复测:发现并修复的 2 个 bug

Section titled “真机功能复测:发现并修复的 2 个 bug”

验收后开独立测试 subagent 对 19 工具 + 5 语义端点 + 写域 gate + 边界做逐项复测,整体 PASS,抓到 2 个 MCP 适配层与 REST 契约错位(均不崩溃,已修 + 加回归测试):

# 现象 根因 修复 + 回归
1 cancel_job(confirm=True) 的 TaskHandle 恒报 state:"working", status:null server.pyjob.get("status"),但 REST POST /jobs/{id}/cancel 返回 {"job_id","result":"CANCELLED"|"cancel-requested"|…}(无 status 键) server.py 改读 resp["result"]result=="CANCELLED"state:"cancelled",否则 workingstatus=result。回归测试覆盖 CANCELLED + cancel-requested 两态;原测试 mock 用错形状({"status":"CANCELLED"})故漏报,已修正为真实 REST 形状
2 query_metrics(names=["train_loss","val_loss"]) 静默只返回 1 条序列 client.py 把 list 直接塞 httpx params → ?names=a&names=b;REST 路由声明 names: str + split(","),FastAPI 对重复同名参数只绑单值,丢一个 client.py",".join(names) 再发 → ?names=a,b。REST 层复现确认:CSV 形式返回两序列,重复形式只返一。回归测试断言 URL 恰含一个 names= 且两名都在

真机回归(fix 后经 tunnel 实测):cancel_job 对 CANCELLED job 返回 state:"cancelled", status:"CANCELLED"query_metrics(names=[train_loss,val_loss]) 返回两序列各 3 点(train 0.9/0.8/0.7,val 0.6/0.35/0.45)。

端到端真实研究员流复测:发现并修复的 7 个集成问题

Section titled “端到端真实研究员流复测:发现并修复的 7 个集成问题”

再开一个 fork subagent 扮演真实研究员,用高保真 torch-free 模拟训练脚本(纯标准库 + gpuctl SDK 真上报指标/checkpoint + lr 驱动的真实 loss 曲线 + 可控失败模式 oom/nan/overfit)跑 lr-sweep:submit×4(好/发散/欠拟合/OOM)→ 监控 → explain_failure → retry → evaluate → compare → recommend,外加 claude -p 自然语言流测 skill 层。原子逐工具测试漏掉、只有连贯真实工作流才暴露的 7 个问题(已修 + 回归测试 + 真机回归):

# 等级 现象 根因 修复 + 回归
1 HIGH diagnose_run 把健康收敛 run 误判 stalled(latest==best 时 stalled=true)→ 误导早停 _is_stalledabs(latest-best)<=eps,latest 等于 best(仍在创新 best)被判停滞 改用 trend:仅 trend=="stable" 才 stalled;unknown/短序列 → False(不哭狼)。回归:8 点递减 run(latest==best)stalled=False,8 点平 run stalled=True
2 HIGH diagnose_run 对短序列(<5 点 trend=unknown)误报 improving=false _is_improvingtrend=="unknown" 落到默认分支返回 False trend=="unknown" → 返回 None(数据不足),不报 False。回归:4 点递减 run improving=None
3 HIGH GET /runs?job_id= 静默忽略,返回全部 run → agent 按文档传 job_id 拿到未过滤列表、映射错 run list_runs 路由 + store 都无 job_id 参数 路由 + store 加 job_id 过滤。回归:两 job 各一 run,?job_id= 只返对应一个
4 MED metric_definitions 允许多个 is_primary=true 共存,_primary 静默选一个(实测 eval/loss + val_loss 同时 primary) upsert_metric_def 不清旧 primary 设新 primary 时先 UPDATE … SET is_primary=0 WHERE is_primary=1 AND name<>?。回归:连设 a、b primary 后仅 b 为 primary
5 MED get_job 返回无 run_id,但 TaskHandle next_actions 指向 get_run_summary(run_id)/diagnose_run(run_id) → submit→monitor→analyze 衔接断裂 Job 模型无 run_id 字段 Job 加 run_idget_job/list_jobs SQL 加 runs.job_id 子查询 join 填充。回归:链 job→run 后 GET /jobs/{id} 返回 run_id;无 run 的 job 返 None
6 MED explain_failure 对 OOM 建议直接 retry_job,但 retry 复用原 command → OOM 必复发,与 CLAUDE.md “改 config 再 retry” 冲突,诱导必败重试 next_actions 无差别建议 retry_job OOM/NaN 时 reason 改为“先应用 suggested_fix(减 batch/降 lr)再 retry,原样重跑必复发;或 submit_job 改参”。回归:断言 retry_job 的 reason 含 unchanged/fix
7 MED retry_job 不递增 attempt,重试计数不可见 retry 路由未 bump attempt retry 时 attempt=job.attempt+1。回归:两次 retry 后 attempt=1→2

真机回归(fix 后部署 WSL 经 tunnel 实测):GET /jobs/{id} 返回 run_id 正确;GET /runs?job_id= 只返对应 run;diagnose_run 对收敛 run(best=latest=0.195, trend=unknown)返回 improving=None, stalled=False;live DB 仅一个 primary。107 tests pass(+7 回归),ruff + mypy 全绿。

当时未改的设计层面问题:adapter 偶发 “Event loop is closed”;多 run 共用 working_dir 时 checkpoint 路径碰撞。二者已在 2026-08-20 发布验收中修复并由 GPT-5.6 Luna 原生 MCP 真机复验,见 09-v0.3-release-acceptance.mdclaude -p 一次性长 prompt 的客户端耗时仍建议通过拆步控制。

原生 MCP 黑盒复测(round 4):真研究员 agent,5 个语义层问题

Section titled “原生 MCP 黑盒复测(round 4):真研究员 agent,5 个语义层问题”

前三轮:round 1 端到端、round 2 逐工具原子、round 3 连贯真实工作流(fork,但用 curl/python 调 MCP HTTP = “coding”)。round 4 纠正方法学——真 agent 模式:把 19 个 MCP 工具作为原生工具注册进 Claude Code(.mcp.json + /reload-plugins),开一个全新 general-purpose subagent(非 fork,不继承父上下文 = 防作弊)只凭 mcp__gpuctl__* 工具 + 读 CLAUDE.md/skills 驱动整套 lr-sweep,禁止packages/ 源码、grep/glob、ssh/curl。这套工作流暴露的全是前几轮没抓到的语义层问题(run 级语义忽略 checkpoint 评估):

# 等级 现象 根因 修复 + 回归
1 HIGH compare_runs训练 best 排名,无视 SUCCEEDED checkpoint 评估 → 能把“晚段过拟合”的 run 误评为最佳,与 get_best_checkpoint(eval 优先)结论相左 compare_runs 只读 summary.best,不读评估 Fix A:eval 优先、训练 best 兜底(与 get_best_checkpoint 同一 _best_eval 助手)。回归:训练 best 0.91 但 eval 0.70 的 run 输给训练 best 0.80 但 eval 0.85 的 run
2 HIGH explain_failure 对 OOM 建议 retry_job,但 retry 复用原 command → OOM 必复发,与 CLAUDE.md“改 config 再 retry”冲突,诱导必败重试 next_actions 无差别 retry_job Fix B:OOM/NaN 改建议 submit_job,把原 command 作为 args.command 基底交给 agent 改(减 batch/降 lr),reason 注明“retry_job reuses this command and re-fails identically”。回归:OOM run 的 next_actions 不含 retry_job,含 submit_job 且 args.command == 原 command
3 HIGH diagnose_run 只报训练收敛(best/best_step/improving/stalled),对 heldout 评估盲——实测报 best_step=40,而 get_best_checkpoint 指向 step 10(早停点),自相矛盾,且无过拟合信号 diagnose_run 不读 checkpoint 评估 Fix D:convergence 加 eval_best/eval_best_step(同一 _best_eval 助手);当 eval_best_step < train best_step 触发 OVERFITTING health warning + 指向 eval-best ckpt 的 next_action。回归:训练 best 0.91@step3 / eval best 0.95@step1 → overfit warning + eval_best_step=1
4 发散/欠拟合 run 不被 EventDetector 标为事件(NaN/OOM 之外的学习病理无覆盖) EventDetector 只覆盖 OOM/NaN/disconnect 未改(更大的 EventDetector 增强,提议后续:divergence=loss 单调上升、underfit=末段 loss 仍高于阈值)
5 LOW evaluate_checkpoint 的 TaskHandle status:null(与 submit_job 的 status:"QUEUED" 不一致);explain_failure 的 suggested_fix 静态通用 adapter 未设 status;fixes 无 run 上下文 Fix C:evaluate TaskHandle status="QUEUED"(与 submit_job 对齐)。回归在 test_mcp.py。explain_failure run-aware fixes 提议后续

真机回归(fix 后部署 WSL 经 tunnel 实测,round 4 的 sim 数据仍在 live DB):

  • Fix Da3-lr1e3-good run 4 个 checkpoint(step 10/20/30/40,heldout eval/loss 0.1596/0.1726/0.1838/0.177)→ diagnose_runconvergence.eval_best=0.1596 @ eval_best_step=10(训练 lens best=0.1963 @ best_step=40),因 10<40 触发 OVERFITTING health warning;get_best_checkpoint 一致指向 step-10 ckpt。
  • Fix Acompare_runs(a3-good, a2-good) 两 run 的 best 字段均为 0.1596(eval-best 值),非训练 latest 0.1963——eval 优先生效,且与 get_best_checkpoint 同值(两语义函数收敛一致)。
  • Fix Bexplain_failure 对 OOM run 返回 submit_job(args.command = 原 --fail-mode oom --batch-size 64 命令基底),next_actions retry_job,reason 注明“re-fails identically”。

109 tests pass(+3 回归:compare_runs eval-preference / diagnose_run eval+overfit / explain_failure submit_job),ruff + mypy 全绿。

方法学结论:round 2 逐工具、round 3 连贯工作流都漏掉了这 3 个 HIGH,因为它们是跨函数一致性问题(compare_runs vs get_best_checkpointdiagnose_run vs get_best_checkpointexplain_failure vs retry_job 语义)——只有真 agent 在完整循环里同时调用多个语义函数、并交叉比对结论才暴露。原生 MCP 注册(非 coding)+ 黑盒防作弊是关键:agent 看不到源码,只能靠工具返回的字段推理,正好复现真实研究员的视角。

round-4 修复的黑盒复验(同一 researcher,native MCP)

Section titled “round-4 修复的黑盒复验(同一 researcher,native MCP)”

修复部署 WSL 后,同一 researcher subagent(保留黑盒约束:只调 mcp__gpuctl__* + 读 CLAUDE.md/skills,不读源码/不 grep/不 ssh+curl)对 3 个 HIGH 做了 native-MCP 复验,全 FIXED,循环端到端 clean

  • Fix Acompare_runs 两 good run 各 best=0.1596(heldout eval)、latest=0.1963(训练,正确降级到 latest);winner a3-lr1e3-goodget_best_checkpoint(step-10 ckpt, value 0.1596)一致。
  • Fix Ddiagnose_run convergence 同时含训练(best=0.1963 @ best_step=40)与 heldout(eval_best=0.1596 @ eval_best_step=10);health_warningsOVERFITTINGnext_actions 指向 eval-best ckpt。与 get_best_checkpoint 一致——前述“diagnose 说 step 40 / best 说 step 10”的矛盾已消。
  • Fix Bexplain_failure 对 OOM run 的 next_actions[0] = submit_job(args.command = 原 OOM 命令基底), retry_job;reason 注明 re-fails identically。round-4 的“OOM 死路”消除。
  • 端到端:fresh 提交 a3-verify-loop(cpu_only, 5 步)→ submit_job QUEUED → get_job SUCCEEDED exit 0 → get_run_summary SUCCEEDED step 5、best eval/loss 0.1641@5、health 干净。submit→get_job→get_run_summary 链通。

残留非阻塞:复验期间 4 个 compare_runs 并发调用时,首个偶发 "Event loop is closed"(传输层,fastmcp stateless),裸重试即返正确 payload。这是 round-3 已记的“首请求偶发”的精化——并行负载下也会触发(非首个请求专属),不破坏正确性但真实 agent 并行调语义函数时会撞到、需重试。建议后续硬化 adapter 的 asyncio 生命周期(per-request client/loop 隔离),但属 fastmcp 薄适配层、可独立于 server。

原生 MCP 黑盒复测 round 5:更宽 lr sweep + 真过拟合 run

Section titled “原生 MCP 黑盒复测 round 5:更宽 lr sweep + 真过拟合 run”

换一个全新 general-purpose subagent(sim5,非 fork,黑盒防作弊同前),场景比 round 4 更宽:4 个 lr(5e-4/1e-3/2e-3/3e-3,跨收敛边界找真“最佳”)+ 一个刻意 --fail-mode overfit run(直压 round-4 新增的过拟合检测)+ experiment 级 get_best_checkpoint(experiment_id=)(前几轮只测 run 级)+ 边界探针(cancel 运行中 job、不存在的 run、单 id compare、无 eval 的 experiment 取 best、多指标 query_metrics)。

找到 1 个 HIGH(round-4 Fix D 的自动过拟合警告是反的)+ 4 个待设计层增强

# 等级 现象 根因 处置
H1 HIGH 过拟合检测反了:健康 winner run(r5-lr1e-3)被误报 OVERFITTING;真过拟合 run(r5-overfit)反而无警告 Fix D 的条件 eval_best_step < best_step,但 best_step 取自 primary(eval/loss)的训练期 in-training 流最佳步——不是训练 loss。过拟合 run 的 in-training eval/loss 也从 step 10 起恶化,故 10<10 false → 漏报;健康 run 的 in-training eval/loss 仍下降到 step 40,故 10<40 true → 误报。任何 step-比较启发式都不对:正确信号需 train 轨迹 vs eval 轨迹对比(短序列安全) 本轮回退 Fix D 的自动警告:移除 OVERFITTING health warning + 其 next_action;保留 eval_best/eval_best_step 字段(正确数据,agent 据此自行推理——sim5 自己就用这些字段+tail_logs 得出正确结论)。真过拟合检测归入 EventDetector(下方 Problem 4,已据此细化)。回归测试改为断言“字段 surfaced + 不发误报警告”。live 验证:健康 winner 现 health_warnings=[]、字段仍在;过拟合 run 字段仍在、best=1.1366@step10(in-training eval/loss 已峰值)留给 agent 推理
M1 MED experiment 级 get_best_checkpoint(experiment_id=)compare_runs值并列时选不同 winner:两者 step-10 eval/loss 都 0.1596(sim 持数确定性并列),get_best_checkpoint(experiment_id=) 把“要保留的 ckpt”指向了过拟合 run 的 checkpoint,而 compare_runs 选了健康 run tie-breaking 按迭代序取首个,未偏向健康 run;且不提示存在 tie 待增强:tie 时偏向 compare_runs/diagnose 健康的 run,或在结果里显式标注并列。属推荐层设计
M2 MED 过拟合 run 的 list_eventsOVERFITTING_SUSPECTED 事件(monitor skill 异常表列了该信号却未触发) EventDetector 不检测过拟合(同 H1/Problem 4) 待增强:EventDetector 加过拟合信号(与 H1 同一 detector)
L1 LOW-MED eval/loss/eval/accuracy每个 run 都 trend=unknown(4 点 < summary.py 的 5 点阈值),即便过拟合 run 的 in-training eval/loss 单调恶化 1.14→1.44→2.34→3.44。只有 train/loss 有真 trend。这饿死了 trend-式过拟合检测 eval 序列点少(eval-every=10、40 步只 4 点)→ trend unknown 待增强:eval 指标用更短阈值或 first-vs-last 兜底;或 EventDetector 用直接首末对比绕过 trend
L2 LOW eval job 名泛化(eval-10..eval-40),跨 run 重名,list_jobs 不读 command 无法区分属于哪个 run/checkpoint evaluate_checkpoint 不给 eval job 起 run-aware 名 待增强(小):eval job 命名 eval:<run_name>:step<N>
L3 LOW MCP 面无 metric-definitions 工具,agent 无法经 MCP 列/设 primary 指标(skill 文档指向 REST) 19 工具未覆盖 metric-definitions 待增强(小):加 list_metric_definitions(只读)MCP 工具

边界探针(clean,无问题)diagnose_run(不存在 run) → 干净 404;get_best_checkpoint(无 ckpt/eval 的 run) → 干净 404 + helpful hint(“set a metric_definitions.is_primary and evaluate or train”);compare_runs(单 id) → 正常 is_best=true;query_metrics([train/loss,eval/loss]) → 两序列各返;tail_logs(过拟合 job) → 逐步日志确认恶化;cancel_job(confirm=True) on RUNNING throwaway → CANCELLED、exit -15、RUN_FINISHED(warning) 事件(危险操作守护生效)。

本轮修复:回退 Fix D 的自动过拟合警告(H1,correctness——发错的信号比不发更糟),保留 eval_best 字段。109 tests pass(回归测试改为断言字段 surfaced + 无误报),ruff + mypy 全绿,WSL live 验证健康 winner 的误报已消。

结论细化:v0.3 的 run 级循环(submit/poll/eval/compare/tail/cancel)端到端 solid;但experiment 级推荐层尚不可全信——三分析函数在并列时会指向不同 winner(M1),过拟合检测未落地(H1/M2/L1,回退后诚实不发误报,待真 detector)。一次 round-5 把“过拟合检测”从“已修”打回“待做”,并把 experiment 级 tie-breaking、eval job 命名、metric-definitions MCP 工具列为后续增强。

round 5 增强项修复 + round 7 黑盒复验

Section titled “round 5 增强项修复 + round 7 黑盒复验”

round-5 列的 H1 + M1/M2/L1/L2/L3 全部在本批处理:

commit 处置
H1(过拟合自动警告反了) 8713917 回退 Fix D 的 OVERFITTING health warning + 其 next_action;保留 eval_best/eval_best_step 字段(正确数据,agent 据此自行推理)。真过拟合检测归入 EventDetector
M2(过拟合 run 无 OVERFITTING_SUSPECTED 事件) 340278e EventDetector 的 _check_overfitting 本就有正确信号(train 下降 + val 较其最佳发散 ≥1.5×,非 step-比较),只是 OVERFIT_MIN_POINTS 阈值 10 对 4-eval run 太严。10→4。回归测试:4 点 val [1.14,1.41,2.34,3.44] 触发;4 点健康 val [0.30,0.25,0.22,0.20] 静默
M1(experiment 级并列选过拟合 run) 340278e get_best_checkpoint 在 primary 值并列时偏向OVERFITTING_SUSPECTED 事件的更健康 run,并新增 tied_checkpoint_ids 显式列出并列 ckpt
L2(eval job 跨 run 重名 eval-10 340278e eval job 命名改 eval:{run_name}:step{N}(run-aware)
L3(MCP 面无 metric-definitions 工具) 340278e list_metric_definitions(只读)MCP 工具,adapter 20 工具
L1(eval 4 点 trend=unknown) e6901ff 见下方 round-7 B2

round 7(sim7,黑盒 native-MCP 复验)

Section titled “round 7(sim7,黑盒 native-MCP 复验)”

全新 general-purpose subagent sim7(非 fork,黑盒约束同前:只调 mcp__gpuctl__* + 读 CLAUDE.md/skills,不读源码/不 grep/不 ssh+curl)做端到端复验:5 个 lr sweep run(含 1 个 --fail-mode overfit)+ 每 run 4 个 heldout eval + experiment 级 get_best_checkpoint + compare_runs + diagnose_run

verdict:完整 submit→monitor→eval→compare→diagnose→recommend 循环在 run 级与 experiment 级均流畅、可信、端到端。H1/M1/M2/L2/L3 修复全部 confirmed FIXED。过拟合 run 正确触发 OVERFITTING_SUSPECTED;健康 winner 不再被误报;experiment 级推荐在并列时选健康 run 并列示 tied。

sim7 另报 6 个 polish 项(B1–B6),处置如下:

# 现象 处置 commit / 依据
B1 同 ckpt 两次 eval 的 job name 相同(L2 的 run-aware 名仍并列:同 run 同 step 无 per-eval 区分) :名尾追加 ULID 随机尾 eval_id[-8:](时间前缀 [5:13] 同毫秒碰撞) e6901ff
B2 4 点 eval 序列 trend=unknown(同 L1,summary.py _trend 阈值 5) :阈值 5→4(half=2 首末均值在 4 点已够稳) e6901ff
B3 CheckpointRecommendation 无法区分 value 来自 heldout eval 还是训练兜底 :加 source 字段(evaluation / training_fallback e6901ff
B4 compare_runs 在同 run 内混用 best(heldout)与 latest(训练)源 判定设计compare_runs 的 best/latest 各列本就分列两字段,混用是 run 内既有 eval 又有训练流的诚实展示,非 bug;文档记之,不改 设计层
B5 tail_logs 时间戳批量化、难对齐 判定 agent-runner 层:log tail 的批量时间戳是 runner 采集行为,非语义层 bug;文档记之,不改 agent-runner 层
B6 compare_runs.next_actionscompare_runs 自指 误报compare_runs 的 next_actions 无 compare_runs 自指(sim7 与 diagnose_run 的 next_action 混淆);不改 misreport

round 7 polish 的 live 验证(native MCP,部署 WSL 后)

Section titled “round 7 polish 的 live 验证(native MCP,部署 WSL 后)”
  • B1:同 ckpt 同毫秒两次 evaluate_checkpoint → job name eval:r7-lr1e-3#1:step10:Q9MZAGYKeval:r7-lr1e-3#1:step10:T57PDZ9F(尾 8 字符不同),均 SUCCEEDED。旧名 eval:r7-lr1e-3#1:step10 会并列。
  • B2:fresh 40 步 / 4-eval run(r8-b2-trend,lr=1e-3)→ get_run_summarytrend.eval/loss="decreasing"eval/accuracy="increasing"(旧阈值 5 下为 "unknown");3 点序列仍 "unknown"
  • B3:r6-overfit-verify run(唯一 eval FAILED)→ get_best_checkpointsource="training_fallback"value=1.1366、step 10;有 SUCCEEDED eval 的 run 返 source="evaluation"

L3 可见性注记list_metric_definitions 工具代码与 adapter 均正确(tools/list 返 20 工具,已验),但 Claude Code 会话在会话启动时缓存 MCP 工具表——会话中途新增的工具对已开会话不可见,需用户执行 /reload-plugins(或新开会话)刷新。这是客户端缓存行为,非服务端 bug。

roadmap §3 验收标准达成:Agent 仅凭自然语言与 MCP,无任何人工平台交互,完成“提交训练 → 监控 → 对比 → 推荐”全循环。语义层用确定性规则给出可审计结论,写操作经 token 域分级守护,插件形态可分发。

经 5 轮黑盒 native-MCP 复测(round 2/3/4/5/7,每轮换全新 general-purpose subagent,黑盒防作弊)收敛:run 级与 experiment 级的 submit→monitor→eval→compare→diagnose→recommend 循环端到端流畅可信;过拟合检测已落地于 EventDetector(train 下降 + val 发散 ≥1.5×,4 点即触发,非脆弱 step-比较);experiment 级推荐在并列时偏向健康 run 并示 tied;eval job 名 run-aware + per-eval 唯一;recommend 结果标注 eval vs 训练兜底来源。已知非阻塞项记于此处:compare_runs 同 run 内 best/latest 分列两源是诚实展示(B4,设计);tail_logs 批量时间戳属 runner 采集层(B5,agent-runner);list_metric_definitions 对已开会话需 /reload-plugins 刷新(L3,客户端缓存)。