mirror of
https://github.com/BerriAI/litellm.git
synced 2026-10-25 05:54:53 +00:00
fix(logging): report the cost-map entry billing used in model_map_information (#47182)
* fix(logging): report the cost-map entry billing used in model_map_information Billing resolved the deployment's own cost-map entry and logging ran a second, name-only lookup, so callbacks and spend logs showed the catalog rates for a custom-priced deployment. completion_cost now stores the entry it billed from on the logging object and the standard logging payload reads it, falling back to the old lookup only when billing never ran. * fix(logging): pass the deployment id into the logging cost-map lookup Drop the logging-object plumbing and keep the lookup where it was: get_standard_logging_object_payload now hands the deployment id to get_model_cost_information as router_model_id, the same id billing uses, so the deployment's own cost-map entry is reported instead of the catalog entry. * test(logging): mirror the proxy metadata in the deployment-price regression test * fix(logging): keep the catalog model_map_key, report only the deployment's own rates --------- Co-authored-by: devin-ai-integration[bot] <158243242+devin-ai-integration[bot]@users.noreply.github.com>
This commit is contained in:
parent
c0d88b46c9
commit
1212260ab1
2 changed files with 97 additions and 1 deletions
|
|
@ -6471,6 +6471,7 @@ class StandardLoggingPayloadSetup:
|
|||
custom_llm_provider: str | None,
|
||||
init_response_obj: object,
|
||||
api_base: str | None = None,
|
||||
router_model_id: str | None = None,
|
||||
) -> StandardLoggingModelInformation:
|
||||
model_cost_name: Final = select_model_name_for_cost_calc(
|
||||
model=base_model if custom_pricing else None,
|
||||
|
|
@ -6478,12 +6479,23 @@ class StandardLoggingPayloadSetup:
|
|||
base_model=base_model,
|
||||
custom_pricing=custom_pricing,
|
||||
)
|
||||
pricing_model_name: Final = (
|
||||
select_model_name_for_cost_calc(
|
||||
model=base_model if custom_pricing else None,
|
||||
completion_response=init_response_obj,
|
||||
base_model=base_model,
|
||||
custom_pricing=custom_pricing,
|
||||
router_model_id=router_model_id,
|
||||
)
|
||||
if router_model_id is not None
|
||||
else model_cost_name
|
||||
)
|
||||
if model_cost_name is None:
|
||||
model_cost_information = StandardLoggingModelInformation(model_map_key="", model_map_value=None)
|
||||
else:
|
||||
try:
|
||||
_model_cost_information: Final = litellm.get_model_info(
|
||||
model=model_cost_name,
|
||||
model=pricing_model_name or model_cost_name,
|
||||
custom_llm_provider=custom_llm_provider,
|
||||
api_base=api_base,
|
||||
)
|
||||
|
|
@ -7193,6 +7205,7 @@ def get_standard_logging_object_payload(
|
|||
custom_llm_provider=kwargs.get("custom_llm_provider"),
|
||||
init_response_obj=init_response_obj,
|
||||
api_base=litellm_params.get("api_base"),
|
||||
router_model_id=logging_obj.get_router_model_id(),
|
||||
)
|
||||
|
||||
error_information, error_str = StandardLoggingPayloadSetup.get_error_information_for_logging_payload(
|
||||
|
|
|
|||
|
|
@ -10718,6 +10718,89 @@ def test_uncached_price_leaves_no_pricing_state_on_the_call():
|
|||
litellm.model_cost.pop(deployment_id, None)
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
("input_cost_per_token", "output_cost_per_token"),
|
||||
[(1e-06, 2e-06), (0.0, 0.0)],
|
||||
ids=["custom_price", "explicit_zero_price"],
|
||||
)
|
||||
def test_standard_logging_payload_reports_the_deployment_entry_the_request_was_billed_from(
|
||||
input_cost_per_token: float, output_cost_per_token: float
|
||||
):
|
||||
"""A deployment with its own price keeps the catalog model as model_map_key but is logged at its own rates."""
|
||||
deployment_id: Final = "lit9660-priced-deployment"
|
||||
deployment_model_info: Final = {
|
||||
"id": deployment_id,
|
||||
"input_cost_per_token": input_cost_per_token,
|
||||
"output_cost_per_token": output_cost_per_token,
|
||||
}
|
||||
litellm.register_model(
|
||||
model_cost={
|
||||
deployment_id: {
|
||||
"litellm_provider": "openai",
|
||||
"mode": "chat",
|
||||
"input_cost_per_token": input_cost_per_token,
|
||||
"output_cost_per_token": output_cost_per_token,
|
||||
}
|
||||
},
|
||||
persist_across_reloads=False,
|
||||
)
|
||||
try:
|
||||
logging_obj: Final = LitellmLogging(
|
||||
model="gpt-5.4-nano",
|
||||
messages=[{"role": "user", "content": "Hi"}],
|
||||
stream=False,
|
||||
call_type="completion",
|
||||
start_time=time.time(),
|
||||
litellm_call_id="lit9660",
|
||||
function_id="fn",
|
||||
)
|
||||
litellm_params: Final = {
|
||||
"metadata": {
|
||||
"model_group": "lit9660-group",
|
||||
"deployment": "openai/gpt-5.4-nano",
|
||||
"model_info": deployment_model_info,
|
||||
}
|
||||
}
|
||||
logging_obj.update_environment_variables(
|
||||
model="gpt-5.4-nano", user="", optional_params={}, litellm_params=litellm_params, custom_llm_provider="openai"
|
||||
)
|
||||
response: Final = ModelResponse(
|
||||
model="gpt-5.4-nano",
|
||||
choices=[litellm.Choices(message=litellm.Message(role="assistant", content="hi"))],
|
||||
usage=litellm.Usage(prompt_tokens=10, completion_tokens=6, total_tokens=16),
|
||||
)
|
||||
|
||||
response_cost: Final = logging_obj.response_cost_calculator(result=response)
|
||||
payload: Final = get_standard_logging_object_payload(
|
||||
kwargs={
|
||||
"model": "gpt-5.4-nano",
|
||||
"custom_llm_provider": "openai",
|
||||
"litellm_params": litellm_params,
|
||||
"response_cost": response_cost,
|
||||
},
|
||||
init_response_obj=response,
|
||||
start_time=datetime.datetime.now(),
|
||||
end_time=datetime.datetime.now(),
|
||||
logging_obj=logging_obj,
|
||||
status="success",
|
||||
)
|
||||
|
||||
assert response_cost == 10 * input_cost_per_token + 6 * output_cost_per_token
|
||||
assert payload is not None
|
||||
assert payload["model_map_information"] == {
|
||||
"model_map_key": "openai/gpt-5.4-nano",
|
||||
"model_map_value": litellm.get_model_info(model=f"openai/{deployment_id}", custom_llm_provider="openai"),
|
||||
}
|
||||
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"], model_map_value["output_cost_per_token"]) == (
|
||||
input_cost_per_token,
|
||||
output_cost_per_token,
|
||||
)
|
||||
finally:
|
||||
litellm.model_cost.pop(deployment_id, None)
|
||||
|
||||
|
||||
def _assert_zeroed_copy(hit_breakdown: CostBreakdown | None, fresh_breakdown: CostBreakdown) -> None:
|
||||
basis_and_rates: Final = ("service_tier", "data_residency", "vertex_location", "discount_percent", "margin_percent")
|
||||
assert hit_breakdown is not None and hit_breakdown.keys() == fresh_breakdown.keys()
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue