> ## Documentation Index
> Fetch the complete documentation index at: https://docs.mutagent.io/llms.txt
> Use this file to discover all available pages before exploring further.

# LangGraph (Python)

> Trace LangGraph Python graph workflows with MutagenT

# LangGraph Integration (Python)

The `mutagent-langgraph` package provides a callback handler that captures LangGraph node executions, graph runs, and edge transitions automatically.

## Installation

<Warning>
  This package is coming soon to PyPI. The install command below will work once published.
</Warning>

```bash theme={null}
pip install mutagent-langgraph
```

This installs `mutagent-langgraph` along with its dependencies. Tracing transport is provided by `mutagent-sdk` via the `mutagent.tracing` module. The `langgraph` SDK (>= 0.0.20) is also required and installed automatically.

## Quick Start

<Steps>
  <Step title="Initialize tracing">
    ```python theme={null}
    from mutagent.tracing import init_tracing

    init_tracing(api_key="mt_xxxxxxxxxxxx")
    ```
  </Step>

  <Step title="Create the callback handler">
    ```python theme={null}
    from mutagent_langgraph import MutagentCallbackHandler

    handler = MutagentCallbackHandler()
    ```
  </Step>

  <Step title="Pass the handler to graph.compile()">
    ```python theme={null}
    app = graph.compile()
    result = app.invoke(inputs, config={"callbacks": [handler]})
    ```
  </Step>
</Steps>

The LangGraph Pregel engine emits standard LangChain callback events enriched with `langgraph_node` / `langgraph_step` metadata. The callback handler detects these and emits `SpanKind.NODE` spans automatically — no manual context managers required.

## Full Example

```python theme={null}
import os
from typing import TypedDict
from langgraph.graph import StateGraph
import asyncio
from mutagent_langgraph import MutagentCallbackHandler
from mutagent.tracing import init_tracing, shutdown_tracing

init_tracing(api_key=os.environ["MUTAGENT_API_KEY"])

handler = MutagentCallbackHandler()


class State(TypedDict):
    text: str
    sentiment: str
    response: str


def classify(state: State) -> State:
    sentiment = "positive" if "good" in state["text"].lower() else "negative"
    return {**state, "sentiment": sentiment}


def respond(state: State) -> State:
    if state["sentiment"] == "positive":
        response = "Glad to hear that!"
    else:
        response = "Sorry to hear that. How can I help?"
    return {**state, "response": response}


graph = StateGraph(State)
graph.add_node("classifier", classify)
graph.add_node("responder", respond)
graph.add_edge("classifier", "responder")
graph.set_entry_point("classifier")
graph.set_finish_point("responder")

app = graph.compile()
result = app.invoke(
    {"text": "This is good!", "sentiment": "", "response": ""},
    config={"callbacks": [handler]},
)
print(result["response"])

asyncio.run(shutdown_tracing())
```

## What Gets Traced

`MutagentCallbackHandler` in `mutagent-langgraph` captures the same events as the LangChain handler, plus LangGraph-specific node metadata:

<CardGroup cols={3}>
  <Card title="Graph Execution" icon="diagram-project">
    Top-level span for the entire graph invocation
  </Card>

  <Card title="Node Execution" icon="circle-dot">
    Individual `SpanKind.NODE` spans for each node, tagged with node name
  </Card>

  <Card title="LLM Calls" icon="message">
    Any LLM invocations within nodes are automatically nested
  </Card>
</CardGroup>

### Span Hierarchy

<Mermaid>
  flowchart TD
  G\["chain: graph invocation"]
  G --> N1\["node: classifier"]
  G --> N2\["node: responder"]
</Mermaid>

## Combining with LangChain Callback Handler

For graphs that invoke LangChain LLMs internally, the same `MutagentCallbackHandler` from `mutagent_langgraph` (or `mutagent_langchain`) handles everything in one pass:

```python theme={null}
from mutagent.tracing import init_tracing
from mutagent_langgraph import MutagentCallbackHandler
from langchain_openai import ChatOpenAI

init_tracing(api_key="mt_xxxxxxxxxxxx")

handler = MutagentCallbackHandler()
llm = ChatOpenAI(model="gpt-4", callbacks=[handler])

app = graph.compile()
result = app.invoke(
    state,
    config={"callbacks": [handler]},
)
```

LLM spans from `ChatOpenAI` are automatically nested under their parent node span in MutagenT's trace viewer.

## Error Handling

Errors raised inside a node are automatically captured with `ERROR` status:

```python theme={null}
result = app.invoke(
    state,
    config={"callbacks": [handler]},
)
# If any node raises, the span gets ERROR status and the error message is preserved.
```

## TypeScript Equivalent

For the TypeScript/Node.js LangGraph integration, see the [LangGraph (TypeScript)](/integrations/langgraph) guide.
