LangGraph Tutorial for Multi-Agent Systems

The industry is shifting from black-box, single-agent systems to more organized, multi-agent workflows. LangGraph helps make this possible. It offers the control, state management, and memory you need to build reliable AI applications that work in real situations. In this article, I’ll walk you through a detailed tutorial on using LangGraph for multi-agent systems.

Understanding LangGraph: Nodes, Edges, and State

To really understand LangGraph, I suggest thinking of it like a regular flow chart or state machine, rather than focusing on AI. LangGraph is basically a cyclical graph execution engine designed to handle the unpredictable behavior of large language models.

Here is how the core pieces fit together:

  1. State: This is the main memory for your application. It’s a Python dictionary or a Pydantic model that moves from one step to the next. Each agent in your system reads from this state and writes updates to it.
  2. Nodes: These act as your workers. In LangGraph, a node is just a Python function. It takes the current state as input, does some work like calling an LLM, querying a database, or running a script, and then returns the updated state.
  3. Edges: These set the rules for how things move. Edges connect your nodes and control the flow of execution. They can be simple, like always going from Node A to Node B, or more dynamic, such as checking if the data is good and deciding whether to end or loop back to Node A.

One of the best things about this setup is how easy it is to debug. Since the state is always passed along, you always know where your data is and which agent is working on it at any moment.

Many of the AI agent and workflow orchestration concepts behind systems like this are covered in my book: Hands-On GenAI, LLMs & AI Agents.

LangGraph Tutorial for Multi-Agent Systems

Let’s build a practical multi-agent system. You can run this right away without needing API keys for OpenAI or Anthropic. We’ll use regular Python functions to simulate our LLMs. Once you get the setup, you can easily switch these simulated functions for real local models, like Llama 3 with Ollama, or cloud APIs by changing just one line inside the node.

We are building an Article Drafting System with three distinct steps:

  1. Researcher: Gathers facts on a given topic.
  2. Writer: Drafts the text based on the research.
  3. Human Reviewer: A human-in-the-loop checkpoint that pauses the application so a user can approve or reject the draft.

Step 1: Install Dependencies

You only need the open-source libraries to get started:

pip install langgraph langchain-core

Step 2: Define the State

Our state should keep track of everything important for the workflow. This includes the topic, research notes, the draft, how many times it’s been rewritten, and whether a human has approved it:

from typing import TypedDict

# The State dictates the exact data schema flowing through our graph
class AgentState(TypedDict):
    topic: str
    research_notes: str
    draft: str
    revision_count: int
    human_approved: bool

Step 3: Create the Nodes (The Agents)

Nodes are simply Python functions. We’ll use basic string operations to simulate LLM generation, so you can see the logic run right away:

def researcher_node(state: AgentState):
    print("\n-> 🕵️‍♂️ Researcher is gathering facts...")
    topic = state["topic"]
    
    # In a production app, you'd call an LLM or an external Search API here
    simulated_research = f"Key facts about {topic}: It relies on state machines, requires tight orchestration, and utilizes cyclical graphs."
    
    # We return a dictionary containing only the keys we want to update in the State
    return {"research_notes": simulated_research}

def writer_node(state: AgentState):
    print("-> ✍️ Writer is drafting the content...")
    notes = state.get("research_notes", "")
    revision = state.get("revision_count", 0)
    
    # Simulate the LLM writing process
    draft = f"Draft (Rev {revision}): A comprehensive guide on {state['topic']}. {notes}"
    
    return {
        "draft": draft, 
        "revision_count": revision + 1
    }

Step 4: Add Routing Logic

We need a way to check the current state and decide the next step. For this, we use a conditional routing function:

def review_router(state: AgentState):
    # If we've rewritten it 3 times, force an end to avoid infinite loops
    if state.get("revision_count", 0) >= 3:
        print("-> Max revisions reached. Forcing publication.")
        return "publish"
    
    # Check if the human flipped the approval flag to True
    if state.get("human_approved", False):
        return "publish"
    else:
        print("-> Draft rejected. Routing back to the Writer.")
        return "rewrite"

Step 5: Wire the Graph Together

Next, we set up the graph by connecting our nodes and edges:

