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.
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.
generationbecomesLLM,toolbecomesTOOL) - Parent-child span nesting
- Any exception if raised
Getting Started
Install Dependencies
pip install mlflow langfuse
Start MLflow Server
- Local (pip)
- Local (docker)
If you have a local Python environment >= 3.10, you can start the MLflow server locally using the mlflow CLI command.
mlflow server
MLflow also provides a Docker Compose file to start a local MLflow server with a postgres database and a minio server.
git clone --depth 1 --filter=blob:none --sparse https://github.com/mlflow/mlflow.git
cd mlflow
git sparse-checkout set docker-compose
cd docker-compose
cp .env.dev.example .env
docker compose up -d
Refer to the instruction for more details, e.g., overriding the default environment variables.
Enable Tracing and Run Your Application
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)
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.
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
| Sync | Async | Generators | Nested Spans |
|---|---|---|---|
| ✅ | ✅ | ✅ | ✅ |
Span Type Mapping
MLflow maps Langfuse's as_type parameter to MLflow span types:
Langfuse as_type | MLflow Span Type |
|---|---|
generation | LLM |
embedding | EMBEDDING |
tool | TOOL |
retriever | RETRIEVER |
agent | AGENT |
chain | CHAIN |
evaluator | EVALUATOR |
guardrail | GUARDRAIL |
span | UNKNOWN |
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:
mlflow.otel.autolog(batch=False)
Or explicitly enable batched export:
mlflow.otel.autolog(batch=True)
Disable auto-tracing
Auto tracing can be disabled globally by calling mlflow.otel.autolog(disable=True).
mlflow.otel.autolog(disable=True)
After disabling, new Langfuse traces will no longer be mirrored to MLflow.