Why LangGraph?
LangChain gives you chains. LangGraph gives you graphs. This means you can build:
- ●Loops (agent retries)
- ●Branching (conditional logic)
- ●Human-in-the-loop (approval steps)
- ●State management (persistent memory)
Basic Graph: A Simple Agent
python
class="text-purple-400 font-medium">from langgraph.graph class="text-purple-400 font-medium">import StateGraph, MessagesState, START, END
class="text-purple-400 font-medium">from langchain_openai class="text-purple-400 font-medium">import ChatOpenAI
llm = ChatOpenAI(model=class="text-emerald-class="text-amber-300">400">"gpt-class="text-amber-300">4")
class=class="text-emerald-class="text-amber-300">400">"text-gray-class="text-amber-300">500 italic"># Define a node
class="text-purple-400 font-medium">def chatbot(state: MessagesState):
return {class="text-emerald-class="text-amber-300">400">"messages": [llm.invoke(state[class="text-emerald-class="text-amber-300">400">"messages"])]}
class=class="text-emerald-class="text-amber-300">400">"text-gray-class="text-amber-300">500 italic"># Build the graph
graph = StateGraph(MessagesState)
graph.add_node(class="text-emerald-class="text-amber-300">400">"chatbot", chatbot)
graph.add_edge(START, class="text-emerald-class="text-amber-300">400">"chatbot")
graph.add_edge(class="text-emerald-class="text-amber-300">400">"chatbot", END)
app = graph.compile()
class=class="text-emerald-class="text-amber-300">400">"text-gray-class="text-amber-300">500 italic"># Run it
result = app.invoke({class="text-emerald-class="text-amber-300">400">"messages": [(class="text-emerald-class="text-amber-300">400">"user", class="text-emerald-class="text-amber-300">400">"What is AI?")]})
print(result[class="text-emerald-class="text-amber-300">400">"messages"][-class="text-amber-300">1].content)Adding Tools
python
class="text-purple-400 font-medium">from langgraph.prebuilt class="text-purple-400 font-medium">import ToolNode
class="text-purple-400 font-medium">from langchain_core.tools class="text-purple-400 font-medium">import tool
class="text-amber-class="text-amber-300">400">@tool
class="text-purple-400 font-medium">def get_weather(city: str) -> str:
class="text-emerald-class="text-amber-300">400">""class="text-emerald-class="text-amber-300">400">"Get current weather for a city."class="text-emerald-class="text-amber-300">400">""
return class="text-emerald-class="text-amber-300">400">f"Weather in {city}: class="text-amber-300">25°C, Sunny"
tools = [get_weather]
llm_with_tools = llm.bind_tools(tools)
class="text-purple-400 font-medium">def agent(state: MessagesState):
response = llm_with_tools.invoke(state[class="text-emerald-class="text-amber-300">400">"messages"])
return {class="text-emerald-class="text-amber-300">400">"messages": [response]}
class="text-purple-400 font-medium">def should_use_tool(state: MessagesState):
last_message = state[class="text-emerald-class="text-amber-300">400">"messages"][-class="text-amber-300">1]
if hasattr(last_message, class="text-emerald-class="text-amber-300">400">"tool_calls") and last_message.tool_calls:
return class="text-emerald-class="text-amber-300">400">"tools"
return END
class=class="text-emerald-class="text-amber-300">400">"text-gray-class="text-amber-300">500 italic"># Build graph with tool routing
graph = StateGraph(MessagesState)
graph.add_node(class="text-emerald-class="text-amber-300">400">"agent", agent)
graph.add_node(class="text-emerald-class="text-amber-300">400">"tools", ToolNode(tools))
graph.add_edge(START, class="text-emerald-class="text-amber-300">400">"agent")
graph.add_conditional_edges(class="text-emerald-class="text-amber-300">400">"agent", should_use_tool)
graph.add_edge(class="text-emerald-class="text-amber-300">400">"tools", class="text-emerald-class="text-amber-300">400">"agent")
app = graph.compile()Adding Memory with Checkpointer
python
class="text-purple-400 font-medium">from langgraph.checkpoint.memory class="text-purple-400 font-medium">import MemorySaver
memory = MemorySaver()
app = graph.compile(checkpointer=memory)
class=class="text-emerald-class="text-amber-300">400">"text-gray-class="text-amber-300">500 italic"># Thread maintains conversation state
config = {class="text-emerald-class="text-amber-300">400">"configurable": {class="text-emerald-class="text-amber-300">400">"thread_id": class="text-emerald-class="text-amber-300">400">"user-class="text-amber-300">123"}}
result1 = app.invoke(
{class="text-emerald-class="text-amber-300">400">"messages": [(class="text-emerald-class="text-amber-300">400">"user", class="text-emerald-class="text-amber-300">400">"Hi, Iclass="text-emerald-class="text-amber-300">400">'m Raj")]},
config=config
)
result2 = app.invoke(
{class="text-emerald-class="text-amber-300">400">"messages": [(class="text-emerald-class="text-amber-300">400">"user", class="text-emerald-class="text-amber-300">400">"What's my name?")]},
config=config
)
class=class="text-emerald-class="text-amber-300">400">"text-gray-class="text-amber-300">500 italic"># The model remembers the user's nameKey Takeaways
- ●LangGraph enables complex, stateful AI workflows
- ●Use conditional edges for routing logic
- ●Checkpointers add memory persistence across interactions
- ●Perfect for building agents that need tool use and conversation state