mirror of
https://github.com/BerriAI/litellm.git
synced 2026-08-28 05:25:59 +00:00
fix(dashscope): honor the model reasoning rate when a tier omits output rates
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
This commit is contained in:
parent
34918d34f9
commit
e46f2ca62f
2 changed files with 70 additions and 10 deletions
|
|
@ -88,19 +88,20 @@ def _calculate_completion_cost(
|
|||
model_info: ModelInfo,
|
||||
tier: dict | None,
|
||||
) -> float:
|
||||
# A tier declaring no output rate falls back to the model's own, since a table spelling out
|
||||
# only input rates would otherwise serve every completion for free
|
||||
# A tier that declares output rates keeps the request on them, all-or-nothing. A tier table
|
||||
# spelling out only input rates would serve every completion for free, so there the model's
|
||||
# own output rates stand in
|
||||
tier_declares_output: Final = tier is not None and "output_cost_per_token" in tier
|
||||
output_cost: Final = (
|
||||
tier_rate(tier, "output_cost_per_token")
|
||||
if tier is not None and "output_cost_per_token" in tier
|
||||
if tier_declares_output
|
||||
else float(model_info.get("output_cost_per_token") or 0.0)
|
||||
)
|
||||
if tier is not None:
|
||||
return (breakdown.completion_tokens * output_cost) + (
|
||||
breakdown.reasoning_tokens * (tier_rate(tier, "output_cost_per_reasoning_token") or output_cost)
|
||||
)
|
||||
|
||||
reasoning_cost: Final = _flat_rate(model_info, "output_cost_per_reasoning_token", "output_cost_per_token")
|
||||
tier_reasoning_cost: Final = tier_rate(tier, "output_cost_per_reasoning_token") if tier is not None else 0.0
|
||||
model_reasoning_cost: Final = (
|
||||
0.0 if tier_declares_output else float(model_info.get("output_cost_per_reasoning_token") or 0.0)
|
||||
)
|
||||
reasoning_cost: Final = tier_reasoning_cost or model_reasoning_cost or output_cost
|
||||
|
||||
return (breakdown.completion_tokens * output_cost) + (breakdown.reasoning_tokens * reasoning_cost)
|
||||
|
||||
|
|
|
|||
|
|
@ -21,7 +21,11 @@ import litellm
|
|||
from litellm.llms.dashscope.cost_calculator import (
|
||||
cost_per_token as dashscope_cost_per_token,
|
||||
)
|
||||
from litellm.types.utils import Usage, PromptTokensDetailsWrapper
|
||||
from litellm.types.utils import (
|
||||
CompletionTokensDetailsWrapper,
|
||||
PromptTokensDetailsWrapper,
|
||||
Usage,
|
||||
)
|
||||
|
||||
|
||||
class TestDashscopeCostCalculator:
|
||||
|
|
@ -344,6 +348,61 @@ class TestDashscopeCostCalculator:
|
|||
assert math.isclose(prompt_cost, 500 * 4e-07, rel_tol=1e-10)
|
||||
assert math.isclose(completion_cost, 200 * 1.6e-06, rel_tol=1e-10)
|
||||
|
||||
def test_dashscope_tier_without_an_output_rate_bills_the_model_reasoning_rate(self):
|
||||
"""
|
||||
Regression: a tier declaring only an input rate billed reasoning tokens at the model's
|
||||
plain output rate, ignoring the model's dedicated reasoning rate.
|
||||
"""
|
||||
litellm.model_cost["dashscope/qwen-input-only-reasoning-test"] = {
|
||||
"litellm_provider": "dashscope",
|
||||
"mode": "chat",
|
||||
"output_cost_per_token": 1.6e-06,
|
||||
"output_cost_per_reasoning_token": 4e-06,
|
||||
"tiered_pricing": [{"range": [0, 1000], "input_cost_per_token": 4e-07}],
|
||||
}
|
||||
|
||||
usage = Usage(
|
||||
prompt_tokens=500,
|
||||
completion_tokens=200,
|
||||
completion_tokens_details=CompletionTokensDetailsWrapper(reasoning_tokens=150),
|
||||
)
|
||||
_, completion_cost = dashscope_cost_per_token(
|
||||
model="qwen-input-only-reasoning-test", usage=usage
|
||||
)
|
||||
|
||||
assert math.isclose(
|
||||
completion_cost, (50 * 1.6e-06) + (150 * 4e-06), rel_tol=1e-10
|
||||
)
|
||||
|
||||
def test_dashscope_tier_output_rate_wins_over_the_model_reasoning_rate(self):
|
||||
"""
|
||||
A tier declaring its own output rate keeps reasoning tokens on that tier rather than
|
||||
mixing in a model-level reasoning rate.
|
||||
"""
|
||||
litellm.model_cost["dashscope/qwen-tier-output-reasoning-test"] = {
|
||||
"litellm_provider": "dashscope",
|
||||
"mode": "chat",
|
||||
"output_cost_per_reasoning_token": 4e-06,
|
||||
"tiered_pricing": [
|
||||
{
|
||||
"range": [0, 1000],
|
||||
"input_cost_per_token": 4e-07,
|
||||
"output_cost_per_token": 1.6e-06,
|
||||
}
|
||||
],
|
||||
}
|
||||
|
||||
usage = Usage(
|
||||
prompt_tokens=500,
|
||||
completion_tokens=200,
|
||||
completion_tokens_details=CompletionTokensDetailsWrapper(reasoning_tokens=150),
|
||||
)
|
||||
_, completion_cost = dashscope_cost_per_token(
|
||||
model="qwen-tier-output-reasoning-test", usage=usage
|
||||
)
|
||||
|
||||
assert math.isclose(completion_cost, 200 * 1.6e-06, rel_tol=1e-10)
|
||||
|
||||
def test_dashscope_tiered_pricing_zero_input_falls_back_to_flat_rates(self):
|
||||
"""
|
||||
No tier can be selected without input tokens, so an empty-prompt request must
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue