Skip to main content
LangGraph builds stateful, multi-step agent graphs on top of LangChain. With OpenInference instrumentation it emits spans tagged with openinference.span.kind, which Lemma reads directly. Point Langfuse at Lemma, enable the instrumentation, and wrap each graph invocation in one root span to get a single nested trace.
One agent execution = one trace. Wrap the graph invocation in a single root span so every node, model, and tool call nests under it. See the trace contract.
LangGraph emits OpenInference-style spans (openinference.span.kind), which are a fully supported shape for Lemma’s automated issue detection (silent failures, bad tool calls, loops) today.

Recipe

1

Install

pip install langgraph langchain langfuse openinference-instrumentation-langchain opentelemetry-sdk opentelemetry-exporter-otlp
2

Register the Langfuse → Lemma exporter

Register the exporter once at startup, before any graph runs. This matches Setup.
# instrumentation.py — imported first, before your app code
import os
from opentelemetry import trace
from opentelemetry.sdk.trace import TracerProvider
from opentelemetry.sdk.trace.export import BatchSpanProcessor
from opentelemetry.exporter.otlp.proto.http.trace_exporter import OTLPSpanExporter

provider = TracerProvider()
provider.add_span_processor(
    BatchSpanProcessor(
        OTLPSpanExporter(
            endpoint=os.environ["LEMMA_BASE_URL"],
            headers={
                "Authorization": f"Bearer {os.environ['LEMMA_API_KEY']}",
                "X-Lemma-Project-ID": os.environ["LEMMA_PROJECT_ID"],
            },
        )
    )
)
trace.set_tracer_provider(provider)
Set the environment variables. Lemma-only export needs no LANGFUSE_* credentials.
export LEMMA_BASE_URL="https://api.uselemma.ai/otel/v1/traces"
export LEMMA_API_KEY="lma_..."
export LEMMA_PROJECT_ID="proj_..."
3

Enable OpenInference instrumentation

LangGraph runs on LangChain, so the LangChain instrumentor captures graph nodes, model calls, and tool calls — emitting the openinference.span.kind spans Lemma reads. See the Langfuse LangGraph guide for more detail.
from openinference.instrumentation.langchain import LangChainInstrumentor

LangChainInstrumentor().instrument()
4

Wrap the whole run in one root span

Wrap graph.invoke in a single Langfuse root span so every node and call nests under one trace. Record the input and final output on the root, and set a stable agent name.
from langfuse import get_client

langfuse = get_client()

def run_support_agent(user_message: str, thread_id: str) -> str:
    with langfuse.start_as_current_span(name="support-agent") as root:
        root.update(input=user_message)
        langfuse.update_current_trace(
            name="support-agent",
            session_id=thread_id,
            metadata={"gen_ai.agent.name": "support-agent"},
        )

        result = graph.invoke({"messages": [{"role": "user", "content": user_message}]})
        final = result["messages"][-1].content

        root.update(output=final)
        return final
Every span emitted inside the with block becomes a child of the root, producing one nested trace:
support-agent              ← trace root (input, output)
├─ agent (llm)             ← generation (model, tokens)
├─ search_docs (tool)      ← tool call (args, result)
└─ agent (llm)             ← generation (final answer)
5

Flush before the process exits

In short-lived runtimes, flush so the whole trace ships in one batch.
from langfuse import get_client

get_client().flush()
If graph nodes show up as their own separate traces, the graph ran outside the root’s active context. Keep graph.invoke inside the start_as_current_span block. See Troubleshooting.

Verify in Lemma

Open the Lemma dashboardTraces and confirm:
  • One trace per run — a full graph invocation is one trace, not one per node.
  • Root has input and output — the root span shows the user message and the final output.
  • Generations are nested — each model call appears as a child generation with model and token usage.
  • Tools are nested — each tool invocation appears as a child tool span with arguments and result.

Next steps

Trace contract

The exact shape Lemma reads.

Setup

Wire the Langfuse → Lemma exporter.

Threads and sessions

Group multi-turn conversations with a thread id.

Good vs bad traces

What issue detection looks for, per shape.