mirror of
https://github.com/BerriAI/litellm.git
synced 2026-10-28 06:23:07 +00:00
fix(logging): report the pay-as-you-go entry billing used on Azure PTU spillover (#47567)
get_standard_logging_object_payload decided custom_pricing from
litellm_params alone, so on an Azure PTU spillover response
model_map_information kept the deployment's zeroed PTU entry while
response_cost already used the standard model rate. Reuse the billing
side LitellmLogging._custom_pricing_for so both read the same decision
Backport of #47567 to stable/1.104.x
Cherry-picked from 4222523261 (main)
Co-authored-by: devin-ai-integration[bot] <158243242+devin-ai-integration[bot]@users.noreply.github.com>
This commit is contained in:
parent
e71d121736
commit
b462563d14
2 changed files with 39 additions and 4 deletions
|
|
@ -1882,7 +1882,7 @@ class Logging(LiteLLMLoggingBaseClass):
|
|||
router_model_id = self.get_router_model_id()
|
||||
|
||||
## RESPONSE COST ##
|
||||
custom_pricing: Final = self._custom_pricing_for(priced_result)
|
||||
custom_pricing: Final = self.custom_pricing_for(priced_result)
|
||||
|
||||
prompt = self._prompt_for_cost_calculation()
|
||||
|
||||
|
|
@ -2021,7 +2021,7 @@ class Logging(LiteLLMLoggingBaseClass):
|
|||
model=model,
|
||||
completion_response=result,
|
||||
custom_llm_provider=custom_llm_provider,
|
||||
custom_pricing=self._custom_pricing_for(result),
|
||||
custom_pricing=self.custom_pricing_for(result),
|
||||
base_model=_get_base_model_from_metadata(model_call_details=self.model_call_details),
|
||||
router_model_id=router_model_id or self.get_router_model_id(),
|
||||
region_name=_resolve_mantle_region_for_cost(
|
||||
|
|
@ -2046,7 +2046,7 @@ class Logging(LiteLLMLoggingBaseClass):
|
|||
usage=usage,
|
||||
)
|
||||
|
||||
def _custom_pricing_for(self, result: object) -> bool:
|
||||
def custom_pricing_for(self, result: object) -> bool:
|
||||
litellm_params: Final = getattr(self, "litellm_params", None)
|
||||
result_hidden_params: Final = getattr(result, "_hidden_params", None) or MappingProxyType({})
|
||||
additional_headers: Final = (
|
||||
|
|
@ -6525,7 +6525,7 @@ def get_standard_logging_object_payload(
|
|||
# Fall back to the actual deployment model set by the router in metadata.
|
||||
if base_model is None:
|
||||
base_model = metadata.get("deployment")
|
||||
custom_pricing: Final = use_custom_pricing_for_model(litellm_params=litellm_params)
|
||||
custom_pricing: Final = logging_obj.custom_pricing_for(init_response_obj)
|
||||
raw_response_cost: Final = kwargs.get("response_cost")
|
||||
llm_response_cost: Final[float] = raw_response_cost or 0.0
|
||||
guardrail_cost: Final = guardrail_information_cost(metadata.get("standard_logging_guardrail_information"))
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@ from litellm.litellm_core_utils.litellm_logging import Logging as LitellmLogging
|
|||
from litellm.litellm_core_utils.litellm_logging import (
|
||||
_extract_response_obj_and_hidden_params,
|
||||
_get_status_fields,
|
||||
get_standard_logging_object_payload,
|
||||
set_callbacks,
|
||||
)
|
||||
from litellm.llms.base_llm.ocr.transformation import OCRUsageInfo
|
||||
|
|
@ -8510,6 +8511,40 @@ class TestAzurePTUSpilloverCost:
|
|||
finally:
|
||||
self._unregister_models()
|
||||
|
||||
def test_spillover_payload_reports_the_pay_as_you_go_entry_billing_used(self, monkeypatch) -> None:
|
||||
self._register_models()
|
||||
try:
|
||||
obj = self._logging_obj(dict(self.PTU_MODEL_INFO), flag="True", litellm_rate=0.0, monkeypatch=monkeypatch)
|
||||
response = self._response()
|
||||
response._hidden_params["additional_headers"] = {"llm_provider-x-ms-is-spilled-over": "true"}
|
||||
response_cost: Final = obj._response_cost_calculator(result=response)
|
||||
|
||||
payload: Final = get_standard_logging_object_payload(
|
||||
kwargs={
|
||||
"model": self.SERVED_MODEL,
|
||||
"custom_llm_provider": "azure",
|
||||
"litellm_params": obj.litellm_params,
|
||||
"response_cost": response_cost,
|
||||
},
|
||||
init_response_obj=response,
|
||||
start_time=datetime.datetime.now(),
|
||||
end_time=datetime.datetime.now(),
|
||||
logging_obj=obj,
|
||||
status="success",
|
||||
)
|
||||
|
||||
assert response_cost == pytest.approx(self.EXPECTED_SPILL_COST)
|
||||
assert payload is not None
|
||||
model_map_value: Final = payload["model_map_information"]["model_map_value"]
|
||||
assert model_map_value is not None
|
||||
assert model_map_value["input_cost_per_token"] == litellm.model_cost[self.SERVED_MODEL]["input_cost_per_token"]
|
||||
assert model_map_value["output_cost_per_token"] == litellm.model_cost[self.SERVED_MODEL]["output_cost_per_token"]
|
||||
assert response_cost == pytest.approx(
|
||||
100 * model_map_value["input_cost_per_token"] + 50 * model_map_value["output_cost_per_token"]
|
||||
)
|
||||
finally:
|
||||
self._unregister_models()
|
||||
|
||||
def test_spillover_header_does_not_touch_non_ptu_custom_pricing(self, monkeypatch) -> None:
|
||||
self._register_models()
|
||||
custom_model_id: Final = "non-ptu-custom-router-model-id"
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue