Skip to content

reflexr.langfuse

The langfuse extra. See Langfuse and Scores.

Langfuse for reflexr: the [langfuse] extra (ADR-0018).

An adapter (ADR-0025) that files reflexr's traces in Langfuse, as artifactr's does:

  • should_export_span keeps whole traces, not only their LLM spans, and no_spans none, when a Collector sends Langfuse the traces
  • langfuse_run is a RunContext for the reactor that sets each run's session (its causal chain), user, trace name (its rule), tags and metadata

Feedback reaches Langfuse as scores through evalr's adapters, evalr.langfuse's LangfuseScoreSink and LangfuseScoreConfigStore (ADR-0045)::

langfuse = langfuse_client(tracer_provider=tracer_provider)
reactor = Reactor(workspaces, actions=actions, run_context=langfuse_run)
await sync_score_configs(LangfuseScoreConfigStore(langfuse))
mirror = FeedbackMirror(workspace, LangfuseScoreSink(langfuse), cursor="langfuse")

Traces

langfuse_client

langfuse_client(
    *,
    tracer_provider: TracerProvider | None = None,
    **options: Any,
) -> Langfuse

Return a Langfuse client that exports whole traces from a tracer provider.

It adds Langfuse's span processor to tracer_provider (the global one, if omitted) with should_export_span as its filter. Keys and the base URL come from options or the LANGFUSE_* environment variables. When a Collector sends Langfuse the traces already, pass should_export_span=no_spans: the client then sets trace attributes and sends scores, and exports no span a second time.

Shared verbatim with artifactr's src/artifactr/langfuse/client.py; change both.

Parameters:

Name Type Description Default
tracer_provider TracerProvider | None

The SDK tracer provider whose spans go to Langfuse.

None
**options Any

Passed to Langfuse(...), such as public_key, environment or should_export_span.

{}

should_export_span

should_export_span(span: ReadableSpan) -> bool

Return whether Langfuse should export a span: pass it as should_export_span.

Langfuse's default keeps only LLM spans. This keeps those, and the spans of every scope in reflexr.telemetry.TRACE_SCOPES (reflexr's, pydantic-graph's, the MCP SDK's and the FastAPI, SQLAlchemy, asyncpg and httpx instrumentations'), so a run's trace is whole: its steps, database queries and HTTP calls around the model calls.

no_spans

no_spans(span: ReadableSpan) -> bool

Keep no spans: the filter for a client that only sets trace attributes and sends scores.

configure_telemetry(langfuse="scores") uses it when a Collector sends Langfuse every trace already, so no span arrives twice. The client's span processor still sets each run's session, user and tags on the spans, which reach Langfuse through the Collector.

Runs

langfuse_run async

langfuse_run(
    reaction: Reaction[Any],
) -> AsyncGenerator[None]

Propagate a run attempt's trace attributes to Langfuse; a RunContext for the reactor.

The attributes are set on every span in the attempt, so Langfuse files the trace under its session and user, with its tags and metadata.

run_attributes

run_attributes(reaction: Reaction[Any]) -> dict[str, Any]

Return a run attempt's Langfuse trace attributes, within Langfuse's limits.

The session is the causal chain, so one incident is one Langfuse session; the user is the person whose event made the rule fire, if a person published it; the trace name is the rule; the tags name the tenant, the workspace and the rule; the metadata holds reflexr's ids. Values are ASCII and at most 200 characters.

MAX_ATTRIBUTE module-attribute

MAX_ATTRIBUTE = 200

The longest trace attribute value Langfuse accepts.

Scores

Feedback reaches Langfuse through evalr's adapters, evalr.langfuse.LangfuseScoreSink and evalr.langfuse.LangfuseScoreConfigStore, which a FeedbackMirror and sync_score_configs take (ADR-0045).