fix(cost): price Vertex AI DeepSeek OCR by token usage - #39414
fix(cost): price Vertex AI DeepSeek OCR by token usage#39414mateo-berri wants to merge 2 commits into
Conversation
DeepSeek OCR on Vertex AI reports prompt and completion tokens and never a page count, so the OCR cost calculator either raised (cost-map name, no cost header at all) or returned 0.0 (short name, no cost-map entry). OCR cost now falls back to the model's token rates when no page pricing applies, the DeepSeek transform reports the canonical deepseek-ai/ model on the response so the short deployment name resolves the cost-map entry, and the unsourced ocr_cost_per_page is dropped from that entry since Google bills it per token. The Rust OCR port mirrors the canonical response model.
Greptile SummaryThis PR prices Vertex AI DeepSeek OCR responses from reported token usage when page usage is unavailable.
Confidence Score: 5/5The PR appears safe to merge. No blocking failure remains.
|
| Filename | Overview |
|---|---|
| litellm/cost_calculator.py | Adds prompt and completion token-cost calculation for OCR responses that lack applicable page pricing. |
| litellm/llms/vertex_ai/ocr/deepseek_transformation.py | Canonicalizes DeepSeek OCR response model names so token pricing resolves for short deployment names. |
| litellm-rust/crates/core/src/providers/vertex_ai/ocr/transformation.rs | Aligns Rust DeepSeek OCR response model normalization with the Python implementation. |
| model_prices_and_context_window.json | Removes the obsolete DeepSeek OCR per-page rate while retaining token rates. |
| litellm/model_prices_and_context_window_backup.json | Keeps the backup model-price map synchronized with the primary map. |
| tests/test_litellm/llms/vertex_ai/ocr/test_deepseek_transformation.py | Covers canonical response naming and nonzero token pricing for both supported model-name forms. |
| tests/test_litellm/test_cost_calculator.py | Covers token fallback, page-pricing precedence, cost splitting, and missing-token behavior. |
Reviews (2): Last reviewed commit: "style(cost): wrap an overlong docstring ..." | Re-trigger Greptile
|
|
||
|
|
||
| @pytest.mark.parametrize("model", ["deepseek-ocr-maas", "deepseek-ai/deepseek-ocr-maas"]) | ||
| def test_response_is_priced_from_token_usage_for_either_model_name(local_model_cost_map: None, model: str) -> None: |
There was a problem hiding this comment.
Several newly added test declarations and assertions exceed the repository's 120-character Python line limit, including this line, line 45, and tests/test_litellm/test_cost_calculator.py:4480; wrap them to keep formatting and lint checks passing.
Context Used: CLAUDE.md (source)
Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!
Codecov Report❌ Patch coverage is
📢 Thoughts on this report? Let us know! |
The Returns line of the ocr_cost docstring ran to 126 columns, past the repo's 120-column limit. Wrapped it; no behavior change.
|
bugbot run |
There was a problem hiding this comment.
✅ Bugbot reviewed your changes and found no new issues!
Comment @cursor review or bugbot run to trigger another review on this PR
Reviewed by Cursor Bugbot for commit 4f99996. Configure here.
TLDR
Problem this solves:
vertex_ai/deepseek-ai/deepseek-ocr-maas: nox-litellm-response-costheader at allvertex_ai/deepseek-ocr-maas: cost 0.0 in the headers and $0 in the spend logsHow it solves it:
deepseek-ai/model name, so the short deployment name finds its priceocr_cost_per_pagefrom the DeepSeek entry: Google bills DeepSeek-OCR on Vertex per tokendeepseek-ai/response modelUser Flow
Before: a developer OCRs an image through the gateway's Vertex AI DeepSeek OCR deployment and the request is never priced, so the logs page and key spend stay at $0
{"model": "vertex_ai/deepseek-ai/deepseek-ocr-maas", "document": {"type": "image_url", "image_url": "data:image/png;base64,..."}}usage_inforeportingprompt_tokens: 901,completion_tokens: 1057,pages_processed: null, but nox-litellm-response-costheader at all andx-litellm-key-spend: 0.0"model": "vertex_ai/deepseek-ocr-maas", the short name their admin deployedx-litellm-response-cost-*breakdown header at0.0andx-litellm-key-spend: 0.0spend: 0.0, so the usage page and the key's budget never moveAfter: the same two requests come back priced from Google's published per-token DeepSeek-OCR rates, and the spend shows up in the logs
{"model": "vertex_ai/deepseek-ai/deepseek-ocr-maas", "document": {"type": "image_url", "image_url": "data:image/png;base64,..."}}x-litellm-response-cost: 0.0003879(901 prompt tokens at $0.30 per 1M plus 98 completion tokens at $1.20 per 1M),x-litellm-response-cost-input: 0.0002703,x-litellm-response-cost-output: 0.0001176, andx-litellm-key-spendmoving by the same amount"model": "vertex_ai/deepseek-ocr-maas"x-litellm-response-cost: 0.0007143for 901 prompt and 370 completion tokensRelevant issues
Linear ticket
Resolves LIT-6727
Pre-Submission checklist
Please complete all items before asking a LiteLLM maintainer to review your PR
uv run pytest tests/test_litellm/<your_test_file>.py -v. Leave the suites (make test-unit-*,make test-unit) to CI: it finishes in ~15 minutes where a laptop takes an hour or more@greptileaito 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
Setup shared by both legs: a proxy booted with
--num_workers 2on a fresh Postgres database,VERTEX_AI_API_KEYset to agcloud auth print-access-tokenvalue, and this configThe same loop runs on both legs against a 100 KB PNG of a rendered text page, then reads each request back through the spend logs API
Before (ba2e5d2)
Cost-map name vertex_ai/deepseek-ai/deepseek-ocr-maas
POST /v1/ocr, nox-litellm-response-costheader at allGET /spend/logs?request_id=89c64bc3-0ca3-4107-a8a1-74ed37e7aee6Short name vertex_ai/deepseek-ocr-maas
POST /v1/ocr, every cost breakdown header at 0.0GET /spend/logs?request_id=cfabd49d-847d-4adb-8f40-e92879d6fbc7After (24299c3)
Head is 4f99996 since this run: the only commit after 24299c3 wraps a docstring line in
litellm/cost_calculator.py, which cannot change behaviorCost-map name vertex_ai/deepseek-ai/deepseek-ocr-maas
POST /v1/ocr, priced at 901 x $0.30/1M + 98 x $1.20/1MGET /spend/logs?request_id=d6adfcce-77db-468d-9d81-ae90541ebc0aShort name vertex_ai/deepseek-ocr-maas
POST /v1/ocr, priced at 901 x $0.30/1M + 370 x $1.20/1MGET /spend/logs?request_id=7af206e7-e2a2-456b-bc60-ef8029a9b8c3QA notes, none caused or changed by this PR:
x-litellm-key-spendshows the request's own cost, not a running total-*breakdown headers, no bare totalType
🐛 Bug Fix
Caveats (if any)
Medium
max_budget: 0.0002made one OCR call, then its next one got429 Budget has been exceededLow
modelfield is now alwaysdeepseek-ai/deepseek-ocr-maasreturn_raw_model_namex-litellm-response-costcan carry float noise (0.00041430000000000004), the same formatting other providers' cost headers already havelitellm_rustnot installed); the page-priced branch was verified live with Mistral OCR and is unchangedFinal 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
24299c3 passes /live-pr-risk
Note
Medium Risk
Changes OCR spend calculation and enables non-zero charges for DeepSeek OCR (including budget 429s); page-priced OCR paths are preserved when pages are reported.
Overview
Fixes $0 spend on Vertex AI DeepSeek OCR when responses report token usage but not pages_processed.
OCR billing now uses
_ocr_token_costinocr_cost: if the model has no applicable per-page (or annotation) pricing but hasinput_cost_per_token/output_cost_per_tokenand integerprompt_tokens/completion_tokens, cost is computed from tokens. Page-based pricing still wins whenpages_processedandocr_cost_per_pageapply (e.g. Mistral OCR).DeepSeek OCR responses (Python and Rust) normalize the returned
modelto the canonicaldeepseek-ai/deepseek-ocr-maasvia_provider_model_name/deepseek_model_name, so short deployment names still match the cost map. Thevertex_ai/deepseek-ai/deepseek-ocr-maasentry drops the unsourcedocr_cost_per_pageso billing aligns with Google’s per-token rates.Tests cover token fallback, page-priority, and end-to-end pricing for both model name forms.
Reviewed by Cursor Bugbot for commit 4f99996. Bugbot is set up for automated code reviews on this repo. Configure here.