feat: 多专业小模型+路由模型系统 MVP(mock 全链路 + FastAPI 网关 + 论文调研)

This commit is contained in:
tzt
2026-08-12 10:40:04 +08:00
commit 1e51167ea5
50 changed files with 49382 additions and 0 deletions
+63
View File
@@ -0,0 +1,63 @@
"""运行指标收集(线程安全,零依赖)。"""
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,
}