import json import math from fractions import Fraction
defevaluate(rows, expected_groups, min_per_group=1): if (notisinstance(expected_groups, (list, tuple)) ornot expected_groups orany(notisinstance(g, str) ornot g.strip() for g in expected_groups) orlen(set(expected_groups)) != len(expected_groups)): raise ValueError("invalid groups") iftype(min_per_group) isnotintor min_per_group < 1: raise ValueError("invalid minimum") ifnotisinstance(rows, list) ornot rows: raise ValueError("empty dataset") groups = {g: [] for g in expected_groups} seen = set() for row in rows: ifnotisinstance(row, dict) orset(row) != { "id", "group", "critical", "base", "candidate"}: raise ValueError("invalid row schema") if (notisinstance(row["id"], str) ornot row["id"].strip() or row["id"] in seen ornotisinstance(row["group"], str) or row["group"] notin groups ortype(row["critical"]) isnotbool): raise ValueError("invalid identity") seen.add(row["id"]) for version in ("base", "candidate"): item = row[version] ifnotisinstance(item, dict) orset(item) != { "ok", "leak", "latency_ms"}: raise ValueError("invalid result schema") ms = item["latency_ms"] try: finite = type(ms) in (int, float) and math.isfinite(ms) except OverflowError: finite = False if (type(item["ok"]) isnotbool ortype(item["leak"]) isnotbool ornot finite or ms <= 0): raise ValueError("invalid result values") groups[row["group"]].append(row) ifany(len(items) < min_per_group for items in groups.values()): raise ValueError("insufficient group coverage")
defstats(version): rates = {g: Fraction(sum(r[version]["ok"] for r in items), len(items)) for g, items in groups.items()} macro = sum(rates.values(), Fraction(0)) / len(rates) delays = sorted(r[version]["latency_ms"] for r in rows) # ceil(95*n/100), expressed in integer arithmetic. rank = (95 * len(delays) + 99) // 100 returndict(micro=Fraction(sum(r[version]["ok"] for r in rows), len(rows)), macro=macro, p95_ms=delays[rank - 1], groups=rates)
base, candidate = stats("base"), stats("candidate") regressions = sorted(r["id"] for r in rows if r["base"]["ok"] andnot r["candidate"]["ok"]) reasons = [] ifany(r["candidate"]["leak"] for r in rows): reasons.append("leak") ifany(r["critical"] and r["base"]["ok"] andnot r["candidate"]["ok"] for r in rows): reasons.append("critical_regression") if candidate["macro"] < base["macro"]: reasons.append("macro_regression") if Fraction(candidate["p95_ms"]) > Fraction(base["p95_ms"]) * Fraction(6, 5): reasons.append("latency_regression")
defwire(s): return {k: ({g: float(v) for g, v in value.items()} if k == "groups"elsefloat(value)) for k, value in s.items()} returndict(publish=not reasons, reasons=reasons, regressions=regressions, base=wire(base), candidate=wire(candidate))
flowchart TD
A[门槛失败] --> B{是哪类问题}
B --> C[缺题或评分格式错误]
B --> D[权限泄露或关键退步]
B --> E[质量或延迟退步]
C --> F[修复测试数据并重新运行]
D --> G[检查权限边界与该题证据链]
E --> H[分组追踪检索重排上下文与生成]