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

# Tips and Tricks

> Practical tips to add observability and debug LangChain apps using verbose logging, custom callbacks, and intermediate capture patterns to trace prompts, outputs, agents, and parsers.

Assuming familiarity with the core LangChain libraries, this article presents practical tips and techniques to debug LangChain applications and gain visibility into their runtime behavior.

LangChain can feel overwhelming at first—many parts of a chain (prompts, LLMs, output parsers, and agents) execute behind the scenes. When formatting is incorrect or responses are unexpected, you need tools that reveal the execution lifecycle so you can diagnose and fix issues quickly.

In this article you'll learn:

* How to enable built-in debug and verbose flags to surface internal information during execution.
* How to use callbacks to intercept and inspect events across prompts, LLM calls, chains, and agents.
* Practical patterns to capture intermediate inputs and outputs so you can trace where formatting or logic errors originate.

<Callout icon="lightbulb" color="#1CB2FE">
  This article focuses on techniques for observability and debugging. A demo in this article shows how to enable debug/verbose output and how to implement callbacks to capture detailed runtime information.
</Callout>

## Why observability matters for LangChain

When a chain produces unexpected results, the root cause can be in any layer:

* prompt formatting or template errors,
* LLM call parameters (temperature, max tokens),
* output parser logic (parsing failures),
* agent/tool execution and tool return values.

Observability helps you answer targeted questions such as:

* What prompt was actually sent to the LLM?
* What intermediate outputs did a chain produce before the final result?
* Which tools did an agent call and with what arguments?
* Did an output parser throw an error or silently return None?

Below are concrete techniques and examples you can adopt to make these answers visible.

## Summary of techniques

| Technique                     | Use case                                                            | Quick example                                                       |
| ----------------------------- | ------------------------------------------------------------------- | ------------------------------------------------------------------- |
| Verbose flags / logging       | Surface internal operations of LLMs and chains                      | `llm = ChatOpenAI(temperature=0, verbose=True)`                     |
| Callback handlers             | Intercept events across LLM calls, chains, agents, and tools        | Implement `BaseCallbackHandler` methods to capture lifecycle events |
| Intermediate capture patterns | Save intermediate inputs/outputs to debug parsing/formatting issues | Store inputs/outputs in memory, files, or a DB for review           |
| Structured tracing            | Combine verbose + callbacks for full traceable execution logs       | Use both `verbose=True` and a custom callback handler               |

## Enable verbose/debug output

Many LangChain classes expose a `verbose` flag that prints helpful information to stdout during execution. You can enable verbose on the LLM, chains, and some high-level components.

Python (Chat models and chains)

```python theme={null}
from langchain.chat_models import ChatOpenAI
from langchain import LLMChain, PromptTemplate

template = "Summarize the following:\n\n{content}"
prompt = PromptTemplate(input_variables=["content"], template=template)

llm = ChatOpenAI(temperature=0.0, verbose=True)  # enable verbose on the LLM
chain = LLMChain(llm=llm, prompt=prompt, verbose=True)  # enable verbose on the chain

result = chain.run({"content": "LangChain is used for prompt orchestration..."})
print(result)
```

JavaScript / TypeScript (chat models and chains)

```javascript theme={null}
import { ChatOpenAI } from "langchain/chat_models";
import { LLMChain } from "langchain/chains";
import { PromptTemplate } from "langchain/prompts";

const prompt = new PromptTemplate({ inputVariables: ["content"], template: "Summarize:\n{content}" });
const llm = new ChatOpenAI({ temperature: 0, verbose: true });
const chain = new LLMChain({ llm, prompt, verbose: true });

const result = await chain.run({ content: "LangChain helps you build LLM-powered apps." });
console.log(result);
```

Tip: enabling verbose will print prompts and responses to stdout. If you have sensitive input (API keys, personal data), avoid printing them or sanitize logs.

<Callout icon="warning" color="#FF6B6B">
  Be careful when enabling verbose debug logging in production. Verbose logs may include user data, prompts, or model outputs that are sensitive. Always sanitize or disable verbose output for production environments.
</Callout>

## Callbacks — capture lifecycle events

Callbacks are the most flexible way to intercept runtime events. With a custom callback handler you can capture:

* prompt text before sending to the LLM
* LLM outputs and timings
* chain inputs/outputs at each step
* agent decisions and tool calls
* parser errors and exceptions

Below are minimal, robust examples that store events in memory (easy to extend to file, DB, or observability platforms).

Python — custom callback handler

```python theme={null}
from langchain.callbacks.base import BaseCallbackHandler
from typing import Any, Dict, List

class RecordingCallbackHandler(BaseCallbackHandler):
    def __init__(self):
        self.events: List[Dict[str, Any]] = []

    # called when a chain starts
    def on_chain_start(self, serialized, inputs, **kwargs):
        self.events.append({"type": "chain_start", "serialized": serialized, "inputs": inputs})

    # called when a chain ends
    def on_chain_end(self, outputs, **kwargs):
        self.events.append({"type": "chain_end", "outputs": outputs})

    # called when the LLM starts; receives prompts
    def on_llm_start(self, serialized, prompts, **kwargs):
        self.events.append({"type": "llm_start", "serialized": serialized, "prompts": prompts})

    # called when the LLM finishes
    def on_llm_end(self, response, **kwargs):
        self.events.append({"type": "llm_end", "response": response})

    # called on errors
    def on_tool_error(self, error, **kwargs):
        self.events.append({"type": "tool_error", "error": str(error)})
```

