
The Mechanics of LangGraph: Nodes and Edges
Master the technical API of LangGraph. Learn how to define state schemas, write node functions, and architect conditional routing for complex autonomous workflows.
Nodes, Edges, and State Transitions
In this lesson, we transition from theory to syntax. We will learn the "Big Three" of the LangGraph API: the State schema, the Node function, and the Edge router. Mastering these will allow you to build any agentic architecture from scratch.
1. Defining the State (The Schema)
The state is a standard Python TypedDict. However, it has a superpower: Reducers.
What is a Reducer?
By default, if you return {"messages": ["Hello"]} from a node, it will overwrite the previous messages. A reducer tells LangGraph how to merge the new data with the old data.
from typing import TypedDict, Annotated
import operator
class AgentState(TypedDict):
# 'operator.add' is a reducer. It tells LangGraph to
# APPEND new messages to the existing list.
messages: Annotated[list, operator.add]
# This field will be OVERWRITTEN every time
current_thought: str
2. Writing Nodes (The Workers)
A node is just a Python function (usually async) that takes the state and returns a dictionary with the updates.
async def researcher_node(state: AgentState):
query = state['messages'][-1].content
# Use a tool or LLM to get data
results = await my_search_tool.ainvoke(query)
# Return ONLY what changed
return {"messages": [results]}
Rule of Thumb: Keep nodes pure. A node should perform one logical task. If a node is doing "Search AND Summarize," break it into two nodes.
3. Defining Edges (The Logic)
Edges connect the nodes. There are two types.
A. Static Edges
These always point from one node to another.
workflow.add_edge("researcher", "summarizer")
B. Conditional Edges
These use a Router Function to decide the next path.
def should_continue(state: AgentState):
# If the LLM outputted a Stop signal, end the graph
if "STOP" in state["messages"][-1].content:
return "end"
return "continue"
workflow.add_conditional_edges(
"researcher",
should_continue,
{
"continue": "researcher", # Loop back!
"end": "summarizer" # Move on
}
)
4. The Graph Compilation
Once you have added your nodes and edges, you must Compile the graph. This transforms your Python definitions into a high-performance execution engine.
from langgraph.checkpoint.memory import MemorySaver
# Add persistence (Module 5.3)
memory = MemorySaver()
# Compile the graph
app = workflow.compile(checkpointer=memory)
5. Visualizing the Graph
One of the best features of LangGraph is the ability to generate a visualization of your logic directly in your terminal or Jupyter notebook.
from IPython.display import Image, display
# Generate a Mermaid mermaid diagram
display(Image(app.get_graph().draw_mermaid_png()))
6. The Execution Flow: invoke vs stream
app.invoke(): Runs the entire graph and returns the final state.app.stream(): Returns an iterator that yields the updates from every node as they happen. This is the secret to building high-quality UIs.
Summary and Mental Model
- The State is your database.
- The Node is your SQL
UPDATEstatement. - The Edge is your
GOTOorSWITCHlogic.
By separating the Logic of Action (Nodes) from the Logic of Movement (Edges), you create a system that is incredibly easy to maintain and scale.
Exercise: Implementation Task
- Coding: Write a Node function called
count_tokensthat looks at the message history and updates a state key calledtotal_tokens. - Logic: Design a
Conditional Edgethat routes to anAlert_Nodeif thetotal_tokensexceeds 10,000. - Reducers: Why is
operator.addnecessary for a list of tool outputs? What would happen if you had 3 parallel tools running and they all tried to update the list without a reducer? Ready for something harder? Let's talk about agents that live for a long time.