Merge pull request #41156 from BerriAI/litellm_weighted_routing_model_id

fix(router): keep weighted routing when a deployment id equals a model_name
This commit is contained in:
Yassin Kortam 2026-09-15 12:55:45 -07:00 committed by GitHub
commit 435f0d22e8
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 56 additions and 2 deletions

View file

@ -2481,7 +2481,7 @@ class Router:
### DEPLOYMENT-SPECIFIC PRE-CALL CHECKS ### (e.g. update rpm pre-call. Raise error, if deployment over limit)
## only run if model group given, not model id
if not self.has_model_id(model):
if model in self.model_names or not self.has_model_id(model):
self.routing_strategy_pre_call_checks(deployment=deployment)
input_kwargs: Final = {
@ -12532,7 +12532,7 @@ class Router:
# check if aliases set on litellm model alias map
if specific_deployment is True:
return model, self._get_deployment_by_litellm_model(model=model)
elif self.has_model_id(model):
elif model not in self.model_names and self.has_model_id(model):
deployment: Final = self.get_deployment(model_id=model)
if deployment is not None:
deployment_model: Final = deployment.litellm_params.model

View file

@ -15975,6 +15975,60 @@ async def test_an_open_circuit_breaker_skips_the_session_binding_without_a_warni
assert any("circuit breaker is open" in record.getMessage() for record in caplog.records)
@pytest.mark.asyncio
async def test_model_name_colliding_with_a_deployment_id_still_load_balances_the_group():
router = litellm.Router(
model_list=[
{
"model_name": "gpt-5-nano",
"litellm_params": {"model": "openai/gpt-5-nano", "api_key": "k", "weight": 0, "mock_response": "A"},
"model_info": {"id": "gpt-5-nano"},
},
{
"model_name": "gpt-5-nano",
"litellm_params": {"model": "openai/gpt-5-mini", "api_key": "k", "weight": 1, "mock_response": "B"},
"model_info": {"id": "gpt-5-mini-dep"},
},
],
routing_strategy="simple-shuffle",
)
by_group = await router.acompletion(model="gpt-5-nano", messages=[{"role": "user", "content": "hi"}])
by_id = await router.acompletion(model="gpt-5-mini-dep", messages=[{"role": "user", "content": "hi"}])
assert by_group._hidden_params["model_id"] == "gpt-5-mini-dep"
assert by_group.choices[0].message.content == "B"
assert by_id._hidden_params["model_id"] == "gpt-5-mini-dep"
def test_sync_completion_runs_pre_call_checks_for_a_model_name_colliding_with_a_deployment_id():
router = litellm.Router(
model_list=[
{
"model_name": "gpt-5-nano",
"litellm_params": {"model": "openai/gpt-5-nano", "api_key": "k", "weight": 0, "mock_response": "A"},
"model_info": {"id": "gpt-5-nano"},
},
{
"model_name": "gpt-5-nano",
"litellm_params": {"model": "openai/gpt-5-mini", "api_key": "k", "weight": 1, "mock_response": "B"},
"model_info": {"id": "gpt-5-mini-dep"},
},
],
routing_strategy="simple-shuffle",
)
with patch.object(router, "routing_strategy_pre_call_checks") as pre_call_checks:
by_group = router.completion(model="gpt-5-nano", messages=[{"role": "user", "content": "hi"}])
assert by_group._hidden_params["model_id"] == "gpt-5-mini-dep"
pre_call_checks.assert_called_once()
assert pre_call_checks.call_args.kwargs["deployment"]["model_info"]["id"] == "gpt-5-mini-dep"
by_id = router.completion(model="gpt-5-mini-dep", messages=[{"role": "user", "content": "hi"}])
assert by_id._hidden_params["model_id"] == "gpt-5-mini-dep"
pre_call_checks.assert_called_once()
class TestMemberAutoRouterInference:
@pytest.fixture(autouse=True)
def runtime(self, monkeypatch: pytest.MonkeyPatch) -> None: