Files
zk-data-agent/skills/model-iteration/SKILL.md
T
hupenglong1 5311e6d97c 修改
2026-05-22 19:48:47 +08:00

506 lines
33 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
name: model-iteration
description: 小爱中控模型自主迭代框架(autoresearch-zk)。用于对小爱同学中控理解调度模型进行假设驱动的自主 SFT+评测迭代循环。触发信号:用户发送"开始,需求集合名"(如"开始,icl_test")时,必须立即使用此 skill 启动迭代,不得自行发挥。任何涉及 cml 评测、zk 模型训练、数据增强、badcase 分析、augment_*.jsonl 生成的任务,也应使用此 skill。
when_to_use: |
用户表达以下任一意图时启用此 skill:
- 直接的核心触发短语:「开始,<需求集合名>」(如「开始,icl_test」)
- 自然语言的训练/迭代请求:「我要进行模型训练」「开始模型训练」「目标集合是 xxx」「跑一下需求集合 xxx」「迭代 xxx」「针对 xxx 做模型迭代」
- 平台运维:「评测当前模型」「分析 badcase」「Gold drift 检查」「数据增强 augment_*.jsonl」「提交 SFT 训练」「跑 CML workflow」「写 iteration_log」
- 关键词:CML 评测 / SFT / autoresearch / zk 中控理解调度 / requirement set / specific test / metric_diff / lark_template
无需用户严格按「开始,xxx」字面匹配;只要意图涉及小爱中控模型 SFT+评测迭代,就立刻使用此 skill。
---
# autoresearch-zk — 小爱中控模型自主迭代框架
## 🚫 严禁问用户的事(违反任一条 = 违反 skill)
每次问用户都让用户烦。program.md 已经把"什么时候停"写得很死(17 类 HiTL 信号 + 用户主动打断),**这之外一律不准停下来等确认**。下面是被反复踩坑的"擅自暂停"模式,**全部禁止**:
| ❌ 禁止说的话 | ✅ 正确做法 |
|---------|---------|
| "要不要我做训练集近邻检索?" | 这是 §2.3 分析必做项,**直接做**,做完把结果落 report |
| "下一步可以继续吗?" | 永远不问。看 program.md 流程图自己判断 |
| "我先把控制权交回,等你来问跑完了吗" | watcher 接手 UI 同步,长任务用 `bash(run_in_background=true, wait_for_completion=true)` 提交后本轮主动结束;后端会在产物落盘后自动起新一轮把结果送回,**直接进 Step 1** |
| "这一步是关键决策点,需要你拍板" | program.md 没写就不是。**自主决策 + 落 iteration_log** |
| "我把现状停在这里,把决策摘要给你 review" | 不准。摘要可以写,但不准停 |
| "Step 4 augment 完成 ✅,等回调后续做 SFT" | augment=complete 那一刻就是 SFT 启动那一刻——**同一轮 bash** 紧接着跑 §4.5 label-master 复核 + 提交 SFT,不许写简报、不许等回调(详见 program.md "Step 4 → Step 5 硬连接"|
| "R1 评测发现 regression,先把诊断给你看,等你拍板再决定要不要回滚" | dist-analysis 发现 regression **也算 dist-analysis 完成**——**同轮 bash** 紧接着写 `results/workflow<runDic>.md`(包含完整 delta 表 + new_fail/new_fix 子集 + 病灶定位 + 回滚建议)+ append `iteration_log.jsonl` R{n} entry。文件落完了再用 chat reply 给人提回滚选项。**不许把诊断只写在 chat 里、不落盘**——前端「分层结果分析」卡片读的是 `results/workflow<runDic>.md`,你不写卡片永远停在上轮。 |
**合法暂停只有**
1. program.md `## Human-in-the-Loop 时机` 章节的 7 类迭代级信号
2. `### 训练集调整专项 H-i-T-L 信号` 的 T1-T10
3. **§4.0.1 Step B 量级判定的 HiTL 分支**
- 候选量 51-200 条 → **必须**全量导出到飞书 sheet 让人逐条审 1/0(**这就是一次合法暂停**,不是擅自停;**不再抽样外推**
- 候选量 >200 条 → 命中触发条件 #3,强制 HiTL 介入让人定更精细 pattern 收窄(仍然全量交付)
4. 用户主动发消息打断
这之外**所有**"我觉得这事大、我先停"的本能都要压下来。命中合法暂停时,**不要只是说"等你确认"**——按 §4.0.1 把**全量候选清单**(不是抽样)/精细 pattern 的具体输出 dump 到飞书 / scratchpad 给人具体可审的东西,再停。
## 📋 每个 Step 的强制准入条件(少一项不准进下一步)
按 Step 编号,**进入下一 Step 前**必须把当前 Step 的准入清单全部完成并落到 state file / iteration_log,否则视为跳步违规。
### Step 0 准入
- [ ] cml 环境检查通过(`which cml` + `cml config show`
- [ ] runDic 已分配(扫 `run_history_dir` 取 max+1
- [ ] CML workflow 已提交(拿到 Execution ID
- [ ] watcher 声明已写入 program-state.jsonl
- [ ] cml workflow + 等 metric_diff 落盘已用 `bash(run_in_background=true, wait_for_completion=true)` 提交(**不要**在 bash 内 sleep+poll
### Step 1 准入(`dist-analysis`
- [ ]`metric_diff/lark_template.json` 提分层指标(specific / 大盘车载 / 目标专项)
- [ ]`metric_diff/specific_comparison.csv` 提取 baseline 错误分布
- [ ] **§2.3 失败 case 与训练数据的关联**:每条错例在 `train_set/zk_intent/*.jsonl` 做近邻检索(前 3 近邻),输出"有近邻 / 无近邻"分类
- [ ] **§2.3 Reward 对齐检查**:全量失败 case 用 `zk_reward_fn` 验 reward 方向(不抽样)
- [ ] §0.1 Gold drift 检查(如未做)
### Step 2 准入(`report`
- [ ] §2.4 根因归类表(每个 pattern 必归一类,可并列但要主次)
- [ ] 写入 `results/workflow<runDic>.md`
- [ ] error_registry 追加本轮错误
### Step 3 准入(`hypothesis` — analysis 收尾,不是 train 开头
- [ ] 写本轮假设到 iteration_log.jsonl 的 hypothesis 字段
- [ ] 假设必须有依据(指向 §2.3 / §2.4 的具体发现)
- [ ] **`step:"hypothesis"` entry 写在当前 roundR{n})名下**——不要写成 R{n+1}。后端把 hypothesis 归类为 analysis 类,是 R{n}·Baseline / R{n}·Analysis 的最后一张卡,不是 R{n+1}·Train 的开头。这样 gateHuman Check / Review)会插在 hypothesis 卡之后、R{n+1}·Train 之前,**用户看到假设内容再拍板是否进 train**。
### Step 1 → Step 2 → Step 3 边界(**NEVER STOP 硬连接**R0 / R1+ regression 都适用)
- [ ] dist-analysis 算完 deltanew_fail / new_fix / persistent / 子集分布)那一刻起,**同一轮 bash 不许结束**:紧接着写 `results/workflow<runDic>.md`(包含完整指标表 + 病灶定位 + 假设 + 回滚/继续建议)→ append `iteration_log.jsonl` R{n} entry`results` 字段填本轮 metric`hypothesis` 字段填下一动作)
- [ ] **regression 场景同样适用**:哪怕 R1 出现导航bvt 纯劣化、可聊可控大幅 -25 这种"必须回滚"信号,**先把分析落到 workflow<runDic>.md 和 iteration_log,再用 chat reply 给人回滚选项**。文件先落、聊天再发——顺序不能反。
- [ ] **不许"诊断只写聊天回复 / 等用户拍板再补盘"**:前端「分层结果分析」卡片读的是 `chat_root/results/workflow<runDic>.md`;你不写盘卡片永远显示上一轮,看不到 R1 结论。
- [ ] **runDic 推进**:每轮新评测结果落盘后,append `iteration_log.jsonl` 一条新 entryrunDic 写新轮的值,比如 R0 是 17793R1 评测的 metric_diff 在 workflow17794,这条 entry 的 runDic 就写 17794),UI 卡片才会切到新一行。
- [ ] **凡是要让用户拍板的检查点(R0 baseline 之后、R{n} regression 之后、>200 候选要定 pattern、Gold drift 复核 等),必须先 append `step:"human-check"` 或 `step:"human-review"` running entry,再用 chat reply 提问**。**禁止只在 chat 里问而不写 gate entry**——UI 看不到拦截 = 视为没做这步,用户面板上看不到任何卡。详见下方 "Human-in-the-Loop 信号 → 写 gate 节点"。
### Step 4 准入(`augment`,需要修改训练集才进)
- [ ] **§4.0 原始训练数据清洗(增强前必做)**——按 4 种动作走完逐 pattern 判定
- [ ] §4.0.1 Step A:候选定位输出 csv**不直接改**
- [ ] §4.0.1 Step B:量级判定走对应支线(≤50 自动 / 51-200 全量人审 / >200 触发 #3,全量交付)
- [ ] §4.0.1 Step C:备份 `.bak` 文件
- [ ] §4.1 输入准备 / §4.2 GPT 调用 / §4.3 sanity check / §4.4 写入
- [ ] **§4.5 label-master 标签复核(落盘后必做,强制)**:对 H1 `modified_samples.jsonl` + H2 `augment_<runDic>.jsonl` 跑两层(`validate_label_output.py` 格式 + Skill 调用 `label-master` 语义),verdict 写 `results/data_clean_<runDic>/label_master_review.jsonl`,不通过比例 ≤ 5% 才能进 Step 5
### Step 4 → Step 5 边界(**NEVER STOP 硬连接**,反复踩坑)
- [ ] 写完 `augment=complete` 那一刻,**同一轮 bash 不许结束**:紧接着跑 §4.5 label-master 复核 → 写 `sft=running` → 调 `submit_sft_via_cml.sh` → 挂 watcher
- [ ] **不许写"Step 4 完成"进度简报后 turn 结束**,不许"等回调后续做 SFT"
- [ ] H2 后台任务回调(`[system] 后台任务 ... exit_code=0`)**不是 turn 结束信号**——它只是 augment 子流程的一个中间节拍,agent 必须在同轮里继续走完 §4.5 → Step 5
### Step 5 准入(`sft`
- [ ] §4.5 label-master 复核报告 `label_master_review.jsonl` 存在且不通过 ≤ 5%
- [ ] 旧 sft_output 已 `mv sft_output sft_output_r{prev}` 备份
- [ ] 训练参数从 config.yaml 读,model_path = basemodel**不从上轮 ckpt 续训**
### Step 6 准入(`log`
- [ ] iteration_log.jsonl 完整 schemahypothesis / intervention / prediction / results / verdict / root_cause_findings / error_delta / next_hypothesis
### 跳步检查
每次写 `{step:"X","status":"running"}` 前,**先看 state file 上一条 step 是不是 complete**。如果上一条还在 running 或者跳过了某个 Step,**回去补**,不要往前走。
## ⚠️ Pipeline UI 同步约定(强制,必读)
**平台用户实时盯着 pipeline UI 看你跑到哪一步**。卡片状态完全靠你写 `program-state.jsonl` 驱动;**你不写、卡片不动;你嘴上说 running、文件里写 failedUI 就显示 failed**。所以下面这些是**硬性纪律,不是建议**:
### R1(最重要)— 每一次状态切换都必须先 echo 再做事
进入新 step 之前,**第一件事**就是 append 一行 `running`。完成后**最后一件事**是 append 一行 `complete`。失败时也必须 append `failed`。**永远不要"嘴上"宣布状态切换却没落盘**。
错误示范(你不许这样):
> 我现在开始 step 0,跑 CML 评测... \[执行很多操作\]... 已完成 ✅
正确示范:
> ```bash
> echo '{"step":"cml","status":"running","ts":"'$(date -Iseconds)'"}' >> "$SESSION_OUTPUT/program-state.jsonl"
> ```
> *(然后才执行 step 0 的具体操作)*
> ...
> ```bash
> echo '{"step":"cml","status":"complete","ts":"'$(date -Iseconds)'"}' >> "$SESSION_OUTPUT/program-state.jsonl"
> ```
### R1.5 — 推荐每条 state entry 带 run_id(让 UI 准确归位 round
新版 UI 按 R0 / R1 / R2 切分 sections。**强烈建议**每行加 `run_id`
```bash
echo '{"step":"cml","status":"running","run_id":"R0","ts":"'$(date -Iseconds)'"}' >> $S
echo '{"step":"hypothesis","status":"complete","run_id":"R0","ts":"..."}' >> $S # hypothesis 跟当前轮(R0),不是 R1
echo '{"step":"augment","status":"running","run_id":"R1","ts":"..."}' >> $S # augment 才是 R1·Train 起点
```
run_id 缺省时后端会按 `iteration_log.jsonl` 行数自动推断(analysis 类 step 含 hypothesis → R{count}train 类 step augment/verify/sft → R{count+1}),但显式写更准——尤其是并发跨轮、补写历史 entry、或要在 R0 强制注入 baseline 时。
### R2 — 写入即生效,最后一行覆盖前面
后端按 `step` 字段取**最后一条**状态。如果你之前写过 failed、现在恢复了,**必须 append 一条新的 `running`**,否则 UI 永远停在 failed。
### R3 — Step 之间不允许跳步骤而不留状态
进入 dist-analysis 前必须确认 cml 状态已写到 `complete`(或显式 `failed` 后用户决定继续)。
### R4 — 中长任务用 progress 字段更新
CML 评测、SFT 训练这种几分钟以上的任务,**每次轮询/心跳时附带 progress 字段**写一条新的 `running` 行(旧 running 不需删,最后一行最新):
```bash
echo '{"step":"cml","status":"running","progress":0.4,"ts":"'$(date -Iseconds)'"}' >> "$SESSION_OUTPUT/program-state.jsonl"
```
UI 卡底部进度条会跟着动;不写就一直显示初始进度。
### State 文件位置
```
<远端 workspace>/output/program-state.jsonl
```
bash 命令是在 **远端 workspace** 里跑的(一般 `/root/zk_agent_workspaces/LOCALID_xxx`),系统提示里的「当前会话目录」是 **后端宿主机的本地路径****不能直接拿来当 SESSION_OUTPUT**——拿了等于在远端凭空建一条同名死路径,后端 sync 永远读不到,前端卡片就一直不动。
正确做法:用远端 cwd 派生(`pwd` 就是当前远端 workspace),目录确保存在:
```bash
SESSION_OUTPUT="$(pwd)/output"
mkdir -p "$SESSION_OUTPUT"
```
或者显式写远端绝对路径 `SESSION_OUTPUT="/root/zk_agent_workspaces/LOCALID_<本会话 id>/output"`。**绝对不要**
- 拷系统提示里的 `/home/mi/zk-data-agent-wsh/.port_sessions/.../output`(那是后端本地,远端没这条)
- 写到 `/mnt/wangsenhao/...` 或项目根目录(多会话互相覆盖)
后端 `_sync_remote_program_state` 只读远端 `{workspace_cwd}/output/program-state.jsonl` —— 路径写错 = 前端死锁。
### Step key 表(必须用这套 key,否则匹配不到卡片)
| step key | 对应卡片 |
|----------|----------|
| `cml` | CML 评测 |
| `gold-drift` | Gold Drift |
| `dist-analysis` | 分层结果分析 |
| `report` | 问题分析 & 报告 |
| `hypothesis` | 形成假设 |
| `augment` | 数据增强 |
| `verify` | 修改返回验证 |
| `sft` | SFT 训练 |
| `log` | 记录迭代日志 |
| `next-round` | 下一轮评测(边界标记,**不生成卡片**,仅推进 UI 的 run_id 推断) |
| `human-check` | Human CheckHiTL 网关;命中 HiTL 时 agent 显式写,UI 在对应 round section 后插入 gate 卡) |
| `human-review` | Human Review(同上,多用于"建议人审 1/0"或"建议回滚"等需要人拍板的检查点) |
### KPI(你不要写,后端读权威源)
顶部 7 个 KPIRUN ID / VERSION / 目标集合 / 大盘车载 / SPECIFIC TEST / ITERATION / 耗时)由后端从权威源直接读取:
| KPI | 后端读取自 |
|-----|-----------|
| RUN ID | `RUN_HISTORY_DIR`(默认 `/mnt/xiaoai-zk-model-train-tj5/workflow5/`)下 `workflow<N>/` 取 max N |
| VERSION | `skills/model-iteration/assets/config.yaml``cml_eval.version` |
| 目标集合 | 从 session 最新 user 消息里解析 `"开始, <name>"` 中的 name |
| 大盘车载 / SPECIFIC TEST | `RUN_HISTORY_DIR/workflow<runDic>/metric_diff/lark_template.json` |
| ITERATION | `$AUTORESEARCH_CHAT_ROOT/results/iteration_log.jsonl` 行数(每 chat 独立) |
| 耗时 | program-state.jsonl 第一条 `{step:"cml",status:"running"}``ts` 到现在 |
**你不要再写 `{"kpi":...}` 行**——写了也会被后端忽略,不显示。如果想让用户看到某个 KPI 的当前值,把它落到对应的权威源(比如改 config.yaml、写 iteration_log),后端会自动读到。
### Watcher(长任务的 UI 状态副车,**不是给你交回控制权的借口**)
CML 评测 / SFT 训练这类几分钟到几十分钟的长任务,声明 watcher 让**后端自动检测产物文件并把 `step=complete` 写到 state file**——这样 UI 的卡片状态不依赖你主动写 complete,watcher 替你写。
但你**仍然必须留在当前迭代里继续干活**,遵守 program.md 里的 **NEVER STOP / 全程不打断用户** 原则:
- **不许**给用户回"控制权交回 / 我先停下 / 等你来问"这种话
- **不许**主动结束本轮(除非命中 program.md 里写明的 H-i-T-L 阻断信号)
- 长任务(cml 评测、SFT 训练)**必须**用 `bash(run_in_background=true, wait_for_completion=true)` 提交:把"提交远端任务 + 等产物落盘"打包成一个 bg 命令;本轮 agent 主动结束(**不是**交回控制权——是把等待这件事 detach 给后端),产物落盘后后端自动起新一轮,agent 收到 stdout 直接进 Step 1
- **不许**在 bash 里写 `while true; do sleep 60; done` 这种轮询循环——bash 命令有 30s 硬超时,会被切成几十个 step,把本轮 50 step 上限耗尽留不出做分析的预算
watcher 解决的是 **UI 与 agent 异步**UI 不用等 agent 写状态,watcher 替 agent 把 complete 落盘。它不是替你"放假"。
格式:
```bash
# 进入 step 时按规则写 running
echo '{"step":"cml","status":"running","ts":"'$(date -Iseconds)'"}' >> "$SESSION_OUTPUT/program-state.jsonl"
# 紧接着声明 watcher:当目标文件出现 → 后端自动写 cml=complete
echo '{"watch":{"step":"cml","kind":"file_exists","path":"/mnt/xiaoai-zk-model-train-tj5/workflow5/workflow17782/metric_diff/lark_template.json","interval":30,"timeout":3600,"run_id":"R0"}}' >> "$SESSION_OUTPUT/program-state.jsonl"
```
字段:
| 字段 | 必填 | 说明 |
|------|------|------|
| `step` | ✅ | 跟卡片 step key 一致(cml / sft / augment ... |
| `kind` | ✅ | 当前只支持 `file_exists` |
| `path` | ✅ | 目标文件**绝对路径**。文件出现就视为 step 完成 |
| `interval` | ⭕ | 轮询间隔秒,默认 30,最小 2 |
| `timeout` | ⭕ | 整体超时秒,默认 3600,超时写 failed |
| `run_id` | ⭕ | 写入 Live Log 时的 iter 标签 |
**watcher 资源管理**
- 同一 (session, step) 已有 watcher 在跑时,重复声明被忽略
- step 已经有 complete/failed 行后,watcher 声明会被忽略
- 后端 scanner 5 秒扫一次所有会话的 state file
**典型用法**CML workflow**用 bg 模式 + watcher**):
长任务必须用 `bash(run_in_background=true, wait_for_completion=true)` 提交。bg 命令在远端 detach 跑、立刻返回 task_id;产物落盘后后端自动起新一轮把 stdout 作为 system 消息送回 agent**不要**在 bash 里 sleep+poll。watcher 仍然要声明——它驱动 UI 卡片状态,跟 bg 任务是两条独立的通道。
```bash
# 1. 写 running + watcher 声明(UI 卡片靠它)
echo '{"step":"cml","status":"running","ts":"'$(date -Iseconds)'"}' >> $S
# 2. 用 bg 模式:把"提交 cml + 等 metric_diff 落盘"一次封装
# wait_for_completion=true(默认):进程结束后后端自动起新一轮把 stdout 送回
bash(run_in_background=true, command='''
set -e
RUNDIC=$(cml workflow run --workflow_id "$WORKFLOW_ID" ...)
echo "RUNDIC=$RUNDIC"
TARGET=/mnt/xiaoai-zk-model-train-tj5/workflow5/workflow$RUNDIC/metric_diff/lark_template.json
while [ ! -f "$TARGET" ]; do sleep 60; done
echo "EVAL_DONE runDic=$RUNDIC target=$TARGET"
''')
# 3. 紧接着声明 watcherUI 卡片切到 complete 靠它,runDic 在 bg 任务 stdout 里)
# watcher path 用稍后从 bg stdout 拿到的 runDic 拼;如果先不知道 runDic
# 可以等 bg 任务返回 RUNDIC 后这一轮里再补声明 watcher。
echo '{"watch":{"step":"cml","kind":"file_exists","path":"'$ROOT/workflow$RUNDIC/metric_diff/lark_template.json'","interval":30,"timeout":7200,"run_id":"R'$N'"}}' >> $S
# 4. 跟用户简报一句"已提交,等产物落盘后会自动续",agent 这一轮主动结束
# (不是交回控制权——是把等待这件事 detach 给后端)
# 5. 产物落盘后,后端起新一轮,agent 收到 stdout(含 RUNDIC + EVAL_DONE
# → 立刻进入 Step 1,读 metric_diff、做分层分析、写报告……整轮 50 step 全用在分析上
```
**为什么不能在 bash 里 sleep+poll**bash 工具有 30s 硬超时,`sleep 60` 会被切成 `sleep 25 + sleep 5` 两个 step;评测跑 25 分钟 = ~50 step 全耗在等待上,留不出做分析的预算。bg 模式只占 1 个 step。
**bg 任务排查**agent 中途想看进度,可以 `bash_status(task_id)` 拿当前 stdout/exit_code 快照;想终止远端进程要 `bash_kill(task_id)`(前端按 stop 不会杀 bg 任务,那是 detach 的本意)。
### Live log(可选)
要把日志推到 UI 底部那块黑色 Live Log 区,追加:
```bash
echo '{"log":{"ts":"11:55:10","iter":"R3","text":"Step 3 开始: 问题分析 & 报告生成"}}' >> "$SESSION_OUTPUT/program-state.jsonl"
```
### 不要做的事
- **不要**写 program.md(旧机制已废弃,写了也没用,平台现在不读它)。
- **不要**把 state 文件写到 `/mnt/wangsenhao` 或仓库根目录——只写当前会话的 `output/program-state.jsonl`
- **不要**用与上表不一致的 step key(比如 `step:"评测"``step:"step0"`),UI 匹配不到。
- **不要**重写整个文件(每行只追加,append 即可),重写会导致 UI 闪。
## 快速参考
| 项目 | 值 |
|---|---|
| 触发信号 | `"开始,<需求集合名>"` |
| 评测 workflow | `f-20260408161444-wu3pz`(版本见 `config.yaml` |
| 训练基模 | `/mnt/wangsenhao/verl_zk/Qwen3-4B-Instruct-2507` |
| 工作目录 | `$AUTORESEARCH_CHAT_ROOT`(每 chat 独立,由后端注入;位于共享 NFS:`/mnt/wangsenhao/autoresearch-zk-users/<email_prefix>/<chat_session_id>/`jupyter pod 与训练 pod 都能读写) |
| 历史记录目录 | `/mnt/xiaoai-zk-model-train-tj5/workflow5/` |
| 需求集合位置 | `https://git.n.xiaomi.com/ai-service/ai-planning/-/tree/autoresearch-v1``ai-planning/data/specific_test_set/` |
## 工作空间隔离(按用户 + 每 chat 二级隔离,落在 NFS)
每个 chat session 一份独立工作区 `$AUTORESEARCH_CHAT_ROOT`(后端在 jupyter 启动时自动注入这个 envagent 每次 bash 都能拿到)。该目录位于共享 NFS:
```
/mnt/wangsenhao/autoresearch-zk-users/<email_prefix>/<chat_session_id>/
```
`<email_prefix>` 是用户登录时的小米邮箱前缀(`xxx@xiaomi.com``xxx`),用作账号根目录;同一用户跨 chat 共享根目录但 chat 之间完全隔离。
**为什么放 NFS 而不是 jupyter pod 私有路径**SFT 训练在独立的 pytorch pod 里跑,那个 pod 不挂载 jupyter pod 的 workspace;放共享 NFS 是双方都能 `cd` 进去的唯一选择。
**所有写入路径都必须以 `$AUTORESEARCH_CHAT_ROOT` 开头**,不要写 hard-coded `/mnt/wangsenhao/autoresearch-zk/...` 全局路径,也不要写 jupyter pod 本地路径(`/root/zk_agent_workspaces/...`),训练 pod 看不到。
| 资产 | 位置 | 隔离方式 |
|---|---|---|
| `prepare_and_train_sft.py` | `$AUTORESEARCH_CHAT_ROOT/scripts/` | 后端 bind 时从 skill bundle 推过来,每次刷新最新版 |
| `ai-planning/`(含 corpus + augment | `$AUTORESEARCH_CHAT_ROOT/ai-planning/` | **首次访问前你自己 git clone**(见 program.md 「ai-planning bootstrap」) |
| `zk_trainer/` | `$AUTORESEARCH_CHAT_ROOT/zk_trainer/` | **Step 5 首次 SFT 前你自己 git clone**(见 program.md §5.0 |
| `results/iteration_log.jsonl` | `$AUTORESEARCH_CHAT_ROOT/results/` | 每 chat 独立累积;后端 KPI 也读这里 |
| `results/error_registry.jsonl` | 同上 | 每 chat 独立 |
| `results/workflow<runDic>.md / data_clean_<runDic>/ / augment_raw/` | 同上 | 每 chat 独立 |
| `sft_output/` | `$AUTORESEARCH_CHAT_ROOT/sft_output/` | 每 chat 独立,互不覆盖;训练 pod 走 NFS 直接写 |
| `augment_<runDic>.jsonl` | `$AUTORESEARCH_CHAT_ROOT/ai-planning/data/train_set/zk_intent/` | 写在 chat 自己的 ai-planning clone 内,下一次 SFT prepare 只合并本 chat 的增量 |
**保持全局共享的资产**(不要按 chat 拆):
- runDic 计数:`/mnt/xiaoai-zk-model-train-tj5/workflow5/`max+1 是平台级唯一标识)
- 训练基模:`/mnt/wangsenhao/verl_zk/Qwen3-4B-Instruct-2507`(只读模型权重)
- metric_diff 输出:`/mnt/xiaoai-zk-model-train-tj5/workflow5/workflow<runDic>/metric_diff/`cml workflow 写)
**每个 step 落产物时务必用 `$AUTORESEARCH_CHAT_ROOT` 作前缀**(例如 `cd $AUTORESEARCH_CHAT_ROOT && python scripts/prepare_and_train_sft.py ...`,或 `echo ... >> $AUTORESEARCH_CHAT_ROOT/results/iteration_log.jsonl`)。
## 核心原则
1. **评测优先**`"开始"` 信号的第一个动作永远是评测当前模型,绝不直接训练
2. **假设驱动**:每轮必须能回答"这轮验证了什么?学到了什么?下一轮改什么?"
3. **NEVER STOP**:全程不打断用户,循环直到达标或人类主动打断
4. **从 basemodel 训练**:每轮 SFT 的 `--model_path` 必须是 basemodel,禁止从上轮 ckpt 继续训
## 达标条件
- **需求集合** ≥ 95%(最高优先级)
- **大盘集(车载)** 降幅 ≤ 0.3%
- **specific test** 降幅 ≤ 1%
## 主流程
读取 `references/program.md` 获取完整的 Step 0-7 迭代循环规范。在任何操作前必须读取该文件。
每个 step 的执行模板(**强制**,配合上文「Pipeline UI 同步约定」R1):
```text
1. echo '{"step":"<key>","status":"running","ts":"..."}' >> $SESSION_OUTPUT/program-state.jsonl
2. (执行该 step 的实际操作 / 调用工具 / 等结果)
3. 成功: echo '{"step":"<key>","status":"complete","ts":"..."}' >> ...
失败: echo '{"step":"<key>","status":"failed","error":"...","ts":"..."}' >> ...
```
step key 跟 Step 编号映射:
| Step | step key | 说明 |
|------|----------|------|
| Step 0 | `cml` | CML 评测当前模型 |
| Step 0 (附带) | `gold-drift` | Gold drift 检查 |
| Step 1 | `dist-analysis` | 分层结果分析 |
| Step 2 | `report` | 问题分析 & 报告 |
| Step 3 | `hypothesis` | 形成假设(写 iteration_log |
| Step 4 | `augment` | 数据增强 / 生成 |
| Step (干预后) | `verify` | 修改返回验证 |
| Step 5 | `sft` | SFT 训练 |
| Step 6 | `log` | 记录迭代日志 |
| 循环 | `next-round` | 回 Step 0 评测新 ckpt |
```
LOOP:
Step 0: CML 评测(当前模型)+ Gold drift 检查
Step 1: 分层结果分析(需求集合 → 大盘车载 → specific test
Step 2: 问题分析 & 报告(根因归类 / 跨轮 diff / 天花板诊断)
Step 3: 形成假设(写入 iteration_log.jsonl
Step 4: 数据生成(仅 data 归因时做)
Step 5: SFT 训练(submit_sft_via_cml.sh
Step 6: 记录结果(iteration_log.jsonl / error_registry.jsonl
→ 回 Step 0
```
## 文件结构
```
references/
program.md # 完整迭代循环规范(必读,包含所有 Step 的详细说明)
knowledge/
navigation_routing_rules.md # 地图导航 Agent/CT 分流规则
travel_routing_rules.md # 旅游 Agent/CT 分流规则
multi_command_rules.md # 多指令 vs ComplexTask 分流规则
multiturn_continuity_rules.md # 多轮对话 CT 继承规则
scripts/
prepare_and_train_sft.py # 数据组装 + SFT 训练脚本
assets/
config.yaml # 评估阈值 + CML workflow 配置
```
## 何时读取各文件
| 操作 | 读取 |
|---|---|
| 启动迭代前 | `references/program.md`(完整流程,必读) |
| badcase 归类 / 数据增强标注时 | `references/knowledge/` 下对应规则文件 |
| 数据组装 / 训练前 | `scripts/prepare_and_train_sft.py`(了解脚本参数) |
| 评测阈值 / workflow 版本 | `assets/config.yaml` |
## Human-in-the-Loop 信号(需暂停问人)
共 7 类迭代级信号 + 10 类训练集调整信号(T1-T10),详见 `references/program.md` 的"Human-in-the-Loop 时机"章节。
**最常触发的**
- Gold drift ≥ 10 条(#1
- 要批改旧标签 > 50 条(#3 / T1
- 跨子集净退步(#4
- 连续 3 轮目标子集净提升 ≤ 0.5pp(#5
### 写 gate 节点(让 UI 显示 Human Check / Review 卡)
凡是要让用户拍板的检查点,**必须** append 一条 gate entry 到 `program-state.jsonl`**再** 用 chat reply 提问。UI 会在当前 round section 之后插入「Human Check」或「Human Review」横向卡片(IN PROGRESS 状态)。
> ⛔ **禁止**:只在 chat 里问用户、不写 gate entry。UI 看不到拦截 = 视为这一步没做——用户在面板里看不到任何卡,会以为流程卡死或还在自动推进。**这是反复踩坑点**:以前 agent 经常在 R0 baseline 跑完后聊天里问"要不要进 R1 train",但 program-state 一直在写 augment runningUI 里完全看不到 gate。
#### 什么时候要写
需要用户拍板就写——不管 R0 还是 R{n≥1},触发条件都按 §HiTL 信号判:
| 时机 | gate 类型 | run_id |
|---|---|---|
| R0 baseline 分析完成、要让用户确认是否进 R1 train(命中 HiTL 信号 / 候选量大 / 目标子集偏低 / 第一次跑想让用户校方向 等) | `human-check` | `R0` |
| R{n≥1} analysis 完成、命中 §HiTL 信号(gold drift / regression / 跨子集退步 / 连续 3 轮无提升 等) | `human-review` | `R{n}` |
| §4.0.1 Step B:候选量 > 200 条命中触发条件 #3 | `human-check` | 当前 round |
| 其他 HiTL 信号(要批改旧标签 > 50 条、Gold drift ≥ 10 条 等) | `human-check`(开始前)/ `human-review`(结果后) | 当前 round |
判断标准就一条:**只要你下一步打算 chat-ask 用户拍板,就先写 gate entry 再问**。
#### 写法
```bash
# R0 baseline 之后想让用户拍板是否进 train
echo '{"step":"human-check","status":"running","run_id":"R0","reason":"R0 baseline 分析完成,目标子集 X.X% 偏低,确认是否按当前 H1 候选进 R1 train","ts":"'$(date -Iseconds)'"}' >> $S
# R1 评测发现 regression,需要用户决定是否回滚
echo '{"step":"human-review","status":"running","run_id":"R1","reason":"R1 vs R0:导航bvt -3.2pp, 可聊可控 -25pp,建议回滚","ts":"'$(date -Iseconds)'"}' >> $S
# 候选量超 200 条命中触发条件 #3
echo '{"step":"human-check","status":"running","run_id":"R0","reason":"候选量 412 条命中触发条件 #3","ts":"'$(date -Iseconds)'"}' >> $S
```
**顺序不能反**:先 echo gate entry → 再 chat reply 给用户。否则用户先看到聊天问话、UI 里却没卡,会困惑"流程是不是卡死了"。
#### 字段说明
| 字段 | 必填 | 说明 |
|---|---|---|
| `step` | ✅ | `human-check``human-review` |
| `status` | ✅ | 卡进入时写 `running`;用户回复后写 `complete` |
| `run_id` | ✅ | 当前所在轮次(决定 gate 插在哪个 section 后) |
| `reason` | ⭕ | 触发原因——直接展示给用户看,写具体一些("Gold drift 12 条,触发 #1" 比 "需要人审" 强得多) |
| `ts` | ✅ | ISO 时间戳 |
**用户拍板回复后**append `status:"complete"` 同 step + run_id 一行,gate 卡变 COMPLETED;然后才继续往下走(继续/回滚/调参)。
**两种 gate 的区分(约定)**
- `human-check`:偏"开始前的检查"——baseline → train 网关、>200 条候选定 pattern、Gold drift 复核
- `human-review`:偏"结果出来要复核"——R{n} 评测出来发现 regression 要不要回滚、目标集合连续 3 轮无提升要不要换思路
实际差别在 UI 上不大(都是横向 dashed 卡),区分主要为了让用户从标题就大致知道是开始前还是结果后的检查点。
## CML 配置(快速查阅)
```yaml
# ~/.config/cloudml/config.yaml
default_config_context: cloudml5-config
xiaomi_cloudml:
cloudml5-config:
xiaomi_auth_type: key
xiaomi_cloudml_endpoint: https://cnbj6-cloudml5.api.xiaomi.net
xiaomi_cloudml_workspace_id: 10065
```
## 结果文件
| 文件 | 用途 | 前端卡片 |
|---|---|---|
| `results/iteration_log.jsonl` | 每轮假设/干预/判定完整记录 | hypothesis / log |
| `results/error_registry.jsonl` | 跨轮错误追踪(case_hash → 出错轮次) | log |
| `results/workflow<runDic>.md` | 每轮回归分析报告 | dist-analysis / report |
| `output/relabel_candidates_<runDic>.csv` | **阶段一**:预计修改训练集候选清单(complex 翻转候选等) | **dist-analysis(分层结果分析)** |
| `results/data_clean_<runDic>/modified_samples.jsonl` | **阶段二**:确认修改最终落盘(用户审核 1/0 后实际生效的改动) | **augment(数据增强)** |
| `results/data_clean_<runDic>/deleted_samples.jsonl` | 旧数据清洗存档(删除项) | — |
| `results/augment_raw/augment_<runDic>_raw.jsonl` | GPT-5.4 仿写原始产物 | augment |
| `ai-planning/data/train_set/zk_intent/augment_<runDic>.jsonl` | 本轮合入训练集的增量(H1 重标 + H2 仿写) | augment |
| `results/gold_drift/drift_<runDic>.json` | Gold drift 检测结果 | gold-drift |
| `results/label_rules.md` | 已确立的标签规则集(R1~RN) | — |
**两阶段训练集修改的展示约定**:候选阶段(量级判定 + 人审 1/0 之前)写在 `output/relabel_candidates_<runDic>.csv`,前端「分层结果分析」卡片读取展示供人审;确认阶段(人审后落盘)写在 `results/data_clean_<runDic>/modified_samples.jsonl`,前端「数据增强」卡片读取展示最终改动。详见 [references/program.md §4.0.1 Step A](references/program.md)。