Step-by-Step Tutorial: Building a Multi-Agent Web Research Pipeline with LangGraph and SerpAPI Tools[2]



Key Takeaways * Single AI agents are limited because they lack real-time information and can get stuck on complex tasks. * LangGraph allows you to build multi-agent AI "teams" with specialized roles (like a Supervisor, Researcher, and Writer) that collaborate to solve problems. * This tutorial walks you through creating a research pipeline where agents use a shared "state" to search the web, verify facts, and synthesize a final report.

An AI that can write flawless code might not be able to tell you the current weather in San Francisco. It's a frustrating paradox. Without access to real-time, external information, they're essentially brilliant minds locked in a windowless room.

These models only know what they were taught months or years ago. Trying to get them to perform up-to-date research often ends in a mess of hallucinations or outdated facts.

That's why I've become obsessed with building systems that don't just think—they act. They search, they verify, they summarize, and they collaborate. Today, we're moving beyond the single-agent model and building an AI team.

Introduction: Why Multi-Agent Pipelines are the Future of AI Research

The Limitations of Single-Agent Systems

Let's be real: a single, monolithic AI trying to do everything is like a chef trying to simultaneously cook, wait tables, and wash dishes. It’s messy and inefficient. A single agent running a ReAct (Reason+Act) loop can get stuck, lose focus, or fail to break down a complex problem.

I’ve explored building these single agents before, like in my post on building an agentic AI with Wikipedia search tools, and they are a fantastic starting point. But for truly complex research tasks, you need specialization.

Introducing LangGraph: Building AI Teams, Not Just AI Tools

This is where LangGraph changes the game. It’s a library from LangChain that lets you define AI workflows as graphs.

Instead of a linear chain of thought, you create a network of "nodes" (your specialized agents) and "edges" (the paths they take). You can create loops, branches, and stateful systems where agents pass work back and forth, just like a real team.

It’s the difference between hiring one overwhelmed intern and assembling a dedicated research team with a project manager, a researcher, and a writer.

What We'll Build: An Automated Web Research Pipeline

Today, we're going to build that exact team. Our pipeline will have: 1. A Supervisor: The project manager that breaks down the user's request. 2. A Search Agent: The researcher that uses SerpAPI to scour the web for real-time information. 3. A Writer Agent: The synthesizer that takes the raw research and drafts a coherent report.

By the end of this tutorial, you'll have a functioning multi-agent system that can take a complex query, research it online, and give you a summarized, up-to-date answer.

Prerequisites and Setup

Before we start building our AI dream team, we need to get our tools in order.

Installing the Necessary Libraries (LangGraph, LangChain, SerpAPI)

First, let's get the core Python libraries installed. I’m a huge fan of how modular the LangChain ecosystem has become.

pip install langgraph langchain langchain-openai langchain-community

This command pulls in LangGraph for building our graph, LangChain for the core components, and the necessary packages for interacting with OpenAI models and community tools like SerpAPI.

Acquiring and Setting Up Your SerpAPI and LLM API Keys

Our agents need credentials to access the web and to think.

  1. SerpAPI Key: Head over to serpapi.com and sign up for a free account to get an API key.
  2. OpenAI API Key: You'll also need a key from OpenAI to power the "brains" of our agents.

Once you have your keys, create a .env file in your project's root directory and add them like this:

SERPAPI_API_KEY="your-serpapi-api-key"
OPENAI_API_KEY="your-openai-api-key"

The code will automatically load these, keeping your secrets out of your source code.

Structuring the Project Directory

I like to keep things clean. A simple structure works best:

