Files
Video-Tree-TRM5/research-wiki/designs/2026-07-14-maintenance-pool-design.md
2026-07-14 10:13:57 -04:00

143 lines
5.2 KiB
Markdown
Raw Permalink 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.
---
id: maintenance-pool
title: 训练池 Maintenance 正确题自动补入机制
type: design
created: 2026-07-14
status: approved
---
# 训练池 Maintenance 正确题自动补入机制
## 1. 目标
`PerCategoryPoolStrategy` 的池构建阶段,baseline infer 完成后、分层划分前,自动检测每个 task_type 分组的正确/错误比例。若正确题占比低于 `batch_correct_ratio`,从 `test_questions_dir`VME benchmark)中补入该 task_type 的已验证正确题,使训练集有足够的正确题满足 batch 构建需求。
### 驱动场景
SubPattern 靶向出题(如 AR30)刻意针对 agent 失败模式,agent 在 baseline infer 中大部分答错。`batch_correct_ratio=0.5` 要求 mini-batch 一半正确一半错误,但 train 池正确题不足会导致 batch 构建失败或质量下降。
## 2. 算法
`PerCategoryPoolStrategy.build()` 的 Phase 2(按 task_type 分组)和 Phase 3(分层划分)之间插入 Phase 2.5。
### 候选筛选
当前 baseline correctness dict 仅包含训练题(如 AR30),**不包含 benchmark 题**。因此补入候选的正确性判定需要额外查询 DB 中的历史推理记录:
```
# 从 DB 查询所有 run 中对 benchmark 题的评估结果(取最新一次)
benchmark_correctness = query_db(
"SELECT question_id, prediction, answer FROM predictions
WHERE question_id IN (benchmark_qids)
ORDER BY timestamp DESC"
)
# 每个 question_id 取最新记录判定正确性
```
若 DB 中无该题的历史记录,该题不作为候选(不假设正确)。
### 补入流程
```
对每个 task_type 分组:
c = 该组正确题数(来自当前 baseline correctness
w = 该组错误题数
r = batch_correct_ratio
if batch_correct_ratio 为 None:
跳过
ratio = c / (c + w)
if ratio > 1 - r:
logger.warning(
"类别 {} 正确率 {:.1%} 过高(阈值 {:.1%}),出题可能太简单",
task_type, ratio, 1 - r,
)
if ratio >= r:
跳过(正确题已充足)
k = ceil((r * w - (1 - r) * c) / (1 - r))
candidates = test_questions_dir 中同 task_type 的题
∩ DB 历史推理中正确的
已在当前组中的 question_id
actual = min(k, len(candidates))
补入 actual 道:
- 构造新 GeneratedQuestionclonefamily="VME_MAINTENANCE"
- correctness[qid] = True
合并到该 task_type 分组
```
### 接口传参
`PerCategoryPoolStrategy.build` 新增 `db_path: Path | None = None` 参数,用于查询历史 benchmark 推理记录。调用方 `build_or_load_pools` 已持有 `db_path`,直接透传。
### 边界情况
| 场景 | 行为 |
|------|------|
| 正确率已满足 r | 不补入 |
| 候选不足(如需 30 道但只有 41 道可用) | 补入全部可用,接受比例不完美 |
| `batch_correct_ratio` 为 None | 跳过补入 |
| `test_questions_dir` 为 None | 跳过补入 |
| DB 中无 benchmark 历史记录 | 无候选,不补入(日志警告) |
| 补入题与 test 池重复 | 允许 — test 池保持完整不动 |
| `_split_one_category` 的 floor 造成 ±1 误差 | 接受 — 比例不完美是预期行为 |
| 正确率 > 1 - r(如 r=0.5 时正确率 > 50% | `logger.warning` 警告出题可能太简单,不阻断 |
## 3. 接口变更
| 组件 | 变更 |
|------|------|
| `PoolConfig` | 新增字段 `batch_correct_ratio: float \| None = None` |
| `_to_pool_config` | 从 `RunConfig.batch_correct_ratio` 映射(`RunConfig` 已有该字段,默认 0.5 |
| `PerCategoryPoolStrategy.build` | 新增 `db_path` 参数;Phase 2 和 Phase 3 之间插入 Phase 2.5 |
| `build_or_load_pools` | 透传 `db_path``strategy.build()` |
### 不变的部分
- `_split_one_category` 不改 — 补入后的分组正常走分层划分
- test 池加载(Phase 4)不改 — 63 道 VME AR 完整保留
- `GlobalPoolStrategy` 不改
- pipeline / runner / batching 不改
## 4. 补入题的标记与追溯
| 字段 | 值 | 说明 |
|------|-----|------|
| `family` | `"VME_MAINTENANCE"` | 区分于 `"ACTION_RECOGNITION"` 生成题 |
| `skill_target` | 保持原题值 | 从 benchmark 原始数据继承 |
| correctness | `True` | 来源定义:从"已验证正确"池选出 |
## 5. 数据流
```
baseline infer (30 道 AR30)
correctness = {qid: True/False} (如: 5 correct, 25 wrong)
PerCategoryPoolStrategy.build()
Phase 1: 按 task_types 过滤
Phase 2: 按 task_type 分组
Phase 2.5: ←── 新增 maintenance 补入
检查: c=5, w=25, r=0.5 → 需补 k=20
从 VME benchmark 加载 AR 正确题 (41 道)
排除已有 → 补入 min(20, 41) = 20 道
组总量: 50 (25 correct, 25 wrong)
Phase 3: _split_one_category (train_ratio=0.667)
train: 33 题 (≈17 correct + 16 wrong)
val: 17 题 (≈8 correct + 9 wrong)
Phase 4: test 池 (63 道 VME AR,完整不动)
```
## 6. 非功能性需求
| 维度 | 设计 |
|------|------|
| 持久化 | 补入题写入 pools.json 冻结,与原生题一视同仁 |
| 幂等性 | pools.json 存在则直接加载,不重复补入 |
| 断点续跑 | 不影响 — pools.json 冻结后训练可断点恢复 |
| 原子性 | 不适用 — 池构建是一次性操作 |