mirror of
https://github.com/BerriAI/litellm.git
synced 2026-09-05 08:07:05 +00:00
Merge pull request #20440 from ryan-crabbe/perf/skip-duplicate-logging-payload
perf: skip duplicate get_standard_logging_object_payload for non-streaming req's
This commit is contained in:
commit
be016b683b
2 changed files with 130 additions and 2 deletions
|
|
@ -1639,6 +1639,13 @@ class Logging(LiteLLMLoggingBaseClass):
|
|||
logging_result, start_time, end_time
|
||||
)
|
||||
|
||||
if (
|
||||
standard_logging_payload := self.model_call_details.get(
|
||||
"standard_logging_object"
|
||||
)
|
||||
) is not None:
|
||||
emit_standard_logging_payload(standard_logging_payload)
|
||||
|
||||
def _build_standard_logging_payload(
|
||||
self, init_response_obj: Any, start_time: Any, end_time: Any
|
||||
) -> Any:
|
||||
|
|
@ -1752,6 +1759,12 @@ class Logging(LiteLLMLoggingBaseClass):
|
|||
] = self._build_standard_logging_payload(
|
||||
result, start_time, end_time
|
||||
)
|
||||
if (
|
||||
standard_logging_payload := self.model_call_details.get(
|
||||
"standard_logging_object"
|
||||
)
|
||||
) is not None:
|
||||
emit_standard_logging_payload(standard_logging_payload)
|
||||
elif standard_logging_object is not None:
|
||||
self.model_call_details[
|
||||
"standard_logging_object"
|
||||
|
|
@ -3211,6 +3224,8 @@ class Logging(LiteLLMLoggingBaseClass):
|
|||
is_async: bool,
|
||||
streaming_chunks: List[Any],
|
||||
) -> Optional[Union[ModelResponse, TextCompletionResponse, ResponsesAPIResponse]]:
|
||||
if self.stream is not True:
|
||||
return None
|
||||
if isinstance(result, ModelResponse):
|
||||
return result
|
||||
elif isinstance(result, TextCompletionResponse):
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ import time
|
|||
from litellm.constants import SENTRY_DENYLIST, SENTRY_PII_DENYLIST
|
||||
from litellm.litellm_core_utils.litellm_logging import Logging as LitellmLogging
|
||||
from litellm.litellm_core_utils.litellm_logging import set_callbacks
|
||||
from litellm.types.utils import ModelResponse
|
||||
from litellm.types.utils import ModelResponse, TextCompletionResponse
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
|
|
@ -264,7 +264,7 @@ async def test_logging_result_for_bridge_calls(logging_obj):
|
|||
mock_response="Hello, world!",
|
||||
)
|
||||
await asyncio.sleep(1)
|
||||
assert mock_should_run_logging.call_count == 2 # called twice per call
|
||||
assert mock_should_run_logging.call_count == 1
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
|
|
@ -1357,3 +1357,116 @@ def test_get_error_information_error_code_priority():
|
|||
assert result["error_class"] == "NoCodeException"
|
||||
|
||||
|
||||
# ──────────────────────────────────────────────────────────────────────
|
||||
# Tests for _get_assembled_streaming_response non-streaming early return
|
||||
# ──────────────────────────────────────────────────────────────────────
|
||||
|
||||
|
||||
def _make_logging_obj(stream: bool) -> LitellmLogging:
|
||||
return LitellmLogging(
|
||||
model="openai/codex-mini-latest",
|
||||
messages=[{"role": "user", "content": "Hey"}],
|
||||
stream=stream,
|
||||
call_type="completion",
|
||||
start_time=time.time(),
|
||||
litellm_call_id="test-123",
|
||||
function_id="test-fn",
|
||||
)
|
||||
|
||||
|
||||
def test_get_assembled_streaming_response_returns_none_for_non_streaming():
|
||||
"""Non-streaming requests should return None so the streaming block is skipped."""
|
||||
import datetime
|
||||
|
||||
logging_obj = _make_logging_obj(stream=False)
|
||||
result = ModelResponse(id="resp-1", choices=[], model="test")
|
||||
assembled = logging_obj._get_assembled_streaming_response(
|
||||
result=result,
|
||||
start_time=datetime.datetime.now(),
|
||||
end_time=datetime.datetime.now(),
|
||||
is_async=True,
|
||||
streaming_chunks=[],
|
||||
)
|
||||
assert assembled is None
|
||||
|
||||
|
||||
def test_get_assembled_streaming_response_returns_result_for_streaming():
|
||||
"""Streaming requests should return the ModelResponse for further processing."""
|
||||
import datetime
|
||||
|
||||
logging_obj = _make_logging_obj(stream=True)
|
||||
result = ModelResponse(id="resp-1", choices=[], model="test")
|
||||
assembled = logging_obj._get_assembled_streaming_response(
|
||||
result=result,
|
||||
start_time=datetime.datetime.now(),
|
||||
end_time=datetime.datetime.now(),
|
||||
is_async=True,
|
||||
streaming_chunks=[],
|
||||
)
|
||||
assert assembled is result
|
||||
|
||||
|
||||
def test_get_assembled_streaming_response_returns_none_for_non_streaming_text_completion():
|
||||
"""Non-streaming TextCompletionResponse should also return None."""
|
||||
import datetime
|
||||
|
||||
logging_obj = _make_logging_obj(stream=False)
|
||||
result = TextCompletionResponse(id="resp-1", choices=[], model="test")
|
||||
assembled = logging_obj._get_assembled_streaming_response(
|
||||
result=result,
|
||||
start_time=datetime.datetime.now(),
|
||||
end_time=datetime.datetime.now(),
|
||||
is_async=True,
|
||||
streaming_chunks=[],
|
||||
)
|
||||
assert assembled is None
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_non_streaming_computes_standard_logging_object_once():
|
||||
"""
|
||||
Non-streaming acompletion should call get_standard_logging_object_payload
|
||||
exactly once, not twice.
|
||||
"""
|
||||
import asyncio
|
||||
|
||||
import litellm
|
||||
|
||||
with patch.object(
|
||||
litellm.litellm_core_utils.litellm_logging,
|
||||
"get_standard_logging_object_payload",
|
||||
) as mock_payload:
|
||||
await litellm.acompletion(
|
||||
max_tokens=100,
|
||||
messages=[{"role": "user", "content": "Hey"}],
|
||||
model="openai/codex-mini-latest",
|
||||
mock_response="Hello, world!",
|
||||
)
|
||||
await asyncio.sleep(1)
|
||||
assert mock_payload.call_count == 1
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_emit_standard_logging_payload_called_for_non_streaming():
|
||||
"""
|
||||
emit_standard_logging_payload should still be called for non-streaming
|
||||
requests (moved from the streaming block to _process_hidden_params_and_response_cost).
|
||||
"""
|
||||
import asyncio
|
||||
|
||||
import litellm
|
||||
|
||||
with patch.object(
|
||||
litellm.litellm_core_utils.litellm_logging,
|
||||
"emit_standard_logging_payload",
|
||||
) as mock_emit:
|
||||
await litellm.acompletion(
|
||||
max_tokens=100,
|
||||
messages=[{"role": "user", "content": "Hey"}],
|
||||
model="openai/codex-mini-latest",
|
||||
mock_response="Hello, world!",
|
||||
)
|
||||
await asyncio.sleep(1)
|
||||
assert mock_emit.call_count >= 1
|
||||
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue