Yesterday, we learned that LangGraph is all about nodes and edges. Today, weβre putting that into practice by building a Stateful Agent that can actually "think," use a tool, and then decide if it needs to do more.
In the old way (Chains), if a tool returned an error, the app crashed. In the LangGraph way, we create a loop where the agent sees the error and tries a different approach.
π§ The Agentic Loop: Thought β Action β Observation
To build this, we need a graph that doesn't just go in a straight line. We need it to circle back.
- Agent Node: The LLM decides what to do.
- Tools Node: If the LLM wants to use a tool, this node executes it.
- The Loop: The result of the tool goes back to the Agent so it can "observe" the result and decide if it's done.
π οΈ Coding the Loop
We'll use the ToolNodeβa pre-built helper from LangGraphβto make this easy.
from typing import Annotated, TypedDict
from langgraph.graph import StateGraph, START, END
from langgraph.graph.message import add_messages
from langgraph.prebuilt import ToolNode, tools_condition
from langchain_openai import ChatOpenAI
from langchain_community.tools.tavily_search import TavilySearchResults
# 1. Define the State (Our notebook)
class State(TypedDict):
# add_messages tells LangGraph to append new messages to history
messages: Annotated[list, add_messages]
# 2. Setup Tools and Model
tools = [TavilySearchResults(max_results=2)]
model = ChatOpenAI(model="gpt-4o").bind_tools(tools)
# 3. Define the Nodes
def chatbot(state: State):
return {"messages": [model.invoke(state["messages"])]}
# 4. Build the Graph
workflow = StateGraph(State)
workflow.add_node("chatbot", chatbot)
# ToolNode automatically executes tool calls found in the messages
workflow.add_node("tools", ToolNode(tools))
# 5. Define the Logic (The "Brain")
workflow.add_edge(START, "chatbot")
# Conditional Edge: If the model called a tool, go to 'tools',
# otherwise, go to 'END'.
workflow.add_conditional_edges("chatbot", tools_condition)
# Loop back! After using tools, go back to the chatbot to see if it's done
workflow.add_edge("tools", "chatbot")
graph = workflow.compile()
β‘ Why tools_condition is Magic
This is a built-in "traffic controller." It looks at the last message from the AI:
If it contains a tool_call, it sends the flow to the
toolsnode.If it is a regular string, it realizes the AI is finished and sends it to
END.
This prevents the AI from getting stuck in an infinite loop!
π― Day 13 Summary
Today, you built a truly autonomous agent. You learned:
Cyclic Graphs: How to point an edge back to a previous node.
ToolNode: Automating the execution of AI-requested actions.
Conditional Routing: Letting the graph decide its own path.
Your Homework: Imagine the search tool returns "No results found." Because of the loop we built today, the AI can see that and try a different search query automatically. Try to prompt your agent to find something obscure and watch it work!
See you tomorrow! β
Top comments (0)