Most teams instrument their LLM app twice: once for the observability tool they started with, and again when they outgrow it. You can skip the second time. Emit the OpenTelemetry GenAI semantic conventions and your traces belong to the standard, not to a vendor — the same spans flow to Langfuse, Arize Phoenix, and Honeycomb through one Collector, and switching backends becomes a config edit.

Here's the whole setup in three steps.

1. Get standard GenAI spans without writing span code#

The GenAI conventions define a shared vocabulary — gen_ai.system, gen_ai.request.model, gen_ai.usage.input_tokens, gen_ai.usage.output_tokens, and conventions for tool calls and agent steps. The fastest way to produce them is an auto-instrumentor that wraps your model client:

pip install opentelemetry-distro opentelemetry-exporter-otlp \
    opentelemetry-instrumentation-openai-v2
opentelemetry-bootstrap -a install

Point it at an OTLP endpoint with environment variables — no code change to your app:

export OTEL_SERVICE_NAME="my-agent"
export OTEL_EXPORTER_OTLP_ENDPOINT="http://localhost:4317"
export OTEL_EXPORTER_OTLP_PROTOCOL="grpc"
# capture prompt/response content (off by default for privacy)
export OTEL_INSTRUMENTATION_GENAI_CAPTURE_MESSAGE_CONTENT="true"

opentelemetry-instrument python agent.py

Every model call now emits a standard chat/gen_ai span with the model, token counts, and latency filled in.

2. Add manual spans for what the instrumentor can't see#

Auto-instrumentation covers the model client. Your own tool functions and retrieval steps are invisible to it, so wrap them yourself — using the same standard attributes so they render as one coherent trace:

from opentelemetry import trace

tracer = trace.get_tracer("my-agent")

def call_tool(name: str, args: dict):
    with tracer.start_as_current_span(f"execute_tool {name}") as span:
        span.set_attribute("gen_ai.operation.name", "execute_tool")
        span.set_attribute("gen_ai.tool.name", name)
        result = TOOLS[name](**args)
        span.set_attribute("gen_ai.tool.call.result_size", len(str(result)))
        return result

Now a single trace shows the full loop — reason, call tool, observe, respond — with token cost and tool latency side by side. That's the view that tells you where an agent run got slow or wrong, which vendor needle-recall numbers never will.

Instrument to the standard, not to a UI. The UI is the part you'll want to change.

3. Fan out to every backend with one Collector#

Here's the move that makes it portable. Instead of exporting straight to a vendor, export OTLP to an OpenTelemetry Collector, and let the Collector's pipeline copy the same spans to as many backends as you want:

# otel-collector.yaml
receivers:
  otlp:
    protocols:
      grpc: { endpoint: 0.0.0.0:4317 }

exporters:
  otlphttp/langfuse:
    endpoint: https://cloud.langfuse.com/api/public/otel
    headers: { Authorization: "Basic ${LANGFUSE_AUTH_B64}" }
  otlp/phoenix:
    endpoint: http://phoenix:4317
    tls: { insecure: true }
  otlp/honeycomb:
    endpoint: api.honeycomb.io:443
    headers: { x-honeycomb-team: "${HONEYCOMB_API_KEY}" }

service:
  pipelines:
    traces:
      receivers: [otlp]
      processors: [batch]
      exporters: [otlphttp/langfuse, otlp/phoenix, otlp/honeycomb]

Your application only ever knows about localhost:4317. The Collector does the rest — and dropping a backend, adding one, or swapping Langfuse for Phoenix is a one-line change to exporters, with your app untouched. Because the Collector runs as its own process and OTLP export is batched by the BatchSpanProcessor, none of this fan-out sits on your request path.

Why this is the version that ages well#

Observability tools get acquired, relicensed, and repriced — Langfuse was bought by ClickHouse in January 2026, Phoenix ships under the Elastic License, prices move every year. Every one of those events is a migration if your instrumentation is vendor-specific. If it's standard GenAI spans, it's a config diff.

Start with whichever backend fits today — self-host Langfuse for the full free feature set, Phoenix if you're OTel-first, Honeycomb for the Agent Timeline view — and read our side-by-side comparison to choose. But instrument to the standard underneath all of them. The traces are the asset. Keep them portable.