fix(cost): add missing cache_read_input_token_cost for DeepSeek models

Several DeepSeek and OpenRouter/DeepSeek models had cache pricing data
under input_cost_per_token_cache_hit but not under the key the cost
calculator actually uses (cache_read_input_token_cost). This caused
cost_breakdown to omit cache_read_cost for these models.

Also adds cache_creation_input_token_cost=0.0 for all DeepSeek provider
models since DeepSeek auto-caches with no creation cost.

Closes #31594

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
This commit is contained in:
Devin AI 2026-07-01 04:37:26 +00:00
parent 70eb4e5d00
commit 8d3c273d55
4 changed files with 144 additions and 0 deletions

View file

@ -11255,6 +11255,7 @@
]
},
"deepseek-chat": {
"cache_creation_input_token_cost": 0.0,
"cache_read_input_token_cost": 2.8e-08,
"input_cost_per_token": 2.8e-07,
"litellm_provider": "deepseek",
@ -11276,6 +11277,7 @@
"supports_tool_choice": true
},
"deepseek-reasoner": {
"cache_creation_input_token_cost": 0.0,
"cache_read_input_token_cost": 2.8e-08,
"input_cost_per_token": 2.8e-07,
"litellm_provider": "deepseek",
@ -13806,6 +13808,8 @@
"supports_tool_choice": true
},
"deepseek/deepseek-coder": {
"cache_creation_input_token_cost": 0.0,
"cache_read_input_token_cost": 1.4e-08,
"input_cost_per_token": 1.4e-07,
"input_cost_per_token_cache_hit": 1.4e-08,
"litellm_provider": "deepseek",
@ -13820,6 +13824,8 @@
"supports_tool_choice": true
},
"deepseek/deepseek-r1": {
"cache_creation_input_token_cost": 0.0,
"cache_read_input_token_cost": 1.4e-07,
"input_cost_per_token": 5.5e-07,
"input_cost_per_token_cache_hit": 1.4e-07,
"litellm_provider": "deepseek",
@ -13835,6 +13841,7 @@
"supports_tool_choice": true
},
"deepseek/deepseek-reasoner": {
"cache_creation_input_token_cost": 0.0,
"cache_read_input_token_cost": 2.8e-08,
"input_cost_per_token": 2.8e-07,
"input_cost_per_token_cache_hit": 2.8e-08,
@ -13875,6 +13882,8 @@
"supports_tool_choice": true
},
"deepseek/deepseek-v3.2": {
"cache_creation_input_token_cost": 0.0,
"cache_read_input_token_cost": 2.8e-08,
"input_cost_per_token": 2.8e-07,
"input_cost_per_token_cache_hit": 2.8e-08,
"litellm_provider": "deepseek",
@ -28324,6 +28333,7 @@
"supports_tool_choice": true
},
"openrouter/deepseek/deepseek-chat-v3.1": {
"cache_read_input_token_cost": 2e-08,
"input_cost_per_token": 2e-07,
"input_cost_per_token_cache_hit": 2e-08,
"litellm_provider": "openrouter",
@ -28339,6 +28349,7 @@
"supports_tool_choice": true
},
"openrouter/deepseek/deepseek-v3.2": {
"cache_read_input_token_cost": 2.8e-08,
"input_cost_per_token": 2.8e-07,
"input_cost_per_token_cache_hit": 2.8e-08,
"litellm_provider": "openrouter",
@ -28354,6 +28365,7 @@
"supports_tool_choice": true
},
"openrouter/deepseek/deepseek-v3.2-exp": {
"cache_read_input_token_cost": 2e-08,
"input_cost_per_token": 2e-07,
"input_cost_per_token_cache_hit": 2e-08,
"litellm_provider": "openrouter",
@ -28369,6 +28381,7 @@
"supports_tool_choice": true
},
"openrouter/deepseek/deepseek-r1": {
"cache_read_input_token_cost": 1.4e-07,
"input_cost_per_token": 5.5e-07,
"input_cost_per_token_cache_hit": 1.4e-07,
"litellm_provider": "openrouter",
@ -28384,6 +28397,7 @@
"supports_tool_choice": true
},
"openrouter/deepseek/deepseek-r1-0528": {
"cache_read_input_token_cost": 1.4e-07,
"input_cost_per_token": 5e-07,
"input_cost_per_token_cache_hit": 1.4e-07,
"litellm_provider": "openrouter",

View file

@ -11255,6 +11255,7 @@
]
},
"deepseek-chat": {
"cache_creation_input_token_cost": 0.0,
"cache_read_input_token_cost": 2.8e-08,
"input_cost_per_token": 2.8e-07,
"litellm_provider": "deepseek",
@ -11276,6 +11277,7 @@
"supports_tool_choice": true
},
"deepseek-reasoner": {
"cache_creation_input_token_cost": 0.0,
"cache_read_input_token_cost": 2.8e-08,
"input_cost_per_token": 2.8e-07,
"litellm_provider": "deepseek",
@ -13806,6 +13808,8 @@
"supports_tool_choice": true
},
"deepseek/deepseek-coder": {
"cache_creation_input_token_cost": 0.0,
"cache_read_input_token_cost": 1.4e-08,
"input_cost_per_token": 1.4e-07,
"input_cost_per_token_cache_hit": 1.4e-08,
"litellm_provider": "deepseek",
@ -13820,6 +13824,8 @@
"supports_tool_choice": true
},
"deepseek/deepseek-r1": {
"cache_creation_input_token_cost": 0.0,
"cache_read_input_token_cost": 1.4e-07,
"input_cost_per_token": 5.5e-07,
"input_cost_per_token_cache_hit": 1.4e-07,
"litellm_provider": "deepseek",
@ -13835,6 +13841,7 @@
"supports_tool_choice": true
},
"deepseek/deepseek-reasoner": {
"cache_creation_input_token_cost": 0.0,
"cache_read_input_token_cost": 2.8e-08,
"input_cost_per_token": 2.8e-07,
"input_cost_per_token_cache_hit": 2.8e-08,
@ -13875,6 +13882,8 @@
"supports_tool_choice": true
},
"deepseek/deepseek-v3.2": {
"cache_creation_input_token_cost": 0.0,
"cache_read_input_token_cost": 2.8e-08,
"input_cost_per_token": 2.8e-07,
"input_cost_per_token_cache_hit": 2.8e-08,
"litellm_provider": "deepseek",
@ -28485,6 +28494,7 @@
"supports_tool_choice": true
},
"openrouter/deepseek/deepseek-chat-v3.1": {
"cache_read_input_token_cost": 2e-08,
"input_cost_per_token": 2e-07,
"input_cost_per_token_cache_hit": 2e-08,
"litellm_provider": "openrouter",
@ -28500,6 +28510,7 @@
"supports_tool_choice": true
},
"openrouter/deepseek/deepseek-v3.2": {
"cache_read_input_token_cost": 2.8e-08,
"input_cost_per_token": 2.8e-07,
"input_cost_per_token_cache_hit": 2.8e-08,
"litellm_provider": "openrouter",
@ -28515,6 +28526,7 @@
"supports_tool_choice": true
},
"openrouter/deepseek/deepseek-v3.2-exp": {
"cache_read_input_token_cost": 2e-08,
"input_cost_per_token": 2e-07,
"input_cost_per_token_cache_hit": 2e-08,
"litellm_provider": "openrouter",
@ -28530,6 +28542,7 @@
"supports_tool_choice": true
},
"openrouter/deepseek/deepseek-r1": {
"cache_read_input_token_cost": 1.4e-07,
"input_cost_per_token": 5.5e-07,
"input_cost_per_token_cache_hit": 1.4e-07,
"litellm_provider": "openrouter",
@ -28545,6 +28558,7 @@
"supports_tool_choice": true
},
"openrouter/deepseek/deepseek-r1-0528": {
"cache_read_input_token_cost": 1.4e-07,
"input_cost_per_token": 5e-07,
"input_cost_per_token_cache_hit": 1.4e-07,
"litellm_provider": "openrouter",

View file

@ -2038,3 +2038,43 @@ def test_token_type_cost_breakdown_applies_regional_uplift():
text_input_cost = 600 * model_info["input_cost_per_token"] * uplift
assert text_output_cost + eu.reasoning_cost == pytest.approx(completion_cost)
assert text_input_cost + eu.cache_read_cost == pytest.approx(prompt_cost)
@pytest.mark.parametrize(
"model,custom_llm_provider,expected_cache_read_rate",
[
("deepseek-chat", "deepseek", 2.8e-08),
("deepseek/deepseek-r1", "deepseek", 1.4e-07),
("deepseek/deepseek-v3.2", "deepseek", 2.8e-08),
("deepseek/deepseek-coder", "deepseek", 1.4e-08),
],
)
def test_deepseek_cache_read_cost_in_breakdown(
model, custom_llm_provider, expected_cache_read_rate
):
"""
DeepSeek models report cached tokens via prompt_cache_hit_tokens. The
cost breakdown must produce a non-zero cache_read_cost matching the
model's cache_read_input_token_cost rate.
Regression for https://github.com/BerriAI/litellm/issues/31594
"""
os.environ["LITELLM_LOCAL_MODEL_COST_MAP"] = "True"
litellm.model_cost = litellm.get_model_cost_map(url="")
cache_hit_tokens = 64
usage = Usage(
prompt_tokens=100,
completion_tokens=50,
total_tokens=150,
prompt_cache_hit_tokens=cache_hit_tokens,
prompt_cache_miss_tokens=36,
)
breakdown = get_token_type_cost_breakdown(
model=model, custom_llm_provider=custom_llm_provider, usage=usage
)
assert breakdown.cache_read_cost == pytest.approx(
cache_hit_tokens * expected_cache_read_rate
)

View file

@ -3176,3 +3176,79 @@ def test_completion_cost_logs_reasoning_and_cache_breakdown():
assert logging_obj.cost_breakdown is not None
assert logging_obj.cost_breakdown["reasoning_cost"] == pytest.approx(3114 * 2.5e-06)
assert logging_obj.cost_breakdown["cache_read_cost"] == pytest.approx(100 * 3e-08)
@pytest.mark.parametrize(
"model,custom_llm_provider,cache_read_rate",
[
("deepseek-chat", "deepseek", 2.8e-08),
("deepseek/deepseek-r1", "deepseek", 1.4e-07),
("deepseek/deepseek-v3.2", "deepseek", 2.8e-08),
("deepseek/deepseek-coder", "deepseek", 1.4e-08),
],
)
def test_deepseek_cost_breakdown_includes_cache_read_cost(
model, custom_llm_provider, cache_read_rate
):
"""
DeepSeek reports cached tokens via prompt_cache_hit_tokens. The cost
breakdown must surface cache_read_cost so spend logs show where cache
savings come from, not just a lower total.
Regression for https://github.com/BerriAI/litellm/issues/31594
"""
from datetime import datetime
from litellm.litellm_core_utils.litellm_logging import Logging
from litellm.types.utils import Choices, Message
os.environ["LITELLM_LOCAL_MODEL_COST_MAP"] = "True"
litellm.model_cost = litellm.get_model_cost_map(url="")
cache_hit_tokens = 64
logging_obj = Logging(
model=model,
messages=[{"role": "user", "content": "Hello"}],
stream=False,
call_type="completion",
start_time=datetime.now(),
litellm_call_id="deepseek-cache-breakdown",
function_id="f",
)
response = ModelResponse(
id="x",
created=1,
model=model,
object="chat.completion",
choices=[
Choices(
index=0,
message=Message(role="assistant", content="hi"),
finish_reason="stop",
)
],
usage=Usage(
prompt_tokens=100,
completion_tokens=50,
total_tokens=150,
prompt_cache_hit_tokens=cache_hit_tokens,
prompt_cache_miss_tokens=36,
),
)
litellm.completion_cost(
completion_response=response,
model=model,
custom_llm_provider=custom_llm_provider,
litellm_logging_obj=logging_obj,
)
assert logging_obj.cost_breakdown is not None
assert "cache_read_cost" in logging_obj.cost_breakdown, (
f"cache_read_cost missing from cost_breakdown for {model}"
)
assert logging_obj.cost_breakdown["cache_read_cost"] == pytest.approx(
cache_hit_tokens * cache_read_rate
)