From f77948b762b58e1d4dff18e0011f08974cf9c566 Mon Sep 17 00:00:00 2001 From: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Date: Thu, 16 Jul 2026 15:35:47 +0000 Subject: [PATCH] fix(simple_shuffle): honor weights when first deployment has none --- litellm/router_strategy/simple_shuffle.py | 6 ++-- .../router_strategy/test_simple_shuffle.py | 34 +++++++++++++++++++ 2 files changed, 37 insertions(+), 3 deletions(-) create mode 100644 tests/test_litellm/router_strategy/test_simple_shuffle.py diff --git a/litellm/router_strategy/simple_shuffle.py b/litellm/router_strategy/simple_shuffle.py index d3349ee29ce..b275b42e07c 100644 --- a/litellm/router_strategy/simple_shuffle.py +++ b/litellm/router_strategy/simple_shuffle.py @@ -41,9 +41,9 @@ def simple_shuffle( ############## Check if 'weight' or 'rpm' or 'tpm' param set for a weighted pick ################# for weight_by in ["weight", "rpm", "tpm"]: - weight = healthy_deployments[0].get("litellm_params").get(weight_by, None) - if weight is not None: - weights = [m["litellm_params"].get(weight_by, 0) for m in healthy_deployments] + raw_weights = [m["litellm_params"].get(weight_by, None) for m in healthy_deployments] + if any(weight is not None for weight in raw_weights): + weights = [weight if weight is not None else 0 for weight in raw_weights] verbose_router_logger.debug(f"\nweight {weights}") total_weight = sum(weights) if total_weight <= 0: diff --git a/tests/test_litellm/router_strategy/test_simple_shuffle.py b/tests/test_litellm/router_strategy/test_simple_shuffle.py new file mode 100644 index 00000000000..474bd194a93 --- /dev/null +++ b/tests/test_litellm/router_strategy/test_simple_shuffle.py @@ -0,0 +1,34 @@ +from collections import Counter +from unittest.mock import MagicMock + +from litellm.router_strategy.simple_shuffle import simple_shuffle + + +def _deployment(deployment_id: str, **litellm_params) -> dict: + return { + "model_name": "test-model", + "litellm_params": {"model": "gpt-4o", **litellm_params}, + "model_info": {"id": deployment_id}, + } + + +def test_weights_respected_when_first_deployment_has_no_weight(): + """Regression for #33329: `simple_shuffle` decided whether weighted routing + was enabled by inspecting only the first healthy deployment. When the first + deployment had no `weight`, every deployment's weight was ignored and the + pick fell back to uniform random. The weighted pick must be driven by any + deployment declaring a weight, regardless of ordering. + """ + healthy_deployments = [ + _deployment("A"), + _deployment("B", weight=1), + _deployment("C", weight=99), + ] + + counts: Counter = Counter() + for _ in range(2000): + deployment = simple_shuffle(MagicMock(), healthy_deployments, "test-model") + counts[deployment["model_info"]["id"]] += 1 + + assert counts["A"] == 0 + assert counts["C"] > counts["B"] * 2