Skip to main content

Tracing Langfuse

Langfuse is an open-source LLM engineering platform for tracing, evaluating, and monitoring AI applications.

The MLflow Langfuse integration lets you add MLflow tracing to your existing Langfuse-instrumented code with a single line. When enabled, every trace that Langfuse generates is automatically mirrored to the MLflow backend as a fully populated MLflow trace. This includes traces from the @observe() decorator, the low-level langfuse.trace() / langfuse.span() APIs, and any Langfuse SDK integration. Langfuse tracing is completely unaffected; this is purely additive.

python
import mlflow

mlflow.otel.autolog()

Because Langfuse is built on OpenTelemetry, mlflow.otel.autolog() registers an MLflow span processor on the global TracerProvider that Langfuse uses. Langfuse attribute translation (span types, inputs, outputs) is handled automatically by the MLflow backend.

MLflow automatically captures the following information from every Langfuse trace:

  • Span inputs and outputs
  • Latencies
  • Span name
  • Span type mapped from Langfuse's observation type (e.g. generation becomes LLM, tool becomes TOOL)
  • Parent-child span nesting
  • Any exception if raised

Getting Started

1

Install Dependencies

bash
pip install mlflow langfuse
2

Start MLflow Server

If you have a local Python environment >= 3.10, you can start the MLflow server locally using the mlflow CLI command.

bash
mlflow server
3

Enable Tracing and Run Your Application

python
import mlflow
from langfuse import Langfuse, observe

# Enable MLflow tracing for all Langfuse traces
mlflow.otel.autolog()

# Set a tracking URI and an experiment
mlflow.set_tracking_uri("http://localhost:5000")
mlflow.set_experiment("Langfuse")

langfuse = Langfuse()


@observe(name="chat_completion", as_type="generation")
def chat_completion(messages):
# Your LLM call here
return "Hello! How can I help you?"


# Use the low-level Langfuse client API to create a trace
trace = langfuse.trace(name="agent_turn")
messages = [{"role": "user", "content": "What is MLflow?"}]
result = chat_completion(messages)
trace.update(output=result)
print(result)
note

mlflow.otel.autolog() can be called before or after Langfuse is imported or initialized. Both Langfuse and MLflow perform the same ProxyTracerProvider to SdkTracerProvider replacement and reuse an existing provider if one is already set, so initialization order does not matter.

4

View Traces in MLflow UI

Browse to the MLflow UI at http://localhost:5000 (or your MLflow server URL) and you should see the traces for your Langfuse-instrumented application. Nested calls will appear as parent-child spans in the trace view, with proper inputs, outputs, and span types.

Supported Features

SyncAsyncGeneratorsNested Spans

Span Type Mapping

MLflow maps Langfuse's as_type parameter to MLflow span types:

Langfuse as_typeMLflow Span Type
generationLLM
embeddingEMBEDDING
toolTOOL
retrieverRETRIEVER
agentAGENT
chainCHAIN
evaluatorEVALUATOR
guardrailGUARDRAIL
spanUNKNOWN

Export Mode

By default, mlflow.otel.autolog() uses batched export (BatchSpanProcessor), which buffers spans and flushes them in the background. This follows the MLFLOW_ENABLE_ASYNC_TRACE_LOGGING environment variable (default True).

For debugging or low-throughput use cases, you can switch to synchronous export so that each trace is sent immediately:

python
mlflow.otel.autolog(batch=False)

Or explicitly enable batched export:

python
mlflow.otel.autolog(batch=True)

Disable auto-tracing

Auto tracing can be disabled globally by calling mlflow.otel.autolog(disable=True).

python
mlflow.otel.autolog(disable=True)

After disabling, new Langfuse traces will no longer be mirrored to MLflow.