feat: add health-aware P2C selector as default
Score is success-rate EWMA over (1 + inflight) with a 0.05 exploration floor so quarantined sources can prove recovery; EWMA climb doubles as slow-start. New optional OutcomeAwareSelector port feeds attempt outcomes.
This commit is contained in:
@@ -24,7 +24,12 @@ from polygateway.middleware.structured import StructuredMW
|
||||
from polygateway.middleware.telemetry import TelemetryEmitter, TelemetryMW
|
||||
from polygateway.pricing import PricingTable
|
||||
from polygateway.providers import get_provider
|
||||
from polygateway.sources import LeastInflightSelector, RoundRobinSelector, SourceCooldownMemo
|
||||
from polygateway.sources import (
|
||||
HealthAwareSelector,
|
||||
LeastInflightSelector,
|
||||
RoundRobinSelector,
|
||||
SourceCooldownMemo,
|
||||
)
|
||||
from polygateway.transports.openai_compat import OpenAICompatTransport
|
||||
from polygateway.types import ChatRequest, LLMResponse
|
||||
|
||||
@@ -193,6 +198,7 @@ class GatewayClient:
|
||||
cache: CacheBackend | None = None,
|
||||
telemetry: TelemetryRecorder | None = None,
|
||||
registry: Mapping[str, ProviderProfile] | None = None,
|
||||
rng: Any = random.random,
|
||||
) -> GatewayClient:
|
||||
"""按配置装配;显式传入的后端实例即共享(None 项按配置自建私有实例)。"""
|
||||
sources = list(settings.sources)
|
||||
@@ -201,7 +207,7 @@ class GatewayClient:
|
||||
return cls(
|
||||
scope=settings.scope,
|
||||
sources=sources,
|
||||
selector=_build_selector(settings.selector),
|
||||
selector=_build_selector(settings.selector, rng=rng),
|
||||
limiter=limiter or _build_limiter(settings, sources),
|
||||
breaker=breaker or _build_breaker(settings),
|
||||
transport=OpenAICompatTransport(registry=registry),
|
||||
@@ -272,8 +278,12 @@ def _build_breaker(settings: GatewaySettings) -> ProviderGate:
|
||||
return InMemoryGate(config=settings.breaker)
|
||||
|
||||
|
||||
def _build_selector(name: str) -> SourceSelector:
|
||||
return RoundRobinSelector() if name == "round_robin" else LeastInflightSelector()
|
||||
def _build_selector(name: str, *, rng: Any = random.random) -> SourceSelector:
|
||||
if name == "round_robin":
|
||||
return RoundRobinSelector()
|
||||
if name == "least_inflight":
|
||||
return LeastInflightSelector()
|
||||
return HealthAwareSelector(rng=rng)
|
||||
|
||||
|
||||
def _build_cache(settings: GatewaySettings) -> CacheBackend | None:
|
||||
|
||||
Reference in New Issue
Block a user