Files
magnus919_agent-skills/langchain/references/callbacks.md
Magnus Hedemark 7f2842b358 feat: langchain v1.1.0 — research-validated deepening
Major deepening of the langchain expert skill based on source audit against
official LangChain docs (docs.langchain.com, reference.langchain.com).

Changes:
- Added references/validation-audit.md documenting all research findings
- Deepened references/agent-patterns.md from 74 to 200+ lines:
  create_react_agent full parameter table, @tool decorator with
  args_schema/parse_docstring, streaming events, multi-agent supervisor
- Deepened references/lcel-reference.md from 79 to 180+ lines:
  RunnablePassthrough.assign(), RunnableParallel dict shorthand,
  RunnableLambda, RunnableConfig, .with_fallbacks(), .configurable_fields()
- Deepened references/rag-strategies.md with advanced retrieval patterns
- Deepened references/production-deployment.md with LangSmith Datasets/
  Evaluation Runs/Prompt Hub
- Added new references/callbacks.md (BaseCallbackHandler, event table,
  agent auditing patterns, async callbacks)
- Deepened references/faq-and-troubleshooting.md with Pydantic v1/v2,
  streaming+tools, checkpoint serialization guidance

All API surface claims verified against official documentation.
v1.0.3 -> v1.1.0
2026-07-09 14:33:42 -04:00

3.4 KiB

LangChain Callbacks

The callbacks system provides real-time hooks into every stage of chain and agent execution. Use it for custom logging, monitoring, token tracking, and debugging.

BaseCallbackHandler

from langchain_core.callbacks import BaseCallbackHandler

class MyHandler(BaseCallbackHandler):
    def on_llm_start(self, serialized: dict, prompts: list[str], **kwargs) -> None:
        print(f"LLM starting with {len(prompts)} prompts")

    def on_llm_end(self, response, **kwargs) -> None:
        text = response.generations[0][0].text[:50]
        print(f"LLM finished: {text}...")

    def on_tool_start(self, serialized: dict, input_str: str, **kwargs) -> None:
        print(f"Tool: {serialized.get('name')}")

    def on_tool_end(self, output: str, **kwargs) -> None:
        print(f"Tool output: {str(output)[:100]}")

    def on_retriever_start(self, query: str, **kwargs) -> None:
        print(f"Retrieving: {query}")

    def on_retriever_end(self, documents: list, **kwargs) -> None:
        print(f"Retrieved {len(documents)} documents")

Event Reference

Event Arguments When
on_llm_start serialized, prompts Model called
on_llm_end response Model returns
on_llm_error error, kwargs Model exception
on_chat_model_start serialized, messages Chat model called
on_chain_start serialized, inputs Chain step begins
on_chain_end outputs Chain step completes
on_tool_start serialized, input_str Tool invoked
on_tool_end output Tool returns
on_tool_error error, kwargs Tool exception
on_retriever_start query Retrieval begins
on_retriever_end documents Retrieval completes
on_text text Custom log messages

Using Callbacks

Per-Invocation

handler = MyHandler()
chain.invoke({"q": "Hello"}, config={"callbacks": [handler]})

Global Verbose Mode

from langchain_core.globals import set_verbose
set_verbose(True)  # Print all callbacks to stdout

Practical: Audit Agent Tool Calls

from langchain_core.callbacks import BaseCallbackHandler

class AgentAuditHandler(BaseCallbackHandler):
    def on_tool_start(self, serialized: dict, input_str: str, **kwargs) -> None:
        print(f"  calling tool: {serialized.get('name')}")
        print(f"  with input: {input_str[:120]}")
    def on_tool_end(self, output: str, **kwargs) -> None:
        print(f"  tool returned: {str(output)[:120]}")
    def on_retriever_end(self, documents: list, **kwargs) -> None:
        print(f"  retrieved {len(documents)} docs")

agent = create_agent(model, tools)
result = agent.invoke(
    {"messages": [("user", "Research LangChain")]},
    config={"callbacks": [AgentAuditHandler()]}
)

Async Callbacks

from langchain_core.callbacks import AsyncCallbackHandler

class AsyncAuditHandler(AsyncCallbackHandler):
    async def on_llm_start(self, serialized, prompts, **kwargs):
        print("LLM starting...")
    async def on_tool_end(self, output, **kwargs):
        print(f"Tool done: {str(output)[:80]}")

LangSmith Integration

When LangSmith tracing is enabled (LANGCHAIN_TRACING_V2=true), all callback events are automatically captured as trace spans. Custom callbacks add additional instrumentation on top — e.g., sending metrics to a custom dashboard while LangSmith handles the canonical trace.