from langgraph.graph import StateGraph, START, END
from langgraph.checkpoint.memory import MemorySaver

# 1. Initialize the graph with our state schema
graph_builder = StateGraph(AgentState)

# 2. Add our nodes
graph_builder.add_node("researcher", researcher_node)
graph_builder.add_node("writer", writer_node)

# 3. Define the standard flow (START -> Researcher -> Writer)
graph_builder.add_edge(START, "researcher")
graph_builder.add_edge("researcher", "writer")

# 4. Define the conditional routing after the writer
graph_builder.add_conditional_edges(
    "writer", 
    review_router, 
    {
        "publish": END,       # If router returns "publish", end the graph
        "rewrite": "writer"   # If router returns "rewrite", loop back to the writer
    }
)

# 5. Compile with memory (Critical for Human-in-the-Loop)
memory = MemorySaver()

# We tell the graph to explicitly pause execution *after* the writer node runs
app = graph_builder.compile(
    checkpointer=memory,
    interrupt_after=["writer"] 
)

LangGraph includes MemorySaver, a built-in checkpointer that saves the graph’s state at each step. This feature lets you pause execution, wait for a human to review the draft, and then pick up right where you left off.

Step 6: Execute with Human-in-the-Loop

Here’s how you run the graph, pause for user input, update the state, and continue:

# We need a thread ID to track this specific execution in memory
config = {"configurable": {"thread_id": "tutorial_thread_1"}}

# Define the starting parameters
initial_state = {
    "topic": "LangGraph Multi-Agent Systems",
    "revision_count": 0,
    "human_approved": False
}

print("=== Starting Graph Execution ===")

# The graph will run START -> researcher -> writer, then PAUSE 
for event in app.stream(initial_state, config=config):
    pass 

# The graph is now paused. Let's fetch the current state from memory.
current_state = app.get_state(config)
print("\n--- HUMAN REVIEW REQUIRED ---")
print(f"Current Draft: {current_state.values.get('draft')}")

# Simulate Human Input (In a real app, this would be a UI button click)
human_decision = input("\nApprove this draft? (y/n): ")

if human_decision.lower() == 'y':
    print("-> Human approved.")
    # Update the state in memory to reflect the approval
    app.update_state(config, {"human_approved": True})
else:
    print("-> Human rejected.")
    # We leave human_approved as False, which the router will see

# Resume the graph execution with the new state
for event in app.stream(None, config=config):
    pass

print("\n=== Graph Execution Finished ===")
=== Starting Graph Execution ===

-> 🕵️‍♂️ Researcher is gathering facts...
-> ✍️ Writer is drafting the content...
-> Draft rejected. Routing back to the Writer.

--- HUMAN REVIEW REQUIRED ---
Current Draft: Draft (Rev 0): A comprehensive guide on LangGraph Multi-Agent Systems. Key facts about LangGraph Multi-Agent Systems: It relies on state machines, requires tight orchestration, and utilizes cyclical graphs.

Approve this draft? (y/n): y
-> Human approved.

=== Graph Execution Finished ===

That’s how you can use LangGraph to build multi-agent systems. Here are some guided projects to help you keep learning through practice:

  1. Build a Multi-Agent System With LangGraph
  2. Build a custom RAG agent with LangGraph

Closing Thoughts

LangGraph is a strong framework for building reliable multi-agent AI systems. With its state management, flexible routing, and human-in-the-loop workflows, developers get much more control than with traditional single-agent setups.

In this tutorial, we created a simple article drafting workflow to explain the basics of State, Nodes, and Edges. As you keep exploring LangGraph, you can add real LLMs, external tools, and RAG pipelines to build even more advanced agent applications. If you want to make production-ready AI workflows, LangGraph is a great place to begin.

I hope you found this detailed tutorial on LangGraph for multi-agent systems helpful.

For more AI and machine learning tips, follow me on Instagram. My book, Hands-On GenAI, LLMs & AI Agents, can also help you grow your AI career.

Aman Kharwal
Aman Kharwal

AI/ML Engineer | Published Author. My aim is to decode data science for the real world in the most simple words.

Articles: 2135

Leave a Reply

Discover more from AmanXai by Aman Kharwal

Subscribe now to keep reading and get access to the full archive.

Continue reading