"""IntentClassifier 测试(intent-understanding-layer 任务 5)。 覆盖需求 3.1–3.4:描述性 / 货架期 / 未知分类,LLM 提示优先与关键词兜底。 """ from __future__ import annotations from kernel.task_sheet import DocumentProfile, Intent from kernel.understanding import IntentClassifier def _empty_profile(): return DocumentProfile() def test_descriptive_by_keyword(): c = IntentClassifier(llm=None) assert c.classify("请帮我梳理各规格样品的质量属性规律", _empty_profile()) is Intent.DESCRIPTIVE_SUMMARY def test_shelf_life_by_keyword(): c = IntentClassifier(llm=None) assert c.classify("请预测该产品的货架期", _empty_profile()) is Intent.SHELF_LIFE assert c.classify("外推 36 个月的稳定性", _empty_profile()) is Intent.SHELF_LIFE def test_unknown_when_no_keyword(): c = IntentClassifier(llm=None) assert c.classify("这是什么", _empty_profile()) is Intent.UNKNOWN def test_unknown_when_ambiguous_both(): c = IntentClassifier(llm=None) # 同时含「梳理」与「货架期」→ 交澄清。 assert c.classify("梳理数据并预测货架期", _empty_profile()) is Intent.UNKNOWN def test_llm_hint_takes_precedence(): c = IntentClassifier(llm=None) out = c.classify("随便什么", _empty_profile(), llm_hint="descriptive_summary") assert out is Intent.DESCRIPTIVE_SUMMARY def test_invalid_llm_hint_falls_back_to_keyword(): c = IntentClassifier(llm=None) out = c.classify("预测货架期", _empty_profile(), llm_hint="nonsense") assert out is Intent.SHELF_LIFE def test_compatibility_by_keyword(): c = IntentClassifier(llm=None) assert c.classify("评估原料药与辅料的相容性", _empty_profile()) is Intent.COMPATIBILITY assert c.classify("API 与乳糖的配伍风险", _empty_profile()) is Intent.COMPATIBILITY def test_compatibility_by_input_signature(): """SMILES + 辅料同时存在 → 相容性强信号(优先于关键词)。""" c = IntentClassifier(llm=None) out = c.classify("", _empty_profile(), has_smiles=True, has_excipient=True) assert out is Intent.COMPATIBILITY def test_smiles_only_leans_compatibility(): c = IntentClassifier(llm=None) out = c.classify("", _empty_profile(), has_smiles=True) assert out is Intent.COMPATIBILITY def test_compatibility_llm_hint(): c = IntentClassifier(llm=None) out = c.classify("随便", _empty_profile(), llm_hint="compatibility") assert out is Intent.COMPATIBILITY def test_shelf_life_not_overridden_by_compat_signal(): """明确外推意图时不被相容性关键词误夺(无 smiles+excipient 双信号)。""" c = IntentClassifier(llm=None) assert c.classify("预测货架期", _empty_profile()) is Intent.SHELF_LIFE