from app.model.advisor_schemas import ComplianceCheckRequest from app.service.compliance_check_service import ComplianceCheckService from scripts.seed.import_compliance_rules import import_rules_from_markdown class FakeLLMClient: def __init__(self, output: str | Exception) -> None: self.output = output self.prompts: list[str] = [] def complete(self, prompt: str, *, timeout_seconds: float) -> str: self.prompts.append(prompt) if isinstance(self.output, Exception): raise self.output return self.output def service_with_fake_llm(output: str | Exception) -> ComplianceCheckService: from app.service.compliance_semantic_service import ComplianceSemanticService semantic_service = ComplianceSemanticService(llm_client=FakeLLMClient(output)) return ComplianceCheckService(semantic_service=semantic_service) def test_semantic_detection_warns_when_llm_finds_implicit_risk(): service = service_with_fake_llm( '{"risk_level":"WARN","reason":"话术暗示确定性收益","suggestion":"改为提示收益波动风险"}' ) result = service.check_text(ComplianceCheckRequest(text="这款产品收益表现很踏实,基本不用担心波动。")) assert result.risk_level == "WARN" assert result.can_copy is True assert result.required_action == "warn_confirm" assert result.hits == [] assert result.ai_analysis is not None assert result.ai_analysis.risk_level == "WARN" assert result.ai_analysis.reason == "话术暗示确定性收益" assert result.ai_analysis.suggestion == "改为提示收益波动风险" assert result.ai_analysis.degraded is False assert result.ai_analysis.prompt_version == "compliance-semantic-v1" def test_semantic_detection_is_skipped_when_hard_rule_matches(): import_rules_from_markdown() fake_llm = FakeLLMClient('{"risk_level":"INFO","reason":"无风险","suggestion":""}') from app.service.compliance_semantic_service import ComplianceSemanticService service = ComplianceCheckService(semantic_service=ComplianceSemanticService(llm_client=fake_llm)) result = service.check_text(ComplianceCheckRequest(text="这款产品保本保收益。")) assert result.risk_level == "BLOCK" assert result.ai_analysis is None assert fake_llm.prompts == [] def test_semantic_detection_degrades_to_warn_on_timeout(): service = service_with_fake_llm(TimeoutError("semantic timeout")) result = service.check_text(ComplianceCheckRequest(text="这款产品表现比较稳,您可以考虑。")) assert result.risk_level == "WARN" assert result.can_copy is True assert result.required_action == "warn_confirm" assert result.ai_analysis is not None assert result.ai_analysis.degraded is True assert result.ai_analysis.reason == "AI semantic detection degraded: timeout" def test_semantic_detection_degrades_to_warn_on_empty_output(): service = service_with_fake_llm("") result = service.check_text(ComplianceCheckRequest(text="请帮我检查这句话。")) assert result.risk_level == "WARN" assert result.ai_analysis is not None assert result.ai_analysis.degraded is True assert result.ai_analysis.reason == "AI semantic detection degraded: empty_output" def test_semantic_detection_degrades_to_warn_on_malformed_output(): service = service_with_fake_llm("not json") result = service.check_text(ComplianceCheckRequest(text="请帮我检查这句话。")) assert result.risk_level == "WARN" assert result.ai_analysis is not None assert result.ai_analysis.degraded is True assert result.ai_analysis.reason == "AI semantic detection degraded: malformed_output" def test_semantic_detection_degrades_to_warn_on_refusal(): service = service_with_fake_llm('{"refusal":"cannot answer"}') result = service.check_text(ComplianceCheckRequest(text="请帮我检查这句话。")) assert result.risk_level == "WARN" assert result.ai_analysis is not None assert result.ai_analysis.degraded is True assert result.ai_analysis.reason == "AI semantic detection degraded: refusal"