Files
projectAIpopular/gateway/sense/labeler.py
T
tzt 324c419c35 feat(sense): T-G3 标签+校准(labeler 四规则推导 + split-conformal + last-good)
- labeler.py:derive_true_tier 纯函数(规则0 人工优先 / plan_multi->T3 /
  失败->下一档(T3保持) / 成功->executed / 空结果跳过)+ derive_true_tiers
  批量回填 + 180d 留存清理
- calibrate.py:compute_thresholds(τ1/τ3 分组扫描——并列分数整组判定,
  精度 >= 1-α 的最大覆盖阈值;<min_labels -> ok=False 沿用 last-good);
  save_thresholds 工件落盘+登记;load_active 回退链 active->同kind扫描->last-good->保守值
- store:all_observations/list_artifacts 支撑方法
- 测试 +9(四规则/批量清理/覆盖达标/标签不足/工件往返与回退),全量 395 passed
2026-09-05 13:53:45 +08:00

61 lines
2.4 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""夜间 true_tier 推导(T-G3,§4 四条规则,确定性)+ 留存清理。
规则(对每条 true_tier 为空的观察,按序判定):
0. human_override 非空 -> 以人工为准(规则 4,优先级最高)。
1. features.plan_multiconsumer=pipeline 发出 brief 的多步信号)-> true=T3。
2. outcome∈{escalated,failed,user_retry,timeout} -> true = executed 的下一档
T1→T2→T3T3 保持 T3)。
3. outcome∈{ok,verified} -> true = executedT1 成功即 T1T2/T3 同理)。
4. 其余(outcome 为空等)-> 跳过,等下一轮。
"""
from __future__ import annotations
import json
import time
from typing import Any, Dict, Optional
NEXT_TIER = {"T1": "T2", "T2": "T3", "T3": "T3"}
SUCCESS = ("ok", "verified")
FAILURE = ("escalated", "failed", "user_retry", "timeout")
def _features(row: Dict[str, Any]) -> Dict[str, Any]:
try:
obj = json.loads(row.get("features") or "{}")
return obj if isinstance(obj, dict) else {}
except json.JSONDecodeError:
return {}
def derive_true_tier(row: Dict[str, Any]) -> Optional[str]:
"""单行推导(纯函数,测试友好)。返回 None = 暂不判定。"""
if row.get("human_override"):
return str(row["human_override"])
outcome = row.get("outcome") or ""
executed = row.get("executed_tier") or "T2"
feats = _features(row)
if feats.get("plan_multi"):
return "T3" # 规则 1pipeline brief 信号)
if outcome in FAILURE: # 规则 2
return NEXT_TIER.get(executed, "T3")
if outcome in SUCCESS: # 规则 3
return executed
return None # 规则 4:等待结果
def derive_true_tiers(store, now: Optional[float] = None,
retention_days: int = 180) -> int:
"""批量推导(§7 签名):返回回填条数;顺带 180d 留存清理。"""
now = time.time() if now is None else now
rows = store.all_observations()
count = 0
for row in rows:
if row.get("true_tier"):
continue
true_tier = derive_true_tier(row)
if true_tier:
store.set_true_tier(row["request_id"], true_tier)
count += 1
store.purge_older_than(now - retention_days * 86400)
return count