mirror of
https://github.com/BerriAI/litellm.git
synced 2026-10-23 05:34:41 +00:00
fix(router): honor reasoning_override_min_score on heuristic_v2
classifier_type=heuristic_v2 routed every request through the TierSuccessPredictor, which reads outcome statistics and never the ask's reasoning markers, so an operator who set reasoning_override_min_score (0 = unconditional) saw 2+ exact reasoning keywords silently ignored and the request classified by the predictor alone. Route the ask through the shared scorer gate first and short-circuit to REASONING when the reasoning-marker override fires, so the documented classifier-wide contract holds on every classification path. Fixes #44527 Signed-off-by: apex-mochen <2756823972@qq.com>
This commit is contained in:
parent
97fc72e5bb
commit
ea441ec0a9
2 changed files with 54 additions and 0 deletions
|
|
@ -1944,6 +1944,21 @@ class ComplexityRouter(CustomLogger):
|
|||
return await self._llm_classifier_outcome(prompt, system_prompt, request_kwargs, messages)
|
||||
|
||||
def _classify_with_heuristic_v2(self, prompt: str) -> ClassificationOutcome:
|
||||
# The reasoning-marker override is a classifier-wide contract, not a
|
||||
# heuristic-scorer quirk: an operator who sets reasoning_override_min_score
|
||||
# (0 = unconditional) expects 2+ markers to promote on every path that
|
||||
# classifies. The success predictor reads outcome statistics, never the
|
||||
# ask's markers, so honor the override here through the same gate the
|
||||
# heuristic scorer uses -- otherwise the setting silently does nothing
|
||||
# under heuristic_v2 while still being documented as classifier-wide.
|
||||
overridden: Final = self._score_and_classify(prompt)
|
||||
if overridden[3] == "reasoning_override":
|
||||
return ClassificationOutcome(
|
||||
tier=overridden[0],
|
||||
score=overridden[1],
|
||||
signals=overridden[2],
|
||||
cause="reasoning_override",
|
||||
)
|
||||
predictor: Final = self._tier_success_predictor
|
||||
if predictor is None:
|
||||
raise ValueError("heuristic v2 predictor is not configured")
|
||||
|
|
|
|||
|
|
@ -661,6 +661,45 @@ class TestReasoningMarkerScoring:
|
|||
assert score == 0.25
|
||||
assert tier == ComplexityTier.REASONING
|
||||
|
||||
def test_heuristic_v2_honors_the_zero_floor_override(self, mock_router_instance, basic_config):
|
||||
"""#44527: reasoning_override_min_score=0 must promote on heuristic_v2 too.
|
||||
|
||||
The success predictor reads outcome statistics, never the ask's reasoning
|
||||
markers, so before the fix a request carrying 2+ exact markers was still
|
||||
classified by the predictor alone and the operator's explicit 0 floor was
|
||||
silently ignored.
|
||||
"""
|
||||
router = ComplexityRouter(
|
||||
model_name="test-complexity-router",
|
||||
litellm_router_instance=mock_router_instance,
|
||||
complexity_router_config={
|
||||
**basic_config,
|
||||
"classifier_type": "heuristic_v2",
|
||||
"heuristic_v2_artifact": _heuristic_v2_artifact(),
|
||||
"reasoning_override_min_score": 0.0,
|
||||
},
|
||||
)
|
||||
outcome = asyncio.run(router.aclassify("hi, step by step, pros and cons"))
|
||||
assert outcome.cause == "reasoning_override"
|
||||
assert outcome.tier == ComplexityTier.REASONING
|
||||
|
||||
def test_heuristic_v2_respects_a_floor_above_the_markers_score(self, mock_router_instance, basic_config):
|
||||
"""A floor above the markers' weighted score leaves heuristic_v2 to the predictor."""
|
||||
router = ComplexityRouter(
|
||||
model_name="test-complexity-router",
|
||||
litellm_router_instance=mock_router_instance,
|
||||
complexity_router_config={
|
||||
**basic_config,
|
||||
"classifier_type": "heuristic_v2",
|
||||
"heuristic_v2_artifact": _heuristic_v2_artifact(),
|
||||
"reasoning_override_min_score": 0.99,
|
||||
},
|
||||
)
|
||||
outcome = asyncio.run(router.aclassify("hi, step by step, pros and cons"))
|
||||
assert outcome.cause != "reasoning_override"
|
||||
assert outcome.cause == "heuristic_v2"
|
||||
assert outcome.tier == ComplexityTier.COMPLEX
|
||||
|
||||
def test_system_prompt_reasoning_not_counted(self, complexity_router):
|
||||
"""Reasoning markers in system prompt should not count for override."""
|
||||
user_prompt = "What is 2+2?"
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue