When a LangChain chain returns garbage or throws an opaque error, you need to see what actually went to the model. LangChain verbose mode debugging is the fastest way to expose prompt construction, intermediate steps, and tool calls without instrumenting every node by hand.
Step 1: Enable verbose on a single chain
The simplest entry point is the verbose=True flag on any chain or agent constructor. This streams the chain’s reasoning, the exact prompt sent to the LLM, and the raw response to stdout.
from langchain_openai import ChatOpenAI
from langchain.prompts import ChatPromptTemplate
from langchain.chains import LLMChain
llm = ChatOpenAI(model="gpt-3.5-turbo", temperature=0)
prompt = ChatPromptTemplate.from_template("Summarize the following: {input}")
chain = LLMChain(llm=llm, prompt=prompt, verbose=True)
result = chain.run(input="LangChain verbose mode debugging helps trace execution.")
Running this prints a block similar to:
> Entering new LLMChain run with input:
{
"input": "LangChain verbose mode debugging helps trace execution."
}
Prompt after formatting:
System:
Human: Summarize the following: LangChain verbose mode debugging helps trace execution.
> Finished chain.
If you don’t see that output, the chain isn’t actually executing the node you think it is—check that you’re calling run or invoke on the verbose instance, not a wrapped copy returned by some helper. The verbose flag is not inherited by chains created from a non-verbose parent via .from_config or similar serialization paths.
Step 2: Flip global verbose for an entire session
When debugging a pipeline composed of many chains, setting the flag on each one is tedious. LangChain reads a global toggle from the langchain module or the LANGCHAIN_VERBOSE environment variable.
import langchain
langchain.verbose = True
Or before process start:
export LANGCHAIN_VERBOSE=true
Every chain created after this assignment inherits verbosity. Be aware this is a module-level boolean, not thread-local. In a multithreaded service, all threads will start emitting verbose logs. That’s usually what you want in a debug script, but in tests it creates log spam. Scope it with a context manager:
import langchain
class temp_verbose:
def __enter__(self):
self.prev = langchain.verbose
langchain.verbose = True
def __exit__(self, *a):
langchain.verbose = self.prev
with temp_verbose():
chain.run(input="test")
Step 3: Capture verbose output in tests
Printing to stdout is fine for a REPL, but for CI you need to assert on the trace. Redirect stdout with contextlib.redirect_stdout and inspect the captured string.
import io
import contextlib
from langchain_openai import ChatOpenAI
from langchain.chains import LLMChain
from langchain.prompts import ChatPromptTemplate
llm = ChatOpenAI(model="gpt-3.5-turbo")
prompt = ChatPromptTemplate.from_template("Reverse: {x}")
chain = LLMChain(llm=llm, prompt=prompt, verbose=True)
buf = io.StringIO()
with contextlib.redirect_stdout(buf):
chain.run(x="abc")
logs = buf.getvalue()
assert "Entering new LLMChain" in logs
assert "abc" in logs
In pytest you can also use the capsys fixture:
def test_chain_logs(capsys):
chain.run(x="abc")
captured = capsys.readouterr()
assert "Reverse: abc" in captured.out
This gives you a programmatic hook to confirm that prompt variable substitution happened correctly—a common source of silent failures.
Step 4: Read the prompt template expansion
The most useful part of langchain verbose mode debugging is the rendered prompt. In the stdout block you’ll see the Prompt after formatting section. Compare it against your template definition.
For example, a SequentialChain passes outputs from step 1 as inputs to step 2. If step 2 receives an empty string, verbose output will show the variable name but no value. That points to a mismatch in output_key naming, not a model problem.
from langchain.chains import SequentialChain, LLMChain
from langchain.prompts import ChatPromptTemplate
first = LLMChain(llm=llm, prompt=ChatPromptTemplate.from_template("Topic: {topic}"), output_key="topic_text", verbose=True)
second = LLMChain(llm=llm, prompt=ChatPromptTemplate.from_template("Tweet about: {topic_text}"), output_key="tweet", verbose=True)
chain = SequentialChain(chains=[first, second], input_variables=["topic"], output_variables=["tweet"], verbose=True)
If topic_text is missing in step two’s prompt, verbose shows Tweet about: with nothing after. Fix the output_key in the first chain or the variable name in the second template. Without verbose mode, you’d only see a vague KeyError or a bland empty completion.
Step 5: Trace agents and tool calls
Agents add a control loop. With verbose=True on initialize_agent, you get the thought, the chosen action, the tool input, and the observation.
from langchain.agents import initialize_agent, Tool
from langchain_openai import ChatOpenAI
def fake_search(q):
return "LangChain is a framework for building LLM apps."
tools = [Tool(name="Search", func=fake_search, description="Search the web")]
agent = initialize_agent(tools, ChatOpenAI(), agent="zero-shot-react-description", verbose=True)
agent.run("What is LangChain?")
The trace prints lines like:
Thought: I should use Search
Action: Search
Action Input: "LangChain"
Observation: LangChain is a framework for building LLM apps.
When an agent fails silently (e.g., repeats the same action), the verbose log reveals the loop. You can then constrain max_iterations or fix the tool description. The verbose trace is the only built-in way to see the exact action string the LLM emitted before it was parsed into a tool call.
Step 6: Corroborate the trace with gateway logs
Verbose mode shows what LangChain thinks it sent. If you suspect a serialization bug or a middleware altering requests, cross-check with the endpoint side. If you route requests through an OpenAI-compatible gateway such as n4n.ai, the verbose trace shows the exact payload, while the gateway’s per-token metering gives you an independent record of what the model received and how many tokens were billed. This separates client-side formatting errors from provider-side rejects.
Set the openai_api_base to your gateway and keep chain-level verbose on:
llm = ChatOpenAI(
model="gpt-3.5-turbo",
openai_api_base="https://api.n4n.ai/v1",
openai_api_key="your-key",
)
chain = LLMChain(llm=llm, prompt=prompt, verbose=True)
The chain’s verbose output remains unchanged; the gateway’s usage metrics confirm the token count matches your prompt length. If LangChain reports 120 prompt tokens but the gateway logs 90, you have a truncation or encoding mismatch worth investigating.
Step 7: Filter verbose noise with a custom callback
Global verbose prints everything. In production you rarely want that. Subclass BaseCallbackHandler to log only on error or only specific events.
from langchain.callbacks.base import BaseCallbackHandler
class ErrorOnlyHandler(BaseCallbackHandler):
def on_chain_error(self, error, **kwargs):
print("CHAIN ERROR:", error)
def on_llm_error(self, error, **kwargs):
print("LLM ERROR:", error)
def on_llm_end(self, response, **kwargs):
# response has usage_metadata in recent versions
if hasattr(response, "llm_output") and response.llm_output:
print("TOKENS:", response.llm_output.get("token_usage"))
chain = LLMChain(llm=llm, prompt=prompt, callbacks=[ErrorOnlyHandler()])
This gives you targeted langchain verbose mode debugging without drowning in successful runs. You can also implement on_llm_start to capture the exact list of messages sent, which is useful when the model receives a system message you didn’t know was injected by a parent chain.
Step 8: Disable verbose in production and keep structured logs
Once you’ve fixed the bug, turn off global verbose. For ongoing observability, replace ad-hoc prints with a handler that emits JSON to your logging stack.
import json
import logging
logger = logging.getLogger("langchain")
class JsonDebugHandler(BaseCallbackHandler):
def on_llm_end(self, response, **kwargs):
logger.debug(json.dumps({"event": "llm_end", "usage": response.llm_output}))
# attach via callbacks=[JsonDebugHandler()] on critical chains
This keeps the spirit of langchain verbose mode debugging—full visibility—without the unstructured stdout flood.
Verify success
A debugging session is successful when you can answer three questions from the trace:
- What exact text was sent to the model? (See formatted prompt)
- What did the model return before parsing? (See raw output)
- Which intermediate step diverged from expectation? (See sequential or agent steps)
To confirm programmatically, capture stdout as in Step 3 and assert the presence of the formatted variable and the model response. If those appear and the chain output is correct, verbose debugging did its job. Turn off global verbose in production or rely on the filtered handler to keep logs clean.
Langchain verbose mode debugging is not a replacement for a full tracing system, but for local iteration it’s the lowest-overhead lens you have. Use it to catch template mismatches, agent loops, and silent empty inputs before they reach users.