修改
This commit is contained in:
+180
-44
@@ -20,20 +20,22 @@ when_to_use: |
|
||||
|---------|---------|
|
||||
| "要不要我做训练集近邻检索?" | 这是 §2.3 分析必做项,**直接做**,做完把结果落 report |
|
||||
| "下一步可以继续吗?" | 永远不问。看 program.md 流程图自己判断 |
|
||||
| "我先把控制权交回,等你来问跑完了吗" | watcher 接手 UI 同步,你还是要在 bash 内 sleep+poll 等 cml 完,看到 complete **直接进 Step 1** |
|
||||
| "我先把控制权交回,等你来问跑完了吗" | 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 条 → **必须**抽样 30-50 条到飞书 sheet 让人审 1/0,按比例外推(**这就是一次合法暂停**,不是擅自停)
|
||||
- 候选量 >200 条 → 命中触发条件 #3,强制 HiTL 介入让人定更精细 pattern 收窄
|
||||
- 候选量 51-200 条 → **必须**全量导出到飞书 sheet 让人逐条审 1/0(**这就是一次合法暂停**,不是擅自停;**不再抽样外推**)
|
||||
- 候选量 >200 条 → 命中触发条件 #3,强制 HiTL 介入让人定更精细 pattern 收窄(仍然全量交付)
|
||||
4. 用户主动发消息打断
|
||||
|
||||
这之外**所有**"我觉得这事大、我先停"的本能都要压下来。命中合法暂停时,**不要只是说"等你确认"**——按 §4.0.1 把抽样表/精细 pattern 的具体输出 dump 到飞书 / scratchpad 给人具体可审的东西,再停。
|
||||
这之外**所有**"我觉得这事大、我先停"的本能都要压下来。命中合法暂停时,**不要只是说"等你确认"**——按 §4.0.1 把**全量候选清单**(不是抽样)/精细 pattern 的具体输出 dump 到飞书 / scratchpad 给人具体可审的东西,再停。
|
||||
|
||||
## 📋 每个 Step 的强制准入条件(少一项不准进下一步)
|
||||
|
||||
@@ -44,13 +46,13 @@ when_to_use: |
|
||||
- [ ] runDic 已分配(扫 `run_history_dir` 取 max+1)
|
||||
- [ ] CML workflow 已提交(拿到 Execution ID)
|
||||
- [ ] watcher 声明已写入 program-state.jsonl
|
||||
- [ ] 在 bash sleep+poll 等到 cml=complete
|
||||
- [ ] 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 错误分布
|
||||
- [ ] 读 `metric_diff/specific_comparison.csv` 提取 baseline 错误分布
|
||||
- [ ] **§2.3 失败 case 与训练数据的关联**:每条错例在 `train_set/zk_intent/*.jsonl` 做近邻检索(前 3 近邻),输出"有近邻 / 无近邻"分类
|
||||
- [ ] **§2.3 Reward 对齐检查**:抽 10 条失败 case 用 `zk_reward_fn` 验 reward 方向
|
||||
- [ ] **§2.3 Reward 对齐检查**:全量失败 case 用 `zk_reward_fn` 验 reward 方向(不抽样)
|
||||
- [ ] §0.1 Gold drift 检查(如未做)
|
||||
|
||||
### Step 2 准入(`report`)
|
||||
@@ -58,18 +60,33 @@ when_to_use: |
|
||||
- [ ] 写入 `results/workflow<runDic>.md`
|
||||
- [ ] error_registry 追加本轮错误
|
||||
|
||||
### Step 3 准入(`hypothesis`)
|
||||
### Step 3 准入(`hypothesis`) — analysis 收尾,不是 train 开头
|
||||
- [ ] 写本轮假设到 iteration_log.jsonl 的 hypothesis 字段
|
||||
- [ ] 假设必须有依据(指向 §2.3 / §2.4 的具体发现)
|
||||
- [ ] **`step:"hypothesis"` entry 写在当前 round(R{n})名下**——不要写成 R{n+1}。后端把 hypothesis 归类为 analysis 类,是 R{n}·Baseline / R{n}·Analysis 的最后一张卡,不是 R{n+1}·Train 的开头。这样 gate(Human Check / Review)会插在 hypothesis 卡之后、R{n+1}·Train 之前,**用户看到假设内容再拍板是否进 train**。
|
||||
|
||||
### Step 1 → Step 2 → Step 3 边界(**NEVER STOP 硬连接**,R0 / R1+ regression 都适用)
|
||||
- [ ] dist-analysis 算完 delta(new_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` 一条新 entry(runDic 写新轮的值,比如 R0 是 17793,R1 评测的 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 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 续训**)
|
||||
|
||||
@@ -101,6 +118,18 @@ when_to_use: |
|
||||
> 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。
|
||||
@@ -122,18 +151,24 @@ UI 卡底部进度条会跟着动;不写就一直显示初始进度。
|
||||
### State 文件位置
|
||||
|
||||
```
|
||||
<当前会话目录>/output/program-state.jsonl
|
||||
<远端 workspace>/output/program-state.jsonl
|
||||
```
|
||||
|
||||
会话目录在系统提示的 `[当前会话目录]` 里给了绝对路径。**直接用那个值**,不要拼。**绝对不要**写到 `/mnt/wangsenhao/...` 或项目根目录——多会话互相覆盖。
|
||||
bash 命令是在 **远端 workspace** 里跑的(一般 `/root/zk_agent_workspaces/LOCALID_xxx`),系统提示里的「当前会话目录」是 **后端宿主机的本地路径**,**不能直接拿来当 SESSION_OUTPUT**——拿了等于在远端凭空建一条同名死路径,后端 sync 永远读不到,前端卡片就一直不动。
|
||||
|
||||
每次写之前先确保目录存在:
|
||||
正确做法:用远端 cwd 派生(`pwd` 就是当前远端 workspace),目录确保存在:
|
||||
|
||||
```bash
|
||||
SESSION_OUTPUT="<从系统提示拷过来>/output"
|
||||
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 | 对应卡片 |
|
||||
@@ -147,7 +182,9 @@ mkdir -p "$SESSION_OUTPUT"
|
||||
| `verify` | 修改返回验证 |
|
||||
| `sft` | SFT 训练 |
|
||||
| `log` | 记录迭代日志 |
|
||||
| `next-round` | 下一轮评测 |
|
||||
| `next-round` | 下一轮评测(边界标记,**不生成卡片**,仅推进 UI 的 run_id 推断) |
|
||||
| `human-check` | Human Check(HiTL 网关;命中 HiTL 时 agent 显式写,UI 在对应 round section 后插入 gate 卡) |
|
||||
| `human-review` | Human Review(同上,多用于"建议人审 1/0"或"建议回滚"等需要人拍板的检查点) |
|
||||
|
||||
### KPI(你不要写,后端读权威源)
|
||||
|
||||
@@ -159,7 +196,7 @@ mkdir -p "$SESSION_OUTPUT"
|
||||
| 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_ROOT>/results/iteration_log.jsonl` 行数 |
|
||||
| ITERATION | `$AUTORESEARCH_CHAT_ROOT/results/iteration_log.jsonl` 行数(每 chat 独立) |
|
||||
| 耗时 | program-state.jsonl 第一条 `{step:"cml",status:"running"}` 的 `ts` 到现在 |
|
||||
|
||||
**你不要再写 `{"kpi":...}` 行**——写了也会被后端忽略,不显示。如果想让用户看到某个 KPI 的当前值,把它落到对应的权威源(比如改 config.yaml、写 iteration_log),后端会自动读到。
|
||||
@@ -172,7 +209,8 @@ CML 评测 / SFT 训练这类几分钟到几十分钟的长任务,声明 watch
|
||||
|
||||
- **不许**给用户回"控制权交回 / 我先停下 / 等你来问"这种话
|
||||
- **不许**主动结束本轮(除非命中 program.md 里写明的 H-i-T-L 阻断信号)
|
||||
- 提交完任务、声明完 watcher 后,**继续在 bash 里轮询 state file** 等 cml=complete,看到就**直接进入 Step 1**(读 metric_diff、做分层分析、写报告等),一气呵成跑完整轮迭代
|
||||
- 长任务(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 落盘。它不是替你"放假"。
|
||||
|
||||
@@ -202,31 +240,41 @@ echo '{"watch":{"step":"cml","kind":"file_exists","path":"/mnt/xiaoai-zk-model-t
|
||||
- step 已经有 complete/failed 行后,watcher 声明会被忽略
|
||||
- 后端 scanner 5 秒扫一次所有会话的 state file
|
||||
|
||||
**典型用法**(CML workflow,**NEVER STOP**):
|
||||
**典型用法**(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. 提交 cml 任务(异步,立刻返回 runDic)
|
||||
RUNDIC=$(cml workflow run --workflow_id "$WORKFLOW_ID" ...)
|
||||
|
||||
# 2. 写 running + watcher 声明
|
||||
# 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. 紧接着声明 watcher(UI 卡片切到 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
|
||||
|
||||
# 3. 跟用户简报一句状态,**不要说"交回控制权"**,紧接着开始等
|
||||
echo "已提交评测 runDic=$RUNDIC,开始轮询 state file 等 watcher 写 complete..."
|
||||
# 4. 跟用户简报一句"已提交,等产物落盘后会自动续",agent 这一轮主动结束
|
||||
# (不是交回控制权——是把等待这件事 detach 给后端)
|
||||
|
||||
# 4. 在 bash 里轮询 state file(不阻塞你下一步思考)
|
||||
while true; do
|
||||
status=$(grep -E '"step":"cml"' $S | tail -1 | python3 -c 'import json,sys; print(json.loads(sys.stdin.read()).get("status",""))')
|
||||
if [ "$status" = "complete" ]; then break; fi
|
||||
if [ "$status" = "failed" ]; then echo "cml failed"; exit 1; fi
|
||||
sleep 60
|
||||
done
|
||||
|
||||
# 5. cml 完成 → 立刻进入 Step 1,读 metric_diff、做分析、写下一步 running...
|
||||
# 整轮迭代不交回控制权,直到达标 / 命中 H-i-T-L 阻断 / 用户主动打断
|
||||
# 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 区,追加:
|
||||
@@ -249,10 +297,42 @@ echo '{"log":{"ts":"11:55:10","iter":"R3","text":"Step 3 开始: 问题分析 &
|
||||
| 触发信号 | `"开始,<需求集合名>"` |
|
||||
| 评测 workflow | `f-20260408161444-wu3pz`(版本见 `config.yaml`) |
|
||||
| 训练基模 | `/mnt/wangsenhao/verl_zk/Qwen3-4B-Instruct-2507` |
|
||||
| 工作目录 | `/mnt/wangsenhao/autoresearch-zk` |
|
||||
| 工作目录 | `$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 启动时自动注入这个 env,agent 每次 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. **评测优先**:`"开始"` 信号的第一个动作永远是评测当前模型,绝不直接训练
|
||||
@@ -343,6 +423,58 @@ assets/
|
||||
- 跨子集净退步(#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 running,UI 里完全看不到 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
|
||||
@@ -357,13 +489,17 @@ xiaomi_cloudml:
|
||||
|
||||
## 结果文件
|
||||
|
||||
| 文件 | 用途 |
|
||||
|---|---|
|
||||
| `results/iteration_log.jsonl` | 每轮假设/干预/判定完整记录 |
|
||||
| `results/error_registry.jsonl` | 跨轮错误追踪(case_hash → 出错轮次) |
|
||||
| `results/workflow<runDic>.md` | 每轮回归分析报告 |
|
||||
| `results/augment_raw/augment_<runDic>_raw.jsonl` | GPT-5.4 原始生成产物 |
|
||||
| `ai-planning/data/train_set/zk_intent/augment_<runDic>.jsonl` | 清洗后的增量训练数据 |
|
||||
| `results/data_clean_<runDic>/` | 旧数据清洗存档(必须在覆盖原文件前写入) |
|
||||
| `results/gold_drift/drift_<runDic>.json` | Gold drift 检测结果 |
|
||||
| `results/label_rules.md` | 已确立的标签规则集(R1~RN) |
|
||||
| 文件 | 用途 | 前端卡片 |
|
||||
|---|---|---|
|
||||
| `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)。
|
||||
|
||||
@@ -51,6 +51,23 @@ ssh -T git@git.n.xiaomi.com
|
||||
# 打开 https://git.n.xiaomi.com/-/profile/keys 粘贴公钥
|
||||
```
|
||||
|
||||
### Chat 工作区 bootstrap(首次启动时)
|
||||
|
||||
每个 chat session 一份独立工作区 `$AUTORESEARCH_CHAT_ROOT`(后端 jupyter 启动时自动注入这个 env)。该路径位于共享 NFS:`/mnt/wangsenhao/autoresearch-zk-users/<email_prefix>/<chat_session_id>/`,`<email_prefix>` 是用户登录的小米邮箱前缀(账号根目录),chat 二级隔离。**jupyter pod 与 SFT 训练 pod 共用这条 NFS**,所以训练 yaml 里 `cd $AUTORESEARCH_CHAT_ROOT` 不会再像旧版(jupyter pod 私有 `/root/zk_agent_workspaces/...`)那样在训练 pod 报 No such file。
|
||||
|
||||
`scripts/`、`results/`、`sft_output/` 由后端 mkdir + 推送 `prepare_and_train_sft.py`;**ai-planning corpus 需要 agent 自己 git clone**(之前依赖全局共享,已废弃):
|
||||
|
||||
```bash
|
||||
# 检测是否已 clone,没有就拉
|
||||
[ -d "$AUTORESEARCH_CHAT_ROOT/ai-planning" ] || git clone -b autoresearch-v1 \
|
||||
git@git.n.xiaomi.com:ai-service/ai-planning.git \
|
||||
"$AUTORESEARCH_CHAT_ROOT/ai-planning"
|
||||
```
|
||||
|
||||
之后所有训练数据读写都走 `$AUTORESEARCH_CHAT_ROOT/ai-planning/...`(包括 augment_<runDic>.jsonl 写入、近邻检索、训练集修改)。`prepare_and_train_sft.py` 用 `Path(__file__)/../ai-planning` 解析数据目录,因为脚本被推到了 `$AUTORESEARCH_CHAT_ROOT/scripts/` 旁边,自然落在 chat 副本上。
|
||||
|
||||
zk_trainer 的 clone 在首次 SFT 前进行(见 §5.0),目标也是 `$AUTORESEARCH_CHAT_ROOT/zk_trainer`。
|
||||
|
||||
### cml 环境检查(每次评测前必做)
|
||||
|
||||
```bash
|
||||
@@ -231,10 +248,11 @@ for k in prev:
|
||||
当前瓶颈是需求集合,单独做一节:
|
||||
|
||||
1. **子集级表格**:每个需求子集 pass rate、距离 95% 的 gap、对比上轮、对比基线。
|
||||
2. **失败 case 与训练数据的关联**:对每个失败 case 在 `ai-planning/data/train_set/zk_intent/` 下所有 `.jsonl`(包括历史增强 `augment_*.jsonl` 和原始种子训练文件,排除 `*_valid.jsonl`)里做近似检索(前 3 近邻),判断:
|
||||
- **数据缺失**:训练集中没有类似样本 → 补数据
|
||||
- **数据充足但仍错**:训练集中有类似样本 → 数据质量 or 学不会,不是加数据的问题
|
||||
3. **Reward 对齐检查**(抽样 10 条失败 case):用 `zk_reward_fn` 对"正确 label"和"实际输出"分别打分,验证 reward 方向是否和准确率一致。如果 reward 给错误输出的分更高 → reward 函数本身就有问题。
|
||||
2. **失败 case 与训练数据的关联**:对每个失败 case 在 `ai-planning/data/train_set/zk_intent/` 下所有 `.jsonl`(包括历史增强 `augment_*.jsonl` 和原始种子训练文件,排除 `*_valid.jsonl`)里做近似检索(前 3 近邻),三档判定:
|
||||
- **无近邻**(最高相似度 < 阈值)→ 分布外,补数据
|
||||
- **有近邻 + 近邻 label 与本 case gold 全部一致** → 训练数据正确,SFT 学不动 → 加 epoch / 改 reward
|
||||
- **有近邻 + 任一近邻 label 与 gold 矛盾** ⚠️ → **训练集打错标**,必须**逐条列出该 mislabeled 训练样本**:`{train_file:line, hash, 当前 label, 应改 label, 与失败 case 相似度, 违反的标签规则}`,进入下一轮的数据修订清单
|
||||
3. **Reward 对齐检查**(全量失败 case,不抽样):用 `zk_reward_fn` 对"正确 label"和"实际输出"分别打分,验证 reward 方向是否和准确率一致。如果 reward 给错误输出的分更高 → reward 函数本身就有问题。
|
||||
#### 2.4 根因归类
|
||||
|
||||
把发现映射到一类根因,**每个 pattern 必须归一类**(可并列,但要主次分明):
|
||||
@@ -243,8 +261,9 @@ for k in prev:
|
||||
|---|---|---|
|
||||
| 分流错误占比高 (>30%) | reward 对 complex 误判惩罚不足 | 改 `zk_reward_fn` 加分流项 |
|
||||
| 语义错误集中在少数 tag | 训练数据该类分布不足 | 定向补数据 |
|
||||
| 需求集合失败 case 在训练集有近邻 | 数据质量 / 标签噪声 / SFT 学不动 | 审核数据 + 加大 SFT epoch |
|
||||
| 需求集合失败 case 在训练集无近邻 | 分布外 | 补数据(最直接) |
|
||||
| 需求集合失败 case 训练集近邻 **label 一致** | SFT 学不动 / reward 信号弱 | 加大 SFT epoch / 改 reward |
|
||||
| 需求集合失败 case 训练集近邻 **label 矛盾**(mislabeled) ⚠️ | 训练集错标 | 按 §2.3 错标清单逐条修标,进 Step 4 数据修订 |
|
||||
| 需求集合失败 case 在训练集**无近邻** | 分布外 | 补数据(最直接) |
|
||||
| new/regressed case 多 | 上轮干预有副作用 | 回退 or 缩小干预范围 |
|
||||
| 训练 prompt ≠ eval prompt | 格式不匹配(silent bug) | 对齐模板,常常能"白捡"几个点 |
|
||||
| 错误 query 含状态描述句但训练集标 Agent | 标签规则违反(R3) | 改训练集对应样本为 CT,按 4.3.1 规则检查 |
|
||||
@@ -313,7 +332,14 @@ conflict_rate = len(conflicts) / len(query_to_golds)
|
||||
| 子集 | 准确率 | 总数 | 错误数 | 距 95% gap |
|
||||
|
||||
### 失败 case 与训练数据关联
|
||||
- <子集>: N 条失败中 X 条在训练集有近邻,Y 条无近邻 → 主要缺口: <数据缺失/质量>
|
||||
- <子集>: N 条失败中 X 条**有近邻且 label 一致**、Y 条**无近邻**、Z 条**近邻 mislabeled** ⚠️ → 主要缺口: <分布外补数据 / SFT 学不动 / 训练集错标>
|
||||
|
||||
#### 训练集错标清单(逐条,对应 Z 条 mislabeled)
|
||||
| 失败 case query | 训练样本 file:line | hash | 当前 label | 应改 label | 相似度 | 违反规则 |
|
||||
|---|---|---|---|---|---|---|
|
||||
| <q1> | augment_<N>.jsonl:42 | <h1> | Agent | CT | 0.93 | R1(单 POI+多形容词) |
|
||||
|
||||
> 没有 mislabeled 时这张表省略;有则进入下一轮 Step 4 的修订清单。
|
||||
|
||||
## 设备维度(只分析车载)
|
||||
| 设备 | 准确率 | 总数 | 错误数 |
|
||||
@@ -332,7 +358,7 @@ query: ...
|
||||
label: ...
|
||||
模型输出: ...
|
||||
归类: 分流/语义
|
||||
训练集近邻: 有/无
|
||||
训练集近邻: 有 label 一致 / 无 / ⚠️ mislabeled(hash=xxx, 相似度 0.xx, 当前=Agent / 应改=CT)
|
||||
|
||||
## 初始错误分布总结
|
||||
| 根因类 | 错误数 | 占比 | 代表 pattern |
|
||||
@@ -375,8 +401,15 @@ label: ...
|
||||
> 准确率来自 lark_template.json(含 complex 门禁检查),B/G 数来自 CSV 的纯模型 GSB(不含 complex 门禁),两者口径不同。
|
||||
|
||||
### 失败 case 与训练数据关联
|
||||
- <子集>: N 条失败中 X 条在训练集有近邻,Y 条无近邻 → 主要缺口: <数据缺失/质量>
|
||||
- Reward 对齐抽样: N/10 条 reward 方向与准确率一致
|
||||
- <子集>: N 条失败中 X 条**有近邻且 label 一致**、Y 条**无近邻**、Z 条**近邻 mislabeled** ⚠️ → 主要缺口: <分布外补数据 / SFT 学不动 / 训练集错标>
|
||||
- Reward 对齐(全量): N/N 条 reward 方向与准确率一致
|
||||
|
||||
#### 训练集错标清单(逐条,对应 Z 条 mislabeled)
|
||||
| 失败 case query | 训练样本 file:line | hash | 当前 label | 应改 label | 相似度 | 违反规则 |
|
||||
|---|---|---|---|---|---|---|
|
||||
| <q1> | augment_<N>.jsonl:42 | <h1> | Agent | CT | 0.93 | R1(单 POI+多形容词) |
|
||||
|
||||
> 没有 mislabeled 时这张表省略;有则 Z 条样本自动进入下一轮 Step 4 的修订清单。
|
||||
|
||||
## 设备维度(只分析车载)
|
||||
| 设备 | 基线准确率 | 新模型准确率 | 变化 | 旧对新错 |
|
||||
@@ -421,7 +454,7 @@ label: xxx
|
||||
旧: xxx # origin_predict_base
|
||||
新: xxx # origin_predict_dev(保留 complex= 前缀)
|
||||
归类: 分流/语义/两者 | 跨轮: persistent/new/regressed
|
||||
训练集近邻: 有/无(hash=xxx, 相似度 0.xx)
|
||||
训练集近邻: 有 label 一致(hash=xxx, 相似度 0.xx)/ 无 / ⚠️ mislabeled(hash=xxx, 相似度 0.xx, 当前=Agent / 应改=CT)
|
||||
```
|
||||
|
||||
> **重要**:对话历史从 input 字段的 `[对话历史]` 段提取,不能省略。很多错误(如短句闲聊被误判为 Agent)只有在多轮上下文中才能理解根因。
|
||||
@@ -589,19 +622,33 @@ for f in glob.glob('ai-planning/data/train_set/zk_intent/*.jsonl'):
|
||||
candidates.append((f, ln, q, d['output']))
|
||||
|
||||
# 3. 输出 csv 让人审核(不改文件)
|
||||
import csv
|
||||
with open(f'/tmp/candidates_r{RUNDIC}.csv', 'w', encoding='utf-8-sig') as fp:
|
||||
# 必须写到 $AUTORESEARCH_CHAT_ROOT/output/ —— 这是 NFS 路径,前端「分层结果分析」
|
||||
# 卡片从 chat_root/output/ 读这条;写到 jupyter pod 本地 cwd 会导致前端 not found。
|
||||
import csv, os
|
||||
out_csv = os.path.join(os.environ['AUTORESEARCH_CHAT_ROOT'],
|
||||
'output', f'relabel_candidates_{RUNDIC}.csv')
|
||||
os.makedirs(os.path.dirname(out_csv), exist_ok=True)
|
||||
with open(out_csv, 'w', encoding='utf-8-sig') as fp:
|
||||
w = csv.writer(fp)
|
||||
w.writerow(['file','line','query','old_label','是否改(1/0)','建议新label'])
|
||||
for c in candidates: w.writerow(list(c)+['',''])
|
||||
```
|
||||
|
||||
**两阶段 UI 展示约定(强制)**:
|
||||
|
||||
| 阶段 | 产物 | 落盘路径 | 前端卡片 |
|
||||
|---|---|---|---|
|
||||
| 阶段一:预计修改候选 | `relabel_candidates_<runDic>.csv` | `$AUTORESEARCH_CHAT_ROOT/output/`(NFS) | **分层结果分析(dist-analysis)** |
|
||||
| 阶段二:确认修改最终 | `modified_samples.jsonl` | `$AUTORESEARCH_CHAT_ROOT/results/data_clean_<runDic>/` | **数据增强(augment)** |
|
||||
|
||||
候选阶段(246 条等量级)的 CSV 必须写到 `output/relabel_candidates_<runDic>.csv` 让分析卡片可读;确认修改阶段(用户审核后落盘的 135 条)写入 `results/data_clean_<runDic>/modified_samples.jsonl` 让数据增强卡片可读。**不要混落**——把候选 CSV 写到 `/tmp/` 或 `data_clean_/` 都会让 UI 看不到。
|
||||
|
||||
**Step B:量级判定(决定是否走人审)**
|
||||
|
||||
| 候选量 | 处理 |
|
||||
|---|---|
|
||||
| ≤ 50 条 | 程序化 sanity check + 自动改 |
|
||||
| 51 ~ 200 条 | **必须**抽样 30~50 条到飞书 sheet 让人审 1/0,按抽样比例外推到全量 |
|
||||
| 51 ~ 200 条 | **必须**全量导出到飞书 sheet 让人逐条审 1/0(不抽样) |
|
||||
| > 200 条 | **强制 H-i-T-L 介入**(触发条件 #3),让人定更精细 pattern 收窄 |
|
||||
|
||||
**Step C:备份(强制,覆盖前必做)**
|
||||
@@ -642,7 +689,7 @@ for f, edits in edits_by_file.items():
|
||||
|
||||
改完不能直接训:
|
||||
1. **数据 sanity**:`prepare_and_train_sft.py prepare`,对比合并后总数(旧总数 - 删除数 = 新总数)
|
||||
2. **抽样人审**:随机抽 5 条,看 query/label/instruction 符合预期
|
||||
2. **全量人审**:所有改动条目逐条过一遍,看 query/label/instruction 符合预期
|
||||
3. **格式校验**:用 4.1.1 字段约束扫一遍改后 output
|
||||
|
||||
**Step F:删除 vs 修改的选择**
|
||||
@@ -828,7 +875,7 @@ def gen_augment(badcase: dict, n: int = 8) -> list[dict]:
|
||||
- **ground_truth 格式校验**:`Agent(tag=...)` / `ComplexTask(...)` / `QA()` / `Chat()` 是否和测试集一致?GPT-5.4 偶尔会把 tag 改写或加空格,必须用 `zk_reward_fn` 里的 parser 过一遍,parse 失败的扔掉。
|
||||
- **context 完整性**:`context` 必须是 dict 且含 `location` / `rag` 两键(可为空字符串但不能缺);`prev_session` 必须是 list。结构不符的丢弃。
|
||||
- **泄漏检测**:生成 `current_query` 与所有测试集(需求集合 + 大盘 + specific)做**精确匹配 + 近似匹配**(MinHash or embedding cos > 0.9)。命中则整条丢弃。
|
||||
- **Label 自洽**:生成的 `(current_query, prev_session, context) → ground_truth` 必须和原 badcase 的 ground_truth 语义一致。抽 10% 跑一次 GPT-5.4 自检("下面这条 current_query 的正确 ground_truth 是什么?"),和声明 ground_truth 不一致的丢弃。
|
||||
- **Label 自洽**:生成的 `(current_query, prev_session, context) → ground_truth` 必须和原 badcase 的 ground_truth 语义一致。**全量**跑一次 GPT-5.4 自检("下面这条 current_query 的正确 ground_truth 是什么?"),和声明 ground_truth 不一致的丢弃。
|
||||
- **Prompt 模板一致性**:并入训练前,把 `(prev_session, context, current_query)` 渲染成最终 SFT prompt,和 eval prompt 逐字段比对(`complex=true/false` 前缀、system prompt、function schema),不一致就对齐模板——常常能白捡几个点。
|
||||
- **去重**:与 `ai-planning/data/train_set/zk_intent/` 下所有已存在的 `*_train.jsonl`(历史增强 + 原始种子训练文件)去重(`current_query` 精确 + 近似)。
|
||||
|
||||
@@ -1014,10 +1061,11 @@ def induce_rule(cluster_cases, all_test_rows, existing_rules):
|
||||
### R{N} 自动归纳({runDic} 轮)
|
||||
**规则**:含 pattern `{regex}` → {gold}
|
||||
**置信度**:c1={c1:.2f}(错例 {support_err}/{support_err_total} 一致), c2={c2:.2f}(全测试集 {full_majority}/{support_total} 一致)
|
||||
**锚定 case**(自动从测试集抽 3 条):
|
||||
**锚定 case**(列出该 pattern 在测试集命中的全部 case,不抽样):
|
||||
- {case1}
|
||||
- {case2}
|
||||
- {case3}
|
||||
- ...(共 {N} 条)
|
||||
**自动检查正则**:`{regex}`
|
||||
```
|
||||
|
||||
@@ -1053,16 +1101,95 @@ ai-planning/data/train_set/zk_intent/augment_<runDic>.jsonl
|
||||
|
||||
JSONL 行里的 `sub_cate` 字段仅用于内部路由/去重,归档时丢弃不写入 CSV。因为 4.2 的输出 schema 已经和 CSV 列名对齐,归档就是把每个 `augment_<runDic>.jsonl` 行序列化成 CSV 单元格(`prev_session` / `context` 两列用 `json.dumps` 回写成字符串),没有字段重命名。
|
||||
|
||||
#### 4.5 label-master 标签复核(落盘后、SFT 前,**强制**)
|
||||
|
||||
任何写入训练目录的修改/新增样本都必须经 [label-master skill](../../label-master/SKILL.md) 复核**两层**:格式 + 语义。**没过这关不许进 Step 5。**
|
||||
|
||||
**复核范围**(两份必须全过):
|
||||
|
||||
| 文件 | 来源 | 复核什么 |
|
||||
|---|---|---|
|
||||
| `$AUTORESEARCH_CHAT_ROOT/results/data_clean_<runDic>/modified_samples.jsonl` | H1 改标(complex 翻转 / tag 改写等) | 改后的 `output` 字段 |
|
||||
| `$AUTORESEARCH_CHAT_ROOT/ai-planning/data/train_set/zk_intent/augment_<runDic>.jsonl` | H2 仿写(新增训练样本) | `output` 字段 |
|
||||
|
||||
**层 1:格式校验(确定性,自动跑)**
|
||||
|
||||
```bash
|
||||
cd /home/mi/zk-data-agent-wsh # 或 wherever skills 包在的项目根
|
||||
# H1 改标
|
||||
python skills/label-master/scripts/validate_label_output.py \
|
||||
--file "$AUTORESEARCH_CHAT_ROOT/results/data_clean_<runDic>/modified_samples.jsonl" \
|
||||
--field output_after
|
||||
# H2 仿写
|
||||
python skills/label-master/scripts/validate_label_output.py \
|
||||
--file "$AUTORESEARCH_CHAT_ROOT/ai-planning/data/train_set/zk_intent/augment_<runDic>.jsonl" \
|
||||
--field output
|
||||
```
|
||||
|
||||
任一行 fail(tag 不存在 / Agent 包装错 / function 引用错)→ **必须修,不许直接跳过**。修完原地重跑直到全过。
|
||||
|
||||
**层 2:语义复核(Skill 调用 label-master Agent)**
|
||||
|
||||
格式过了不代表标对了。每条修改/新增样本要用 label-master 做边界判断:
|
||||
|
||||
1. 抽出 `(query, output_after)` 或 `(query, output)` 对,按 `sub_cate` 分组(每组 ≤30 条作为一批)
|
||||
2. 每批用 `Skill(skill="label-master", args=...)` 调用,args 里给:
|
||||
- 全部 `(query, 当前 label)` 对
|
||||
- 让 label-master 按 §决策流程 / §候选召回索引 / §高频混淆边界 判定每条
|
||||
- 输出格式:每条 → `{verdict: 通过 | 不通过, 推荐标签, 排除理由, 易混淆边界}`
|
||||
3. 收集 verdict,写入 `$AUTORESEARCH_CHAT_ROOT/results/data_clean_<runDic>/label_master_review.jsonl`,每行一条 verdict
|
||||
|
||||
**verdict 处置规则(自动)**:
|
||||
|
||||
| 比例 | 处置 |
|
||||
|---|---|
|
||||
| 不通过 ≤ 5% | 自动丢弃这些样本(H2 → 从 augment_<N>.jsonl 删行;H1 → 回滚改动到 .bak)+ 写明丢弃数到 iteration_log |
|
||||
| 不通过 5%~20% | **触发 H-i-T-L #6**(gold 可疑),把不通过样本导出飞书 sheet 让人审 |
|
||||
| 不通过 > 20% | **强制暂停**,Step 4 假设本身有问题,回 Step 3 重新形成假设 |
|
||||
|
||||
**写完复核报告才允许进 Step 5。**verdict 文件不存在 / 没跑层 2 → Step 5 拒绝启动(5.0 的准入检查会查 `label_master_review.jsonl` 存在)。
|
||||
|
||||
🚨 **注意**:label-master 是"知识 + Agent 推理"型 Skill,不是黑盒分类器。批量调用时严禁要求它返回 1/0 标量;必须输出 `verdict + 推荐标签 + 排除理由` 三件套,便于人类回查。
|
||||
|
||||
### 5. SFT 训练
|
||||
|
||||
🚨 **Step 4 → Step 5 硬连接(NEVER STOP,反惯性反复强调)**
|
||||
|
||||
写完 `{"step":"augment","status":"complete",...}` 那一行**之后**,**同一轮 bash 不许结束、不许写"Step 4 完成"简报、不许等回调**。必须**紧接着**:
|
||||
|
||||
1. `echo '{"step":"sft","status":"running",...}' >> $SESSION_OUTPUT/program-state.jsonl`
|
||||
2. 跑层 1 + 层 2 label-master 复核(§4.5)
|
||||
3. 如果复核全过:在 SAME bash turn 里调 `bash scripts/submit_sft_via_cml.sh <RUNDIC> <PREV_RUNDIC>` 并立刻挂 watcher(§5.2 的 cml custom_train + workflow chain)
|
||||
|
||||
**反模式**(被反复踩坑,永远禁止):
|
||||
|
||||
- ❌ 写完 `augment=complete` → 写一份漂亮的"Step 4 完成"进度简报 → turn 结束 → 等下一次触发
|
||||
- ❌ "augment 已完成,下一步等回调后续做 SFT" — 不存在等回调,augment 完成的那一刻就是 SFT 启动的那一刻
|
||||
- ❌ 把 H2 后台任务的 stdout 当成"用户消息"处理完就 turn 结束 — bg 任务回调不是 turn 结束信号,augment=complete 也不是
|
||||
|
||||
**模型本能会想停("任务段落感"),SKILL NEVER STOP 压不住这个本能**——所以这里写成硬命令清单,照清单第一条到第三条机械执行,做完才允许 turn 结束。
|
||||
|
||||
|
||||
使用 `prepare_and_train_sft.py` 完成数据组装和训练。
|
||||
|
||||
#### 5.0 环境准备
|
||||
|
||||
**准入检查(少一项不许进)**:
|
||||
|
||||
```bash
|
||||
# 克隆 zk_trainer(仅首次)
|
||||
cd /mnt/wangsenhao/autoresearch-zk
|
||||
git clone git@git.n.xiaomi.com:wangsenhao/zk_trainer.git
|
||||
# 1. label-master 复核报告必须存在且全通过
|
||||
REVIEW="$AUTORESEARCH_CHAT_ROOT/results/data_clean_${RUNDIC}/label_master_review.jsonl"
|
||||
[ -f "$REVIEW" ] || { echo "label-master 复核未完成,回 §4.5"; exit 1; }
|
||||
NOT_PASS=$(grep -c '"verdict":"不通过"' "$REVIEW" || echo 0)
|
||||
TOTAL=$(wc -l < "$REVIEW")
|
||||
if [ "$TOTAL" -gt 0 ] && [ $((NOT_PASS * 100 / TOTAL)) -gt 5 ]; then
|
||||
echo "不通过比例 $NOT_PASS/$TOTAL > 5%,按 §4.5 处置规则走 H-i-T-L 或回 Step 3"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# 2. zk_trainer 仓库已 clone
|
||||
cd "$AUTORESEARCH_CHAT_ROOT"
|
||||
[ -d zk_trainer ] || git clone git@git.n.xiaomi.com:wangsenhao/zk_trainer.git
|
||||
```
|
||||
|
||||
**训练配置**:
|
||||
@@ -1098,8 +1225,8 @@ git clone git@git.n.xiaomi.com:wangsenhao/zk_trainer.git
|
||||
- `prepare_and_train_sft.py train` 命令行参数 `--model_path` 必须检查为 basemodel 路径
|
||||
|
||||
**反模式**:
|
||||
- ❌ `--model_path /mnt/wangsenhao/autoresearch-zk/sft_output`(继续训练)
|
||||
- ❌ `--model_path /mnt/wangsenhao/autoresearch-zk/sft_output_r17776`(从历史轮 ckpt)
|
||||
- ❌ `--model_path $AUTORESEARCH_CHAT_ROOT/sft_output`(继续训练)
|
||||
- ❌ `--model_path $AUTORESEARCH_CHAT_ROOT/sft_output_r17776`(从历史轮 ckpt)
|
||||
- ❌ 任何形式的 "增量 SFT"(除非显式声明是为了验证"从 X ckpt 继续是否更好"的对照实验,且单次性,log 要明确标记)
|
||||
|
||||
#### 5.0.1 训练产物备份(R23-R28 经验沉淀)
|
||||
@@ -1127,13 +1254,15 @@ R29 起 SFT 走 cml custom_train submit(见 5.2),watcher 直接复用 `sub
|
||||
|
||||
```bash
|
||||
# 预清理:必须在挂 watcher 之前执行
|
||||
rm -f /mnt/wangsenhao/autoresearch-zk/sft_output/_SUCCESS
|
||||
rm -f "$AUTORESEARCH_CHAT_ROOT/sft_output/_SUCCESS"
|
||||
|
||||
# Watcher 1:训练阶段 —— cml state 为主判据,_SUCCESS 辅助
|
||||
# 注意:heredoc 用 'EOF' 防止外层 shell 展开,$AUTORESEARCH_CHAT_ROOT
|
||||
# 在 watcher 子进程里运行时再展开(远端 bash 会自动注入这个 env)。
|
||||
cat > /tmp/wait_train_<RUNDIC>.sh <<'EOF'
|
||||
#!/bin/bash
|
||||
JOB_ID=<t-xxx-xxx>
|
||||
SUCCESS=/mnt/wangsenhao/autoresearch-zk/sft_output/_SUCCESS
|
||||
SUCCESS="$AUTORESEARCH_CHAT_ROOT/sft_output/_SUCCESS"
|
||||
export PATH=$HOME/.cloudml-cli/bin:$PATH
|
||||
while true; do
|
||||
sleep 60
|
||||
@@ -1174,7 +1303,7 @@ EOF
|
||||
# /tmp/auto_eval_after_train.sh —— 等本地训练 PID 结束 → 自动起 cml workflow
|
||||
TRAIN_PID=$1
|
||||
RUN_DIC=$2
|
||||
MODEL_NEW=/mnt/wangsenhao/autoresearch-zk/sft_output
|
||||
MODEL_NEW=$AUTORESEARCH_CHAT_ROOT/sft_output
|
||||
MODEL_OLD=<基线模型>
|
||||
|
||||
while kill -0 $TRAIN_PID 2>/dev/null; do sleep 60; done
|
||||
@@ -1217,7 +1346,7 @@ R23-R28 期间用本地 `nohup python3 prepare_and_train_sft.py train ...` 启
|
||||
##### 一键提交脚本
|
||||
|
||||
```bash
|
||||
cd /mnt/wangsenhao/autoresearch-zk
|
||||
cd "$AUTORESEARCH_CHAT_ROOT"
|
||||
./scripts/submit_sft_via_cml.sh <RUNDIC> [PREV_RUNDIC]
|
||||
|
||||
# 例:R29 训练(上一轮 R28)
|
||||
@@ -1333,7 +1462,7 @@ tail -f /tmp/r<RUNDIC>_logs/cml_watcher.log
|
||||
| **跨子集净退步:目标子集 +X / 其他子集合计 -Y, 净 < 0.3pp** | **回退或缩小干预范围**(R27 经验:单看目标子集涨容易自欺)|
|
||||
| **连续 3 轮目标子集净提升 ≤ 0.5pp** | **进入瓶颈期**:输出 SFT 天花板报告,触发 H-i-T-L #6 |
|
||||
| **跨子集 gold 矛盾率 > 5%** | **结构性天花板**:触发 H-i-T-L #2,停 SFT 转 RL 或返工标注 |
|
||||
| **要批改旧标签 > 50 条** | **触发 H-i-T-L #3**,抽样人审,按比例外推 |
|
||||
| **要批改旧标签 > 50 条** | **触发 H-i-T-L #3**,全量人审 |
|
||||
| **Gold drift ≥ 10 条** | **触发 H-i-T-L #1**,暂停迭代确认是否同步训练集 |
|
||||
| 训练前未备份 sft_output | **强制 mv sft_output sft_output_r{prev}**,不允许覆盖 |
|
||||
|
||||
@@ -1347,7 +1476,7 @@ tail -f /tmp/r<RUNDIC>_logs/cml_watcher.log
|
||||
|---|---|---|---|
|
||||
| 1 | **Gold drift 检测到 ≥10 条** | 暂停迭代,让人确认是否同步更新训练集 | R23 100 条翻转 |
|
||||
| 2 | **跨子集同形 query gold 矛盾率 > 5%** | 输出"结构性天花板"报告,让人选:硬推目标子集 / 接受 / 转 RL | 复杂导航 vs 可聊可控 矛盾 |
|
||||
| 3 | **要批改旧标签 > 50 条** | 暂停,导出抽样 ≥30 条到飞书 sheet 让人逐条确认 | R28 改 230 条引发副作用 |
|
||||
| 3 | **要批改旧标签 > 50 条** | 暂停,导出全量到飞书 sheet 让人逐条确认 | R28 改 230 条引发副作用 |
|
||||
| 4 | **跨子集净退步**(目标 +X / 其他合计 -Y, 净 < 0.3pp) | 暂停,让人决策回退 / 接受 / 换策略 | R27 可聊可控 -1.34pp |
|
||||
| 5 | **连续 3 轮目标子集净提升 ≤ 0.5pp** | 输出 SFT 天花板报告,让人选继续 SFT / 转 RL / 接受 / 换基模 | R25-R28 复杂导航 +0.7~3pp 递减 |
|
||||
| 6 | **测试集错例里 gold 可疑(自相矛盾的同 pattern)** | 列出可疑 gold 让人确认 / 反馈标注团队 | R28「找+模糊属性」双向标注 |
|
||||
@@ -1359,8 +1488,8 @@ tail -f /tmp/r<RUNDIC>_logs/cml_watcher.log
|
||||
|
||||
| # | 触发条件 | 应对动作 | 经验来源 |
|
||||
|---|---|---|---|
|
||||
| T1 | **单轮批改旧标签 > 50 条** | 抽样 30 条到飞书 sheet 逐条审;按抽样的"改/不改"比例外推全量 | R28 改 230 条引发跨子集副作用 |
|
||||
| T2 | **单轮新仿写 > 100 条 OR 单类 (同 sub_cate / 同 pattern) > 50 条** | 抽样 20 条让人审风险,量级大要拆批 | R23 一次 670 条仿写过载,规则错全反 |
|
||||
| T1 | **单轮批改旧标签 > 50 条** | 全量导出到飞书 sheet 逐条审,逐条标 1/0 | R28 改 230 条引发跨子集副作用 |
|
||||
| T2 | **单轮新仿写 > 100 条 OR 单类 (同 sub_cate / 同 pattern) > 50 条** | 全量让人审风险,量级大要拆批 | R23 一次 670 条仿写过载,规则错全反 |
|
||||
| T3 | **删除训练样本 > 30 条** | 列删除清单 + 删除原因,人确认后才执行(删比改更不可逆) | R26 删 23 P0 通用短词产生副作用 |
|
||||
| T4 | **修改 `all_train.jsonl` 主集 > 20 条** | 核心训练集动一行都贵;列改动给人确认 | 主集影响所有 sub_cate,副作用范围最大 |
|
||||
| T5 | **跨子集冲突 query:同结构 query 在 ≥3 条训练样本里 gold 不一致** | 让人定边界规则(如「沿途搜 X」是 Agent 还是 CT),不许两边都加 | R26 augment_17752 同 pattern 矛盾仿写 |
|
||||
@@ -1396,7 +1525,7 @@ tail -f /tmp/r<RUNDIC>_logs/cml_watcher.log
|
||||
2. **现状量化**:目标子集 +X / 其他子集 -Y / 大盘 ±Z
|
||||
3. **2-4 个选项**(用 AskUserQuestion 工具):每个选项含预期收益 + 风险
|
||||
4. **推荐选项**:基于经验给出推荐(标 "(推荐)")
|
||||
5. **本地产物**:抽样 / 错例 csv / 飞书 sheet 链接
|
||||
5. **本地产物**:全量错例 csv / 飞书 sheet 链接
|
||||
|
||||
### 介入后的恢复
|
||||
|
||||
|
||||
@@ -2,16 +2,16 @@
|
||||
"""
|
||||
从 ai-planning 组装 SFT 训练/验证集,并启动 zk_trainer SFT 训练。
|
||||
|
||||
用法:
|
||||
用法(先 cd "$AUTORESEARCH_CHAT_ROOT",所有产物落 chat 工作区):
|
||||
# 仅组装数据
|
||||
python prepare_and_train_sft.py prepare --output_dir /mnt/wangsenhao/autoresearch-zk/sft_data
|
||||
python scripts/prepare_and_train_sft.py prepare --output_dir "$AUTORESEARCH_CHAT_ROOT/sft_data"
|
||||
|
||||
# 启动训练(需先 prepare)
|
||||
python prepare_and_train_sft.py train \
|
||||
--data_dir /mnt/wangsenhao/autoresearch-zk/sft_data \
|
||||
python scripts/prepare_and_train_sft.py train \
|
||||
--data_dir "$AUTORESEARCH_CHAT_ROOT/sft_data" \
|
||||
--model_path /mnt/wangsenhao/verl_zk/Qwen3-4B-Instruct-2507 \
|
||||
--model_type qwen3 \
|
||||
--train_output /mnt/wangsenhao/autoresearch-zk/sft_output
|
||||
--train_output "$AUTORESEARCH_CHAT_ROOT/sft_output"
|
||||
"""
|
||||
|
||||
import argparse
|
||||
|
||||
Reference in New Issue
Block a user