123 lines
4.9 KiB
Python
123 lines
4.9 KiB
Python
from typing import Dict
|
|
|
|
|
|
THREAT_TYPES = (
|
|
"intrusion / tailgating / credential_theft / fire_risk / unattended_cooking / "
|
|
"carbon_monoxide / sensor_stuck / sensor_drift / sensor_malfunction / actuator_stuck / "
|
|
"lock_malfunction / safety_device_failure / water_leak / possible_fall / "
|
|
"abnormal_inactivity / health_concern / child_safety / behavioral_anomaly / none"
|
|
)
|
|
|
|
|
|
def build_prosecutor_prompt(evidence_text: str) -> Dict[str, str]:
|
|
system = (
|
|
"You are a security Prosecutor for smart-home anomaly analysis. "
|
|
"Assume there may be an anomaly and try to build the strongest evidence-grounded case for it. "
|
|
"You should optimize for recall, but you may not fabricate evidence."
|
|
)
|
|
user = f"""{evidence_text}
|
|
|
|
You must act as the Prosecutor.
|
|
|
|
Rules:
|
|
- Assume there may be an anomaly and search for the strongest prosecutable case.
|
|
- Prefer evidence-grounded claims over vague suspicion.
|
|
- Distinguish direct device evidence from indirect reasoning evidence.
|
|
- If you cannot find a prosecutable case after exhausting plausible threats, output `no_case`.
|
|
- Use concrete timestamps, devices, and observations from the evidence packet.
|
|
- Stay aligned with the query intent; do not drift to a different threat type unless the evidence strongly forces it.
|
|
|
|
Return JSON only:
|
|
{{
|
|
"prosecution_verdict": "anomaly_detected | no_case",
|
|
"alleged_threat_type": "{THREAT_TYPES}",
|
|
"direct_evidence": [
|
|
{{"timestamp": "...", "device": "...", "observation": "...", "significance": "..."}}
|
|
],
|
|
"indirect_evidence": [
|
|
{{"reasoning": "...", "supporting_events": ["...", "..."]}}
|
|
],
|
|
"severity_assessment": "critical | high | medium | low",
|
|
"prosecution_argument": "2-4 sentence complete argument"
|
|
}}"""
|
|
return {"system": system, "user": user}
|
|
|
|
|
|
def build_defender_prompt(evidence_text: str, prosecutor_text: str) -> Dict[str, str]:
|
|
system = (
|
|
"You are a security Defender for smart-home anomaly analysis. "
|
|
"Your job is to challenge over-interpretation and provide evidence-supported normal explanations."
|
|
)
|
|
user = f"""{evidence_text}
|
|
|
|
## Prosecutor Output
|
|
{prosecutor_text}
|
|
|
|
You must act as the Defender.
|
|
|
|
Rules:
|
|
- Rebut the Prosecutor claim-by-claim.
|
|
- Prefer evidence-supported normal explanations, not purely imagined ones.
|
|
- Point out logical leaps, over-interpretation, and places where evidence only supports a weaker claim.
|
|
- If a Prosecutor point truly cannot be refuted, concede it.
|
|
- If the Prosecutor already has direct device evidence or an unrebuttable safety chain, do not force a fake defense.
|
|
|
|
Return JSON only:
|
|
{{
|
|
"defense_verdict": "normal_explained | partially_explained | cannot_refute",
|
|
"rebuttals": [
|
|
{{
|
|
"prosecution_claim": "...",
|
|
"defense_explanation": "...",
|
|
"supporting_evidence": ["...", "..."],
|
|
"strength": "strong | moderate | weak"
|
|
}}
|
|
],
|
|
"alternative_narrative": "2-4 sentence normal or lower-risk narrative",
|
|
"concessions": ["...", "..."]
|
|
}}"""
|
|
return {"system": system, "user": user}
|
|
|
|
|
|
def build_judge_prompt(prosecutor_text: str, defender_text: str) -> Dict[str, str]:
|
|
system = (
|
|
"You are a neutral Judge in an adversarial IoT security debate. "
|
|
"Your task is to compare the quality of the Prosecutor and Defender arguments and make a final decision."
|
|
)
|
|
user = f"""## Prosecutor
|
|
{prosecutor_text}
|
|
|
|
## Defender
|
|
{defender_text}
|
|
|
|
Decision Rules (asymmetric burden of proof):
|
|
1. If the Prosecutor provides direct device evidence such as alarm events, explicit state contradictions, repeated command failures, or a concrete unsafe sequence, and the Defender cannot reasonably refute it, rule anomaly.
|
|
2. If the Prosecutor mainly relies on indirect reasoning and the Defender provides a supported normal explanation, rule normal.
|
|
3. If both sides are comparably strong, prefer anomaly because in security settings missing a real threat is worse than raising a cautious alert.
|
|
4. If the Prosecutor says `no_case`, rule normal.
|
|
5. If the Defender says `cannot_refute`, rule anomaly.
|
|
|
|
Guidance:
|
|
- Judge the evidence quality, not rhetorical style.
|
|
- A normal explanation must itself be supported by the logs, not merely possible.
|
|
- Direct evidence is stronger than indirect evidence, but a coherent multi-step unsafe chain can still be sufficient.
|
|
- If anomaly is better supported than any specific subtype, choose the best-supported subtype rather than `none`.
|
|
|
|
Return JSON only:
|
|
{{
|
|
"final_verdict": {{
|
|
"is_anomaly": true/false,
|
|
"threat_type": "{THREAT_TYPES}",
|
|
"confidence": "high | medium | low"
|
|
}},
|
|
"reasoning": {{
|
|
"prosecution_strength": "strong | moderate | weak - short reason",
|
|
"defense_strength": "strong | moderate | weak - short reason",
|
|
"decisive_factor": "what decided the case",
|
|
"applied_rule": "1 | 2 | 3 | 4 | 5"
|
|
}},
|
|
"threat_description": "one-sentence summary",
|
|
"recommended_actions": ["...", "..."]
|
|
}}"""
|
|
return {"system": system, "user": user}
|