opncrafter

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: str

3. 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:

  1. Pause execution (Human-in-the-loop).
  2. "Time Travel" (rewind the state to fix a mistake).
  3. 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.

Why LangGraph Over Simple Agent Loops?

Before LangGraph, developers built agents using simple while True loops with manual state management. This approach breaks down quickly in production: you get no visibility into what the agent is doing, no way to pause for human review, no ability to recover from failures, and no checkpointing for long-running tasks.

LangGraph formalizes the agent loop as a directed graph with typed state, conditional routing, and built-in persistence. Think of it as the difference between a hand-drawn circuit diagram and a professional CAD schematicβ€”both describe the same circuit, but only one lets you simulate, debug, and safely modify without causing fires.

LangGraph is now the recommended way to build agents in the LangChain ecosystem, with LangChain's own documentation pointing developers to LangGraph for any agentic use case. It's used in production at companies like Replit, Elastic, and Rakuten.

LangGraph vs. Other Agent Approaches

ReAct Agent (Simple)

Thought β†’ Action β†’ Observation loop. Easy to implement but brittle. No state persistence, no human-in-the-loop, no complex routing. Good for demos, bad for production.

LangGraph βœ…

Stateful graph with typed nodes and conditional edges. Supports persistence, human-in-the-loop, time travel, parallel execution, and subgraphs. Production-ready.

CrewAI (Role-based)

Higher-level abstraction for multi-agent teams. Less flexible than LangGraph but easier to set up for role-playing agent workflows. Built on top of LangChain.

Advanced Pattern: Human-in-the-Loop

One of LangGraph's most powerful features is the ability to pause execution and wait for human approval before continuing. This is critical for high-stakes agents (financial transactions, email sending, code deployment):

from langgraph.graph import StateGraph, END
from langgraph.checkpoint.sqlite import SqliteSaver

memory = SqliteSaver.from_conn_string(":memory:")
workflow = StateGraph(AgentState)

# ... add nodes and edges ...

# Compile with interrupt BEFORE a critical action
app = workflow.compile(
    checkpointer=memory,
    interrupt_before=["send_email"]  # Pause before this node
)

# Run until interrupt
config = {"configurable": {"thread_id": "session-1"}}
result = app.invoke({"messages": [("user", "Draft and send a status email")]}, config)

# Review state, approve, then continue
print(result["draft_email"])  # Human reviews the draft
app.invoke(None, config)  # Resume - None means "continue from checkpoint"

Advanced Pattern: Parallel Node Execution

LangGraph supports running multiple nodes simultaneously when they don't depend on each other, dramatically reducing latency for complex agents:

from langgraph.graph import StateGraph, START
from typing import TypedDict

class ResearchState(TypedDict):
    query: str
    web_results: list
    db_results: list
    final_answer: str

workflow = StateGraph(ResearchState)

# Add parallel research nodes
workflow.add_node("web_search", fetch_web_results)    # Runs in parallel
workflow.add_node("db_search", fetch_db_results)       # Runs in parallel
workflow.add_node("synthesize", combine_results)       # Runs after both complete

# Both searches start from START simultaneously
workflow.add_edge(START, "web_search")
workflow.add_edge(START, "db_search")

# Synthesize waits for both to complete
workflow.add_edge("web_search", "synthesize")
workflow.add_edge("db_search", "synthesize")
workflow.add_edge("synthesize", END)

Real-World Use Cases

1. Coding Assistant with Self-Correction

GitHub Copilot-style agents use LangGraph to implement a generate β†’ test β†’ fix loop. The agent writes code, runs it in a sandbox, reads the error output, and loops back to fix itβ€”without giving up after the first failure. The conditional edge routes: "if tests pass β†’ END, else β†’ fix_code β†’ run_tests β†’ repeat." This cycle can handle 80% of common coding errors automatically.

2. Research Agent with Source Verification

