Skip to main content

What it does

Every call has two layers:
  • Voice layer: STT hears the user and TTS speaks the reply (your transport). You already track this.
  • Brain layer: LangGraph decides which step runs next, and LangChain runs the LLM and tools inside each step. This is invisible unless you instrument it.
tuner-langchain makes the brain layer visible. It records node transitions, timing, and tool calls automatically, with no hand-wrapping of individual nodes or tools. How you attach it depends on your stack. On LiveKit and Pipecat, the host SDK wraps your graph and flushes the events for you. On a custom stack, you attach a callback handler and include the resulting segments in your own Create Call payload.

How it works

Three pieces do the work. A simple way to picture them:
  1. Handler (TunerLangGraphHandler or TunerLangChainHandler): a LangChain callback. It’s passed to invoke(); you never call its methods yourself.
  2. Accumulator (TunerAccumulator): one per call. It stores every event the brain layer produced.
  3. Segment builder (segments_from_invocation()): converts one turn’s events into Tuner transcript rows, with timestamps as milliseconds since call start.
On LiveKit and Pipecat, wrap_graph() wires all three for you — you never touch them directly.
One handler sees both frameworks. LangGraph is built on LangChain, so a single handler on graph.invoke() captures the graph’s nodes and the LLM/tool calls nested inside them, with no extra wiring per LLM.

Attach to your stack

Pick your host. Each tab covers the install and the full wiring for that stack.
You attach the handler yourself and include the segments in your own Create Call payload. See Custom stack for the surrounding integration.

Install

Requires Python ≥ 3.10 and langchain-core ≥ 1.0 (langgraph ≥ 1.0 for graphs). Pin a version in production. See the package on PyPI.

The flow

You touch the library at three moments in a call: set up once, attach the handler on every turn, then format and send when the call ends.
1

Set up once per call

Create one accumulator (the notebook) and one handler (the ears).
2

Attach the handler on every turn

Pass the handler in config each time you run the graph or chain. This is the only wiring you add.
3

Format and send when the call ends

Turn the captured events into transcript rows, merge them with your own voice turns, and POST.
Then include transcript in your Create Call request.

Data privacy

By default the library forwards node inputs, outputs, system prompts, and tool payloads. Pass a CaptureConfig to suppress what you don’t need:
Where you pass it depends on your stack:
Tool error output is always captured, regardless of tool_outputs. Errors aren’t treated as sensitive and are needed for debugging.

Public API

The symbols below are what you use on a custom stack. On LiveKit and Pipecat, the host SDK calls them for you — you only need CaptureConfig.

Minimal starter (custom stack)


Next steps

Custom stack

Connecting to LiveKit

Connecting to Pipecat

Create Call API Reference