diff --git a/app/question_gen/distractor_selector.py b/app/question_gen/distractor_selector.py index f09a728..5c3d1a1 100644 --- a/app/question_gen/distractor_selector.py +++ b/app/question_gen/distractor_selector.py @@ -188,7 +188,11 @@ async def _score_options( if not isinstance(scores_raw, list) or len(scores_raw) != len(options): msg = f"打分数量({len(scores_raw) if isinstance(scores_raw, list) else 'NA'}) != 选项数({len(options)})" raise ValueError(msg) - return [max(0.0, min(1.0, float(s))) for s in scores_raw] + try: + return [max(0.0, min(1.0, float(s))) for s in scores_raw] + except (TypeError, ValueError) as e: + msg = f"打分含非数值元素: {e}" + raise ValueError(msg) from e async def build_grounded_options( diff --git a/tests/unit/test_distractor_selector.py b/tests/unit/test_distractor_selector.py index 95edc3f..513c52f 100644 --- a/tests/unit/test_distractor_selector.py +++ b/tests/unit/test_distractor_selector.py @@ -63,6 +63,14 @@ async def test_generate_pool_degrades_on_malformed_response(): assert out == [] +@pytest.mark.asyncio +async def test_score_options_raises_valueerror_on_non_numeric(): + from app.question_gen.distractor_selector import _score_options + vlm = _FakeVLM(['{"scores": [0.9, null, 0.5]}']) # null 不是数值 + with pytest.raises(ValueError): + await _score_options(vlm, "?", ["蒸", "炒", "煮"], _Material(), session_id="s") + + @pytest.mark.asyncio async def test_build_grounded_options_happy_path(): pool = '{"distractors": ["炒", "煮", "炸", "烤"]}'