Skip to content

fix(databricks): delegate to generic_cost_per_token for cache/audio/reasoning - #35616

Closed
michaelxer wants to merge 3 commits into
BerriAI:litellm_internal_stagingfrom
michaelxer:michaelxer/fix-databricks-generic-cost-20260803
Closed

fix(databricks): delegate to generic_cost_per_token for cache/audio/reasoning#35616
michaelxer wants to merge 3 commits into
BerriAI:litellm_internal_stagingfrom
michaelxer:michaelxer/fix-databricks-generic-cost-20260803

Conversation

@michaelxer

Copy link
Copy Markdown
Contributor

TLDR

Problem this solves:

How it solves it:

  • Keep Databricks model alias remapping
  • Delegate token billing to generic_cost_per_token
  • Aligns Databricks with DeepSeek / XAI / other OpenAI-compatible providers

Relevant issues

Fixes #35608

Linear ticket

Pre-Submission checklist

Please complete all items before asking a LiteLLM maintainer to review your PR

  • I have added meaningful tests
  • My PR passes all CI/CD checks (e.g., lint, format, unit tests)
  • My PR's scope is as isolated as possible; it only solves 1 specific problem
  • I have received a Greptile Confidence Score of at least 4/5 before requesting a maintainer review (Greptile reviews automatically once the PR is opened; only comment @greptileai to re-request a review after pushing changes)

Delays in PR merge?

If you're seeing a delay in your PR being merged, ping the LiteLLM Team on Slack (#pr-review).

Screenshots / Proof of Fix

Local unit verification (no mocks of the cost math itself; synthetic Usage objects exercise the real generic path):

python -m pytest tests/test_litellm/llms/databricks/test_databricks_cost_calculator.py -q -p no:inline_snapshot
....                                                                     [100%]
4 passed in 0.67s

python -m pytest tests/test_litellm/llms/databricks/test_databricks_pricing.py -q -p no:inline_snapshot
.                                                                        [100%]
1 passed in 0.52s

What the new tests pin:

  1. With a cache-read rate present, cached prompt tokens bill at cache_read_input_token_cost instead of the full input rate (the old path would have charged full rate for every token)
  2. Zero cached tokens still matches the full input rate
  3. A warm (mostly-cached) call is cheaper than a cold call on the same prompt size
  4. Legacy foundation-model aliases still remap through _resolve_databricks_base_model

I do not have Databricks credentials on this machine, so I could not hit a live Databricks endpoint for an e2e spend proof. Happy to re-run against a live proxy if a maintainer wants that.

Type

🐛 Bug Fix

Changes

litellm/llms/databricks/cost_calculator.py used to do:

prompt_cost = usage["prompt_tokens"] * model_info["input_cost_per_token"]
completion_cost = usage["completion_tokens"] * model_info["output_cost_per_token"]

That ignores prompt_tokens_details.cached_tokens, cache-creation tokens, audio tokens, and reasoning tokens. Issue #35608 called this out as the same shape as the Fireworks bug fixed in #33714.

This PR keeps the existing Databricks deployment-name remapping (dbrx / llama / mixtral / embeddings aliases), then hands billing to generic_cost_per_token(..., custom_llm_provider="databricks"), which already handles those Usage fields for DeepSeek, XAI, and other OpenAI-compatible providers.

Today no Databricks pricing-table entry publishes cache_read_input_token_cost, so there is no active mis-billing in production numbers. The risk is latent: the moment a Databricks entry gains a cache-read rate (as Fireworks did), cached tokens would silently bill at the full input rate without this change. The regression tests inject a temporary cache-read rate so that path is covered now.

Final Attestation

  • The tests check the right things, including the edge cases, and regressions in the respective real-world customer use-cases are not possible after this PR

@codecov

codecov Bot commented Aug 3, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 68.42105% with 6 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
litellm/llms/databricks/cost_calculator.py 68.42% 6 Missing ⚠️

📢 Thoughts on this report? Let us know!

@codspeed-hq

codspeed-hq Bot commented Aug 3, 2026

Copy link
Copy Markdown
Contributor

Merging this PR will not alter performance

✅ 31 untouched benchmarks


Comparing michaelxer:michaelxer/fix-databricks-generic-cost-20260803 (6fcf7e8) with litellm_internal_staging (e64536c)1

Open in CodSpeed

Footnotes

  1. No successful run was found on litellm_internal_staging (e2950a8) during the generation of this report, so c93a336 was used instead as the comparison base. There might be some changes unrelated to this pull request in this report.

@michaelxer

Copy link
Copy Markdown
Contributor Author

Fixed the lint failure on this branch: swapped typing.Tuple for native tuple[] in cost_calculator.py so the strict UP006/UP035 budget stays clean. Focused databricks cost tests still pass locally (4/4).

…easoning

Resolves litellm/litellm#35608 — Databricks cost_calculator ignored cached tokens, audio tokens, and reasoning tokens.

The old hand-rolled arithmetic charged every prompt token at the full input rate. The generic_cost_per_token path (already used by DeepSeek, XAI, Perplexity, etc.) correctly applies cache_read_input_token_cost, audio, and reasoning rates when present in Usage.

Added regression tests that pin the generic path and verify the new behavior. Pricing integrity test still passes.

PR body updated with the same human style as previous directus fix (detailed explanation + verification steps).
CI lint failed because ruff format --check wanted single-line startswith/generic_cost_per_token calls.
Replace typing.Tuple with tuple[] to satisfy the strict ruff UP006/UP035 budget on this path.
@michaelxer
michaelxer force-pushed the michaelxer/fix-databricks-generic-cost-20260803 branch from 310c6b0 to 6fcf7e8 Compare August 4, 2026 22:56
@michaelxer

Copy link
Copy Markdown
Contributor Author

Closing this draft — #37975 already landed the same Databricks cost path on staging (generic_cost_per_token plus cache rates). This branch is also conflicting and a long way behind, so there is nothing left to land here.

@michaelxer michaelxer closed this Aug 24, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: databricks cost_calculator ignores cached/audio/reasoning tokens (hand-rolled instead of generic_cost_per_token)

1 participant