Learning Hub
Lesson #39 of 70
Python Development9 min readAdvanced
Building State Machines & AI Agents with LangGraph & LangChain
Build robust, multi-actor AI agents using LangGraph: Graph-based state machines, cyclical reasoning loops (ReAct), conditional edges, and human-in-the-loop approvals.
Works with:LangGraphLangChain CoreStateGraphMemorySaver
Key Takeaways
- Simple linear LLM chains fail on complex tasks; LangGraph models agentic workflows as cyclical state graphs (Nodes, Edges, State)
- State objects (`TypedDict` / Pydantic) persist conversation memory, tool results, and execution history across multi-turn reasoning loops
- Conditional edges route execution dynamically based on model decisions (e.g., execute tool vs respond to user vs seek human approval)
- Checkpointers provide persistent state persistence, enabling Human-in-the-Loop workflows (pausing for human approval before financial/database actions)
The Diagnostic Context
Traditional LangChain linear pipelines break down when tasks require loops, error recovery, and tool iteration. LangGraph treats agentic applications as stateful directed graphs, giving developers precise programmatic control over agent cycles and decision boundaries.
The Core Technique
The LangGraph State Machine Pattern
DIAGRAM / WORKFLOW
graph TD
Start([__start__]) --> AgentNode["Agent Node (LLM Decision)"]
AgentNode --> Decision{"Model Decided: Call Tool or Finish?"}
Decision -->|Has Tool Calls| ToolNode["Tool Execution Node<br/>(SQL Query / API Call)"]
Decision -->|No Tool Calls| FinalNode["Generate Final Answer"]
ToolNode --> AgentNode
FinalNode --> End([__end__])
Building an Agent with LangGraph in Python
PYTHON
from typing import TypedDict, Annotated, Sequence
from langchain_core.messages import BaseMessage, HumanMessage, AIMessage, ToolMessage
from langgraph.graph import StateGraph, END
from langgraph.graph.message import add_messages
# 1. Define Graph State Schema:
class AgentState(TypedDict):
# 'add_messages' reducer appends new messages to history instead of overwriting
messages: Annotated[Sequence[BaseMessage], add_messages]
iterations_count: int
# 2. Define Node Functions:
def agent_reasoner_node(state: AgentState) -> dict:
messages = state["messages"]
# Simulated model decision:
print(f"Reasoner step {state.get('iterations_count', 0)} with {len(messages)} messages")
# In real code: response = llm_with_tools.invoke(messages)
return {"iterations_count": state.get("iterations_count", 0) + 1}
def tool_execution_node(state: AgentState) -> dict:
print("Executing requested tool action...")
return {"messages": [ToolMessage(content="Tool execution success result", tool_call_id="call_123")]}
# 3. Define Conditional Routing Edge:
def should_continue(state: AgentState) -> str:
if state.get("iterations_count", 0) >= 3:
return "end_workflow"
# Inspect if last message has tool calls:
return "execute_tools"
# 4. Assemble the Graph:
workflow = StateGraph(AgentState)
workflow.add_node("agent", agent_reasoner_node)
workflow.add_node("tools", tool_execution_node)
workflow.set_entry_point("agent")
workflow.add_conditional_edges(
"agent",
should_continue,
{
"execute_tools": "tools",
"end_workflow": END
}
)
workflow.add_edge("tools", "agent") # Loop back to agent
app = workflow.compile()
5-Minute Activation Challenge
Try This Right Now
In a LangGraph project, configure a `MemorySaver` checkpointer and add a breakpoint before an "execute_payment" node to simulate a Human-in-the-Loop workflow where the user must approve the action in the UI before execution resumes.
Tip: Knowledge only becomes capability once you run the prompt yourself.
Comprehension Check
Test Your Instincts (3 Questions)
1
Why does LangGraph use state graphs rather than traditional linear DAG chains for agentic workflows?
2
In LangGraph, what is the function of a State Reducer (such as `Annotated[list, add_messages]`)?
3