DEV Community

Ramesh S
Ramesh S

Posted on

LangChain for Absolute Beginners - Part 6: Debugging & Observing Agents with LangSmith

Over this series you've built an agent that reasons (Part 3), reads your documents (Part 4), and remembers conversations while respecting guardrails (Part 5). There's one problem: right now, if it picks the wrong tool or gives a strange answer, you're debugging blind - printing messages by hand and guessing.

LangSmith is LangChain's observability platform. It records every step of every agent run - every model call, every tool call, every token - as a structured, inspectable trace. This final article in the series shows you how to turn it on and actually use it.

Recap: The Series So Far

  1. Part 1 - What LangChain is & your first script
  2. Part 2 - Prompts, models, and LCEL chains
  3. Part 3 - Tools and your first agent
  4. Part 4 - RAG: reading your own documents
  5. Part 5 - Memory and middleware
  6. Part 6 (this article) - Debugging and observing with LangSmith

Why You Need This

Agents are non-deterministic and multi-step by nature - the same question can trigger a different sequence of tool calls on different runs. Print statements don't scale to that. LangSmith gives you a visual, timestamped tree of exactly what happened on any given run: which tool was called, with what arguments, what it returned, how many tokens were used, and how long each step took.

Step 1: Get a LangSmith API Key

Sign up at smith.langchain.com and generate an API key from your account settings.

Step 2: Turn On Tracing

Add these to your .env file:

LANGSMITH_TRACING=true
LANGSMITH_API_KEY=your-langsmith-key-here
LANGSMITH_PROJECT=langchain-beginner-series
Enter fullscreen mode Exit fullscreen mode

LANGSMITH_PROJECT is optional - traces group under "default" if you skip it - but naming your project keeps traces organized once you have more than one app running.

Step 3: Run Any Agent From This Series - No Code Changes Needed

This is the best part: tracing is automatic. Take the RAG agent from Part 4 and just run it again with those environment variables set:

from dotenv import load_dotenv
from langchain.agents import create_agent

load_dotenv()

agent = create_agent(
    "gpt-5",
    tools=[search_company_docs],
    system_prompt="You are a helpful support assistant. Use the search tool when relevant.",
)

response = agent.invoke(
    {"messages": [{"role": "user", "content": "What is our refund policy?"}]}
)
print(response["messages"][-1].content)
Enter fullscreen mode Exit fullscreen mode

Nothing in this code mentions LangSmith. As long as the environment variables are set, LangChain's tracer picks up every step automatically and ships it to your LangSmith project - that's the whole integration.

Step 4: Reading a Trace

Open your project on smith.langchain.com and click into the run. You'll see a nested tree that mirrors the agent loop from Part 3:

  • The top-level AgentExecutor (or graph) run, with total latency and token count
  • A ChatModel run showing the exact prompt sent, including your system prompt and every prior message
  • A Tool run for each tool call, showing the exact arguments the model chose and what your function returned
  • The final ChatModel run that produced the answer you saw in your terminal

This is where the "black box" feeling of agents disappears. If your Part 4 RAG agent gives a wrong answer, you can open the trace, look at exactly which chunks the retriever tool returned, and immediately see whether the problem was bad retrieval or the model misreading good context - the same diagnosis we did by hand with print() statements back in Part 4, except now it's a click away for every run, not just the one you happened to be debugging.

Step 5: Tagging and Filtering Runs

Once your app is used by more than just you, add metadata to your calls so you can filter traces later - by user, by feature, or by conversation:

config = {
    "configurable": {"thread_id": "conversation-1"},
    "tags": ["support-agent", "production"],
    "metadata": {"user_id": "user-42"},
}

response = agent.invoke(
    {"messages": [{"role": "user", "content": "What is our refund policy?"}]},
    config=config,
)
Enter fullscreen mode Exit fullscreen mode

Now, in LangSmith, you can filter to just this user's traces, or just this feature's traces, instead of scrolling through everything.

A Quick Word on Evaluation

Tracing tells you what happened on a run you already made. LangSmith also supports evaluations - running a fixed set of test questions against your agent automatically and scoring the answers, so you catch regressions before you ship a prompt or tool change. That's a deeper topic on its own; for now, tracing alone will solve the vast majority of the debugging pain you've likely already felt while working through this series.

Series Wrap-Up

Here's everything you've built, in order:

  1. Part 1: A basic chat model call and your first tool-using agent
  2. Part 2: Reusable prompts and multi-step LCEL chains
  3. Part 3: A real agent that reasons about which tool to call
  4. Part 4: RAG - grounding answers in your own documents
  5. Part 5: Memory across turns, plus middleware for guardrails and human approval
  6. Part 6: Full visibility into what your agent actually did, with LangSmith

That's the complete path from "never touched LangChain" to a genuinely production-shaped agent - reasoning, grounded, persistent, guarded, and observable. From here, the best next step is picking a real project of your own and rebuilding it with everything from this series, one piece at a time.

Thanks for following along - if you build something with this series, I'd love to hear about it in the comments.


This is Part 6, the final article, of a 6-part LangChain beginner series.

Top comments (0)