What we're building
The identical calculator/word-counter ReAct agent from the LangGraph course, run again unchanged, plus one config dict added to .invoke() purely for organization. Every lesson before this one built tracing into new code from scratch. This lesson proves you don't have to: anything built with LangChain or LangGraph is traced automatically the moment LANGSMITH_TRACING=true is set.
What this reveals
StateGraph, ToolNode, bind_tools, every LangChain/LangGraph component is already instrumented internally, the same way ChatGoogleGenerativeAI was in Lesson 3. You never write a single @traceable in this file. Compile the graph, invoke it, and the entire run, the agent node deciding to call a tool, the tool executing, the loop back to the agent, the final answer, shows up in LangSmith as a full nested run tree, matching the graph's actual structure.
This is the practical reason LangSmith exists alongside LangChain and LangGraph rather than as an unrelated add-on: for anything you build with those two libraries, tracing is opt-in at the environment level, not something you write into your application code.
The config dict passed to .invoke() here isn't required for tracing to happen, it's already happening. It's there to make the resulting trace more useful: run_name gives the top-level run a readable name instead of a generic one, tags and metadata make it filterable later (Lesson 18 covers filtering).
The code, piece by piece
builder = StateGraph(MessagesState)...app = builder.compile()Unchanged from the LangGraph course, word for word.
result = app.invoke( {"messages": [HumanMessage(question)]}, config={ "run_name": "calculator_word_counter_agent", "tags": ["langsmith-course", "langgraph-agent"], "metadata": {"lesson": 6}, },)The only addition. run_name overrides the default run name LangSmith would otherwise generate (usually the graph's internal name). tags and metadata behave exactly as they did on @traceable functions in Lesson 3, just passed through LangGraph's config argument instead.
Checkpoint
- LangChain/LangGraph components trace themselves: no
@traceableneeded for anything built fromStateGraph,ToolNode, chat models, or other LangChain primitives, once tracing is on globally. configon.invoke(): the LangGraph/LangChain-native way to attachrun_name,tags, andmetadatato a run, equivalent to@traceable's parameters orlangsmith_extra.- Zero-instrumentation tracing: existing LangChain/LangGraph applications get full observability just from an environment variable, no code changes.
If anything here still feels unclear, ask before moving to Lesson 7.