feat(proxy): T-P2 上游客户端(流式派发/usage 注入过滤/三家归一化/首 token 前 failover)
- upstream.py:httpx.AsyncClient 模块级单例(keepalive,limits=100, 超时 connect10/read120/write10/pool30);stream() 始终注入 stream_options.include_usage(计量不依赖客户端)+ filter_usage_chunk (客户端未要求 usage 时剥除该 chunk);D-P4 首 token 前 failover 链、 流中失败抛 UpstreamAborted(不可切换);ttfb_ms 记录 - normalize_usage 三家归一:deepseek prompt_cache_hit_tokens / openai prompt_tokens_details.cached_tokens / anthropic cache_read_input_tokens (命中数>总数时钳制) - model_pool:+provider(枚举校验 deepseek/openai/anthropic)+in_hit_price (缺省 = price_in×1/30,D-P3) - 测试 +6:透传+sink/failover/流中 aborted/全挂 502/三家归一/过滤,全量 345 passed
This commit is contained in:
@@ -21,11 +21,13 @@ _POOL_PATH = Path(__file__).resolve().parent.parent / "config" / "model_pool.jso
|
||||
TIERS = ("local", "budget", "premium")
|
||||
BACKENDS = ("mock", "llama_server", "openai")
|
||||
ROLES = ("architect", "worker", "agent")
|
||||
PROVIDERS = ("deepseek", "openai", "anthropic") # 代理层 usage 归一化用(D-P3)
|
||||
|
||||
# 池条目允许的字段(其余字段拒绝写入)
|
||||
ENTRY_FIELDS = {
|
||||
"id", "name", "tier", "backend", "base_url", "model", "api_key",
|
||||
"price_in", "price_out", "temperature", "max_tokens", "enabled",
|
||||
"provider", "in_hit_price", # 代理层扩展(D-P3):usage 归一化 / 按命中价选上游
|
||||
}
|
||||
|
||||
# 单价默认值($/1M tokens);local 档为 0
|
||||
@@ -177,6 +179,8 @@ class PoolStore:
|
||||
backend = entry.get("backend", "openai")
|
||||
if backend not in BACKENDS:
|
||||
raise PoolError(f"backend 必须是 {BACKENDS} 之一")
|
||||
if entry.get("provider") and entry["provider"] not in PROVIDERS:
|
||||
raise PoolError(f"provider 必须是 {PROVIDERS} 之一")
|
||||
tier = entry.get("tier", "budget")
|
||||
if tier not in TIERS:
|
||||
raise PoolError(f"tier 必须是 {TIERS} 之一")
|
||||
@@ -212,6 +216,10 @@ class PoolStore:
|
||||
"temperature": temperature,
|
||||
"max_tokens": max_tokens,
|
||||
"enabled": bool(entry.get("enabled", True)),
|
||||
# 代理层扩展(D-P3):provider 缺省 openai;in_hit_price 缺省 = price_in × 1/30
|
||||
"provider": (str(entry["provider"]) if entry.get("provider") else "openai"),
|
||||
"in_hit_price": (float(entry["in_hit_price"]) if entry.get("in_hit_price") is not None
|
||||
else round(price_in / 30.0, 6)),
|
||||
}
|
||||
|
||||
@staticmethod
|
||||
|
||||
Reference in New Issue
Block a user