Register the handler with a chain or LLM:

```python theme={null}
from langchain.callbacks.manager import CallbackManager
from langchain.chat_models import ChatOpenAI
from langchain import LLMChain, PromptTemplate

handler = RecordingCallbackHandler()
manager = CallbackManager([handler])

llm = ChatOpenAI(temperature=0.0, verbose=False, callback_manager=manager)
prompt = PromptTemplate(input_variables=["content"], template="Summarize:\n{content}")
chain = LLMChain(llm=llm, prompt=prompt, callback_manager=manager)

chain.run({"content": "Debugging LangChain step-by-step"})
# examine handler.events to inspect the full lifecycle
```

JavaScript — callback-like handlers

* The JS SDK uses a `callbacks` array to pass handlers. Create a handler object with methods such as `onLLMStart`, `onLLMEnd`, `onChainStart`, `onChainEnd`, etc., and pass it to the model/chain.
* Example reference: [LangChain.js callbacks docs](https://js.langchain.com/docs/modules/callbacks/overview) (link for reference).

Patterns for callbacks

* Persist events to a JSON file or database for later analysis.
* Enrich events with timestamps, latencies, and environment metadata.
* Correlate events with unique run IDs to stitch together multi-step flows.

## Capture intermediate inputs and outputs

When parsing fails or outputs are malformed, locating the exact intermediate value that caused the failure is crucial.

Common capture patterns:

* In-memory capture: store intermediate values in a list or dict on a callback handler for quick debugging.
* File-based capture: dump prompts and responses to a file (rotating logs) for persistent review.
* Structured logging & tracing: send events to an observability backend (e.g., Datadog, Elastic, or OpenTelemetry).

Example: writing prompts + responses to a file

```python theme={null}
import json
from datetime import datetime

def persist_event(event, filename="langchain_trace.jsonl"):
    event["_ts"] = datetime.utcnow().isoformat()
    with open(filename, "a") as f:
        f.write(json.dumps(event) + "\n")

# inside your callback handler methods:
# persist_event({"type":"llm_start", "prompts": prompts})
# persist_event({"type":"llm_end", "response": response})
```

## Debugging common problems

* Unexpected output format from parser:
  * Capture raw LLM text before parsing to see if the model deviated from the template.
  * Use output parser tests with unit tests (feed sample LLM outputs to parser and assert parse results).

* Agent selects wrong tool:
  * Enable agent callbacks to capture `on_agent_action` and `on_agent_finish`.
  * Inspect tool inputs to verify the agent's reasoning step.

* Prompt formatting issues:
  * Enable `verbose=True` or capture the final prompt text in callbacks.
  * Validate templates with example inputs before running them in production.

## Best practices

* Always start with `verbose=True` in development to surface immediate issues.
* Use callback handlers to store traces, then switch verbose off in production.
* Sanitize logs before persisting or sending to external observability systems.
* Add unit tests for prompts and parsers to catch format regressions early.

## Quick reference table

| Topic                 | What to enable                                       | Where to capture                              |
| --------------------- | ---------------------------------------------------- | --------------------------------------------- |
| Prompt debugging      | `verbose=True` on chain or LLM                       | Callback `on_llm_start` or `on_chain_start`   |
| Output parsing        | Capture raw LLM output                               | Callback `on_llm_end` then run parser locally |
| Agent troubleshooting | Agent-specific callbacks (agent actions, tool calls) | `on_agent_action`, `on_agent_finish`          |
| Persistent traces     | Use callback handler to persist JSON lines           | File, DB, or observability backend            |

## Links and references

* LangChain documentation — [https://langchain.com/docs](https://langchain.com/docs)
* LangChain callbacks (Python) — [https://python.langchain.com/en/latest/modules/callbacks/index.html](https://python.langchain.com/en/latest/modules/callbacks/index.html)
* LangChain.js callbacks — [https://js.langchain.com/docs/modules/callbacks/overview](https://js.langchain.com/docs/modules/callbacks/overview)

***

By combining verbose runtime flags with custom callback handlers and a standardized persistence pattern for traces, you can quickly locate the source of errors, validate prompt formats, and build a robust observability workflow around LangChain applications.

<CardGroup>
  <Card title="Watch Video" icon="video" cta="Learn more" href="https://learn.kodekloud.com/user/courses/langchain/module/b5f7771a-fdbc-45b1-a786-6c84bb7ffc76/lesson/873344b7-d6b4-4c2f-86ad-82ae24246258" />
</CardGroup>
