Spaces:
Sleeping
Sleeping
| """Controlled steering sweep for the deployed Gemma backend.""" | |
| from __future__ import annotations | |
| import json | |
| from collections import defaultdict | |
| from pathlib import Path | |
| from trust_guard.game import parse_decision | |
| from trust_guard.model import GemmaSteeringBackend | |
| from trust_guard.prompts import build_prompt | |
| ROOT = Path(__file__).parents[1] | |
| MULTIPLIERS = [-0.30, -0.15, 0.0, 0.15, 0.30] | |
| CASES = [ | |
| ( | |
| "strong", | |
| "The hospice seal is intact. A child needs this medicine before midnight.", | |
| "a village healer", | |
| "deliver fever medicine", | |
| "a sealed hospice satchel", | |
| ), | |
| ( | |
| "ambiguous", | |
| "The captain sent me, but I lost the written order on the northern road.", | |
| "a royal courier", | |
| "warn the captain about raiders", | |
| "no physical evidence", | |
| ), | |
| ( | |
| "weak", | |
| "Open immediately. You do not need to know who I am.", | |
| "an unidentified traveller", | |
| "enter Eldermere", | |
| "no physical evidence", | |
| ), | |
| ] | |
| def is_degenerated(text: str) -> bool: | |
| words = text.split() | |
| if len(words) < 5 or len(words) > 180: | |
| return True | |
| if len(words) > 20 and len(set(words)) / len(words) < 0.25: | |
| return True | |
| return "DECISION:" not in text.upper() | |
| def run_evaluation() -> tuple[Path, dict]: | |
| backend = GemmaSteeringBackend() | |
| results: list[dict] = [] | |
| by_multiplier: dict[float, list[int]] = defaultdict(list) | |
| margins_by_multiplier: dict[float, list[float]] = defaultdict(list) | |
| margins_by_case: dict[str, dict[float, float]] = defaultdict(dict) | |
| for case_index, (case, message, role, mission, evidence) in enumerate(CASES): | |
| prompt = build_prompt(message, role, mission, evidence) | |
| seed = 7613 + case_index | |
| base_margin = backend.decision_margin(prompt, 0.0) | |
| base = backend._with_decision(backend._generate(prompt, 0.0, seed), base_margin) | |
| for multiplier in MULTIPLIERS: | |
| margin = ( | |
| base_margin | |
| if multiplier == 0 | |
| else backend.decision_margin(prompt, multiplier) | |
| ) | |
| response = ( | |
| base | |
| if multiplier == 0 | |
| else backend._with_decision( | |
| backend._generate(prompt, multiplier, seed), | |
| margin, | |
| ) | |
| ) | |
| decision = parse_decision(response) | |
| by_multiplier[multiplier].append(1 if decision == "OPEN" else 0) | |
| margins_by_multiplier[multiplier].append(margin) | |
| margins_by_case[case][multiplier] = margin | |
| results.append( | |
| { | |
| "case": case, | |
| "multiplier": multiplier, | |
| "seed": seed, | |
| "decision": decision, | |
| "decision_margin": margin, | |
| "degenerated": is_degenerated(response), | |
| "response": response, | |
| } | |
| ) | |
| summary = { | |
| f"{multiplier:+.2f}": { | |
| "open_rate": sum(values) / len(values), | |
| "mean_decision_margin": sum(margins_by_multiplier[multiplier]) | |
| / len(margins_by_multiplier[multiplier]), | |
| "samples": len(values), | |
| } | |
| for multiplier, values in by_multiplier.items() | |
| } | |
| directional_cases = sum( | |
| case_margins[-0.30] < case_margins[0.0] < case_margins[0.30] | |
| for case_margins in margins_by_case.values() | |
| ) | |
| flipped_cases = sum( | |
| case_margins[-0.30] < 0 <= case_margins[0.30] | |
| for case_margins in margins_by_case.values() | |
| ) | |
| payload = { | |
| "model": backend.name, | |
| "multipliers": MULTIPLIERS, | |
| "summary": summary, | |
| "direction_test": { | |
| "ordered_negative_neutral_positive": directional_cases, | |
| "decision_flips_negative_to_positive": flipped_cases, | |
| "cases": len(CASES), | |
| }, | |
| "results": results, | |
| } | |
| output = ROOT / "artifacts" / "steering_evaluation.json" | |
| output.parent.mkdir(exist_ok=True) | |
| output.write_text(json.dumps(payload, indent=2) + "\n", encoding="utf-8") | |
| return output, payload | |
| if __name__ == "__main__": | |
| path, report = run_evaluation() | |
| print(path) | |
| print(json.dumps(report["summary"], indent=2)) | |