Observability with LangSmith for LangGraph Agents
LangSmith traces LangGraph runs as nested spans so you can see which node ran, what the model emitted, which tools fired, and how state evolved.
Search across all documentation pages
LangSmith traces LangGraph runs as nested spans so you can see which node ran, what the model emitted, which tools fired, and how state evolved.
For graph agents, that node-by-node view is the difference between "it failed" and "the router sent us to escalate after a bad tool observation."
Set LANGSMITH_TRACING=true and LANGSMITH_API_KEY, run your compiled graph as usual, open the run in LangSmith Details/Messages views, and wrap non-LangChain I/O with traceable / SDK wrappers so tool and HTTP spans nest under the correct node.
LANGSMITH_TRACING=trueLANGSMITH_API_KEY=...LANGSMITH_PROJECT, LANGSMITH_WORKSPACE_ID, regional LANGSMITH_ENDPOINTwrap_openai) and decorate tools with @traceable.thread_id / metadata tags for searchability.import os
from typing import Literal
from langchain.messages import HumanMessage
from langchain_openai import ChatOpenAI # or another provider package
from langchain.tools import tool
from langgraph.graph import StateGraph, MessagesState, START, END
from langgraph.prebuilt import ToolNode
# Required outside the snippet:
# export LANGSMITH_TRACING=true
# export LANGSMITH_API_KEY=...
# export OPENAI_API_KEY=... # or provider key
@tool
def search(query: str) -> str:
"""Demo web search tool."""
if "sf" in query.lower():
return "60F and foggy"
return "90F and sunny"
tools = [search]
tool_node = ToolNode(tools)
model = ChatOpenAI(model="gpt-4o-mini").bind_tools(tools) # verify model id at build
def call_model(state: MessagesState):
response = model.invoke(state["messages"])
return {"messages": [response]}
def should_continue(state: MessagesState) -> Literal["tools", "__end__"]:
last = state["messages"][-1]
if getattr(last, "tool_calls", None):
return "tools"
return "__end__"
workflow = StateGraph(MessagesState)
workflow.add_node("agent", call_model)
workflow.add_node("tools", tool_node)
workflow.add_edge(START, "agent")
workflow.add_conditional_edges("agent", should_continue, {"tools": "tools", "__end__": END})
workflow.add_edge("tools", "agent")
app = workflow.compile()
final = app.invoke(
{"messages": [HumanMessage(content="weather in sf?")]},
config={"configurable": {"thread_id": "obs-demo-1"}},
)
print(final["messages"][-1].content)
# Open LangSmith UI -> find the trace for this runWithout LangChain models, keep the graph and wrap the SDK:
from langsmith import traceable
from langsmith.wrappers import wrap_openai
import openai
client = wrap_openai(openai.Client())
@traceable(run_type="tool", name="Search Tool")
def search(query: str) -> str:
return "demo"thread_id for multi-turn agentsUse Details view for the tree; Messages view for conversation-shaped summaries.
Attach tags/metadata via runnable config so you can filter prod vs staging, tenant, or agent version.
Stable thread_id values make "show me this user's last failed run" possible.
Traces explain why; checkpoints recover where.
On incidents, open the LangSmith trace first, then get_state on the thread if you need to resume or re-run from a safe point.
Pull failing traces into a dataset.
Run offline evals when you change prompts, routers, or models so path mix and tool-error rates stay visible.
Agents dump CRM fields and tokens into tool observations.
Configure masking, drop high-sensitivity projects from default retention, and keep PII policies aligned with your OpenRouter/provider data filters when those apply.
| Approach | Strength | Weakness |
|---|---|---|
| LangSmith native | Deep LangGraph nesting | SaaS dependency |
| Langfuse / OTEL stacks | Open standards | More wiring for graph semantics |
| Custom structured logs | Full control | Rebuild UI and join logic |
| Print debugging | Instant | Useless in multi-node prod |
| Provider dashboards only | Token bills | No graph path visibility |
No, but LangChain integrations auto-nest. Custom code needs traceable / wrappers.
Yes when models emit streamed tokens under a traced context. Confirm your stream mode and model integration support.
Use sampling/project settings available in LangSmith (verify current controls at build) or gate env vars per canary deployment.
LangSmith deployment options evolve; check current LangSmith docs for self-hosted/enterprise if required.
This page focuses on LangGraph wiring and graph-native reading. The agent-observability LangSmith recipe sits with broader monitoring choices.
Paused runs and resume turns should show as linked activity on the thread; exact UI chrome changes over time, so confirm with a HITL demo trace.
Yes for integration suites with a dedicated project and low retention, so flaky tool paths are inspectable.
Task success rate, tool error rate, p95 node latency, cost per successful thread, and interrupt wait time.
Related: LangSmith for LangChain/LangGraph-Native Tracing
Related: Agent Observability Basics
Related: LangGraph 1.0's Per-Node Timeouts and v2 Streaming
Related: Persistence and Checkpoints
Related: LangChain & LangGraph Best Practices
Stack versions: Pins from the category manifest (verify at build): OpenRouter (~315+ models, July 2026 pricing/fees); LangGraph 1.0+; CrewAI 1.14+; Microsoft Agent Framework 1.0; Vercel AI SDK 6; Pydantic AI (latest); LlamaIndex (latest); OpenAI Agents SDK (latest + MCP); MCP (Linux Foundation governance); A2A (HTTP+SSE+JSON-RPC 2.0); Solana
@solana/web3.js+@solana/spl-token.
Reviewed by Chris St. John·Last updated Jul 16, 2026