feat(v1): T-R1 采纳 ai-model-router 可解释路由评分——五维加权+硬过滤带拒绝理由+置信度分差推导
- 新增 router_system/explain.py:CandidateProfile(capability/cost/latency/ reliability/difficulty 画像)+ explain_routing(硬过滤先行、逐条人话拒绝理由、 五维归一评分、同分按领域字典序、confidence=0.8+分差推导封顶 0.99) - Router._explain 纯解释层装配(解释层任何异常不影响主链路,D-G4 同款纪律); 路由胜负与既有决策完全等价,/chat 响应新增 route_explanation 字段(缓存命中为 None) - experts:Expert.nominal_latency_ms 标称延迟元数据(mock 1/hf 300/api 800) - stats:upgraded_by_domain 计数 + domain_reliability()(无数据给 0.9 中性先验) - .gitignore 登记 extra/(参考项目目录不入库) - 新增 tests/test_explain.py 8 项;全量 33 passed(基线 25)
This commit is contained in:
+74
-63
@@ -1,63 +1,74 @@
|
||||
"""运行指标收集(线程安全,零依赖)。"""
|
||||
from __future__ import annotations
|
||||
|
||||
import threading
|
||||
from collections import Counter, deque
|
||||
from typing import Any, Deque, Dict
|
||||
|
||||
|
||||
class Stats:
|
||||
def __init__(self, window: int = 1000):
|
||||
self._lock = threading.Lock()
|
||||
self.requests = 0
|
||||
self.domain_counter: Counter = Counter()
|
||||
self.difficulty_counter: Counter = Counter()
|
||||
self.upgraded = 0
|
||||
self.cache_hits = 0
|
||||
self.cache_levels: Counter = Counter()
|
||||
self.errors = 0
|
||||
self.latencies: Deque[float] = deque(maxlen=window)
|
||||
self.cost_total = 0.0
|
||||
self.model_usage: Counter = Counter()
|
||||
|
||||
def record(self, latency_ms: float, domain: str, difficulty: str,
|
||||
upgraded: bool, cache_hit: bool, cache_level: str | None,
|
||||
cost_est: float, model_used: str):
|
||||
with self._lock:
|
||||
self.requests += 1
|
||||
self.domain_counter[domain] += 1
|
||||
self.difficulty_counter[difficulty] += 1
|
||||
if upgraded:
|
||||
self.upgraded += 1
|
||||
if cache_hit:
|
||||
self.cache_hits += 1
|
||||
if cache_level:
|
||||
self.cache_levels[cache_level] += 1
|
||||
self.latencies.append(latency_ms)
|
||||
self.cost_total += cost_est
|
||||
self.model_usage[model_used] += 1
|
||||
|
||||
def record_error(self):
|
||||
with self._lock:
|
||||
self.errors += 1
|
||||
|
||||
def summary(self) -> Dict[str, Any]:
|
||||
with self._lock:
|
||||
n = self.requests
|
||||
lat = list(self.latencies)
|
||||
avg_lat = sum(lat) / len(lat) if lat else 0.0
|
||||
p99 = sorted(lat)[int(len(lat) * 0.99) - 1] if len(lat) >= 100 else (max(lat) if lat else 0.0)
|
||||
return {
|
||||
"total_requests": n,
|
||||
"domain_distribution": dict(self.domain_counter),
|
||||
"difficulty_distribution": dict(self.difficulty_counter),
|
||||
"fallback_rate": round(self.upgraded / n, 4) if n else 0.0,
|
||||
"upgraded_requests": self.upgraded,
|
||||
"cache_hit_rate": round(self.cache_hits / n, 4) if n else 0.0,
|
||||
"cache_levels": dict(self.cache_levels),
|
||||
"avg_latency_ms": round(avg_lat, 3),
|
||||
"p99_latency_ms": round(p99, 3),
|
||||
"total_cost_est_usd": round(self.cost_total, 6),
|
||||
"model_usage": dict(self.model_usage),
|
||||
"errors": self.errors,
|
||||
}␍
|
||||
"""运行指标收集(线程安全,零依赖)。"""
|
||||
from __future__ import annotations
|
||||
|
||||
import threading
|
||||
from collections import Counter, deque
|
||||
from typing import Any, Deque, Dict
|
||||
|
||||
|
||||
class Stats:
|
||||
def __init__(self, window: int = 1000):
|
||||
self._lock = threading.Lock()
|
||||
self.requests = 0
|
||||
self.domain_counter: Counter = Counter()
|
||||
self.difficulty_counter: Counter = Counter()
|
||||
self.upgraded = 0
|
||||
self.upgraded_by_domain: Counter = Counter() # 可解释评分 reliability 维输入
|
||||
self.cache_hits = 0
|
||||
self.cache_levels: Counter = Counter()
|
||||
self.errors = 0
|
||||
self.latencies: Deque[float] = deque(maxlen=window)
|
||||
self.cost_total = 0.0
|
||||
self.model_usage: Counter = Counter()
|
||||
|
||||
def record(self, latency_ms: float, domain: str, difficulty: str,
|
||||
upgraded: bool, cache_hit: bool, cache_level: str | None,
|
||||
cost_est: float, model_used: str):
|
||||
with self._lock:
|
||||
self.requests += 1
|
||||
self.domain_counter[domain] += 1
|
||||
self.difficulty_counter[difficulty] += 1
|
||||
if upgraded:
|
||||
self.upgraded += 1
|
||||
self.upgraded_by_domain[domain] += 1
|
||||
if cache_hit:
|
||||
self.cache_hits += 1
|
||||
if cache_level:
|
||||
self.cache_levels[cache_level] += 1
|
||||
self.latencies.append(latency_ms)
|
||||
self.cost_total += cost_est
|
||||
self.model_usage[model_used] += 1
|
||||
|
||||
def record_error(self):
|
||||
with self._lock:
|
||||
self.errors += 1
|
||||
|
||||
def domain_reliability(self, domain: str, prior: float = 0.9) -> float:
|
||||
"""领域可靠性 = 1 - 升级率(无数据时返回中性先验,可解释评分用)。"""
|
||||
with self._lock:
|
||||
n = self.domain_counter.get(domain, 0)
|
||||
if n <= 0:
|
||||
return prior
|
||||
up = self.upgraded_by_domain.get(domain, 0)
|
||||
return max(0.0, min(1.0, 1.0 - up / n))
|
||||
|
||||
def summary(self) -> Dict[str, Any]:
|
||||
with self._lock:
|
||||
n = self.requests
|
||||
lat = list(self.latencies)
|
||||
avg_lat = sum(lat) / len(lat) if lat else 0.0
|
||||
p99 = sorted(lat)[int(len(lat) * 0.99) - 1] if len(lat) >= 100 else (max(lat) if lat else 0.0)
|
||||
return {
|
||||
"total_requests": n,
|
||||
"domain_distribution": dict(self.domain_counter),
|
||||
"difficulty_distribution": dict(self.difficulty_counter),
|
||||
"fallback_rate": round(self.upgraded / n, 4) if n else 0.0,
|
||||
"upgraded_requests": self.upgraded,
|
||||
"cache_hit_rate": round(self.cache_hits / n, 4) if n else 0.0,
|
||||
"cache_levels": dict(self.cache_levels),
|
||||
"avg_latency_ms": round(avg_lat, 3),
|
||||
"p99_latency_ms": round(p99, 3),
|
||||
"total_cost_est_usd": round(self.cost_total, 6),
|
||||
"model_usage": dict(self.model_usage),
|
||||
"errors": self.errors,
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user