LangGraph: Graph-Based Agent Workflows¶
Overview¶
LangGraph is a framework for building agent workflows as directed graphs. Perfect for complex, multi-step agent systems with loops and conditional logic.
StateGraph Basics¶
from langgraph.graph import StateGraph
from typing import TypedDict
class AgentState(TypedDict):
"""Shared agent state"""
messages: list
next: str
final_answer: str = None
class ResearchAgent:
"""Build agent with LangGraph"""
def __init__(self):
self.workflow = StateGraph(AgentState)
self.setup_workflow()
def setup_workflow(self):
"""Define graph structure"""
# Add nodes
self.workflow.add_node("research", self.research_node)
self.workflow.add_node("analyze", self.analyze_node)
self.workflow.add_node("synthesize", self.synthesize_node)
# Add edges
self.workflow.add_edge("research", "analyze")
self.workflow.add_edge("analyze", "synthesize")
# Set entry point
self.workflow.set_entry_point("research")
# Compile
self.graph = self.workflow.compile()
def research_node(self, state: AgentState):
"""Research phase"""
query = state["messages"][-1]
results = self.search(query)
return {
"messages": state["messages"] + [f"Found: {results}"],
"next": "analyze"
}
def analyze_node(self, state: AgentState):
"""Analysis phase"""
findings = state["messages"][-1]
analysis = self.analyze(findings)
return {
"messages": state["messages"] + [f"Analysis: {analysis}"],
"next": "synthesize"
}
def synthesize_node(self, state: AgentState):
"""Final synthesis"""
analysis = state["messages"][-1]
final = self.synthesize(analysis)
return {
"messages": state["messages"],
"final_answer": final
}
def run(self, query: str):
"""Execute workflow"""
initial_state = {
"messages": [query],
"next": "research"
}
result = self.graph.invoke(initial_state)
return result["final_answer"]
Conditional Routing¶
Dynamic Decision Making¶
class ConditionalWorkflow:
"""Route based on conditions"""
def __init__(self):
self.workflow = StateGraph(AgentState)
self.setup_conditional_routing()
def setup_conditional_routing(self):
"""Add conditional edges"""
self.workflow.add_node("classify", self.classify_node)
self.workflow.add_node("simple_response", self.simple_node)
self.workflow.add_node("complex_analysis", self.complex_node)
# Conditional routing
self.workflow.add_conditional_edges(
"classify",
self.route_based_on_complexity, # Routing function
{
"simple": "simple_response",
"complex": "complex_analysis"
}
)
self.workflow.set_entry_point("classify")
self.graph = self.workflow.compile()
def classify_node(self, state: AgentState):
"""Classify query difficulty"""
query = state["messages"][-1]
complexity = self.estimate_complexity(query)
return {
"messages": state["messages"],
"complexity": complexity
}
def route_based_on_complexity(self, state: AgentState):
"""Route based on complexity"""
if state["complexity"] < 0.5:
return "simple"
else:
return "complex"
def simple_node(self, state):
"""Handle simple queries"""
answer = self.quick_answer(state["messages"][-1])
return {"messages": state["messages"], "final": answer}
def complex_node(self, state):
"""Handle complex queries"""
answer = self.deep_analysis(state["messages"][-1])
return {"messages": state["messages"], "final": answer}
Loops & Reflection¶
Self-Improvement Cycles¶
class ReflectiveWorkflow:
"""Agent that reflects on its work"""
def __init__(self):
self.workflow = StateGraph(AgentState)
self.setup_reflection_loop()
def setup_reflection_loop(self):
"""Create loop with reflection"""
self.workflow.add_node("generate", self.generate_node)
self.workflow.add_node("critique", self.critique_node)
self.workflow.add_node("revise", self.revise_node)
# Create loop
self.workflow.add_edge("generate", "critique")
# Conditional: should we revise?
self.workflow.add_conditional_edges(
"critique",
self.should_revise,
{
"yes": "revise",
"no": "end"
}
)
self.workflow.add_edge("revise", "generate") # Loop back
self.workflow.set_entry_point("generate")
self.graph = self.workflow.compile()
def generate_node(self, state):
"""Generate solution"""
solution = self.generate_solution(state["messages"][-1])
return {"messages": state["messages"] + [solution]}
def critique_node(self, state):
"""Critique solution"""
critique = self.critique(state["messages"][-1])
return {
"messages": state["messages"] + [critique],
"critique_score": self.score_critique(critique)
}
def should_revise(self, state):
"""Decide if we should revise"""
score = state["critique_score"]
return "yes" if score < 0.7 else "no"
def revise_node(self, state):
"""Improve solution based on critique"""
revised = self.improve(state["messages"])
return {"messages": state["messages"] + [revised]}
Streaming & Monitoring¶
Real-Time Output¶
class MonitoredWorkflow:
"""Monitor workflow execution"""
def run_with_streaming(self, query):
"""Execute with streaming"""
initial_state = {"messages": [query], "next": None}
# Stream events
for event in self.graph.stream(initial_state):
node_name = list(event.keys())[0]
node_output = event[node_name]
print(f"Node: {node_name}")
print(f"Output: {node_output}")
yield node_output
3 Warnings ⚠️¶
Warning 1: Infinite Loops¶
# ❌ WRONG
# Loop without termination condition
workflow.add_edge("revise", "generate") # Always loops
# ✅ RIGHT
# Use conditional edge to exit
workflow.add_conditional_edges(
"revise",
should_continue,
{
"continue": "generate",
"end": END
}
)
Warning 2: State Explosion¶
# ❌ WRONG
# State grows unbounded
state["messages"].append(every_output)
# Memory usage explodes
# ✅ RIGHT
# Clean up old state
if len(state["messages"]) > 20:
state["messages"] = state["messages"][-20:]
Warning 3: Overcomplex Graphs¶
# ❌ WRONG
# Graph with too many nodes
# Hard to understand and debug
# ✅ RIGHT
# Start simple, add complexity if needed
# 3-5 nodes initially
# Add more only when necessary
Last Updated: August 9, 2026