Files
lijiaoqiao/llm-gateway-competitors/litellm-wheel-src/litellm/integrations/langfuse/langfuse_otel_attributes.py
2026-03-26 16:04:46 +08:00

109 lines
3.1 KiB
Python

"""
If the LLM Obs has any specific attributes to log request or response, we can add them here.
Relevant Issue: https://github.com/BerriAI/litellm/issues/13764
"""
import json
from typing import TYPE_CHECKING, Any, Dict, Optional, Union
from pydantic import BaseModel
from typing_extensions import override
from litellm.integrations.opentelemetry_utils.base_otel_llm_obs_attributes import (
BaseLLMObsOTELAttributes,
safe_set_attribute,
)
from litellm.types.llms.openai import HttpxBinaryResponseContent, ResponsesAPIResponse
from litellm.types.utils import (
EmbeddingResponse,
ImageResponse,
ModelResponse,
RerankResponse,
TextCompletionResponse,
TranscriptionResponse,
)
if TYPE_CHECKING:
from opentelemetry.trace import Span
def get_output_content_by_type(
response_obj: Union[
None,
dict,
EmbeddingResponse,
ModelResponse,
TextCompletionResponse,
ImageResponse,
TranscriptionResponse,
RerankResponse,
HttpxBinaryResponseContent,
ResponsesAPIResponse,
list,
],
kwargs: Optional[Dict[str, Any]] = None,
) -> str:
"""
Extract output content from response objects based on their type.
This utility function handles the type-specific logic for converting
various response objects into appropriate output formats for Langfuse logging.
Args:
response_obj: The response object returned by the function
kwargs: Optional keyword arguments containing call_type and other metadata
Returns:
The formatted output content suitable for Langfuse logging, or None
"""
if response_obj is None:
return ""
kwargs = kwargs or {}
call_type = kwargs.get("call_type", None)
# Embedding responses - no output content
if call_type == "embedding" or isinstance(response_obj, EmbeddingResponse):
return "embedding-output"
# Binary/Speech responses
if isinstance(response_obj, HttpxBinaryResponseContent):
return "speech-output"
if isinstance(response_obj, BaseModel):
return response_obj.model_dump_json()
if response_obj and (
isinstance(response_obj, dict) or isinstance(response_obj, list)
):
return json.dumps(response_obj)
else:
return ""
class LangfuseLLMObsOTELAttributes(BaseLLMObsOTELAttributes):
@staticmethod
@override
def set_messages(span: "Span", kwargs: Dict[str, Any]):
prompt = {"messages": kwargs.get("messages")}
optional_params = kwargs.get("optional_params", {})
functions = optional_params.get("functions")
tools = optional_params.get("tools")
if functions is not None:
prompt["functions"] = functions
if tools is not None:
prompt["tools"] = tools
input = prompt
safe_set_attribute(span, "langfuse.observation.input", json.dumps(input))
@staticmethod
@override
def set_response_output_messages(span: "Span", response_obj):
safe_set_attribute(
span,
"langfuse.observation.output",
get_output_content_by_type(response_obj),
)