model-iteration: runDic 单一可信源 + label-master 逐条调用

- 新增 scripts/resolve_run_ids.sh:从 workflow5/ 解析出 SFT_RUNDIC / EVAL_RUNDIC,禁止 agent 心算 +1
- submit_sft_via_cml.sh 拆成 <SFT_RUNDIC> <EVAL_RUNDIC> [PREV_RUNDIC] 三参,yaml 用 SFT_RUNDIC,cml workflow run 用 EVAL_RUNDIC
- program.md §746 / §5.2 / §1.2 同步约束,并加 R2 落盘多 +1 的踩坑案例
- §4.0.1 Step A.5 / §4.5 label-master 复核改逐条调用(≤8 路并发),禁止批量塞多条 query

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
hupenglong1
2026-05-25 11:42:44 +08:00
parent 362321c460
commit 57f5b60a3e
6 changed files with 606 additions and 74 deletions
+131 -25
View File
@@ -18,7 +18,7 @@ when_to_use: |
| ❌ 禁止说的话 | ✅ 正确做法 |
|---------|---------|
| "要不要我做训练集近邻检索?" | 这是 §2.3 分析必做项,**直接做**,做完把结果落 report |
| "要不要我做训练集近邻检索?" | 这是 §2.3 分析必做项,**直接做**,做完把结果落 dist-analysis 报告(`workflow<runDic>.md` |
| "下一步可以继续吗?" | 永远不问。看 program.md 流程图自己判断 |
| "我先把控制权交回,等你来问跑完了吗" | watcher 接手 UI 同步,长任务用 `bash(run_in_background=true, wait_for_completion=true)` 提交后本轮主动结束;后端会在产物落盘后自动起新一轮把结果送回,**直接进 Step 1** |
| "这一步是关键决策点,需要你拍板" | program.md 没写就不是。**自主决策 + 落 iteration_log** |
@@ -48,16 +48,17 @@ when_to_use: |
- [ ] watcher 声明已写入 program-state.jsonl
- [ ] cml workflow + 等 metric_diff 落盘已用 `bash(run_in_background=true, wait_for_completion=true)` 提交(**不要**在 bash 内 sleep+poll
### Step 1 准入(`dist-analysis`
### Step 1 准入(`dist-analysis`,含原 Step 2 报告产出
- [ ]`metric_diff/lark_template.json` 提分层指标(specific / 大盘车载 / 目标专项)
- [ ]`metric_diff/specific_comparison.csv` 提取 baseline 错误分布
- [ ] **§2.3 失败 case 与训练数据的关联**:每条错例在 `train_set/zk_intent/*.jsonl` 做近邻检索(前 3 近邻),输出"有近邻 / 无近邻"分类
- [ ] **§2.3 mislabel 命中必须落盘 CSV**:列固定为 `file,line,query,old_label,是否改(1/0),建议新label`,写到 `$AUTORESEARCH_CHAT_ROOT/output/relabel_candidates_<runDic>.csv`(前端「分层结果分析」卡片就读这一份)。本轮无 mislabel 也写一份只含表头的空 CSV,明示"已检查、无候选"。**禁止**只 print 到 stdout 或只写进 workflow.md——卡片读不到 CSV 等同漏交
- [ ] **§2.3 判别器自检**:写完任何"把 raw output 抽成可比对值"的函数后(complex 二值 / tag / function / code label / slot 等都算)、跑全量前——端点验证(每类训练侧 ≥1 条 + eval 侧 ≥1 条;二分类 4 条、N 分类 ≥2N 条)+ 报告并列原文 + 零计数兜底(详见 program.md §2.3 自检小节)
- [ ] **§2.3 Reward 对齐检查**:全量失败 case 用 `zk_reward_fn` 验 reward 方向(不抽样)
- [ ] §0.1 Gold drift 检查(如未做)
### Step 2 准入(`report`
- [ ] §2.4 根因归类表(每个 pattern 必归一类,可并列但要主次)
- [ ] 写入 `results/workflow<runDic>.md`
- [ ] 写入 `results/workflow<runDic>.md`(根因 / 跨轮 diff / 需求集合深度分析 / 天花板诊断)
- [ ] `output/relabel_candidates_<runDic>.csv` 已落盘(无候选则空表头 CSV
- [ ] error_registry 追加本轮错误
### Step 3 准入(`hypothesis` — analysis 收尾,不是 train 开头
@@ -65,7 +66,7 @@ when_to_use: |
- [ ] 假设必须有依据(指向 §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 都适用)
### Step 1 → 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 结论。
@@ -75,10 +76,11 @@ when_to_use: |
### 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 A.5**先走 label-master 预审**(用推荐标签覆盖 new_label,剔除 label-master 不认同要改的条目
- [ ] §4.0.1 Step B:量级判定基于 label-master 处理后的**残留候选量**走对应支线(≤50 自动按 label-master 推荐改 / 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
- [ ] **§4.5 label-master 标签复核(落盘后必做,强制)**:H1 `modified_samples.jsonl` 只跑层 1(格式)—— 语义已在 §4.0.1 Step A.5 完成;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
@@ -148,6 +150,75 @@ echo '{"step":"cml","status":"running","progress":0.4,"ts":"'$(date -Iseconds)'"
UI 卡底部进度条会跟着动;不写就一直显示初始进度。
### R5 — bg 任务作用域 = 单 step(**反复踩坑**
bg 任务(`bash(run_in_background=true)`)的合法范围是**一个 step 内的"提交一个远端动作 + 等它的产物落盘"**——比如「提 cml workflow run + 等 metric_diff 落盘」、「提 SFT custom_train + 等 `_SUCCESS`」。这是 §「典型用法」推荐的标准结构。
**禁止**把 bg 范围扩到跨 step
| ❌ 禁止 | ✅ 正确 |
|---|---|
| 一个 bg 串行 `等 SFT _SUCCESS → 提 cml workflow run(评测)→ 等评测 lark_template.json` | sft watcher fire complete 那一刻,agent 主对话**当轮**完成:写 `cml=running` + 起新 bg(提评测 + 等 lark_template.json+ 注册新 watcher |
| bg 内部 sleep+poll 跨多个 step 的状态 | 每个 step 一个 bg + 一个 watcherwatcher fire = step 边界 = 主对话轮回来推进 |
**为什么是死规则**bg 脚本本身不会 append `program-state.jsonl`,状态只活在 bg 进程内存。一个 bg 跨 step 跑起来后,前端从第一个 step complete 之后就完全感知不到后续 step——卡片永远停在第一个 step,watcher 也没注册新的。**bg 进程死了 / session 重连 / 中途想插手** 都补不回来,因为 program-state.jsonl 上没任何线索。
**自查判据**:bg 脚本里出现新 step 的关键词(`cml workflow run` 提评测、`submit_sft_via_cml.sh`、对应新 step 的 `echo running`),就是越界。bg 只该做"提一个远端 job 然后等它的产物",**绝不能跨 step 边界**。
**watcher fire → 当轮 4 件套**(漏一件就断片):
1. echo 上一 step `complete`watcher 已自动写也算)
2. echo 下一 step `running`
3. 起新 bg「提交下一 step 的远端动作 + 等产物」
4. 注册新 watcher 监听下一 step 的产物文件
回主对话轮前自问一句:**"如果我现在被 kill,单看 program-state.jsonl 最后一行,下一个 agent 能不能接着干?"** 答不上来就是 4 件套没补全。
**绝不"事后补 status"绕过 watcher**:发现 step 在 UI 上一直 running、watcher 没自动标 complete**正确做法是 debug watcher**(看 `_SUCCESS` / `lark_template.json` 是否真的落盘、watcher 进程是否还在),**不是**自己手 echo 一条 `step=complete` 把状态条点亮。后者掩盖 bug 但留下错位的 run_id,下一轮 watcher 会接着错。
### R6 — 同秒 running + complete 视为虚假完成(**反复踩坑**)
每个真实 step 都有最低耗时下限:
| step | 最低耗时 | 原因 |
|---|---|---|
| `cml` | 数分钟到数十分钟 | 远端 workflow 启动 + 评测 |
| `sft` | 30 分钟以上 | 训练 pod |
| `augment` | 数分钟 | GPT 仿写 + sanity + label-master 复核 |
| `dist-analysis` | 1-3 分钟 | 读 metric_diff + 跨轮 diff + 写 workflow.md |
| `gold-drift` | 1-2 分钟 | drift 检测 |
如果 `step=running``step=complete` 两条 entry 的 `ts` 在**同一秒**(或差距远小于该 step 最低耗时),就是**虚假完成**——agent 平铺 echo 状态绕过了真实工作。**禁止**。
最常见踩坑:human-review / human-check 拿到用户决策后,agent 在同一轮里把 `hypothesis + augment + sft + watcher` 一口气 echo 出来,只真做了最后一步(提 SFT),中间的 `augment` 被跳过——`augment_<runDic>.jsonl` 根本没生成,前端 augment 卡永远空。
**正确做法**human-review 之后必须按 program.md 逐 step 真跑:
1.`hypothesis=running` → 真写假设到 iteration_log → 写 `hypothesis=complete`
2.`augment=running` → 真跑 §4.0.1 + §4.1 + §4.2 + §4.3 + §4.5 label-master 复核 → 写 `augment=complete`**这一步至少 5 分钟**
3.`sft=running` → 提交 cml custom_train + 起 watcher
**自查**:连续两个 step 的 `ts` 间隔 < 60 秒,必然有一个是假的。复盘时 grep program-state.jsonl 看相邻 entry 时间戳。
**前端表现的迷惑性**:虚假完成的 step **状态条仍显示 ✓ complete**(因为 entry 写了 complete),但**详情卡空**(因为 backend 按 step 关联的产物文件读内容——augment 卡读 4 个 `augment_<runDic>.*` 文件,文件不存在 = 卡片空)。**状态条说做完了、详情卡却空**——这是最具迷惑性的失败模式,必须从源头杜绝。
### R7 — `step=running` 与对应 `watch` 条目必须同事务落盘(**反复踩坑**)
watcher 触发 complete 时使用的 `run_id` **必须等于触发它的 watch 条目的 run_id**。后端 scanner 改造后实施两道闸门:
1. **每个 step 只 register 最新一条 watch 条目**append-only jsonl 里历史 round 的 watch 不再被复活)
2. watch 条目的 `run_id` 必须**等于**该 step 最新一条 `status=running` 条目的 `run_id`,否则跳过等下一轮 scanner
这意味着 agent 一侧必须遵守:
- **写 `step=running, run_id=R<N>` 之后,必须紧接着写 `watch {step, run_id=R<N>, ...}`**——同一秒、同一个工具调用块内、不要被别的写入打断。理想是把"reset status + watcher 声明"做成一次 append 数组写入。
- **跨 round 的 watch path 即使重复也要重发**(如同样的 `_SUCCESS` 路径),不能依赖"上一 round 那个 watch 还在"——`run_id` 不一样,watcher 任务也是新的。
- **`run_id` 字段必填**,缺失会被 scanner 当成 `'?'` 处理,`'?' != 'R2'` 直接 skipwatcher 永远起不来。
**反模式(实际踩过的坑)**
- agent 写完 `sft=running` 后没在同事务里写 watch → scanner 这一轮扫到时只有 status,没有匹配 run_id 的 watch → 用历史 watch 的 path 注册 watcher(旧逻辑下),run_id 错位
- watcher fire 后 agent 看 status 没动,又手动 echo 一条 `sft=complete`(违反 R5 末段)→ 后端的 scanner 已经修,但 agent 协议层面还是要 hold 住
**自查**grep `program-state.jsonl` 里所有 `watch` 条目,每条的 `run_id` 必须能在前面(同一 round)找到匹配的 `step=<step>, status=running, run_id=<同值>` 条目。
### State 文件位置
```
@@ -175,8 +246,7 @@ mkdir -p "$SESSION_OUTPUT"
|----------|----------|
| `cml` | CML 评测 |
| `gold-drift` | Gold Drift |
| `dist-analysis` | 分层结果分析 |
| `report` | 问题分析 & 报告 |
| `dist-analysis` | 分层结果分析 & 报告(含根因归类、workflow<runDic>.md 产出) |
| `hypothesis` | 形成假设 |
| `augment` | 数据增强 |
| `verify` | 修改返回验证 |
@@ -280,7 +350,7 @@ echo '{"watch":{"step":"cml","kind":"file_exists","path":"'$ROOT/workflow$RUNDIC
要把日志推到 UI 底部那块黑色 Live Log 区,追加:
```bash
echo '{"log":{"ts":"11:55:10","iter":"R3","text":"Step 3 开始: 问题分析 & 报告生成"}}' >> "$SESSION_OUTPUT/program-state.jsonl"
echo '{"log":{"ts":"11:55:10","iter":"R1","text":"Step 1 dist-analysis: 写 workflow<runDic>.md,根因归类完成"}}' >> "$SESSION_OUTPUT/program-state.jsonl"
```
### 不要做的事
@@ -339,6 +409,11 @@ echo '{"log":{"ts":"11:55:10","iter":"R3","text":"Step 3 开始: 问题分析 &
2. **假设驱动**:每轮必须能回答"这轮验证了什么?学到了什么?下一轮改什么?"
3. **NEVER STOP**:全程不打断用户,循环直到达标或人类主动打断
4. **从 basemodel 训练**:每轮 SFT 的 `--model_path` 必须是 basemodel,禁止从上轮 ckpt 继续训
5. **复杂度优先**:分析类任务(近邻检索 / 聚类 / 相似度统计)选算法前先估数据规模。**忌**对几万行训练集用 `sklearn.fit_transform` 这类要全量物化稀疏矩阵或 embedding 矩阵的 API — 单次 600s 仍可能 timeout。**>1 万行训练集做近邻必须先粗筛后精排(倒排索引 → 每错例 50–300 候选 → 精排),禁止 O(M·N) 全量比对**——37×30k=1.1M 次朴素比较 ~3min,粗筛后 7.4k 次 ~10s。错例侧的"剪枝"只是常数优化,不能替代粗筛。详见 [references/program.md §2.3](references/program.md)
6. **大文件先切片**>10MB 量级的远端 CSV/JSONL(如 `specific_comparison.csv`),先用 bash `awk/grep/head` 在远端切出目标子集再处理。**忌**直接 `pd.read_csv` 整体加载或把 DataFrame 当返回值穿过工具调用 — 会撞 runtime 的输出/返回大小限制(实测 99MB 直接读 → "太大了" 失败)
7. **跨脚本复用走 /tmp pickle 缓存**:同一轮 dist-analysis 里 all_train.jsonl 这种"多个脚本都要读的训练集"必须缓存——第一次读完用 `pickle.dump(rows, '/tmp/all_train_<runDic>.pkl')`pod /tmp 是本地 SSD),后续脚本以 `if path.exists(): pickle.load(path) else: 重建 + 落盘` 模式启动。倒排索引同理。**忌**每个脚本都重新 `for line in open(jsonl): json.loads(line)` 全表 — 30k 行 NFS jsonl 每次 515s,从本地 pickle unpickle <1sv32 R0 5 次重读累计 ~50s 可省。脚本文件名最好写 cache key(如 `kn_search_v2_<runDic>.py`),换轮换 runDic 自动失效。
8. **stdout 即 LLM 下一轮 input,分级 print**:每个分析脚本的 stdout 会原样喂回 LLM 当下一轮上下文,每 KB 都要 prefill。**只 print 决策需要的聚合**(端点抽样总数、各 verdict 的计数、top-3 exemplars 文字),**明细落 `/tmp/<step>_<runDic>_detail.json`**(每条错例的 3 近邻 + 相似度 + token overlap 等)后续要回看再 `cat` 该文件。v32 R0 实测 kn_search 一次 stdout 18KB、judge_check 4.7KB、mislabel 11.3KB60% 是重复的 per-case 全量 dump,LLM 看完只用一句话总结——这部分 prefill cost 是直接浪费。还有:`cat > /tmp/x.py <<EOF ... EOF` 模式 runtime 会把每行 PS2 提示符 `> ` 回显进 stdout(实测一次累计 1–2KB),改用 `python3 -c "open('/tmp/x.py','w').write(open('/dev/stdin').read())" <<'PY' ... PY``base64 -d` 注入,可以彻底消掉 `> > >` 噪声。
9. **一律走 bash + 脚本文件,禁用 python_exec**:所有 python 任务把代码写到远端 `/tmp/xxx.py`,用 `bash``python3 -u /tmp/xxx.py 2>&1 | tee /tmp/xxx.log`。**忌**用 python_exec — 它 stdout 全缓冲、turn 结束才 flush,超时被 kill 时 buffer 直接丢,故障时连 phase 时序都看不到(实测 600s/1800s 撞墙后 `tool_result` 没有任何 stdout 字段)。bash + tee 模式 stdout 实时落盘,超时也能 `tail /tmp/xxx.log` 看到死在哪。
## 达标条件
@@ -365,8 +440,7 @@ step key 跟 Step 编号映射:
|------|----------|------|
| Step 0 | `cml` | CML 评测当前模型 |
| Step 0 (附带) | `gold-drift` | Gold drift 检查 |
| Step 1 | `dist-analysis` | 分层结果分析 |
| Step 2 | `report` | 问题分析 & 报告 |
| Step 1 | `dist-analysis` | 分层结果分析 + 问题分析 & 报告(写 workflow<runDic>.md |
| Step 3 | `hypothesis` | 形成假设(写 iteration_log |
| Step 4 | `augment` | 数据增强 / 生成 |
| Step (干预后) | `verify` | 修改返回验证 |
@@ -377,8 +451,7 @@ step key 跟 Step 编号映射:
```
LOOP:
Step 0: CML 评测(当前模型)+ Gold drift 检查
Step 1: 分层结果分析(需求集合 → 大盘车载 → specific test
Step 2: 问题分析 & 报告(根因归类 / 跨轮 diff / 天花板诊断)
Step 1: 分层结果分析 + 问题分析 & 报告(需求集合 → 大盘车载 → specific test;根因归类 / 跨轮 diff / 天花板诊断 / 写 workflow<runDic>.md
Step 3: 形成假设(写入 iteration_log.jsonl
Step 4: 数据生成(仅 data 归因时做)
Step 5: SFT 训练(submit_sft_via_cml.sh
@@ -423,6 +496,27 @@ assets/
- 跨子集净退步(#4
- 连续 3 轮目标子集净提升 ≤ 0.5pp(#5
### ⛔ 落 gate 前必读:30 秒自检三问(**任一不过 = 不写 gate,直接进下一步**)
写 gate entry / 在 chat 里向用户提问之前,**逐条过这三问**。下面任何一段流程示例都默认你已经过了这三问;过不了,再漂亮的 summary/proposal/ask 也是干扰用户。
**Q1. 是真 §HiTL 信号吗?**
- ✅ 真信号:label-master 预审后残留 > 50/200、Gold drift ≥ 10、跨子集净退步、连续 3 轮无提升 等列表里写明的条件
- ❌ 凑出来的理由:`第一次跑想让用户校方向` / `我担心副作用` / `想让用户拍板更稳` / `proposal 听起来风险大` —— 这些都是脑补,不是信号
**Q2. `ask` 是真分叉吗?**
- ✅ 真分叉 = 用户的判断能改变下一步动作:候选量收窄策略、回滚 vs 续训、换目标子集思路、改阈值
-**"H? 假设组合"不是分叉**`H1+H2 一起 vs 只跑 H1``先做 H1 还是先做 H2``激进 vs 保守 vs 中庸``要不要追加 H3` —— 假设的**拆分、组合、顺序、激进度**全是 agent 自己根据信号该决定的,决定完写进 `proposal` 公布即可,**不要甩给用户**
**Q3. 拆 H 的依据是数据信号还是脑补 trade-off?**
- ✅ 数据信号:mislabel 近邻数、no_neighbor 占比、pattern 分布、其他子集的实测分数差
- ❌ 脑补:`改这 12 条可能会让 X 子集下降` / `H2 加多了可能过拟合` —— 没跑过就是推测;推测可以写进 `proposal` 当 caveat"预期回收 ~10 条,trade-off 待 R1 验证"),**做不出 ask**
> **反复踩坑案例**5/24 真实复盘):R0 baseline 跑完,37 错例里 12 条 mislabel(远低于 50 阈值),agent 自己脑补"H1 修标可能拖累线上挖掘召回complex 子集",于是抛 `H1+H2 一起 vs 只跑 H1(激进 vs 保守)` 让用户拍板。**三问全挂**:信号没命中(Q1 ❌,12 < 50)、ask 是 H 组合(Q2 ❌)、副作用是推测(Q3 ❌)。**正确做法**:定下方案写进 proposal 公布,直接进 augmenttrade-off 留给 R1 评测验证。
如果三问都过 = 真有事要用户拍 → 按下面 `### 写 gate 节点` 的写法落盘 + chat ask。
如果有一条不过 = 没事 → 不写 gate、不在 chat 里凑问题、直接进下一步。
### 写 gate 节点(让 UI 显示 Human Check / Review 卡)
凡是要让用户拍板的检查点,**必须** append 一条 gate entry 到 `program-state.jsonl`**再** 用 chat reply 提问。UI 会在当前 round section 之后插入「Human Check」或「Human Review」横向卡片(IN PROGRESS 状态)。
@@ -435,10 +529,10 @@ assets/
| 时机 | gate 类型 | run_id |
|---|---|---|
| R0 baseline 分析完成、要让用户确认是否进 R1 train命中 HiTL 信号 / 候选量大 / 目标子集偏低 / 第一次跑想让用户校方向 等 | `human-check` | `R0` |
| R0 baseline 分析完成、命中 §HiTL 信号要让用户拍板(label-master 预审后残留候选超阈值、目标子集异常、跨子集分歧大 等真实信号;⛔ **不是**"第一次跑想让用户校方向" / "我担心 H1 修标的副作用" / "想让用户在激进/保守里选"这种凑出来的理由——先过上面的自检三问 | `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 |
| §4.0.1 Step B**label-master 预审后**残留候选 > 200 条命中触发条件 #3(原扫数不算数) | `human-check` | 当前 round |
| 其他 HiTL 信号(label-master 预审后残留 > 50 条、Gold drift ≥ 10 条 等) | `human-check`(开始前)/ `human-review`(结果后) | 当前 round |
判断标准就一条:**只要你下一步打算 chat-ask 用户拍板,就先写 gate entry 再问**。
@@ -447,11 +541,16 @@ assets/
**强烈推荐结构化三段写法**`summary` / `proposal` / `ask`)——UI 会渲染成"现状 / 提议 / 请选"三个带标签行,用户一眼看明白。`reason` 留作 fallback。
```bash
# R0 baseline 之后想让用户拍板是否进 train(推荐结构化)
# ⛔ 写之前已经过了上面 §"30 秒自检三问"——否则不要写这条 gate。
# ⛔ ask 必须是真分叉。⛔ "H1+H2 一起 vs 只跑 H1"、"激进 vs 保守"、"先 H1 还是先 H2" 这类
# "假设组合"统统不是分叉——是 agent 自己根据信号决定的,决定完写进 proposal 公布即可。
# R0 baseline 后命中真实 HiTL 信号(这里是候选量超阈值),让用户拍板更精细 pattern
# ⚠️ 给用户排板的候选数量必须是 §4.0.1 Step A.5 label-master 预审之后的残留数(推荐 != old_label 的那部分),
# 不是 wide pattern 原始扫出来的数。原始数 label-master 还要剔掉一大半,先用原始数找用户=干扰用户判断。
echo '{"step":"human-check","status":"running","run_id":"R0",
"summary":"R0 baseline 完成;复杂导航过召专项0511 = 58.89%(53/90)37 错全为 complex 误判",
"proposal":"H1(标签纠错):7 条原标 complex=true 但实际是简单导航的样本改回 complex=false。 H2(数据增强):仿写 100 条 complex=false 的简单导航 query 补进训练集,平衡正负样本",
"ask":"是否按 H1+H2 一起进 R1 train?还是先只跑 H1 验证一轮?",
"summary":"R0 baseline 完成;复杂导航过召专项0511 = 58.89%(53/90)wide pattern 原扫 412 条,label-master 预审后残留 287 条(> 200 阈值)",
"proposal":"H1(标签纠错):按 label-master 推荐改这 287 条 complex=true complex=false。 H2(数据增强):仿写 100 条 complex=false 的简单导航 query 补进训练集",
"ask":"残留 287 条仍偏多,是全部按 label-master 推荐改、还是先收窄到 query 含「打开/进入」的子集(约 110 条)单独审一轮?",
"ts":"'$(date -Iseconds)'"}' >> $S
# R1 评测发现 regression
@@ -462,7 +561,8 @@ echo '{"step":"human-review","status":"running","run_id":"R1",
"ts":"'$(date -Iseconds)'"}' >> $S
# fallback:只写 reason 也能跑(前端会启发式切分),但不如结构化清晰
echo '{"step":"human-check","status":"running","run_id":"R0","reason":"候选量 412 命中规则上限,需要人工定更精细 pattern 收窄","ts":"'$(date -Iseconds)'"}' >> $S
# 注意 reason 里的"412"也是 label-master 预审后残留数,不是原扫数
echo '{"step":"human-check","status":"running","run_id":"R0","reason":"label-master 预审后残留 412 条仍超阈值,需要人工定更精细 pattern 收窄","ts":"'$(date -Iseconds)'"}' >> $S
```
**顺序不能反**:先 echo gate entry → 再 chat reply 给用户。否则用户先看到聊天问话、UI 里却没卡,会困惑"流程是不是卡死了"。
@@ -476,7 +576,7 @@ echo '{"step":"human-check","status":"running","run_id":"R0","reason":"候选量
| `run_id` | ✅ | 当前所在轮次(决定 gate 插在哪个 section 后) |
| `summary` | 🔼 | **现状一句话**:跑了什么、关键数字。例:`R0 baseline 完成;专项 58.89%(53/90)37 错全为 complex 误判` |
| `proposal` | 🔼 | **打算怎么干**:每个 H 单独说"H? (类型):具体做什么"。详见下面规则 |
| `ask` | 🔼 | **让用户选什么**用问句给出 A/B 选项。例:`是否按 H1+H2 进 R1 train?还是先只跑 H1 验证一轮?` |
| `ask` | 🔼 | **让用户选什么**必须是真分叉(用户的判断能改变下一步动作)。例:`label-master 预审后残留 287 条偏多,全改、还是收窄到「打开/进入」子集(~110 条)单独审一轮?` ⚠️ 写候选数量必须是 §4.0.1 Step A.5 label-master 预审后的残留数,不是原扫数。⛔ 反例:`H1+H2 一起 vs 只跑 H1`——假设组合是你定的,不甩给用户 |
| `reason` | ⭕ | 兜底用:没写 summary/proposal/ask 时前端会拿 reason 做启发式切分。但**优先用结构化三段**,别只写 reason |
| `ts` | ✅ | ISO 时间戳 |
@@ -496,6 +596,12 @@ echo '{"step":"human-check","status":"running","run_id":"R0","reason":"候选量
- 流程自洽说明(`需要人工逐条审 1/0``走 sanity check``过 label-master 复核`)—— 这些是 agent 内部流程,对用户决策没用
- 候选量区间括号注释(`100~150 触发 51-200 区间`)—— 数量 OK,区间归属归属是规则细节,删
**`ask` 字段尤其要注意:**
**不要把"H? 假设组合"作为分叉抛给用户**——如 "H1+H2 一起 vs 只跑 H1"、"先做 H1 还是先做 H2"。假设的拆分和组合是 agent 自己根据信号决定的,决定完写进 proposal 公布即可,不需要用户拍板。`ask` 只在**真有分叉**时才写:候选量收窄策略、回滚还是续训、目标子集换思路 等用户判断能改变下一步动作的场景。
如果一个 R0/R{n} 没有任何真分叉(只是想"汇报+确认"),不要硬凑 ask、也不要写 gate——直接进下一步。
写 proposal 时问自己:**"这句话如果交给一个新加入的产品同学看,他能不能 5 秒内明白要干什么"**。能 = ✅;得回头查 §X.X.X 才能懂 = ❌,重写。
**用户拍板回复后**append `status:"complete"` 同 step + run_id 一行,gate 卡变 COMPLETED;然后才继续往下走(继续/回滚/调参)。
@@ -524,7 +630,7 @@ xiaomi_cloudml:
|---|---|---|
| `results/iteration_log.jsonl` | 每轮假设/干预/判定完整记录 | hypothesis / log |
| `results/error_registry.jsonl` | 跨轮错误追踪(case_hash → 出错轮次) | log |
| `results/workflow<runDic>.md` | 每轮回归分析报告 | dist-analysis / report |
| `results/workflow<runDic>.md` | 每轮回归分析报告 | dist-analysis |
| `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` | 旧数据清洗存档(删除项) | — |