mirror of
https://github.com/BerriAI/litellm.git
synced 2026-08-28 05:25:59 +00:00
Merge pull request #37966 from BerriAI/litellm_1787426863_strategy_router_health_check
fix(proxy): skip health checks for strategy routers
This commit is contained in:
commit
28b433a007
2 changed files with 31 additions and 35 deletions
|
|
@ -18,6 +18,7 @@ from litellm.constants import (
|
|||
DEFAULT_HEALTH_CHECK_PROMPT,
|
||||
HEALTH_CHECK_TIMEOUT_SECONDS,
|
||||
)
|
||||
from litellm.router_utils.auto_router_model_naming import classify_strategy_router_model
|
||||
|
||||
ILLEGAL_DISPLAY_PARAMS: Final = [
|
||||
"messages",
|
||||
|
|
@ -182,30 +183,17 @@ async def run_with_timeout(task, timeout):
|
|||
return {"error": "Timeout exceeded", "exception": timeout_exception}
|
||||
|
||||
|
||||
def _is_semantic_auto_router_deployment(litellm_params: dict) -> bool:
|
||||
"""
|
||||
True for semantic auto_router deployments (auto_router/<name>) that are not
|
||||
sub-strategies (complexity_router, adaptive_router, quality_router).
|
||||
|
||||
These are meta-routers that select among real LLM deployments at request time;
|
||||
they have no LLM endpoint to health-check.
|
||||
"""
|
||||
def _is_strategy_router_deployment(litellm_params: dict) -> bool:
|
||||
"""True for strategy-router deployments."""
|
||||
model: Final[object] = litellm_params.get("model", "")
|
||||
if not isinstance(model, str):
|
||||
return False
|
||||
if not model.startswith("auto_router/"):
|
||||
return False
|
||||
for sub_strategy in ("complexity_router", "adaptive_router", "quality_router"):
|
||||
if model.startswith(f"auto_router/{sub_strategy}"):
|
||||
return False
|
||||
return True
|
||||
return isinstance(model, str) and classify_strategy_router_model(model) is not None
|
||||
|
||||
|
||||
async def _run_model_health_check(model: dict):
|
||||
litellm_params = model["litellm_params"]
|
||||
model_info: Final = model.get("model_info", {})
|
||||
|
||||
if _is_semantic_auto_router_deployment(litellm_params):
|
||||
if _is_strategy_router_deployment(litellm_params):
|
||||
return {}
|
||||
|
||||
mode: Final = _resolve_health_check_mode(
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ import pytest
|
|||
from litellm.litellm_core_utils.health_check_helpers import HealthCheckHelpers
|
||||
from litellm.proxy import health_check as hc_module
|
||||
from litellm.proxy.health_check import (
|
||||
_is_semantic_auto_router_deployment,
|
||||
_is_strategy_router_deployment,
|
||||
_resolve_health_check_max_tokens,
|
||||
_resolve_health_check_mode,
|
||||
_update_litellm_params_for_health_check,
|
||||
|
|
@ -495,33 +495,22 @@ def test_autodetected_embedding_skips_reasoning_effort():
|
|||
assert "max_tokens" not in updated
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# auto_router (semantic router) deployments must be skipped by health checks.
|
||||
#
|
||||
# These are meta-routers that select among real LLM deployments at request
|
||||
# time. They have no LLM endpoint to probe. Before this fix, the health check
|
||||
# passed model="auto_router/router_1" to get_llm_provider(), which raised
|
||||
# BadRequestError: "Unmapped LLM provider for this endpoint" because
|
||||
# auto_router is not a real LLM provider.
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"model, expected",
|
||||
[
|
||||
("auto_router/router_1", True),
|
||||
("auto_router/my_router", True),
|
||||
("auto_router/complexity_router", False),
|
||||
("auto_router/adaptive_router", False),
|
||||
("auto_router/quality_router", False),
|
||||
("auto_router/adaptive_router/subpath", False),
|
||||
("auto_router/complexity_router", True),
|
||||
("auto_router/adaptive_router", True),
|
||||
("auto_router/quality_router", True),
|
||||
("auto_router/adaptive_router/subpath", True),
|
||||
("gpt-4", False),
|
||||
("openai/gpt-4", False),
|
||||
("bedrock/claude", False),
|
||||
],
|
||||
)
|
||||
def test_is_semantic_auto_router_deployment(model, expected):
|
||||
assert _is_semantic_auto_router_deployment({"model": model}) == expected
|
||||
def test_is_strategy_router_deployment(model, expected):
|
||||
assert _is_strategy_router_deployment({"model": model}) == expected
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
|
|
@ -543,3 +532,22 @@ async def test_run_model_health_check_skips_auto_router_deployment():
|
|||
|
||||
fake_ahealth_check.assert_not_called()
|
||||
assert result == {}
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_run_model_health_check_skips_complexity_router_deployment():
|
||||
fake_ahealth_check = AsyncMock(return_value={})
|
||||
model = {
|
||||
"litellm_params": {
|
||||
"model": "auto_router/complexity_router",
|
||||
"complexity_router_config": {"tiers": {"simple": "gpt-4o-mini"}},
|
||||
"complexity_router_default_model": "gpt-4o-mini",
|
||||
},
|
||||
"model_info": {},
|
||||
}
|
||||
|
||||
with patch.object(hc_module.litellm, "ahealth_check", fake_ahealth_check):
|
||||
result = await hc_module._run_model_health_check(model)
|
||||
|
||||
fake_ahealth_check.assert_not_called()
|
||||
assert result == {}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue