refactor(question_gen): adapt generator/gates/store signatures for strategy

- generator_v2: _load_prompt_template takes template_name str instead of
  QuestionFamilySpec; _build_v2_prompt takes prompt_template + strategy_name
  + sub_pattern_instruction; generate_one_v2 takes discrete params
  (prompt_template, strategy_name, skill_target, sub_pattern_instruction)
- gates: _gate_leak_test and run_gates take leak_probe_template str
  instead of QuestionFamilySpec
- run_store: add sub_pattern column to DDL + idempotent migration;
  record_item accepts optional sub_pattern param
- Remove QuestionFamilySpec imports from generator_v2 and gates modules
- Update test call sites accordingly

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-07-14 05:50:47 -04:00
parent c49d0ff12f
commit afa77173e3
4 changed files with 155 additions and 76 deletions
+20 -21
View File
@@ -117,6 +117,7 @@ CREATE TABLE IF NOT EXISTS question_gen_items (
skill_target TEXT NOT NULL,
attempt INTEGER NOT NULL,
question_text TEXT NOT NULL,
sub_pattern TEXT,
gate_key_verify TEXT,
gate_blind_answer TEXT,
gate_multi_true TEXT,
@@ -176,6 +177,12 @@ class QuestionGenStore:
self._conn.execute(idx_sql)
self._conn.commit()
# 幂等迁移:为已有表加 sub_pattern 列
cols = {r[1] for r in self._conn.execute("PRAGMA table_info(question_gen_items)")}
if "sub_pattern" not in cols:
self._conn.execute("ALTER TABLE question_gen_items ADD COLUMN sub_pattern TEXT")
self._conn.commit()
def record_run_start(self, run_id: str, git_sha: str, config_snapshot: str) -> None:
"""记录批次开始。
@@ -250,6 +257,7 @@ class QuestionGenStore:
skill_target: str,
attempt: int,
question_text: str,
sub_pattern: str | None = None,
) -> None:
"""记录一道新生成的题目(初始状态 pending)。
@@ -273,14 +281,16 @@ class QuestionGenStore:
当前重出轮次(1-based)。
question_text : str
题目文本。
sub_pattern : str | None
子模式标识(如有)。
"""
now = datetime.now(tz=UTC).isoformat(timespec="seconds")
self._conn.execute(
"""
INSERT INTO question_gen_items
(item_id, run_id, slot_id, video_id, family, task_type,
skill_target, attempt, question_text, created_at)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
skill_target, attempt, question_text, sub_pattern, created_at)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
""",
(
item_id,
@@ -292,6 +302,7 @@ class QuestionGenStore:
skill_target,
attempt,
question_text,
sub_pattern,
now,
),
)
@@ -400,21 +411,16 @@ class QuestionGenStore:
)
def load_progress(self) -> dict[str, str]:
"""加载已完成 slot 的进度映射(用于断点续跑)。
"""加载已接受 slot 的进度映射(用于断点续跑)。
从最近一次 running 状态的批次中,读取所有 final_status 非 pending 的 item
聚合为 slot_id → "accepted"|"rejected" 映射
若存在同一 slot_id 的多条记录(多次重出),取最终状态:
- 任一条 accepted → accepted
- 全部 rejected → rejected
从最近一次 running 状态的批次中,读取 accepted 的 slot。
rejected 的 slot 不纳入 progress,以便重跑时重新尝试
Returns
-------
dict[str, str]
{slot_id: "accepted"|"rejected"} 映射。无进度时返回空 dict。
{slot_id: "accepted"} 映射。无进度时返回空 dict。
"""
# 取最近一次未结束的 run_id
row = self._conn.execute(
"SELECT run_id FROM question_gen_runs WHERE status='running' "
"ORDER BY started_at DESC LIMIT 1",
@@ -425,19 +431,12 @@ class QuestionGenStore:
run_id = row[0]
rows = self._conn.execute(
"SELECT slot_id, final_status FROM question_gen_items "
"WHERE run_id=? AND final_status != 'pending'",
"SELECT DISTINCT slot_id FROM question_gen_items "
"WHERE run_id=? AND final_status='accepted'",
(run_id,),
).fetchall()
progress: dict[str, str] = {}
for slot_id, status in rows:
if status == "accepted":
progress[slot_id] = "accepted"
elif slot_id not in progress:
progress[slot_id] = "rejected"
return progress
return {row[0]: "accepted" for row in rows}
def close(self) -> None:
"""关闭数据库连接。"""