Deep research tools (like Perplexity's deep research feature) use LangGraph to orchestrate multi-step research: search β†’ read β†’ extract claims β†’ verify claims β†’ search for contradictions β†’ synthesize. The conditional routing decides whether to do more research or compile the final report based on confidence scores. LangGraph's persistence means multi-hour research sessions can be resumed after interruptions.

3. Customer Support Escalation Flow

A support agent uses LangGraph to route tickets: initial triage β†’ knowledge base search β†’ if found: draft response β†’ human review β†’ send; if not found: escalate to specialist β†’ specialist response β†’ human review β†’ send. The state tracks the full conversation history, ticket category, and resolution status, making it auditable and debuggable.

4. Financial Report Generation

FinTech companies use LangGraph for report generation workflows: fetch data β†’ validate data β†’ if invalid: request re-fetch; if valid β†’ analyze β†’ draft report β†’ compliance check β†’ if issues: revise β†’ send for approval β†’ publish. The interrupt-before feature handles the compliance review step, pausing for human approval before publication.

Troubleshooting Common LangGraph Issues

Issue: Graph enters infinite loop

Cause: Conditional edge always returns the same routing decision, looping the agent endlessly.

Fix: Add a iteration_count field to your state and add a max-iteration condition:

def should_continue(state):
    if state["iteration_count"] >= 5:  # Safety limit
        return "end"  # Force exit
    if "tool_calls" in state["messages"][-1]:
        return "continue"
    return "end"

Issue: Checkpoint not found after restart

Cause: Using in-memory SQLite (":memory:") which resets on restart.

Fix: Use a file-based or PostgreSQL checkpointer for persistent state:

from langgraph.checkpoint.postgres import PostgresSaver
memory = PostgresSaver.from_conn_string(os.environ["DATABASE_URL"])

Issue: State fields not updating as expected

Cause: Returning a full state dict from a node instead of just the changed fields overwrites other state keys.

Fix: Return only the keys you want to update. LangGraph merges partial updates:

# ❌ Wrong: overwrites all other state fields
def my_node(state): return {"messages": [...], "query": "...", "results": None}

# βœ… Correct: only update what changed
def my_node(state): return {"messages": [new_message]}

Frequently Asked Questions

Is LangGraph production-ready?

Yes. LangGraph is used by large companies including Elastic, Rakuten, and Replit in production systems. LangChain Inc. offers LangGraph Cloud for managed deployment with built-in monitoring, scaling, and a visual graph debugger.

Can I use LangGraph without LangChain?

Partially. LangGraph is designed to work with LangChain models and tools, but the core graph infrastructure (StateGraph, nodes, edges, checkpointers) is standalone. You can use it with any Python functions as nodes, but integrations like LangChain retrievers and tools make development significantly faster.

How does LangGraph compare to Microsoft AutoGen?

AutoGen focuses on multi-agent conversation patterns (agents talking to each other). LangGraph focuses on stateful execution graphs with explicit state management. LangGraph gives you more control over state transitions; AutoGen is easier for conversational multi-agent scenarios. They can actually be combinedβ€”LangGraph for orchestration, AutoGen agents as nodes.

What's the LangGraph Studio?

LangGraph Studio is a visual IDE for building and debugging LangGraph applications. It shows a live visualization of your graph, lets you inspect state at each node, replay execution from any checkpoint, and edit state on the fly during debugging. It's available as a desktop app and the cloud version in LangSmith.

Next Steps

  • Build the ReAct Agent: Implement the classic Reason + Act loop using LangGraph with a web search tool.
  • Add Human-in-the-Loop: Extend your agent with an interrupt point that pauses for human approval on sensitive actions.
  • Explore Multi-Agent Graphs: Create a supervisor graph that delegates to specialized subgraphs for research, writing, and review.
  • Connect to LangSmith: Enable tracing to visualize every step of your graph execution for debugging and optimization.

Continue Reading

πŸ‘¨β€πŸ’»
Written by

Vivek

AI Engineer

Full-stack AI engineer with 4+ years building LLM-powered products, autonomous agents, and RAG pipelines. I've shipped AI features to production for startups and worked hands-on with GPT-4o, LangChain, LlamaIndex, and the Vercel AI SDK. I started OpnCrafter to share everything I wish I had when learning β€” no fluff, just working code and real-world context.

GPT-4oLangChainNext.jsVector DBsRAGVercel AI SDK