fix: Codex 全量审查修正
Critical: - C1: assemble_mode 'plain' → 'ids'(合法枚举值) - C2: question_id 加入 task_type slug 避免跨题型冲突 Important/Minor: - generate_one 移除未用的 embed_fn/similarity_threshold 参数 - config.py 注释 11→12 同步 - 测试 question_id 断言更新 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -267,7 +267,7 @@ def _validate_minibatch(config: RunConfig) -> None:
|
||||
|
||||
关键实现细节:
|
||||
val_size 必须 >= eval_min_per_class * _VIDEO_MME_TASK_TYPE_COUNT,保证验证池
|
||||
能为 Video-MME 的全部 11 个任务类型各保底 eval_min_per_class 题。
|
||||
能为 Video-MME 的全部 12 个任务类型各保底 eval_min_per_class 题。
|
||||
"""
|
||||
if config.batch_size <= 0:
|
||||
raise ValueError(f"batch_size 必须 > 0,实际: {config.batch_size}")
|
||||
|
||||
@@ -624,7 +624,7 @@ def parse_vlm_response(
|
||||
raise ValueError(f"answer 必须是 A/B/C/D 之一,实际 '{answer}': {raw[:200]}")
|
||||
|
||||
return {
|
||||
"question_id": f"gen-{video_id}-{seq:03d}",
|
||||
"question_id": f"gen-{video_id}-{task_type.lower().replace(' ', '_')}-{seq:03d}",
|
||||
"question": data["question"],
|
||||
"options": list(options),
|
||||
"answer": answer,
|
||||
@@ -669,7 +669,6 @@ def is_duplicate(
|
||||
|
||||
async def generate_one(
|
||||
vlm: VLMProvider,
|
||||
embed_fn: Callable[[str | list[str]], np.ndarray],
|
||||
tree: TreeIndex,
|
||||
video_id: str,
|
||||
task_type: str,
|
||||
@@ -678,7 +677,6 @@ async def generate_one(
|
||||
exemplars: list[GeneratedQuestion],
|
||||
used_node_ids: set[str],
|
||||
max_retries: int,
|
||||
similarity_threshold: float,
|
||||
rng: random.Random,
|
||||
session_id: str,
|
||||
) -> GeneratedQuestion | None:
|
||||
@@ -695,7 +693,6 @@ async def generate_one(
|
||||
|
||||
参数:
|
||||
vlm: VLM 调用端口。
|
||||
embed_fn: 文本嵌入函数(本函数内未使用,由调用方统一去重)。
|
||||
tree: 三层树索引。
|
||||
video_id: 所属视频标识。
|
||||
task_type: 12 种 Video-MME 题型之一。
|
||||
@@ -703,7 +700,6 @@ async def generate_one(
|
||||
exemplars: 少样本示例列表。
|
||||
used_node_ids: 已用节点 ID 集合。
|
||||
max_retries: 最大重试次数。
|
||||
similarity_threshold: 余弦相似度阈值(本函数内未使用)。
|
||||
rng: 可控随机数生成器。
|
||||
session_id: 会话 ID(传递给 VLM 遥测)。
|
||||
|
||||
|
||||
@@ -346,14 +346,14 @@ class TestParseVlmResponse:
|
||||
assert result["question"] == "What?"
|
||||
assert result["answer"] == "A"
|
||||
assert len(result["options"]) == 4
|
||||
assert result["question_id"] == "gen-vid1-001"
|
||||
assert result["question_id"] == "gen-vid1-object_recognition-001"
|
||||
|
||||
def test_json_in_code_block(self) -> None:
|
||||
"""从 markdown 代码块中提取 JSON。"""
|
||||
raw = '```json\n{"question": "Q?", "options": ["A. 1", "B. 2", "C. 3", "D. 4"], "answer": "B"}\n```'
|
||||
result = parse_vlm_response(raw, "vid1", "Object Recognition", 2)
|
||||
assert result["question"] == "Q?"
|
||||
assert result["question_id"] == "gen-vid1-002"
|
||||
assert result["question_id"] == "gen-vid1-object_recognition-002"
|
||||
|
||||
def test_invalid_json_raises(self) -> None:
|
||||
"""非 JSON 文本应抛出 ValueError。"""
|
||||
@@ -382,7 +382,7 @@ class TestParseVlmResponse:
|
||||
"""seq 应按 3 位零填充格式化到 question_id 中。"""
|
||||
raw = '{"question": "Q?", "options": ["A. 1", "B. 2", "C. 3", "D. 4"], "answer": "C"}'
|
||||
result = parse_vlm_response(raw, "video_abc", "Action Reasoning", 42)
|
||||
assert result["question_id"] == "gen-video_abc-042"
|
||||
assert result["question_id"] == "gen-video_abc-action_reasoning-042"
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
@@ -448,14 +448,9 @@ class TestGenerateOne:
|
||||
content='{"question":"Q?","options":["A. 1","B. 2","C. 3","D. 4"],"answer":"A"}',
|
||||
)
|
||||
|
||||
def embed_fn(t: str | list[str]) -> np.ndarray:
|
||||
shape = (1, 4) if isinstance(t, str) else (len(t), 4)
|
||||
return np.zeros(shape, dtype=np.float32)
|
||||
|
||||
tree, vid = self._load_test_tree()
|
||||
result = await generate_one(
|
||||
vlm=vlm,
|
||||
embed_fn=embed_fn,
|
||||
tree=tree,
|
||||
video_id=vid,
|
||||
task_type="Object Recognition",
|
||||
@@ -463,12 +458,11 @@ class TestGenerateOne:
|
||||
exemplars=[],
|
||||
used_node_ids=set(),
|
||||
max_retries=3,
|
||||
similarity_threshold=0.85,
|
||||
rng=random.Random(42),
|
||||
session_id="test",
|
||||
)
|
||||
assert result is not None
|
||||
assert result.question_id == f"gen-{vid}-001"
|
||||
assert result.question_id == f"gen-{vid}-object_recognition-001"
|
||||
assert result.task_type == "Object Recognition"
|
||||
assert result.source_nodes # non-empty
|
||||
assert result.difficulty == "medium"
|
||||
@@ -479,13 +473,9 @@ class TestGenerateOne:
|
||||
vlm = AsyncMock()
|
||||
vlm.chat_with_images.return_value = MagicMock(content="invalid")
|
||||
|
||||
def embed_fn(t: str | list[str]) -> np.ndarray:
|
||||
return np.zeros((1, 4), dtype=np.float32)
|
||||
|
||||
tree, vid = self._load_test_tree()
|
||||
result = await generate_one(
|
||||
vlm=vlm,
|
||||
embed_fn=embed_fn,
|
||||
tree=tree,
|
||||
video_id=vid,
|
||||
task_type="Object Recognition",
|
||||
@@ -493,7 +483,6 @@ class TestGenerateOne:
|
||||
exemplars=[],
|
||||
used_node_ids=set(),
|
||||
max_retries=2,
|
||||
similarity_threshold=0.85,
|
||||
rng=random.Random(42),
|
||||
session_id="test",
|
||||
)
|
||||
|
||||
@@ -594,7 +594,7 @@ async def _run_inference_for_questions(
|
||||
ocr=None,
|
||||
verify_vision=False,
|
||||
anchor=False,
|
||||
assemble_mode="plain",
|
||||
assemble_mode="ids",
|
||||
)
|
||||
result = await run_inference(
|
||||
group,
|
||||
@@ -861,7 +861,6 @@ async def _run_generate(args: argparse.Namespace) -> None:
|
||||
|
||||
async def _generate_with_sem(
|
||||
vlm_client,
|
||||
embed_fn_inner,
|
||||
tree,
|
||||
video_id,
|
||||
task_type,
|
||||
@@ -870,7 +869,6 @@ async def _run_generate(args: argparse.Namespace) -> None:
|
||||
exemplars,
|
||||
used_node_ids,
|
||||
max_retries_inner,
|
||||
similarity_threshold_inner,
|
||||
rng_inner,
|
||||
session_id,
|
||||
):
|
||||
@@ -878,7 +876,6 @@ async def _run_generate(args: argparse.Namespace) -> None:
|
||||
async with sem:
|
||||
return await generate_one(
|
||||
vlm_client,
|
||||
embed_fn_inner,
|
||||
tree,
|
||||
video_id,
|
||||
task_type,
|
||||
@@ -886,7 +883,6 @@ async def _run_generate(args: argparse.Namespace) -> None:
|
||||
exemplars=exemplars,
|
||||
used_node_ids=used_node_ids,
|
||||
max_retries=max_retries_inner,
|
||||
similarity_threshold=similarity_threshold_inner,
|
||||
rng=rng_inner,
|
||||
session_id=session_id,
|
||||
)
|
||||
@@ -929,7 +925,6 @@ async def _run_generate(args: argparse.Namespace) -> None:
|
||||
for _attempt in range(max_retries):
|
||||
candidate = await _generate_with_sem(
|
||||
vlm,
|
||||
embed_fn,
|
||||
tree,
|
||||
video_id,
|
||||
task_type,
|
||||
@@ -937,7 +932,6 @@ async def _run_generate(args: argparse.Namespace) -> None:
|
||||
exemplars=exemplars,
|
||||
used_node_ids=used_node_ids,
|
||||
max_retries_inner=1,
|
||||
similarity_threshold_inner=similarity_threshold,
|
||||
rng_inner=rng,
|
||||
session_id=session_id,
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user