docs: revise question-gen v2 design per Codex review (pair-unit contract, AR-only gate, phasing)
This commit is contained in:
@@ -20,7 +20,9 @@ v2 从**四层**对症重构,用户锁定三个治本方向:
|
|||||||
| grounding | **独立 VLM(MiniMax-M3)打分**(CLIP 跨模态 embedding 无法服务,退回独立 judge,仍断循环自证) |
|
| grounding | **独立 VLM(MiniMax-M3)打分**(CLIP 跨模态 embedding 无法服务,退回独立 judge,仍断循环自证) |
|
||||||
| 对抗位置 | **轻量代理内联 + 完整 agent 后置第二道网** |
|
| 对抗位置 | **轻量代理内联 + 完整 agent 后置第二道网** |
|
||||||
|
|
||||||
**范围铁律**:v2 只重构 **Action Recognition** 路径;11 个非 AR 题型走现有 `generate-v2` **零改动**(路径隔离)。代价:题库出现"AR 新格式 + 非 AR 旧格式"混格,评测/训练侧须兼容两种。
|
**范围铁律**:v2 只重构 **Action Recognition** 路径;11 个非 AR 题型走现有 `generate-v2` **零改动**(路径隔离,byte-identical)。代价:题库出现"AR 新格式 + 非 AR 旧格式"混格,评测/训练侧须兼容两种。
|
||||||
|
|
||||||
|
> **multi_true 收紧口径(C4 隔离)**:Phase A 的 multi_true 收紧原为 12 类统一门,会破坏"非 AR byte-identical"铁律。v2 将收紧做成 **AR-only**——新增 AR 专属 gate 变体/参数,由 strategy 分流;**非 AR 仍走 Phase A 现有 gate**(不动 rubric,保住 byte-identical)。AR sub-pattern 的改动全部锚定 `app/question_gen/strategy_action_recognition.py`(6 个 SubPattern 定义)与 `app/question_gen/strategy.py::SubPattern`(`supports_flip`/`flip_axis` 字段),**不涉及** `families.py`。
|
||||||
|
|
||||||
### 路径归属
|
### 路径归属
|
||||||
|
|
||||||
@@ -29,24 +31,24 @@ v2 从**四层**对症重构,用户锁定三个治本方向:
|
|||||||
| 双模式生成 | 新建 `app/question_gen/contrastive_gen.py` | 仅 AR(strategy 声明开关分流) |
|
| 双模式生成 | 新建 `app/question_gen/contrastive_gen.py` | 仅 AR(strategy 声明开关分流) |
|
||||||
| 独立 VLM grounding | 改 `distractor_selector.py` `_score_options` + 装配加第二 VLM | 仅 AR selector 调用点 |
|
| 独立 VLM grounding | 改 `distractor_selector.py` `_score_options` + 装配加第二 VLM | 仅 AR selector 调用点 |
|
||||||
| 内联对抗探针 | 新建 `app/question_gen/adversarial_probes.py` | 仅 AR |
|
| 内联对抗探针 | 新建 `app/question_gen/adversarial_probes.py` | 仅 AR |
|
||||||
| 门收紧 + NLI + 歧义门 | `gate_multi_true.md` 收紧 + 新 gate | multi_true 公共(收紧,用户批准);NLI/歧义门仅 AR |
|
| 门收紧 + NLI + 歧义门 | AR 专属 multi_true gate 变体 + 新 gate | **仅 AR**(收紧、NLI、歧义门均 AR-only,由 strategy 分流;非 AR 走 Phase A 现有 gate 不动) |
|
||||||
| pair 契约 | `core/types.py` `GeneratedQuestion` + harness/loader | 公共类型(新字段默认值兼容非 AR) |
|
| pair 契约 | `core/types.py` `GeneratedQuestion` + `app/question_gen/loader.py` + `app/harness/batching.py` + `app/harness/inference.py` | 公共类型(新字段默认值兼容非 AR);QuestionUnit 抽象贯穿采样/分批/聚合三处 |
|
||||||
| 后置双向评分 | 改造 `adversarial_filter.py` | filter 层,`filter_task_types` 默认 AR |
|
| 后置双向评分 | 改造 `app/question_gen/adversarial_filter.py` | filter 层,`filter_task_types` 默认 AR |
|
||||||
|
|
||||||
## 2. Prior-Version Audit(v2 替换/改造的既有行为)
|
## 2. Prior-Version Audit(v2 替换/改造的既有行为)
|
||||||
|
|
||||||
| 既有行为 | v2 处置 |
|
| 既有行为 | v2 处置 |
|
||||||
|---------|---------|
|
|---------|---------|
|
||||||
| `distractor_selector` VLM 自评选负项 | **改造**:打分器换独立 MiniMax-M3;区间选择/退火/hard-fail 落库**保留** |
|
| `distractor_selector` VLM 自评选负项 | **改造**:打分器换独立 MiniMax-M3;区间选择/退火/hard-fail 落库**保留** |
|
||||||
| `adversarial_filter` 翻转门(事后生成镜像 Q) | **改造**:镜像在生成期已产出,翻转门→对 pair 做双向 AND 评分(不再事后生成) |
|
| `adversarial_filter` 翻转门(事后生成镜像 Q) | **改造**:镜像在生成期已产出,不再事后生成;翻转门语义**沿用 Phase B 修正**([2026-07-14-adversarial-question-gen-phaseB-design.md §4.2]:不判对错,只看 canonical answer 是否随问题翻转),作为对抗有效性 filter(见 §4.5,与 pair correctness 评分正交) |
|
||||||
| `adversarial_filter` 作弊门(后置试答) | **保留**,定位为后置第二道网 |
|
| `adversarial_filter` 作弊门(后置试答) | **保留**,定位为后置第二道网 |
|
||||||
| `adversarial_filter` 补生成迭代 / 两份 JSON | **保留** |
|
| `adversarial_filter` 补生成迭代 / 两份 JSON | **保留** |
|
||||||
| `gate_multi_true` 松绑 rubric | **反向收紧**(precision over recall,撤销 Phase A 松绑) |
|
| `gate_multi_true` 松绑 rubric | **反向收紧**(precision over recall,撤销 Phase A 松绑);**仅 AR**(AR 专属 gate 变体,非 AR 保持 Phase A rubric 不动) |
|
||||||
| on_accept 逐题追加 / progress 断点 / verdicts 表续跑 / 原子写 | **保留**,pair 需原子成对落盘(见 §7) |
|
| on_accept 逐题追加 / progress 断点 / verdicts 表续跑 / 原子写 | **保留**,pair 需原子成对落盘(见 §7) |
|
||||||
| 4 选项 + 字母答案契约 | **扩展**:加 pair 语义;单题仍 4 选,pair 双向 AND 评分 |
|
| 4 选项 + 字母答案契约 | **扩展**:加 pair 语义;单题仍 4 选,pair 双向 AND 评分 |
|
||||||
| 11 非 AR generate-v2 全流程 | **零改动** |
|
| 11 非 AR generate-v2 全流程 | **零改动** |
|
||||||
|
|
||||||
未发现隐式删除。唯一有意行为变更:AR 出题机制整体重构;multi_true 全局收紧(有意,用户批准)。
|
未发现隐式删除。唯一有意行为变更:AR 出题机制整体重构;multi_true 收紧限定 **AR-only**(有意,用户批准;非 AR byte-identical 不受影响)。
|
||||||
|
|
||||||
## 3. 架构与数据流
|
## 3. 架构与数据流
|
||||||
|
|
||||||
@@ -60,7 +62,7 @@ flowchart TD
|
|||||||
GRD --> PROXY[内联轻量对抗探针<br/>text-only 盲答 + MiniMax 快解]
|
GRD --> PROXY[内联轻量对抗探针<br/>text-only 盲答 + MiniMax 快解]
|
||||||
PROXY -->|被秒杀| RE[回灌失败模式重生]
|
PROXY -->|被秒杀| RE[回灌失败模式重生]
|
||||||
RE --> GRD
|
RE --> GRD
|
||||||
PROXY -->|存活| GATE[门: key_verify + multi_true收紧<br/>+ NLI禁蕴含 + leak + MiniMax歧义门]
|
PROXY -->|存活| GATE[门: key_verify + multi_true收紧-AR变体<br/>+ NLI禁蕴含 + leak + MiniMax歧义门+NLI]
|
||||||
GATE -->|失败| RE
|
GATE -->|失败| RE
|
||||||
GATE -->|通过| ACC[on_accept 落盘<br/>pair 原子成对写]
|
GATE -->|通过| ACC[on_accept 落盘<br/>pair 原子成对写]
|
||||||
ACC -.批次后置.-> NET2[完整 agent 作弊门第二道网<br/>pair 双向 AND 评对 + 补生成迭代]
|
ACC -.批次后置.-> NET2[完整 agent 作弊门第二道网<br/>pair 双向 AND 评对 + 补生成迭代]
|
||||||
@@ -71,7 +73,7 @@ flowchart TD
|
|||||||
|
|
||||||
### 4.1 双模式生成(`contrastive_gen.py`,仅 AR)
|
### 4.1 双模式生成(`contrastive_gen.py`,仅 AR)
|
||||||
|
|
||||||
`SubPattern` 已有 `supports_flip`/`flip_axis`(Phase B Task 1)。生成分流:
|
`SubPattern`(`app/question_gen/strategy.py::SubPattern`)已有 `supports_flip`/`flip_axis`(Phase B Task 1),6 个 AR SubPattern 定义在 `app/question_gen/strategy_action_recognition.py`(`temporal`/`cross_segment` 标 `supports_flip=True`)。**本节所有 sub-pattern 改动锚定这两个文件,不涉及 `families.py`。** 生成分流:
|
||||||
|
|
||||||
**A. 可翻转(temporal→before/after, cross_segment→first/last)— 镜像对**
|
**A. 可翻转(temporal→before/after, cross_segment→first/last)— 镜像对**
|
||||||
- VLM 生成题 P(正解 + 干扰项)后,**同素材翻转 flip_axis** 生成镜像 Q(正解天然相反);
|
- VLM 生成题 P(正解 + 干扰项)后,**同素材翻转 flip_axis** 生成镜像 Q(正解天然相反);
|
||||||
@@ -82,12 +84,29 @@ flowchart TD
|
|||||||
- VLM 生成正解 + 3 个**单维反事实**(各改一维、互不重叠 → 防逐槽多数投票);
|
- VLM 生成正解 + 3 个**单维反事实**(各改一维、互不重叠 → 防逐槽多数投票);
|
||||||
- 硬约束(写进 prompt + 后置校验):**等信息量/等长**、**禁蕴含**(正解非任一干扰项子串、反之亦然)、**动词/事件结构**上反事实(非名词替换,VITATECS 警示名词替换易解)。
|
- 硬约束(写进 prompt + 后置校验):**等信息量/等长**、**禁蕴含**(正解非任一干扰项子串、反之亦然)、**动词/事件结构**上反事实(非名词替换,VITATECS 警示名词替换易解)。
|
||||||
|
|
||||||
|
> **不可翻转 4 子模式的可量化验收指标(I4)**:1-vs-3 结构仍有残留偏置风险,探针 + 歧义门是**过滤**(拦截)而非**构造消除**,故须以下量化闸门验收(阈值进科研 YAML,见 §10):
|
||||||
|
>
|
||||||
|
> | 指标 | 验收阈值 | 手段 |
|
||||||
|
> |------|---------|------|
|
||||||
|
> | text-only 盲答正确率 | 接近随机基线(4 选 ≈ 0.25,超出容差即判可纯文本解) | §4.3 盲答探针 |
|
||||||
|
> | 选项长度 / 词频均衡 | 各选项 token 长度极差 ≤ 阈值、词频分布通过均衡检查 | 后置校验 |
|
||||||
|
> | 禁蕴含通过率 | 100%(存在蕴含即 fail) | §4.4 NLI 门 |
|
||||||
|
> | MiniMax 快解拒绝率 | ≤ 上限(快解率过高说明视觉依赖不足) | §4.3 快解探针 |
|
||||||
|
|
||||||
### 4.2 独立 VLM grounding(改 `distractor_selector.py`)
|
### 4.2 独立 VLM grounding(改 `distractor_selector.py`)
|
||||||
|
|
||||||
- **装配拆分**:`InfraSettings` 新增读 `M3_VL_LLM_*`;adapter 产出**第二个 `GovernedVLMClient`**(scorer_vlm=MiniMax-M3)。生成用主 VLM(qwen),打分用 scorer_vlm。
|
- **装配拆分**:`InfraSettings` 新增读 `M3_VL_LLM_*`;adapter 产出**第二个 `GovernedVLMClient`**(scorer_vlm=MiniMax-M3)。生成用主 VLM(qwen),打分用 scorer_vlm。
|
||||||
- `build_grounded_options` 增 `scorer_vlm` 形参;`_score_options` 用 scorer_vlm。区间选择 `[s_correct-δ_high, s_correct-δ_low]` / 退火 / hard-fail 落库**逻辑不变**。
|
- `build_grounded_options` 增 `scorer_vlm` 形参;`_score_options` 用 scorer_vlm。区间选择 `[s_correct-δ_high, s_correct-δ_low]` / 退火 / hard-fail 落库**逻辑不变**。
|
||||||
- **早期风险校验**:MiniMax-M3 打分粒度未知(Phase A 观测到 qwen 自评是 1.0/0.1 粗档)。实现第一步抽验 scorer 打分是否够细;过粗则记录为已知局限并考虑候选池扩容补偿。
|
- **早期风险校验**:MiniMax-M3 打分粒度未知(Phase A 观测到 qwen 自评是 1.0/0.1 粗档)。实现第一步抽验 scorer 打分是否够细;过粗则记录为已知局限并考虑候选池扩容补偿。
|
||||||
|
|
||||||
|
> **ADR 风格决策说明(I1)——用 MiniMax-M3 当 grounding scorer 偏离 findings 技术建议**:
|
||||||
|
> - **偏离点**:findings 建议 grounding 不该由生成同源的 VLM 打分,应改用 CLIP 式 **embedding 跨模态度量**(对齐 GroundAttack)。本设计仍用一个 LLM/VLM(MiniMax-M3)作判分器,是**有意决策**——CLIP 在本项目基础设施上无法服务(无跨模态 embedding 通路),退而求其次用一个**独立于生成器**的 judge。
|
||||||
|
> - **解决了什么**:断掉 Phase A 的"生成器用自己的 VLM 自评 = 循环自证"。
|
||||||
|
> - **没解决什么**:不等价于 GroundAttack 的 embedding 跨模态度量;判分仍是 LLM 主观打分,非几何相似度。
|
||||||
|
> - **可观测风险 + 验收阈值**:scorer 打分粒度(是否退化成 1.0/0.1 粗档)为主要风险 → 实现第一步做 **scorer 打分粒度校验**(抽验分档分布),过粗即记为已知局限并触发候选池扩容补偿。
|
||||||
|
>
|
||||||
|
> **配置归属(I6,对照 CLAUDE.md §4.5)**:MiniMax API **endpoint/key 属工程配置**(`.env`,`M3_VL_LLM_*`,敏感不提交);**scorer 粒度阈值、探针阈值、`filter_task_types`** 属科研 YAML 配置,**进 run 快照保证可复现**。
|
||||||
|
|
||||||
### 4.3 内联轻量对抗探针(`adversarial_probes.py`,仅 AR)
|
### 4.3 内联轻量对抗探针(`adversarial_probes.py`,仅 AR)
|
||||||
|
|
||||||
生成候选通过 grounding 后、进正式门前,跑两个**便宜**探针(都不跑完整树搜索 agent):
|
生成候选通过 grounding 后、进正式门前,跑两个**便宜**探针(都不跑完整树搜索 agent):
|
||||||
@@ -101,24 +120,67 @@ flowchart TD
|
|||||||
| 门 | v2 处置 |
|
| 门 | v2 处置 |
|
||||||
|----|--------|
|
|----|--------|
|
||||||
| key_verify | 保留 |
|
| key_verify | 保留 |
|
||||||
| multi_true | **收紧**:撤销 Phase A 松绑,回到"≥2 选项在题干限定下都完全为真→fail",且取向 precision over recall(宁杀错) |
|
| multi_true(收紧,**仅 AR 变体**) | **收紧**:撤销 Phase A 松绑,回到"≥2 选项在题干限定下都完全为真→fail",且取向 precision over recall(宁杀错)。**仅作用于 AR**(AR 专属 gate 变体/参数,由 strategy 分流);**非 AR 走 Phase A 现有 multi_true gate 不动**(保 byte-identical) |
|
||||||
| NLI 禁蕴含门(新,仅 AR) | 用 NLI 模型(如 Sentence-BERT / 现有文本 embed 近似)判正解与各干扰项**互不蕴含**;存在蕴含→fail(杀子串/最模糊项) |
|
| NLI 禁蕴含门(新,仅 AR) | 用 NLI 模型(如 Sentence-BERT / 现有文本 embed 近似)判正解与各干扰项**互不蕴含**;存在蕴含→fail(杀子串/最模糊项) |
|
||||||
| MiniMax 歧义门(新,仅 AR) | MiniMax-M3 独立判:是否有干扰项其实**也正确/语义等价于正解**;有→fail(独立于生成器的"错误性/wrongness"核验) |
|
| MiniMax 歧义门 + NLI 复核(新,仅 AR) | MiniMax-M3 独立判:是否有干扰项其实**也正确/语义等价于正解**;有→fail(独立于生成器的"错误性/wrongness"核验)。**并加一路独立信号 NLI 文本蕴含复核**:干扰项与正解构成互相蕴含/语义等价(NLI 判定)亦→fail,**不单靠 MiniMax** |
|
||||||
| leak_test | 保留 |
|
| leak_test | 保留 |
|
||||||
|
|
||||||
### 4.5 完整 agent 后置第二道网(改造 `adversarial_filter.py`)
|
> **单模型多角色风险(I2)**:MiniMax-M3 在本设计里同时承担 **grounding 打分(§4.2)+ 快解探针(§4.3)+ 歧义门(本节)** 三个角色——这是**单模型多角色,不是多裁判**。若 MiniMax 对某类视频存在系统性偏差,三门会**同向失效**(同时误判、无相互纠偏)。缓解:歧义门**至少加一路与 MiniMax 独立的信号(NLI 文本蕴含)**,不把歧义判定完全押在 MiniMax 上;scorer 粒度校验(§4.2)持续监控系统性偏差。
|
||||||
|
|
||||||
- **作弊者门**:定位为后置第二道网(非唯一裁判)。完整树搜索 agent 试答;对 pair 做**双向 AND**(P、Q 都答对=太简单→剔)。
|
### 4.5 完整 agent 后置第二道网(改造 `app/question_gen/adversarial_filter.py`)
|
||||||
- **翻转门**:镜像已在生成期产出,**不再事后生成**;直接对 (P,Q) 做双向评对(reuse judge_flip:答案随问题翻转=有效,否则剔)。
|
|
||||||
|
> **两个正交口径(C5,务必分清,勿复用同一句)**:pair correctness 与翻转有效性是**两件事**,Phase B 已把翻转门语义修正为"不判对错、只看答案是否随问题翻转"([2026-07-14-adversarial-question-gen-phaseB-design.md §4.2])。v2 显式拆成两条互不复用的口径:
|
||||||
|
|
||||||
|
| 口径 | 定义 | 用途 | 判据 |
|
||||||
|
|------|------|------|------|
|
||||||
|
| **(a) pair correctness(评测/训练评分)** | P、Q **都答对**才得 1 分,否则 0 | 喂 harness 评分 / 诊断 / 进化(correctness 信号,见 §5) | prediction==answer 的**双向 AND** |
|
||||||
|
| **(b) 对抗翻转有效性 filter** | canonical answer 是否**随问题翻转**(**不判对错**) | 后置剔除偏置题(沿用 Phase B 修正语义) | 答案随问题翻转=有效保留,否则剔 |
|
||||||
|
|
||||||
|
- **作弊者门**:定位为后置第二道网(非唯一裁判)。完整树搜索 agent 试答;套用口径 (a) 对 pair 做**双向 AND**(P、Q 都答对=太简单→剔)。
|
||||||
|
- **翻转有效性 filter**:镜像已在生成期产出,**不再事后生成**;套用口径 (b)(reuse `judge_flip`)——只看 canonical answer 是否随问题翻转,**不判对错**;不翻转(偏置题)→剔。**与 (a) 分开执行,不复用同一次评分。**
|
||||||
- 补生成迭代 / 难度报告 / 两份 JSON / verdicts 续跑:**保留**。
|
- 补生成迭代 / 难度报告 / 两份 JSON / verdicts 续跑:**保留**。
|
||||||
|
|
||||||
## 5. 契约改动(评测/训练适配)
|
## 5. 契约改动(评测/训练适配)
|
||||||
|
|
||||||
|
核心抽象:引入 **`QuestionUnit`(single | pair)** 作为采样/分批/聚合三处的统一粒度,AgentLoop 仍逐题(MCQ)执行——unit 只活在 unit 层与聚合层,flatten 后喂 AgentLoop。三处必须一致使用同一 QuestionUnit 抽象(见自检)。
|
||||||
|
|
||||||
|
### 5.0 类型扩展
|
||||||
- `core/types.py::GeneratedQuestion` 新增:`pair_id: str | None`、`question_role: str`("single"|"pair_original"|"pair_mirror",默认 "single")、`flip_axis: str | None`。默认值保证 11 非 AR + 现有构造点不变。
|
- `core/types.py::GeneratedQuestion` 新增:`pair_id: str | None`、`question_role: str`("single"|"pair_original"|"pair_mirror",默认 "single")、`flip_axis: str | None`。默认值保证 11 非 AR + 现有构造点不变。
|
||||||
- **harness/eval 评分**:`question_role=="single"` 照常 MCQ;pair(同 `pair_id` 的 original+mirror)按**双向 AND**——两题都判对,pair 才计 1 分,否则 0。correctness 信号按 **pair 粒度**喂诊断/进化。
|
- 新增 `QuestionUnit` 抽象:`kind`("single"|"pair")、`unit_id`、`task_type`、`size`(single=1、pair=2)、`correctness`(用于 batching 混样)、以及所含的 1 或 2 条 `GeneratedQuestion`。
|
||||||
- **loader/batching**:pair 作为**一个不可拆单元**进 batch(original 与 mirror 同批,避免跨批割裂)。
|
- **`QuestionUnit` 组装规则 + 非法 pair 状态处理(M2)**:同一 `pair_id` **必须恰好 2 条**(1 个 `pair_original` + 1 个 `pair_mirror`),且两题 **video_id / task_type / flip_axis 一致**。不满足(孤儿题、数量≠2、角色重复、字段不一致)→ **hard-fail 或剔除该 pair**(不静默拼半个 unit);single 题恒组成 size=1 的 unit。
|
||||||
- **AgentLoop 本身不改**:仍一次答一道 MCQ;pair 语义只在评分/聚合层。
|
|
||||||
- **loader 读回**:`load_benchmark` 补 `pair_id`/`question_role`/`flip_axis`(`.get` 向后兼容旧 JSON)。
|
### 5.1 采样按 unit 计数(C2,`app/question_gen/loader.py::stratified_sample`)
|
||||||
|
真实 loader 是 **`app/question_gen/loader.py`**(不是 `harness/loader.py`)。现 `stratified_sample` 按单个 `GeneratedQuestion` 采样、按 `question_id` 分层、去重补足——会**把 pair 拆开**。改为:
|
||||||
|
- 采样对象改为 **`QuestionUnit`**;所有**比例 / size / min_per_class 均按 unit 计数**(pair 计 1 个 unit,不是 2);
|
||||||
|
- 采样完成后再 **flatten 成逐题列表**喂 AgentLoop(pair 展开为 original+mirror 两条)。
|
||||||
|
|
||||||
|
### 5.2 分批按 unit(C3,`app/harness/batching.py`)
|
||||||
|
真实 batching 是 **`app/harness/batching.py`**(`build_batches`:FFD 按 task_type group 分箱、大类 round-robin 每次放一个 q)——现按单题会**把 pair 拆到不同 batch**。改为:
|
||||||
|
- batching 输入改为 **unit 列表**(unit 携带 `task_type` / `unit_id` / `size` / `correctness`);
|
||||||
|
- **FFD 容量按 `unit.size` 计**(pair 占 2 个容量);round-robin 以 unit 为分发粒度;
|
||||||
|
- flatten 成逐题前,保证 **pair 的 original 与 mirror 落在同一 batch**(不跨批割裂)。
|
||||||
|
|
||||||
|
### 5.3 pair-level 评分聚合(C1,`app/harness/inference.py::run_inference`)
|
||||||
|
现 `run_inference` **按单题聚合**(`total=len(records)`、`correct=sum(prediction==answer)`、`per_task_type` 逐题)。pair 要求双向 AND 计 1 个 unit,聚合算法明确改为:
|
||||||
|
|
||||||
|
1. **逐题推理不变**:每条 `GeneratedQuestion`(含 pair 的 original / mirror)照常各答一次 MCQ,**per-question prediction 仍逐题写 predictions 表**(保留逐题 prediction 追踪字段,供溯源/诊断)。
|
||||||
|
2. **合成 pair-level record**:single 题的 per-question record 直接作为 1 条 unit record;pair 先按 `pair_id` **收齐 original + mirror 两条** per-question record,合成 **1 条 pair-level record**——`pair 正确 = (P.prediction==P.answer) AND (Q.prediction==Q.answer)`。
|
||||||
|
3. **unit 粒度统计**:`InferenceResult.total / correct / per_task_type` 全部按 **unit 粒度**统计(total = single 数 + pair 数;correct 用上面的 unit 正确判据;pair 归入其 task_type 计 1 个 unit)。
|
||||||
|
4. correctness 信号按 **unit(pair)粒度**喂诊断/进化。
|
||||||
|
5. **非法 pair 防御**:聚合时若某 `pair_id` 收不齐 2 条(孤儿)→ 按 M2 hard-fail 或剔除该 unit,不计入 total(并告警,不静默)。
|
||||||
|
|
||||||
|
### 5.4 序列化边界(I3,全部显式写出/读回 pair 字段)
|
||||||
|
现有序列化点只到 `sub_pattern`,会丢 pair 字段。以下每处都必须显式写出/读回 `pair_id` / `question_role` / `flip_axis`,读回用 `.get(..., 默认)` 向后兼容旧 JSON:
|
||||||
|
|
||||||
|
| 边界 | 位置 | 处置 |
|
||||||
|
|------|------|------|
|
||||||
|
| 读回 benchmark | `app/question_gen/loader.py::load_benchmark` | 补读 `pair_id`/`question_role`/`flip_axis`(`.get` 兼容旧 JSON) |
|
||||||
|
| 记录序列化 | `app/question_gen/adversarial_filter.py::_question_to_record` | 显式写出三字段 |
|
||||||
|
| final bank 写盘 | `app/question_gen/adversarial_filter.py::write_final_bank` | 显式写出三字段 |
|
||||||
|
| on_accept 写 JSON | tools 的 `on_accept` 回调(逐题追加落盘) | 显式写出三字段 |
|
||||||
|
| final JSON 重建 | final JSON 反序列化重建 `GeneratedQuestion` | `.get` 读回三字段并校验 pair 完整 |
|
||||||
|
|
||||||
|
- **AgentLoop 本身不改**:仍一次答一道 MCQ;pair / unit 语义只在采样、分批、评分聚合层。
|
||||||
|
|
||||||
## 6. 错误处理
|
## 6. 错误处理
|
||||||
|
|
||||||
@@ -129,30 +191,40 @@ flowchart TD
|
|||||||
|
|
||||||
## 7. 非功能性需求
|
## 7. 非功能性需求
|
||||||
|
|
||||||
|
> **on_accept 逐题追加 vs pair 原子的协议消歧(I5)**:二者不矛盾——**接受粒度是 unit,落盘粒度是 unit**。pair 先在内存 **pending buffer** 收齐 `pair_original` + `pair_mirror` 两题(single 题恒直接成 unit),**收齐后一次性作为一个 unit 进 accepted 列表**;文件写用**全量 tmp + `os.replace`** 原子替换(不做真正的行内 append,避免半写);读回时**校验 pair 成对完整、拒绝/剔除孤儿题**(对齐 §5 M2)。即"逐题追加"在语义上是"逐 unit 追加",pair 永不半落。
|
||||||
|
|
||||||
| 维度 | 设计 |
|
| 维度 | 设计 |
|
||||||
|------|------|
|
|------|------|
|
||||||
| **持久化** | on_accept 逐题追加;**pair 原子成对写**——P、Q 同时落盘或都不落(tmp 缓冲一对再 os.replace),崩溃不留半个 pair。selector/探针观测随题落 run_store |
|
| **持久化** | 接受与落盘均以 **unit** 为粒度:pair 在内存 pending buffer 收齐 original+mirror 后一次性进 accepted;文件写全量 tmp + `os.replace`,**pair 原子成对写**——P、Q 同时落盘或都不落,崩溃不留半个 pair。selector/探针观测随题落 run_store |
|
||||||
| **幂等性** | 同 seed→同 slot;镜像由 flip_axis 确定性构造;VLM 非确定性为既有属性,不新增 |
|
| **幂等性** | 同 seed→同 slot;镜像由 flip_axis 确定性构造;VLM 非确定性为既有属性,不新增 |
|
||||||
| **断点续跑** | progress(slot→status);pair 以"整对完成"为 accepted 单位;后置 verdicts 表按 (question_id/hash/stage) 续跑 |
|
| **断点续跑** | progress(slot→status);pair 以"整对完成"为 accepted 单位;后置 verdicts 表按 (question_id/hash/stage) 续跑 |
|
||||||
| **原子性** | 逐 slot / 逐 pair 落盘;final JSON 全量 tmp+os.replace;pair 半写检测(读回时校验成对完整,缺半剔除并重生) |
|
| **原子性** | 逐 slot / 逐 unit 落盘;final JSON 全量 tmp+os.replace;pair 半写检测(读回时校验成对完整,缺半剔除并重生) |
|
||||||
|
|
||||||
## 8. 测试策略
|
## 8. 测试策略
|
||||||
|
|
||||||
- 单元:双模式分流(flippable→pair、非 flippable→4 选);bag-of-words 匹配校验;NLI 禁蕴含判定;text-only 探针与快解探针(mock VLM);pair 原子写/半写检测;双向 AND 评分。
|
- 单元:双模式分流(flippable→pair、非 flippable→4 选);bag-of-words 匹配校验;NLI 禁蕴含判定;text-only 探针与快解探针(mock VLM);pair 原子写/半写检测;双向 AND 评分。
|
||||||
- 集成:AR 端到端(mock 主 VLM + mock scorer VLM + mock 探针)→ 验证 pair 成对落盘、非 flippable 走 4 选、门收紧生效;后置双向评对。
|
- 集成:AR 端到端(mock 主 VLM + mock scorer VLM + mock 探针)→ 验证 pair 成对落盘、非 flippable 走 4 选、门收紧生效;后置双向评对。
|
||||||
- 回归:11 非 AR 题型 generate-v2 行为**字节级不变**(现有测试全绿);harness/loader 对混格题库(AR pair + 非 AR single)评分正确。
|
- 回归:11 非 AR 题型 generate-v2 行为**字节级不变**(现有测试全绿,含 multi_true 非 AR gate 不动);harness/loader 对混格题库(AR pair + 非 AR single)评分正确。
|
||||||
|
- 回归(pair 不拆,M3):
|
||||||
|
- `app/question_gen/loader.py::stratified_sample`——自然采样 / 按 ratio / 按 min_per_class 三种口径下,**pair 的 original+mirror 始终同进同出**、不被拆开、比例按 unit 计数正确;
|
||||||
|
- `app/harness/batching.py::build_batches`——FFD + round-robin 分批后,**同 pair_id 的两题必落同一 batch**,FFD 容量按 unit.size 计;
|
||||||
|
- `app/harness/inference.py::run_inference`——pair-level 聚合:unit 粒度 total/correct 正确、双向 AND 判据正确、孤儿 pair 按 M2 剔除。
|
||||||
- Agent 类测试产出 MD(§4.6 规范)。
|
- Agent 类测试产出 MD(§4.6 规范)。
|
||||||
|
|
||||||
## 9. 分期实现(一个设计,writing-plans 分阶段)
|
## 9. 分期实现(一个设计,writing-plans 分阶段)
|
||||||
|
|
||||||
1. **契约 + 双模式生成骨架**(GeneratedQuestion 新字段 + contrastive_gen 分流 + pair 落盘);
|
> **消除前向依赖(C6)**:原分期把"harness/eval/loader/batching 混格适配"放阶段 5,但阶段 4"后置双向评分"依赖它,构成前向依赖。现将 **pair-unit 的最小 harness/loader/batching 支持前移到阶段 1(契约阶段)**;阶段 4 只**接入阶段 1 已存在的 pair-unit scorer**,不再依赖后置阶段。
|
||||||
|
|
||||||
|
1. **契约阶段(QuestionUnit + 最小 pair-unit 支持)**:`GeneratedQuestion` 新字段 + `QuestionUnit` 抽象 + M2 pair 组装/校验 + **最小 pair-unit 支持**(`loader.stratified_sample` 按 unit 采样、`harness/batching.build_batches` pair 同批、`harness/inference.run_inference` pair-level 聚合 scorer)+ 双模式生成骨架(contrastive_gen 分流)+ pair 原子落盘;
|
||||||
2. **独立 VLM grounding**(装配第二 VLM + selector 换 scorer + 粒度校验);
|
2. **独立 VLM grounding**(装配第二 VLM + selector 换 scorer + 粒度校验);
|
||||||
3. **内联对抗 + 门收紧 + NLI/歧义门**;
|
3. **内联对抗 + 门收紧(AR 变体)+ NLI/歧义门**;
|
||||||
4. **后置双向评分 + 补生成**(改造 adversarial_filter);
|
4. **后置双向评分 + 补生成**(改造 `adversarial_filter`:作弊门口径 (a) **直接接入阶段 1 已存在的 pair-unit scorer**、翻转有效性 filter 口径 (b));
|
||||||
5. **harness/eval/loader/batching 混格适配**。
|
5. **混格题库全链路验证 + 剩余适配**(AR pair + 非 AR single 端到端评分正确性验收,兜底剩余序列化边界)。
|
||||||
|
|
||||||
## 10. 风险与回退
|
## 10. 风险与回退
|
||||||
|
|
||||||
|
> **配置归属(I6)**:本节及 §4 涉及的可调参数——scorer 粒度阈值、探针阈值(盲答/快解容差)、`filter_task_types`、§4.1 各量化验收阈值——均属**科研 YAML 配置**并**进 harness run 快照**(可复现、可对比扫动);MiniMax API endpoint/key 属**工程配置**(`.env`,`M3_VL_LLM_*`)。二者不混用(对照 CLAUDE.md §4.5)。
|
||||||
|
|
||||||
| 风险 | 回退 |
|
| 风险 | 回退 |
|
||||||
|------|------|
|
|------|------|
|
||||||
| MiniMax-M3 打分过粗/不准 | 扩候选池补偿;或记录为已知局限,后置 agent 门兜底 |
|
| MiniMax-M3 打分过粗/不准 | 扩候选池补偿;或记录为已知局限,后置 agent 门兜底 |
|
||||||
|
|||||||
Reference in New Issue
Block a user