/langgraph-research-pipeline
|-- main.py         # Our main script
|-- .env            # Where our API keys live
`-- venv/           # Your Python virtual environment

Core Concepts: The Anatomy of a LangGraph Agentic System

LangGraph might seem complex, but it boils down to three simple ideas that mimic how a team works.

State: The Shared Memory of Your Agent Team

Imagine a whiteboard in an office where the team updates new findings, tasks, and questions. In LangGraph, this is called State. It’s a shared Python object (specifically, a TypedDict) that every agent can read from and write to, ensuring everyone is on the same page.

Nodes: The Specialized Workers (Our Agents)

A node is a function or a runnable that performs a specific job. In our case, each node will represent one of our agents: the supervisor, the searcher, and the writer. Each node takes the current State as input, does its work, and returns an updated State.

Edges: The Workflow and Decision-Making Logic

Edges are the arrows that connect the nodes. They define the flow of work. An edge can be simple ("after 'search', go to 'writer'") or conditional ("if results are good, go to 'writer'; if not, go back to 'search'").

Step 1: Defining the Agent Roles and Shared State

Let's start by defining our team members and the "whiteboard" (AgentState) they'll all share.

The Research Supervisor: The Team Lead

This agent will be our entry point. It takes the initial user query, plans the next step, and decides which agent should take over.

The Search Agent: The Information Gatherer (with SerpAPI Tools)

This is our boots-on-the-ground researcher. It will take a query, use the SerpAPI tool to search Google, and return the raw findings.

The Writer Agent: The Report Synthesizer

This agent's job is to take the messy, raw data from the search agent and synthesize it into a clean, human-readable summary.

Coding the AgentState Graph

Now, let's define that shared whiteboard in Python. We'll use a TypedDict to enforce a schema.

from typing import TypedDict, List

class AgentState(TypedDict):
    query: str          # The initial user query
    messages: List[str] # A log of actions
    research: str       # The raw data from SerpAPI
    summary: str        # The final report

This simple class will hold all the information as it flows through our graph.

Step 2: Building the Nodes for Each Agent

With our state defined, it's time to build the Python functions that will act as our agent nodes.

Implementing the Supervisor Node Logic

The supervisor will be a simple planner for this tutorial. In a real-world scenario, you might have a more complex LLM call here to generate a multi-step plan.

# We will define the full node functions later inside the graph setup.
# For now, just conceptualize them.

def supervisor_node(state: AgentState):
    print("---SUPERVISOR---")
    # For now, the supervisor just passes the query to the search agent.
    return {"messages": ["Supervisor: Starting research..."]}

Implementing the Search Node with the SerpAPI Tool

This is where the magic happens. We'll initialize our tools and define the node that calls SerpAPI.

from langchain_community.utilities import SerpAPIWrapper

def search_node(state: AgentState):
    print("---SEARCHING THE WEB---")
    search = SerpAPIWrapper()
    results = search.run(state["query"])
    return {"research": results, "messages": [*state["messages"], "Search: Found results."]}

This node takes the query from the state, runs it through the SerpAPIWrapper, and puts the results back into the state's research field.

Implementing the Writer Node

Finally, our writer agent will use an LLM to summarize the research findings.

from langchain_openai import ChatOpenAI

def writer_node(state: AgentState):
    print("---WRITING SUMMARY---")
    llm = ChatOpenAI(model="gpt-4o-mini", temperature=0)
    prompt = f"""
    Based on the following research, please provide a concise summary for the user query: "{state['query']}"

    Research Data:
    {state['research']}
    """
    summary = llm.invoke(prompt).content
    return {"summary": summary, "messages": [*state["messages"], "Writer: Summary complete."]}

Step 3: Assembling the Graph - Connecting Nodes with Edges

Now we get to the fun part: wiring everything together with StateGraph.

Adding Agent Nodes to the StateGraph

We'll create a StateGraph instance and add our functions as nodes.

from langgraph.graph import StateGraph, END

graph_builder = StateGraph(AgentState)

# Add the nodes
graph_builder.add_node("supervisor", supervisor_node)
graph_builder.add_node("searcher", search_node)
graph_builder.add_node("writer", writer_node)

Setting the Entry and End Points

We need to tell the graph where to start and what the final step is.

graph_builder.set_entry_point("supervisor")
graph_builder.add_edge("writer", END)

The END constant is a special node that terminates the graph execution.

Creating Conditional Edges for Dynamic Routing

Here, we define the flow. The supervisor hands off to the searcher, and the searcher hands off to the writer.

# This is a simple linear flow for our first pipeline
graph_builder.add_edge("supervisor", "searcher")
graph_builder.add_edge("searcher", "writer")

In a more complex system, you could add a conditional edge here. For example, a "critique" node could check the writer's work and send it back for revision, creating a loop.

Step 4: Compiling and Running Your Multi-Agent Pipeline

With our graph fully defined, we can compile it into a runnable application.

Compiling the Graph into a Runnable

This one line of code turns our abstract graph definition into an executable object.

app = graph_builder.compile()

Executing the Pipeline with a Test Query

Let's give our AI team a task. We'll invoke the app with an initial state containing our query.

# Load environment variables
from dotenv import load_dotenv
load_dotenv()

query = {"query": "What are the latest developments in multi-agent AI systems using LangGraph?"}
result = app.invoke(query)

Analyzing the Output and Visualizing the Agent's Path

The final result object will contain the complete AgentState after the graph has finished running. You can inspect the final summary.

print("---FINAL REPORT---")
print(result['summary'])

# You can also see the log of messages
print("\n---AGENT LOG---")
for msg in result['messages']:
    print(msg)

For a cool visual, you can enable LangSmith tracing to see a diagram of your agents' path through the graph. It's incredibly helpful for debugging!

Conclusion: Your First Multi-Agent System and What's Next

Congratulations! You've just built a collaborative AI team that can perform real-time web research. This is a huge leap beyond simple prompt-and-response chatbots.

Recap of the Pipeline We Built

We created a three-agent system—a Supervisor, a Searcher, and a Writer—that work together by passing information through a shared AgentState. We used LangGraph to define the workflow, connecting our specialized agents to solve a complex problem.

Ideas for Expansion: Adding a Critique Agent or More Tools

This is just the beginning. You could easily expand this pipeline: * Add a Critique Agent: A fourth agent that reviews the writer's summary and can send it back for revisions, creating a quality-control loop. * Integrate RAG: After the search step, use the retrieved data to populate a vector database for a Retrieval-Augmented Generation (RAG) agent, giving your system long-term memory. * Add More Tools: Give your search agent tools beyond web search, like fetching data from arXiv, Wikipedia, or even your own internal documents.

Link to Full Source Code on GitHub

You can find the complete, runnable source code for this project on my GitHub. [Link to be added here]

I'm genuinely excited about the future of multi-agent systems. This is how we build more robust, reliable, and capable AI. Now go build your own team



Recommended Watch

📺 Python Advanced AI Agent Tutorial - LangGraph, LangChain, Firecrawl & More!
📺 AI Agents | Web Search For LLMs | LangGraph & Tavily Tutorial

💬 Thoughts? Share in the comments below!

Comments