Fix LLM tracing for LLMContext
This commit is contained in:
@@ -1316,6 +1316,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
|
|
||||||
|
- Fixed an issue with OpenTelemetry where tracing wasn't correctly displaying
|
||||||
|
LLM completions and tools when using the universal LLMContext.
|
||||||
|
|
||||||
- Fixed an RTVI issue that was causing frames to be pushed before pipeline was
|
- Fixed an RTVI issue that was causing frames to be pushed before pipeline was
|
||||||
properly initialized.
|
properly initialized.
|
||||||
|
|
||||||
|
|||||||
@@ -23,6 +23,8 @@ if TYPE_CHECKING:
|
|||||||
from opentelemetry import context as context_api
|
from opentelemetry import context as context_api
|
||||||
from opentelemetry import trace
|
from opentelemetry import trace
|
||||||
|
|
||||||
|
from pipecat.processors.aggregators.llm_context import LLMContext
|
||||||
|
from pipecat.processors.aggregators.openai_llm_context import OpenAILLMContext
|
||||||
from pipecat.utils.tracing.service_attributes import (
|
from pipecat.utils.tracing.service_attributes import (
|
||||||
add_gemini_live_span_attributes,
|
add_gemini_live_span_attributes,
|
||||||
add_llm_span_attributes,
|
add_llm_span_attributes,
|
||||||
@@ -382,43 +384,57 @@ def traced_llm(func: Optional[Callable] = None, *, name: Optional[str] = None) -
|
|||||||
# Replace push_frame to capture output
|
# Replace push_frame to capture output
|
||||||
self.push_frame = traced_push_frame
|
self.push_frame = traced_push_frame
|
||||||
|
|
||||||
# Detect if we're using Google's service
|
# Get messages for logging
|
||||||
is_google_service = "google" in service_class_name.lower()
|
# For OpenAILLMContext: use context's own get_messages_for_logging() method
|
||||||
|
# For LLMContext: use adapter's get_messages_for_logging() which returns
|
||||||
# Try to get messages based on service type
|
# messages in provider's native format with sensitive data sanitized
|
||||||
messages = None
|
messages = None
|
||||||
serialized_messages = None
|
serialized_messages = None
|
||||||
|
|
||||||
# TODO: Revisit once we unify the messages across services
|
if isinstance(context, OpenAILLMContext):
|
||||||
if is_google_service:
|
# OpenAILLMContext and subclasses have their own method
|
||||||
# Handle Google service specifically
|
messages = context.get_messages_for_logging()
|
||||||
if hasattr(context, "get_messages_for_logging"):
|
elif isinstance(context, LLMContext):
|
||||||
messages = context.get_messages_for_logging()
|
# Universal LLMContext - use adapter for provider-native format
|
||||||
else:
|
if hasattr(self, "get_llm_adapter"):
|
||||||
# Handle other services like OpenAI
|
adapter = self.get_llm_adapter()
|
||||||
if hasattr(context, "get_messages"):
|
messages = adapter.get_messages_for_logging(context)
|
||||||
messages = context.get_messages()
|
elif hasattr(context, "get_messages"):
|
||||||
elif hasattr(context, "messages"):
|
# Fallback for unknown context types
|
||||||
messages = context.messages
|
messages = context.get_messages()
|
||||||
|
elif hasattr(context, "messages"):
|
||||||
|
messages = context.messages
|
||||||
|
|
||||||
# Serialize messages if available
|
# Serialize messages if available
|
||||||
if messages:
|
if messages:
|
||||||
try:
|
serialized_messages = json.dumps(messages)
|
||||||
serialized_messages = json.dumps(messages)
|
|
||||||
except Exception as e:
|
|
||||||
serialized_messages = f"Error serializing messages: {str(e)}"
|
|
||||||
|
|
||||||
# Get tools, system message, etc. based on the service type
|
# Get tools
|
||||||
tools = getattr(context, "tools", None)
|
# For OpenAILLMContext: tools may need adapter conversion if set
|
||||||
|
# For LLMContext: use adapter's from_standard_tools() to convert ToolsSchema
|
||||||
|
tools = None
|
||||||
serialized_tools = None
|
serialized_tools = None
|
||||||
tool_count = 0
|
tool_count = 0
|
||||||
|
|
||||||
if tools:
|
if isinstance(context, OpenAILLMContext):
|
||||||
try:
|
# OpenAILLMContext: tools property handles adapter conversion internally
|
||||||
serialized_tools = json.dumps(tools)
|
tools = context.tools
|
||||||
tool_count = len(tools) if isinstance(tools, list) else 1
|
elif isinstance(context, LLMContext):
|
||||||
except Exception as e:
|
# Universal LLMContext - use adapter to convert ToolsSchema
|
||||||
serialized_tools = f"Error serializing tools: {str(e)}"
|
if hasattr(self, "get_llm_adapter") and hasattr(context, "tools"):
|
||||||
|
adapter = self.get_llm_adapter()
|
||||||
|
tools = adapter.from_standard_tools(context.tools)
|
||||||
|
elif hasattr(context, "tools"):
|
||||||
|
# Fallback for unknown context types
|
||||||
|
tools = context.tools
|
||||||
|
|
||||||
|
# Serialize and count tools if available
|
||||||
|
# Check if tools is not None and not NOT_GIVEN (using attribute check as fallback)
|
||||||
|
if tools is not None and not (
|
||||||
|
hasattr(tools, "__name__") and tools.__name__ == "NOT_GIVEN"
|
||||||
|
):
|
||||||
|
serialized_tools = json.dumps(tools)
|
||||||
|
tool_count = len(tools) if isinstance(tools, list) else 1
|
||||||
|
|
||||||
# Handle system message for different services
|
# Handle system message for different services
|
||||||
system_message = None
|
system_message = None
|
||||||
|
|||||||
Reference in New Issue
Block a user