Spaces:
Sleeping
Sleeping
File size: 6,071 Bytes
b18ef79 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 | """
generate_l3_pairs.py
ββββββββββββββββββββ
Builds Layer 3 training pairs from existing datasets.
No external LLM required.
Design
ββββββ
label=0 (manipulated) : attack text used as the "response"
label=1 (compliant) : benign text wrapped in answer-style framing
Usage
βββββ
python generate_l3_pairs.py
python layer3_semantic.py
"""
import json
import random
from pathlib import Path
SYSTEM_PROMPT = "Answer using only the provided knowledge base."
OUTPUT_PATH = Path("data/l3_pairs.jsonl")
RANDOM_SEED = 42
def _load_attacks(max_n: int = 2000) -> list[str]:
attacks = []
# HackAPrompt
hp_path = Path("data/hackaprompt.jsonl")
if hp_path.exists():
with open(hp_path, encoding="utf-8") as f:
for line in f:
try:
row = json.loads(line)
text = str(row.get("text", "")).strip()
if len(text) >= 10:
attacks.append(text)
except json.JSONDecodeError:
continue
if len(attacks) >= max_n // 2:
break
print(f" [+] HackAPrompt attacks loaded: {len(attacks)}")
else:
print(" [warn] hackaprompt.jsonl not found")
# InjecAgent
ia_path = Path("data/injecagent.jsonl")
if ia_path.exists():
ia_count = 0
with open(ia_path, encoding="utf-8") as f:
for line in f:
try:
row = json.loads(line)
text = str(row.get("text", "")).strip()
if len(text) >= 10:
attacks.append(text)
ia_count += 1
except json.JSONDecodeError:
continue
print(f" [+] InjecAgent attacks loaded: {ia_count}")
else:
print(" [warn] injecagent.jsonl not found")
return attacks
def _load_benign(max_n: int = 2000) -> list[str]:
benign = []
# MS MARCO
bq_path = Path("data/benign_queries.jsonl")
if bq_path.exists():
with open(bq_path, encoding="utf-8") as f:
for line in f:
try:
row = json.loads(line)
text = str(row.get("text", "")).strip()
if len(text) >= 10:
benign.append(text)
except json.JSONDecodeError:
continue
if len(benign) >= max_n // 2:
break
print(f" [+] MS MARCO benign loaded: {len(benign)}")
else:
print(" [warn] benign_queries.jsonl not found")
# MultiNLI
nli_path = Path("data/multinli_sample.jsonl")
if nli_path.exists():
nli_count = 0
with open(nli_path, encoding="utf-8") as f:
for line in f:
try:
row = json.loads(line)
text = str(row.get("text", "")).strip()
if len(text) >= 15:
benign.append(text)
nli_count += 1
except json.JSONDecodeError:
continue
if nli_count >= max_n // 4:
break
print(f" [+] MultiNLI benign loaded: {nli_count}")
else:
print(" [warn] multinli_sample.jsonl not found")
return benign
def _build_clean_responses(benign_texts: list[str]) -> list[str]:
"""
Wrap benign text in answer-style framing so clean responses
look realistic for a RAG system.
"""
templates = [
"Based on the knowledge base: {text}",
"According to the provided documents: {text}",
"The information available indicates that {text}",
"{text}",
"From the retrieved content: {text}",
"The knowledge base states: {text}",
]
rng = random.Random(RANDOM_SEED)
responses = []
for text in benign_texts:
template = rng.choice(templates)
responses.append(template.format(text=text[:300]))
return responses
def main():
print("\n=== Generating Layer 3 Training Pairs ===\n")
rng = random.Random(RANDOM_SEED)
print("[+] Loading attack texts ...")
attacks = _load_attacks(max_n=2000)
print("\n[+] Loading benign texts ...")
benign = _load_benign(max_n=2000)
if not attacks:
print("\n[error] No attack texts loaded.")
print(" Check that data/hackaprompt.jsonl exists.")
return
if not benign:
print("\n[error] No benign texts loaded.")
print(" Check that data/benign_queries.jsonl exists.")
return
# Shuffle with fixed seed
rng.shuffle(attacks)
rng.shuffle(benign)
# Balance classes
n = min(len(attacks), len(benign), 1500)
attacks = attacks[:n]
benign = benign[:n]
print(f"\n[+] Building {n * 2} pairs ({n} attack + {n} benign) ...")
clean_responses = _build_clean_responses(benign)
pairs = []
# label=0 β manipulated
for text in attacks:
pairs.append({
"system_prompt": SYSTEM_PROMPT,
"response": text[:400],
"label": 0,
})
# label=1 β compliant
for response in clean_responses:
pairs.append({
"system_prompt": SYSTEM_PROMPT,
"response": response[:400],
"label": 1,
})
# Shuffle pairs
rng.shuffle(pairs)
# Save
OUTPUT_PATH.parent.mkdir(exist_ok=True)
with open(OUTPUT_PATH, "w", encoding="utf-8") as f:
for pair in pairs:
f.write(json.dumps(pair) + "\n")
n_attack = sum(1 for p in pairs if p["label"] == 0)
n_clean = sum(1 for p in pairs if p["label"] == 1)
print(f"\n[ok] {len(pairs)} pairs saved to {OUTPUT_PATH}")
print(f" Manipulated (label=0): {n_attack}")
print(f" Compliant (label=1): {n_clean}")
print(f"\n[next] Run: python layer3_semantic.py")
if __name__ == "__main__":
main() |