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:
+131
-25
@@ -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 写在当前 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 都适用)
|
||||
### Step 1 → 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 结论。
|
||||
@@ -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 + 一个 watcher;watcher 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'` 直接 skip,watcher 永远起不来。
|
||||
|
||||
**反模式(实际踩过的坑)**:
|
||||
- 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 每次 5–15s,从本地 pickle unpickle <1s,v32 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.3KB,60% 是重复的 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 公布,直接进 augment,trade-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` | 旧数据清洗存档(删除项) | — |
|
||||
|
||||
Reference in New Issue
Block a user