File size: 2,639 Bytes
d27b187
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
"""Run the AgroSense RAG evaluation harness and print a report.

Usage:
    python scripts/evaluate.py                 # uses data/eval_set.json
    python scripts/evaluate.py path/to/set.json --json out.json

Runs fully offline (set AGROSENSE_EMBEDDING_BACKEND=hashing for determinism).
Exit code is non-zero if any report target is missed (handy for CI).
"""
from __future__ import annotations

import json
import sys
from pathlib import Path

sys.path.insert(0, str(Path(__file__).resolve().parent.parent))

from agrosense import RAGEngine
from agrosense.config import DATA_DIR
from agrosense.evaluation import evaluate, load_cases


def main(argv: list[str]) -> int:
    args = [a for a in argv[1:] if not a.startswith("--")]
    out_json = None
    if "--json" in argv:
        idx = argv.index("--json")
        if idx + 1 < len(argv):
            out_json = argv[idx + 1]

    set_path = Path(args[0]) if args else (DATA_DIR / "eval_set.json")
    print(f"Loading eval set: {set_path}")
    cases = load_cases(set_path)
    print(f"{len(cases)} cases. Building engine...")
    engine = RAGEngine()

    report = evaluate(engine, cases)
    m, t = report["metrics"], report["targets_met"]

    print("\n=== AgroSense RAG Evaluation ===")
    print(f"  In-domain cases     : {m['n_in_domain']}")
    print(f"  Out-of-domain cases : {m['n_out_of_domain']}")
    print("  --- quality ---")
    print(f"  Context relevance   : {m['context_relevance']:.1%}   "
          f"(target >=95%)  {'PASS' if t['context_relevance'] else 'FAIL'}")
    print(f"  Citation MRR        : {m['citation_mrr']:.3f}")
    print(f"  Faithfulness        : {m['faithfulness']:.1%}   "
          f"(target >=95%)  {'PASS' if t['faithfulness'] else 'FAIL'}")
    print(f"  Hallucination rate  : {m['hallucination_rate']:.1%}   "
          f"(target <5%)   {'PASS' if t['hallucination_rate'] else 'FAIL'}")
    print(f"  Answer relevance    : {m['answer_relevance']:.1%}")
    print(f"  Out-of-domain acc.  : "
          + ("n/a" if m['ood_accuracy'] is None else f"{m['ood_accuracy']:.1%}"))
    print("  --- latency ---")
    print(f"  p50 / p95 / max ms  : {m['latency_ms_p50']} / {m['latency_ms_p95']} / "
          f"{m['latency_ms_max']}   (p95 target <=3000)  "
          f"{'PASS' if t['latency_ms_p95'] else 'FAIL'}")
    print(f"\n  ALL TARGETS MET: {report['all_targets_met']}")

    if out_json:
        Path(out_json).write_text(json.dumps(report, indent=2), encoding="utf-8")
        print(f"  (full report written to {out_json})")

    return 0 if report["all_targets_met"] else 1


if __name__ == "__main__":
    raise SystemExit(main(sys.argv))