mirror of
https://github.com/BerriAI/litellm.git
synced 2026-08-28 05:25:59 +00:00
Merge pull request #37425 from BerriAI/litellm_fix_passthrough_embeddings_unmapped_spend
Some checks are pending
CodSpeed Benchmarks / benchmarks (push) Waiting to run
Unit Tests: Enterprise, Google GenAI & Routing / enterprise-routing (push) Waiting to run
Unit Tests: Integrations (Callbacks & Logging) / integrations (push) Waiting to run
Unit Tests: LLM Provider Transformations / All Other Providers (push) Waiting to run
Unit Tests: Proxy DB Operations / endpoints-and-responses (push) Blocked by required conditions
Unit Tests: Proxy API Endpoints / proxy-endpoints (push) Waiting to run
Unit Tests: Proxy API Endpoints / proxy-server (push) Waiting to run
Unit Tests: Proxy Infrastructure / proxy-infra (push) Waiting to run
Unit Tests: Responses, Caching & Types / responses-caching-types (push) Waiting to run
GitHub Actions Security Analysis / zizmor (push) Waiting to run
CI Coverage / assert-ci-coverage (push) Waiting to run
Publish basedpyright base counts / publish (push) Waiting to run
Code Quality Checks / code-quality (push) Waiting to run
UI Unit Tests / ui-unit-tests (push) Waiting to run
Unit Tests: Core Utilities / core-utils (push) Waiting to run
Unit Tests: Documentation Validation / documentation (push) Waiting to run
Unit Tests: LLM Provider Transformations / Vertex AI (push) Waiting to run
Unit Tests: MCP, Secrets, Containers & Misc / misc (push) Waiting to run
Unit Tests: Proxy Auth & Key Management / proxy-auth (push) Waiting to run
Unit Tests: Proxy DB Operations / assert-shard-coverage (push) Waiting to run
Unit Tests: Proxy DB Operations / auth-checks (push) Blocked by required conditions
Unit Tests: Proxy DB Operations / budgets (push) Blocked by required conditions
Unit Tests: Proxy DB Operations / key-generation (push) Blocked by required conditions
Unit Tests: Proxy DB Operations / custom-logging (push) Blocked by required conditions
Unit Tests: Proxy DB Operations / db-and-spend (push) Blocked by required conditions
Unit Tests: Proxy DB Operations / guardrails-hooks (push) Blocked by required conditions
Unit Tests: Proxy DB Operations / jwt-and-keys (push) Blocked by required conditions
Unit Tests: Proxy DB Operations / logging-misc (push) Blocked by required conditions
Unit Tests: Proxy DB Operations / proxy-runtime (push) Blocked by required conditions
Unit Tests: Proxy DB Operations / proxy-server-core (push) Blocked by required conditions
Unit Tests: Proxy DB Operations / proxy-utils (push) Blocked by required conditions
Some checks are pending
CodSpeed Benchmarks / benchmarks (push) Waiting to run
Unit Tests: Enterprise, Google GenAI & Routing / enterprise-routing (push) Waiting to run
Unit Tests: Integrations (Callbacks & Logging) / integrations (push) Waiting to run
Unit Tests: LLM Provider Transformations / All Other Providers (push) Waiting to run
Unit Tests: Proxy DB Operations / endpoints-and-responses (push) Blocked by required conditions
Unit Tests: Proxy API Endpoints / proxy-endpoints (push) Waiting to run
Unit Tests: Proxy API Endpoints / proxy-server (push) Waiting to run
Unit Tests: Proxy Infrastructure / proxy-infra (push) Waiting to run
Unit Tests: Responses, Caching & Types / responses-caching-types (push) Waiting to run
GitHub Actions Security Analysis / zizmor (push) Waiting to run
CI Coverage / assert-ci-coverage (push) Waiting to run
Publish basedpyright base counts / publish (push) Waiting to run
Code Quality Checks / code-quality (push) Waiting to run
UI Unit Tests / ui-unit-tests (push) Waiting to run
Unit Tests: Core Utilities / core-utils (push) Waiting to run
Unit Tests: Documentation Validation / documentation (push) Waiting to run
Unit Tests: LLM Provider Transformations / Vertex AI (push) Waiting to run
Unit Tests: MCP, Secrets, Containers & Misc / misc (push) Waiting to run
Unit Tests: Proxy Auth & Key Management / proxy-auth (push) Waiting to run
Unit Tests: Proxy DB Operations / assert-shard-coverage (push) Waiting to run
Unit Tests: Proxy DB Operations / auth-checks (push) Blocked by required conditions
Unit Tests: Proxy DB Operations / budgets (push) Blocked by required conditions
Unit Tests: Proxy DB Operations / key-generation (push) Blocked by required conditions
Unit Tests: Proxy DB Operations / custom-logging (push) Blocked by required conditions
Unit Tests: Proxy DB Operations / db-and-spend (push) Blocked by required conditions
Unit Tests: Proxy DB Operations / guardrails-hooks (push) Blocked by required conditions
Unit Tests: Proxy DB Operations / jwt-and-keys (push) Blocked by required conditions
Unit Tests: Proxy DB Operations / logging-misc (push) Blocked by required conditions
Unit Tests: Proxy DB Operations / proxy-runtime (push) Blocked by required conditions
Unit Tests: Proxy DB Operations / proxy-server-core (push) Blocked by required conditions
Unit Tests: Proxy DB Operations / proxy-utils (push) Blocked by required conditions
fix(proxy): log spend for OpenAI passthrough embeddings with unmapped models
This commit is contained in:
commit
9cb3cf7bef
2 changed files with 96 additions and 3 deletions
|
|
@ -229,6 +229,25 @@ class OpenAIPassthroughLoggingHandler(BasePassthroughLoggingHandler):
|
|||
verbose_proxy_logger.warning("Error calculating image editing cost: %s", e)
|
||||
return 0.0
|
||||
|
||||
@staticmethod
|
||||
def _calculate_embeddings_cost(
|
||||
litellm_model_response: EmbeddingResponse,
|
||||
model: str,
|
||||
custom_llm_provider: str,
|
||||
) -> float:
|
||||
try:
|
||||
return litellm.completion_cost(
|
||||
completion_response=litellm_model_response,
|
||||
model=model,
|
||||
custom_llm_provider=custom_llm_provider,
|
||||
call_type="aembedding",
|
||||
)
|
||||
except Exception as e: # noqa: BLE001 # completion_cost raises bare Exception for unmapped models; cost failure must never drop the spend log
|
||||
verbose_proxy_logger.warning(
|
||||
"Error calculating embeddings cost for model %s, logging spend with cost 0: %s", model, e
|
||||
)
|
||||
return 0.0
|
||||
|
||||
@staticmethod
|
||||
def _build_responses_api_response_and_cost(
|
||||
model: str,
|
||||
|
|
@ -351,11 +370,10 @@ class OpenAIPassthroughLoggingHandler(BasePassthroughLoggingHandler):
|
|||
model_response_object=EmbeddingResponse(),
|
||||
response_type="embedding",
|
||||
)
|
||||
response_cost = litellm.completion_cost(
|
||||
completion_response=litellm_model_response,
|
||||
response_cost = OpenAIPassthroughLoggingHandler._calculate_embeddings_cost(
|
||||
litellm_model_response=litellm_model_response,
|
||||
model=model,
|
||||
custom_llm_provider=custom_llm_provider,
|
||||
call_type="aembedding",
|
||||
)
|
||||
litellm_model_response._hidden_params["response_cost"] = response_cost
|
||||
elif is_image_generation:
|
||||
|
|
@ -471,6 +489,12 @@ class OpenAIPassthroughLoggingHandler(BasePassthroughLoggingHandler):
|
|||
|
||||
except Exception as e:
|
||||
verbose_proxy_logger.error("Error in OpenAI passthrough cost tracking: %s", e)
|
||||
if not is_chat_completions:
|
||||
unbilled_result: Final[PassThroughEndpointLoggingTypedDict] = {
|
||||
"result": None,
|
||||
"kwargs": kwargs,
|
||||
}
|
||||
return unbilled_result
|
||||
# Fall back to base handler without cost tracking
|
||||
base_handler = OpenAIPassthroughLoggingHandler()
|
||||
return base_handler.passthrough_chat_handler(
|
||||
|
|
|
|||
|
|
@ -1286,6 +1286,75 @@ class TestOpenAIPassthroughIntegration:
|
|||
mock_chat_handler.assert_called_once()
|
||||
assert result == {"result": None, "kwargs": {}}
|
||||
|
||||
def test_openai_passthrough_handler_embeddings_unmapped_model_logs_zero_cost(self):
|
||||
response_body = {
|
||||
"object": "list",
|
||||
"model": "lit5787-unmapped-embeddings-deployment",
|
||||
"data": [{"object": "embedding", "index": 0, "embedding": [0.1, 0.2]}],
|
||||
"usage": {"prompt_tokens": 9, "total_tokens": 9},
|
||||
}
|
||||
mock_logging_obj = self._create_mock_logging_obj()
|
||||
result = OpenAIPassthroughLoggingHandler.openai_passthrough_handler(
|
||||
httpx_response=self._create_mock_httpx_response(response_body),
|
||||
response_body=response_body,
|
||||
logging_obj=mock_logging_obj,
|
||||
url_route="https://my-resource.openai.azure.com/openai/v1/embeddings",
|
||||
result="",
|
||||
start_time=self.start_time,
|
||||
end_time=self.end_time,
|
||||
cache_hit=False,
|
||||
request_body={
|
||||
"model": "lit5787-unmapped-embeddings-deployment",
|
||||
"input": "spend probe",
|
||||
},
|
||||
passthrough_logging_payload=PassthroughStandardLoggingPayload(
|
||||
url="https://my-resource.openai.azure.com/openai/v1/embeddings",
|
||||
request_body={
|
||||
"model": "lit5787-unmapped-embeddings-deployment",
|
||||
"input": "spend probe",
|
||||
},
|
||||
request_method="POST",
|
||||
),
|
||||
litellm_params={},
|
||||
)
|
||||
|
||||
assert result["result"] is not None
|
||||
assert result["result"].usage.prompt_tokens == 9
|
||||
assert result["kwargs"]["response_cost"] == 0.0
|
||||
assert result["kwargs"]["model"] == "lit5787-unmapped-embeddings-deployment"
|
||||
assert result["result"]._hidden_params["response_cost"] == 0.0
|
||||
assert mock_logging_obj.model_call_details["response_cost"] == 0.0
|
||||
|
||||
def test_openai_passthrough_handler_embeddings_error_skips_chat_fallback(self):
|
||||
response_body = {
|
||||
"object": "list",
|
||||
"model": "text-embedding-3-small",
|
||||
"usage": {"prompt_tokens": 9, "total_tokens": 9},
|
||||
}
|
||||
kwargs_in = {
|
||||
"passthrough_logging_payload": PassthroughStandardLoggingPayload(
|
||||
url="https://api.openai.com/v1/embeddings",
|
||||
request_body={"model": "text-embedding-3-small", "input": "spend probe"},
|
||||
request_method="POST",
|
||||
),
|
||||
"litellm_params": {},
|
||||
}
|
||||
result = OpenAIPassthroughLoggingHandler.openai_passthrough_handler(
|
||||
httpx_response=self._create_mock_httpx_response(response_body),
|
||||
response_body=response_body,
|
||||
logging_obj=self._create_mock_logging_obj(),
|
||||
url_route="https://api.openai.com/v1/embeddings",
|
||||
result="",
|
||||
start_time=self.start_time,
|
||||
end_time=self.end_time,
|
||||
cache_hit=False,
|
||||
request_body={"model": "text-embedding-3-small", "input": "spend probe"},
|
||||
**kwargs_in,
|
||||
)
|
||||
|
||||
assert result["result"] is None
|
||||
assert result["kwargs"]["passthrough_logging_payload"] == kwargs_in["passthrough_logging_payload"]
|
||||
|
||||
@patch(
|
||||
"litellm.proxy.pass_through_endpoints.llm_provider_handlers.openai_passthrough_logging_handler.OpenAIPassthroughLoggingHandler.openai_passthrough_handler"
|
||||
)
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue