Tutorial: Building Cyclic Agents with LangGraph
Dec 30, 2025 • 25 min read
What is LangGraph? A library for building stateful, multi-actor applications with LLMs. Unlike "Chains" (DAGs), LangGraph supports Cycles.
1. The Mental Model: State Machines
Most agent frameworks (AutoGPT, BabyAGI) are just `while` loops. LangGraph formalizes this as a Graph.
- State: A shared schema (Python Dictionary) that evolves over time.
- Nodes: Functions that modify the state.
- Edges: Control flow rules (If X, go to Node A. Else, go to Node B).
2. Step 1: Define the State
We use Python's TypedDict to enforce type safety.
from typing import TypedDict, Annotated, List, Union
from langchain_core.messages import BaseMessage
import operator
class AgentState(TypedDict):
# 'Annotated' allows us to define reducer functions.
# operator.add means "append to list" instead of overwriting.
messages: Annotated[List[BaseMessage], operator.add]
next_step: str3. Step 2: Define Nodes
Nodes are just Python functions that take the current state and return a state update.
async function call_model(state: AgentState):
messages = state['messages']
response = await model.ainvoke(messages)
return {"messages": [response]}
async function run_tool(state: AgentState):
last_message = state['messages'][-1]
tool_input = last_message.tool_calls[0]
result = await tool_executor.invoke(tool_input)
return {"messages": [result]}4. Step 3: The Graph (Edges & Conditional Logic)
This is where the magic happens. We wire the nodes together.
from langgraph.graph import StateGraph, END
workflow = StateGraph(AgentState)
# 1. Add Nodes
workflow.add_node("agent", call_model)
workflow.add_node("action", run_tool)
# 2. Set Entry Point
workflow.set_entry_point("agent")
# 3. Add Conditional Edge (The "Router")
def should_continue(state):
last_message = state['messages'][-1]
if "tool_calls" in last_message:
return "continue"
return "end"
workflow.add_conditional_edges(
"agent",
should_continue,
{
"continue": "action",
"end": END
}
)
# 4. Add Normal Edge
workflow.add_edge("action", "agent") # Loop back!
# 5. Compile
app = workflow.compile()5. Persistence (Time Travel)
Agents need memory. LangGraph has built-in Checkpointers (Postgres, SQLite, Redis).
This allows you to:
- Pause execution (Human-in-the-loop).
- "Time Travel" (rewind the state to fix a mistake).
- Resume a conversation days later.
from langgraph.checkpoint.sqlite import SqliteSaver
memory = SqliteSaver.from_conn_string(":memory:")
app = workflow.compile(checkpointer=memory)
# Run with a thread_id
config = {"configurable": {"thread_id": "123"}}
app.invoke({"messages": [("user", "Hi")]}, config=config)Conclusion
Status: Essential Skill. Linear Chains are dead. If you are building reliable agents, you need Cycles, and LangGraph is the best way to manage them.