| """Evaluate rule routing vs lightweight ML routing.""" |
|
|
| from __future__ import annotations |
|
|
| import argparse |
| import csv |
| import json |
| from pathlib import Path |
| import sys |
|
|
| ROOT = Path(__file__).resolve().parents[1] |
| sys.path.insert(0, str(ROOT / "src")) |
|
|
| from pipeline.ml_router import DEFAULT_MODEL_DIR, MLRouter |
| from pipeline.v2_schema import SafetyTier, classify_route |
|
|
|
|
| DEFAULT_DATASET = ROOT / "eval" / "empathrag_core_supervised.csv" |
|
|
|
|
| def read_rows(path: Path) -> list[dict]: |
| with path.open("r", encoding="utf-8-sig", newline="") as handle: |
| return list(csv.DictReader(handle)) |
|
|
|
|
| def main() -> None: |
| parser = argparse.ArgumentParser() |
| parser.add_argument("--dataset", type=Path, default=DEFAULT_DATASET) |
| parser.add_argument("--model-dir", type=Path, default=ROOT / DEFAULT_MODEL_DIR) |
| parser.add_argument("--split", default="test") |
| parser.add_argument("--output", type=Path, default=ROOT / "eval" / "router_eval_results.json") |
| args = parser.parse_args() |
|
|
| rows = [row for row in read_rows(args.dataset) if row.get("split") == args.split] |
| router = MLRouter(args.model_dir) |
| cases = [] |
| rule_route_correct = 0 |
| ml_route_correct = 0 |
| ml_tier_correct = 0 |
|
|
| for row in rows: |
| expected_route = row["route_label"] |
| expected_tier = row["safety_tier"] |
| rule_route = classify_route(row["query_text"], SafetyTier(expected_tier), row.get("audience_mode") or "student").route.value |
| pred = router.predict(row["query_text"], rule_route, expected_tier) |
| rule_route_correct += int(rule_route == expected_route) |
| ml_route_correct += int(pred.route_label == expected_route) |
| ml_tier_correct += int(pred.safety_tier == expected_tier) |
| cases.append( |
| { |
| "query_id": row["query_id"], |
| "query_text": row["query_text"], |
| "expected_route": expected_route, |
| "rule_route": rule_route, |
| "ml_route": pred.route_label, |
| "expected_tier": expected_tier, |
| "ml_tier": pred.safety_tier, |
| "route_confidence": pred.route_confidence, |
| "tier_confidence": pred.tier_confidence, |
| "used_ml": pred.used_ml, |
| "reason": pred.reason, |
| } |
| ) |
|
|
| total = len(rows) |
| result = { |
| "summary": { |
| "rows": total, |
| "model_available": router.available, |
| "rule_route_accuracy": rule_route_correct / total if total else None, |
| "ml_route_accuracy": ml_route_correct / total if total else None, |
| "ml_tier_accuracy": ml_tier_correct / total if total else None, |
| }, |
| "cases": cases, |
| } |
| args.output.write_text(json.dumps(result, indent=2), encoding="utf-8") |
| print(json.dumps(result["summary"], indent=2)) |
|
|
|
|
| if __name__ == "__main__": |
| main() |
|
|