Skip to content

artifactr.langfuse

The langfuse extra. See Observability and Evaluation.

Langfuse for artifactr: the [langfuse] extra (ADR-0027).

An adapter (ADR-0034) that files artifactr's traces in Langfuse:

  • should_export_span keeps whole traces, not only their LLM spans, and no_spans none, when a Collector sends Langfuse the traces
  • langfuse_turn is a TurnContext for the Runner that sets each turn's session, user, tags and metadata

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

langfuse = langfuse_client(tracer_provider=tracer_provider)
runner = Runner(agent, app=deps, turn_context=langfuse_turn)
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 reflexr's src/reflexr/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 artifactr.telemetry.TRACE_SCOPES (artifactr's, pydantic-graph's, the MCP SDK's and the FastAPI, SQLAlchemy, asyncpg and httpx instrumentations'), so a turn's trace is whole: its commits, 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 turn's session, user and tags on the spans, which reach Langfuse through the Collector.

langfuse_turn async

langfuse_turn(
    session: Session[Any],
) -> AsyncGenerator[None]

Propagate a turn's trace attributes to Langfuse; a TurnContext for the Runner.

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

turn_attributes async

turn_attributes(session: Session[Any]) -> dict[str, Any]

Return a turn's Langfuse trace attributes, within Langfuse's limits.

The session is the thread; the user is the person whose message or answer started the turn; the tags name the tenant, the workspace and the kinds of artifact the thread follows; the metadata holds artifactr'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's scores reach Langfuse through evalr's adapters, evalr.langfuse.LangfuseScoreSink and LangfuseScoreConfigStore, which a FeedbackMirror and sync_score_configs take (ADR-0049).