feat: add pure decision core for adversarial filter (hash/fingerprint/canonical/flip)
This commit is contained in:
@@ -0,0 +1,63 @@
|
||||
"""adversarial_filter 纯判定:hash / 指纹 / canonical / 翻转判定。"""
|
||||
|
||||
from app.question_gen.adversarial_filter import (
|
||||
FlipDecision,
|
||||
agent_config_fingerprint,
|
||||
canonical_answer_text,
|
||||
judge_flip,
|
||||
question_hash,
|
||||
)
|
||||
from core.types import GeneratedQuestion
|
||||
|
||||
|
||||
def _q(qid="q1", options=("A. 蒸", "B. 炒", "C. 煮", "D. 炸"), answer="A"):
|
||||
return GeneratedQuestion(
|
||||
question_id=qid, video_id="v1", task_type="Action Recognition",
|
||||
question="?", options=options, answer=answer,
|
||||
source_nodes=("n1",), difficulty="hard",
|
||||
sub_pattern="temporal_reasoning_failure",
|
||||
)
|
||||
|
||||
|
||||
def test_question_hash_stable_and_payload_sensitive():
|
||||
h1 = question_hash(_q())
|
||||
h2 = question_hash(_q())
|
||||
assert h1 == h2
|
||||
h3 = question_hash(_q(answer="B")) # answer 变 → hash 变
|
||||
assert h1 != h3
|
||||
h4 = question_hash(_q(options=("A. 蒸", "B. 炒", "C. 煮", "D. 烤"))) # option 变 → 变
|
||||
assert h1 != h4
|
||||
|
||||
|
||||
def test_agent_config_fingerprint_changes_with_inputs():
|
||||
a = agent_config_fingerprint(skill_mode="auto", max_steps=40, model="m1")
|
||||
b = agent_config_fingerprint(skill_mode="auto", max_steps=41, model="m1")
|
||||
c = agent_config_fingerprint(skill_mode="manual", max_steps=40, model="m1")
|
||||
assert a != b and a != c
|
||||
|
||||
|
||||
def test_canonical_answer_text_maps_letter_to_option_text():
|
||||
assert canonical_answer_text(_q(), "C") == "煮"
|
||||
assert canonical_answer_text(_q(), "c") == "煮"
|
||||
|
||||
|
||||
def test_canonical_answer_text_invalid_returns_none():
|
||||
assert canonical_answer_text(_q(), "Z") is None
|
||||
assert canonical_answer_text(_q(), "") is None
|
||||
assert canonical_answer_text(_q(), None) is None
|
||||
|
||||
|
||||
def test_judge_flip_different_answers_passed():
|
||||
# P 选"蒸",Q(镜像)选"炒"→ 语义不同 → passed
|
||||
d = judge_flip(p_text="蒸", q_text="炒")
|
||||
assert d is FlipDecision.PASSED
|
||||
|
||||
|
||||
def test_judge_flip_same_answer_filtered():
|
||||
d = judge_flip(p_text="蒸", q_text="蒸")
|
||||
assert d is FlipDecision.FILTERED_NO_FLIP
|
||||
|
||||
|
||||
def test_judge_flip_invalid_answer_skipped():
|
||||
assert judge_flip(p_text=None, q_text="炒") is FlipDecision.FLIP_SKIPPED
|
||||
assert judge_flip(p_text="蒸", q_text=None) is FlipDecision.FLIP_SKIPPED
|
||||
Reference in New Issue
Block a user