-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy patheval.py
More file actions
75 lines (60 loc) · 2.36 KB
/
Copy patheval.py
File metadata and controls
75 lines (60 loc) · 2.36 KB
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
from __future__ import annotations
from dataclasses import dataclass, field
from typing import List, Optional, Set
from .core import Budget, ContextItem, ContextPack, ScoringWeights, pack
@dataclass
class EvalCase:
name: str
items: List[ContextItem]
budget: int
required_ids: Set[str] # Must be present
disallowed_ids: Set[str] = field(default_factory=set) # Must NOT be present
weights: Optional[ScoringWeights] = None
@dataclass
class EvalResult:
name: str
missing_required: Set[str]
included_disallowed: Set[str]
budget_usage: float
passed: bool
class Backtester:
def __init__(self, redundancy_threshold: float = 0.95):
self.cases: List[EvalCase] = []
self.redundancy_threshold = redundancy_threshold
def add_case(self, case: EvalCase):
self.cases.append(case)
def run_all(self) -> List[EvalResult]:
results = []
for case in self.cases:
packed = pack(
case.items,
Budget(maxTokens=case.budget),
weights=case.weights,
redundancy_threshold=self.redundancy_threshold,
)
results.append(self._calculate_metrics(case, packed))
return results
def _calculate_metrics(self, case: EvalCase, packed: ContextPack) -> EvalResult:
selected_ids = {i.id for i in packed.selected}
missing = case.required_ids - selected_ids
forbidden = selected_ids.intersection(case.disallowed_ids)
usage = packed.total_tokens / case.budget if case.budget > 0 else 0.0
passed = len(missing) == 0 and len(forbidden) == 0
return EvalResult(
name=case.name,
missing_required=missing,
included_disallowed=forbidden,
budget_usage=round(usage, 2),
passed=passed,
)
def print_report(self, results: List[EvalResult]):
print("\nCASE NAME | USAGE | STATUS")
print("-" * 50)
for r in results:
status = "OK" if r.passed else "FAIL"
print(f"{r.name:<25} | {r.budget_usage:<5} | {status}")
if not r.passed:
if r.missing_required:
print(f" - MISSING REQUIRED: {r.missing_required}")
if r.included_disallowed:
print(f" - INCLUDED FORBIDDEN: {r.included_disallowed}")