Skip to main content
Available for: Python and TypeScript.
The ZespanCallbackHandler integrates with LangChain’s callback system to automatically capture every LLM call, tool invocation, chain step, and retrieval operation as linked spans in Zespan. You pass it once and it instruments the entire execution graph — no changes to your chain or agent logic are needed.

How it works

LangChain calls lifecycle methods on every registered BaseCallbackHandler at each stage of execution. The Zespan handler subscribes to: All events share the same trace_id so you see the entire chain as a single flame graph in the Traces view.

TypeScript

Installation

Basic usage

Chains

Pass the handler to RunnableSequence or any chain using the config argument:

Agents and tools

The handler captures the full agent loop: plan → tool call → observation → next plan. Each iteration appears as linked spans.

RAG with retriever tracing


Python

Installation

Basic usage

Chains

Agents


Tool calls join the tool’s trace

A model, MCP or HTTP call made inside a tool belongs to the tool’s span and to the same trace as the rest of the run, even if you did not wrap the run in withZespanTrace / with_zespan_trace. Before, such a call started a trace of its own. The handler makes the tool’s span the current context when the tool starts and puts the previous context back when it ends or fails; tools running in parallel each see their own span.
  • TypeScript: the handler is awaited by LangChain so this happens before the tool runs. If you set LANGCHAIN_CALLBACKS_BACKGROUND=true, LangChain runs handlers in the background and the tool’s own calls start their own traces, as before.
  • Python: the handler runs inline, so this also holds for async runs. A handler created with guardrails keeps LangChain’s default delivery, because its guardrail check is a blocking call that would stall your event loop; in async runs its tools’ own calls then start their own traces, as before.
  • A tool cancelled by a timeout (Python) never reports its end to LangChain. Its context is put back when the run that called it ends, or at the next top-level LangChain run (Python 3.11 or newer). Wrap each job in with_zespan_trace to put it back as soon as the job ends.

LangGraph node steps

A LangGraph node run is recorded as an agent_step span: zespan.agent.step is the superstep, zespan.agent.route is the node name, and a node that raises also carries zespan.agent.stop_reason: error. Other chains are recorded as before. See Agent steps.

How traces look in the dashboard

A LangChain agent run produces a trace like this in the flame graph:
Each row is a span. The total trace cost is the sum of both LLM spans. Tool call spans show the tool name and execution time but have no token cost.
To associate a LangChain trace with a user session, wrap the chain invocation in withZespanContext:

Guardrails with LangChain

Pass guardrail options to ZespanCallbackHandler to enable pre/post content checks on LLM calls made by the chain:
With guardrails in block mode the call waits for the check and stops on a block: invoke / stream throws (raises) GuardrailBlockedError and the model is not called for a pre-check block. Catch GuardrailBlockedError where you call the chain, drop guardrails from the handler to record without blocking, or set the rule’s action to warn in the dashboard (no deploy needed). Any other problem inside the handler never reaches your code.
  • Streaming: a pre-check block yields nothing. A post-check block runs after the model has answered, so the stream ends with GuardrailBlockedError after its chunks were already yielded.
  • Retries: retry wrappers (withRetry / with_retry, a LangGraph retry policy) treat a block like any other error and retry it up to their attempt limit. Exclude GuardrailBlockedError from retries if a retry cannot change the outcome.
  • The check itself fails (service unreachable, timeout): the call goes on, unless you set failClosed: true / "fail_closed": True on the handler, in which case the check’s error stops the call.
In TypeScript, with LANGCHAIN_CALLBACKS_BACKGROUND=true LangChain delivers handlers after the fact, so a block is recorded but cannot stop the call. The SDK prints one warning and raises nothing. Unset the variable to let a block stop the call.