Langfuse¶
Langfuse is an open-source LLM engineering platform with tracing/observability capabilities. Burr integrates with it through the OpenTelemetry-native Langfuse Python SDK, building on the opentelemetry integration.
Install the integration:
pip install "apache-burr[langfuse]"
Then add the bridge as a hook – credentials are read from the standard
LANGFUSE_PUBLIC_KEY, LANGFUSE_SECRET_KEY, and LANGFUSE_HOST
environment variables:
from burr.core import ApplicationBuilder
from burr.integrations.langfuse import LangfuseBridge
app = (
ApplicationBuilder()
.with_graph(graph)
.with_entrypoint("prompt")
.with_hooks(LangfuseBridge())
.build()
)
app.run(halt_after=["response"]) # logs one trace to Langfuse
Each application execution call becomes a Langfuse trace, each step becomes a span
(with state/inputs/results captured as observation input/output), and spans opened
through Burr’s tracing API become nested spans. Any additional
OpenTelemetry LLM instrumentation (e.g. opentelemetry-instrumentation-openai)
appears nested within the corresponding Burr step.
See the following resources for more information:
Reference for the various useful methods:
- class burr.integrations.langfuse.LangfuseBridge(
- langfuse_client: Langfuse | None = None,
- *,
- session_id: str | None = None,
- user_id: str | None = None,
- capture_state: bool = True,
- tracer: Tracer | None = None,
- tracer_provider: TracerProvider | None = None,
- **langfuse_kwargs: Any,
Adapter to log Burr application execution to Langfuse.
Each application execution call (
run/step/iterate/stream_result/…) opens a root span, which defines the Langfuse traceEach step opens a span, capturing the action’s inputs/read state as the observation input and its result/written state as the observation output
Each span opened through Burr’s tracing API (
__tracer) opens a spanAttributes logged through
__tracer.log_attribute(s)are captured as observation metadata
Burr’s
app_idmaps to the Langfuse session (so multiple execution calls of the same application group together), and thepartition_keymaps to the Langfuse user - both can be overridden.Basic usage - credentials are read from the standard
LANGFUSE_PUBLIC_KEY,LANGFUSE_SECRET_KEY, andLANGFUSE_HOSTenvironment variables:from burr.integrations.langfuse import LangfuseBridge app = ( ApplicationBuilder() .with_graph(graph) .with_entrypoint("prompt") .with_hooks(LangfuseBridge()) .build() ) app.run(halt_after=["response"]) # logs one trace to Langfuse
You can also pass credentials explicitly, or pass a pre-constructed client:
LangfuseBridge(public_key="pk-lf-...", secret_key="sk-lf-...", host="...") # or, equivalently LangfuseBridge(langfuse_client=my_langfuse_client)
The underlying client is available as
bridge.langfuse_client– for example toflush()in short-lived scripts, or to score traces.Note
With langfuse v4+, spans are filtered before export, and only LLM-relevant spans are exported by default. If you construct the
Langfuseclient yourself, passshould_export_span=burr_span_export_filterto its constructor so Burr spans are exported (seeburr_span_export_filter()). WhenLangfuseBridgeconstructs the client for you, this is applied automatically.- __init__(
- langfuse_client: Langfuse | None = None,
- *,
- session_id: str | None = None,
- user_id: str | None = None,
- capture_state: bool = True,
- tracer: Tracer | None = None,
- tracer_provider: TracerProvider | None = None,
- **langfuse_kwargs: Any,
Initializes the Langfuse bridge.
- Parameters:
langfuse_client – A pre-constructed Langfuse client to use. If not passed, one is created from
langfuse_kwargs(falling back to the standardLANGFUSE_*environment variables), with the Burr span export filter applied.session_id – Langfuse session ID to group traces under. Defaults to the Burr
app_id.user_id – Langfuse user ID to attach to traces. Defaults to the Burr
partition_key(if set).capture_state – Whether to capture state/inputs/results as observation input/output. Set to False if your state contains data you do not want sent to Langfuse.
tracer – OpenTelemetry tracer to use – for testing/advanced use. Defaults to a tracer named
burr.integrations.langfusefrom the global provider.tracer_provider – OpenTelemetry tracer provider to use for both the Langfuse client and Burr spans. When passing a pre-constructed client that uses a custom provider, pass the same provider here.
langfuse_kwargs – Keyword arguments forwarded to the
Langfuseconstructor (e.g.public_key,secret_key,host). Only valid iflangfuse_clientis not passed.
- post_run_step(
- *,
- state: State,
- action: Action,
- result: Dict[str, Any] | None,
- exception: Exception,
- **future_kwargs: Any,
Run after a step is executed.
- Parameters:
state – State after step execution
action – Action that was executed
result – Result of the action
sequence_id – Sequence ID of the action
exception – Exception that was raised
future_kwargs – Future keyword arguments
- pre_run_step(
- *,
- app_id: str,
- partition_key: str,
- sequence_id: int,
- state: State,
- action: Action,
- inputs: Dict[str, Any],
- **future_kwargs: Any,
Run before a step is executed.
- Parameters:
state – State prior to step execution
action – Action to be executed
inputs – Inputs to the action
sequence_id – Sequence ID of the action
future_kwargs – Future keyword arguments
- burr.integrations.langfuse.burr_span_export_filter(span: ReadableSpan) bool¶
You only need this if you construct the
Langfuseclient yourself –LangfuseBridgeapplies it automatically when it creates the client for you:from langfuse import Langfuse from burr.integrations.langfuse import LangfuseBridge, burr_span_export_filter client = Langfuse(should_export_span=burr_span_export_filter) app = ApplicationBuilder().with_hooks(LangfuseBridge(langfuse_client=client))...