Zenaique

Identify the lifecycle events that a LangChain `BaseCallbackHandler` natively exposes (select all that apply)

Multi-select·Medium·4.0 · 0·~1 min·Asked atAdobeLyzrPwc
Attempt it
TL;DR

LangChain's BaseCallbackHandler exposes start/end/error events for LLM calls, chains, tools, and retrievers, plus agent action/finish, and nothing about GPU or auth.

Memory aid
Sign in to see the mnemonic that makes this stick.
Easy to grasp

Imagine a relay race coach who can only stopwatch the runners on her own team. She can clock when each runner starts a leg, when they finish, and whether they dropped the baton. She cannot clock the scoreboard wiring or the parking attendants because those are not her runners. LangChain's coach watches its own runners, model calls, chains, tools, retrievers, and tells you when each one started, ended, or tripped. Anything happening outside her team, like graphics-card timings or login screens, lives on a different scoreboard entirely.

Concept explanation~2 min read

Everything you need to truly understand this topic: intuition, mechanics, step by step explanation, code, formulas, and worked example. Click to expand.

The LangChain callback API looks like a small thing and is actually the integration point for the entire observability ecosystem around the framework. Every tracing product that claims a LangChain integration, LangSmith, Langfuse, Phoenix, Helicone, Weave, the OpenTelemetry auto-instrumentation packages, does its work through this one interface.

Getting the surface right matters for two reasons. First, knowing which events exist lets you wire tracing without writing extra glue. Second, knowing which events do not exist saves you from instrumenting the wrong layer and shipping observability that misses the signal you actually need.

The shape of the surface

BaseCallbackHandler is an abstract base with around twenty methods. They group into five clusters by the kind of operation each one wraps.

LLM calls

A start/end/error trio (on_llm_start, on_llm_end, on_llm_error). These fire around every model invocation that goes through a LangChain BaseLLM or BaseChatModel. The start hook receives the serialized model config and the prompts list; the end hook receives the response with usage metadata if the provider returned it.

Chains

A matching start/end/error trio for chains. A chain in LangChain is any Runnable. RunnableSequence, RunnableParallel, custom RunnableLambda. The chain events fire around the orchestrator, not the individual steps inside it; an LCEL pipeline of three steps produces one chain event triple plus the per-step events for whatever runs inside.

Tools

A start/end/error trio for tools. These fire whenever an agent or chain invokes a BaseTool. The start hook gets the tool name and the input string; the end hook gets the tool's output. This is the primary surface for instrumenting function calls.

Retrievers

A start/end/error trio for retrievers. Fires around BaseRetriever.invoke. The end hook gets the list of returned documents, which makes it the natural place to instrument RAG retrieval quality.

Agents

on_agent_action and on_agent_finish. These exist because the agent loop is a control structure that emits decisions, not just runs. on_agent_action fires when the agent picks a tool to call; on_agent_finish fires when the agent decides to stop. Both are useful for debugging loops that wander.

Why the run_id and parent_run_id pair matters
Sync, async, and the silent-skip trap
Wiring tracing vendors and the OTel bridge
Sign in to unlock the full deep dive.

Situations where this technique stops working.

Sign in to see when this approach fails.

2–4 min · Everything important, quickly.

Sign in to see the quick scan of the deep dive.
python
from langchain_core.callbacks import BaseCallbackHandler

class MyTracer(BaseCallbackHandler):
    def on_llm_start(self, serialized, prompts, *, run_id, parent_run_id=None, **kw):
        print(f'LLM start: {run_id} parent={parent_run_id}')

    def on_llm_end(self, response, *, run_id, **kw):
        print(f'LLM end: {run_id} usage={response.llm_output}')

    def on_tool_start(self, serialized, input_str, *, run_id, **kw):
        print(f'Tool start: {serialized["name"]} run={run_id}')

    def on_tool_error(self, error, *, run_id, **kw):
        print(f'Tool error: {run_id} err={error}')

Real products, models, and research that use this idea.

  • Langfuse's LangChain integration registers a BaseCallbackHandler subclass and re-emits each event as an OpenTelemetry span.
  • LangSmith's tracing client is a callback handler under the hood; nothing magic happens that you cannot replicate.
Sign in to see more production examples.

What an interviewer would ask next. Try answering before peeking at the approach.

QHow would you implement a redaction layer that strips PII from prompts before they hit a tracing backend?
A

Subclass BaseCallbackHandler, override on_llm_start to run a redaction pass over the prompts list, then forward the redacted version to the downstream tracer; keep the redaction rules in a shared library so other entry points use the same patterns.

2 more follow-ups an interviewer would ask next. Sign in to reveal them.

Red flags & common mistakes

The phrases that signal junior thinking. Click to expand.

Most common mistake

Assuming the callback surface includes provider-side details like token by token GPU timings, then writing custom handlers for events that never fire.

Sign in to see all red flags and common mistakes.

60 second bullets to scan on the way to the call.

  • The four primary callback categories and their start/end/error shape

  • The two agent-specific events and what they signal

Sign in to unlock the revision sheet.

Primary sources. Browse if you want the original framing.

Similar questions

Same topic, related formats. Practice these next.

4 curated
Next question
What does one agent trace capture step by step?
Flashcard·Easy