Hi folks, quick update on my issue! I've followed Lucas M. suggestion and setup otel as central collector with his remap plugin. So far everything seems ok. I'm running on laptop, so it's not yet a production setup but the traces now seems to be properly handled on both backends with all UI/UX features working as expected. Thanks again for all the help and as my project evolves I got back to share more updates! best regards to all! 🔒[private user] RunLLM Lucas M. .
RunLLM Is it possible for a child method to access the root span created by an earlier executed method, so it can add the openinference attributes at the root level? can you provide some working code or provide me with some internet reference that demosntrates? Otherwise how are we supposed to achieve the recommended approach? (legitim question, I'm not criticizing the recommendation).
Hi everyone, forgive me for the looong text. 😅 I’ve been exploring different ways to integrate a test project with Phoenix OSS using OpenTelemetry to identify how my team can use Phoenix effectively in paralell with other open telemetry backend used to monitor the application. So I built a "pet project" used to test different ways to feed both backends simultaneously: Phoenix (for tracing and evals) and Jaeger (for general application and infrastructure monitoring). After some trial and error, and with help from 🔒[private user] and Anthony P., I ended with two integration approaches:
Single Global Context: Using a single global context configured to feed two distinct trace providers (required to handle the separate backend addresses).
Manual Separation: Manually creating separate tracers, contexts with distinct spans, one for each backend and manually picking which span to use in each method.
Ultimately, I couldn't get Phoenix to behave as expected in either case. I’d like to confirm if I’m missing something or if these are current practical limitations in current UI/UX. Starting with strategy #2: While manually managing separate contexts works, it is much more complex and prone to errors. I couldn't send/capture all spans properly when using frameworks like strandsagents or LiteLLM proxy, which plug directly into the global OpenTelemetry SDK. Therefore, I’m ruling this out as a viable solution. The issue with strategy #1 (Single Global Context / Dual Providers): This approach works well only if I initialize telemetry exactly when the code starts agent tasks. Phoenix seems to expect OpenInference attributes to be present on the root span (please see the attached images). However, in a "real-world" application, the root span is created with application data (e.g., an HTTP handler or Lambda entry point) before any prompt, LLM, or agent data is captured. The spans containing the OpenInference info will always be child spans, never the root. To illustrate this, I ran a "dialogue" via a pytest test (where the agent invocation produces the root span) and the same dialogue via the "application" (a Lambda function, where the agent is a child span from the application span): pytest scenarios (Agent = Root Span):
phoenix-pytest-traces.png: "status", "input", and "output" columns contain proper values as expected.
phoenix-pytest-sessions.png: Sessions are tracked properly with the first and last input.
phoenix-pytest-session-details.png: User can see the AI and Human input/outputs and easily annotate from this screen.
phoenix-pytest-trace-spans.png: This shows the OpenInference attributes are present in the root span.
Application scenarios (Agent = Child Span):
phoenix-app-traces.png: "status", "input", and "output" are blank/undefined.
phoenix-app-sessions.png: Sessions are tracked, but first/last inputs are blank.
phoenix-app-session-details.png: Nothing is shown; this screen becomes useless for annotation.
phoenix-app-trace-spans.png: This shows the root span is an "extra span" (created by the app code) without OpenInference attributes. Inspecting the second span shows it contains the data (identical to the root span in the pytest scenario), but the UI doesn't seem to pick it up.
My Questions:
How are you handling telemetry in production projects where the Agent is not the root span?
How do you monitor the application (infrastructure) while simultaneously using Phoenix for LLM tracing/evals without these UI issues?
Given the need for distinct addresses, is my setup of feeding two trace providers from a global context the correct way to handle this?
Any insights would be appreciated, and big thanks in advance to all (and in particular to 🔒[private user] and Anthony P. for their help)!
🔒[private user] I think I'm almost there but given the amount of manual setup required, I'm under the impression that I may be going down a bad path. with this setup phoneix is reciving and showing traces from litellm proxy, completions but still not receiviing the strands agent traces and metrics. Those keep going to the jaeger server even with the manual setup. In your experience do you think it would be better to just use a global trace feeding both service (phoenix and app otel service)? If so, what are attributes that would need to setup to feed phoenix properly? Once again thanks for yout time and help!
Hi 🔒[private user] thanks for the help. I'm not totally familiar with the otel protocol and with your explanations things are making more sense. 😃 There is one point thou that I didn't fully understand: In the lambda handler I'm calling span = trace.get_current_span() to get my "application span" (the one I use to add events, attributes and child spans regarding the application logic). Should I call span.set_attribute(SpanAttributes.OPENINFERENCE_SPAN_KIND, "agent") on this span object or should I obtain a different span object from the phoneix trace provider from otel.py?
Hi guys. I'm working on a chat agent using StrandsAgents deployed as AWS Lambdas that uses a self-hosted LiteLLM Proxy to interact with the Models. This environment already uses opentelemetry with a Jaeger service to monitor application issues, overall metrics, latency, etc. I'd like to use Phoenix OSS to collect the model statistics and prompts interactions so I can analyze and improve the conversation flows in Phoneix. The setup I made is pretty standard, using Phoneix environment variables and manually set two trace providers, one for the app e other for the StrandsAgents, but in phoneix I'm getting all spans making the trace harder to analyze. Is there a way to set the telemetry so te phoneix tracer provider to create it's span indenependently from the global tracer provider which is feeding the app provider? Also it seems that not all information are being properly ingested into Phoenix. Columns, "Kind", "Status", "Tokens" does not look like to being populated. below is my current setup with some code snippets:
-- python (otel.py)
import os
from typing import Dict, Optional
from opentelemetry import trace
from opentelemetry.sdk.trace import TracerProvider
from opentelemetry.sdk.trace.export import BatchSpanProcessor, ConsoleSpanExporter
from opentelemetry.exporter.otlp.proto.grpc.trace_exporter import OTLPSpanExporter
from strands.telemetry import StrandsTelemetry
from phoenix.otel import register
phoenix_tracer_provider = register()
strands_telemetry = StrandsTelemetry(tracer_provider=phoenix_tracer_provider)
strands_telemetry.setup_meter(enable_otlp_exporter=True)
strands_telemetry.setup_otlp_exporter().setup_console_exporter()
app_provider = TracerProvider()
processor = BatchSpanProcessor(ConsoleSpanExporter())
app_provider.add_span_processor(processor)
# Sets the global default tracer provider
trace.set_tracer_provider(app_provider)
tracer = trace.get_tracer(__name__)Than in my lambda handlers I just import the tracer and use it as usual.
--- python (agent.py)
from .otel import tracer
@tracer.start_as_current_span("lambda_handler")
def handler(event: Dict[str, Any], _context) -> Dict[str, Any]:
span = trace.get_current_span()
span.add_event("some application info")
...
span.set_attribute("session.id", user_input.session_id)
span.set_attribute("user.message", message_str)
...
session_params = {
"session_id": user_input.session_id,
"bucket": settings.agents.session_bucket,
"prefix": f"{settings.agents.session_prefix}/agente-triagem",
}
agent = Agent(
system_prompt=system_prompt,
model=model,
session_manager=session_manager,
conversation_manager=conversation_manager,
structured_output_model=TriagemOutput,
tools=[],
trace_attributes=trace_attributes,
)
result = agent(message_str)Hi all, not really an Arize AI question, but I believe this community would have valuable insights in this matter. I was thinking about caching in LLM applications and its implications for user data privacy/security. Suppose I have a chat server application that serves multiple users simultaneously with prompt caching at the proxy level (e.g., using LiteLLM) or even without proxy but using a single API key for the entire application (which would use the provider API internal caching), is there a risk that user-specific data could be inadvertently cached and then served to other users? Example: user A's query invoke a tool calling to retreive his account balance and then the LLM generated response is cached. User B makes a similar query that hits the cache? Could the response containing user A's account balance be served to user B? If yes, is there a mechanism to prevent this from happening? Has anyone faced this kind of issue in production systems? Any insights on how developers are controling the LLM caching across different user sessions or even between different phases (ie application cache versus user cache)?
hi all! I'm Eric from Brazil. I'm taking my first steps using phoenix. I have a long time developing all sort of systems and now I'm entering the world of building "AI powered applications" (dont ask em to define what this means...😆 ) I heard about phoenix couple of months ago during an eval course by Hamel & Shreya but only now I had the opportunity to start building something aimed for production. As expected from a newbie, I have ton of questions and I'm count on the experienced people here to help me out. Happy xmas to all!
