top of page

Build Your First Multi-Agent Team

  • Jun 17
  • 10 min read

When developers first experiment with Large Language Models (LLMs), they typically start with a single prompt or a simple agent. You prompt the LLM, give it access to a search tool, and let it run.


This works beautifully for simple tasks. But as you push the system to perform complex, long-horizon operations like writing a comprehensive market research report, auditing codebase directories, or generating an entire marketing campaign—the single-agent approach breaks down.


The agent loses focus. The system prompt gets diluted by too many instructions. The model runs out of context space, starts hallucinating, or enters infinite tool-call loops. To solve this, the AI engineering community has moved toward a modular paradigm: Multi-Agent Teams. Instead of building one massive "god-agent" that tries to do everything, we divide the task among multiple, specialized "worker-agents" that collaborate, debate, and pass structured work back and forth.


In this guide, you will learn the core architecture of multi-agent systems, evaluate the top frameworks (specifically CrewAI and LangGraph), and write your first multi-agent team from scratch in Python.


Why Single Agents Fail at Scale


To understand why multi-agent teams are necessary, we have to look at the cognitive limitations of LLMs. 1. Instruction Dilution: If you give an LLM a 3-page prompt detailing twenty different rules, formatting guidelines, and tool descriptions, it suffers from "attention dispersion." It will execute some instructions perfectly while ignoring others.

2. Context Window Drift: As a single agent chats, retrieves data, and runs tools, its history grows. Crucial initial constraints get pushed out of the context window or lose weight, leading to drift.

3. Tool Selection Overload: If you give an LLM 15 different tools (e.g., search Google, read database, call API, email client), it will often select the wrong tool or get confused by matching arguments.

4. Lack of Critical Review: A single agent rarely double-checks its own work effectively. If it outputs a factual error, it will build upon that error in subsequent steps.

By breaking the problem down into a team of agents, you solve these issues:

- Separation of Concerns: Each agent has one simple role, one short system prompt, and access to 1-2 specific tools.

- Fact-Checking Loops: One agent can write, while another acts as an editor, sending drafts back for revision if validation checks fail.

- Resilience: If one agent fails or halts, the supervisor agent can handle the exception or assign the task to someone else.



Architectural Patterns of Multi-Agent Systems


How do agents talk to one another? There are three main patterns:




  1. The Sequential Chain Pattern


    Work moves in a straight line. Agent A performs a task, writes the output to a file or variable, and passes it to Agent B. Agent B processes it and passes it to Agent C. Best For: Linear production pipelines (e.g., Web Scraper → Summarizer → Translator).


  2. The Supervisor (Hub-and-Spoke) Pattern


    A central "Supervisor" agent acts as the manager. It receives the user’s request, decides which specialized worker agent is best suited, delegates the sub-task, collects the result, and decides the next step. Best For: Dynamic, conversational workflows where the execution path depends entirely on the input query.


  1. The Graph-Based (State-Machine) Pattern


    Agents are nodes in a state machine. Transitions between nodes are governed by conditional logic (written in code or decided by LLM routers). Crucially, this pattern allows for cycles—loops where an agent can repeatedly send work back to a predecessor until a condition is met. Best For: Complex, iterative engineering tasks, software development agents, or strict compliance audits.



Choosing Your Framework: CrewAI vs. LangGraph


Two main frameworks dominate Python multi-agent development in 2026: CrewAI: A high-level, role-playing framework. You define your agents like members of a corporate department (complete with goals, backstories, and roles) and assign them tasks. The framework orchestrates the execution under the hood.

LangGraph: A low-level, graph-based extension of LangChain. You explicitly define nodes (Python functions or agents), edges (logic routing), and a global state schema. Let's compare them:




Case Study: The Research and Editing Squad


To show both frameworks in action, we will build a Content Marketing Squad that creates blog posts:

1. Fact Researcher: Searches the web for up-to-date facts about a topic.

2. Copywriter: Writes an engaging, structured draft based only on the facts provided by the researcher.

3. SEO Editor: Evaluates the draft for key SEO optimization metrics. If it fails (e.g., lacks keywords or is too short), it sends it back to the Copywriter with suggestions. If it passes, it compiles the final output. Let’s write the code for both frameworks to see how they differ.



Implementation 1: Building with CrewAI


CrewAI makes role-playing teams extremely simple to implement.


Step 1: Install Dependencies
pip install crewai duckduckgo-search langchain-openai

Step 2: Write the Python Code
Create a file named `crew_team.py`:

import os
from crewai import Agent, Task, Crew, Process
from crewai_tools import SerperDevTool # Or DuckDuckGo Search tool
from langchain_openai import ChatOpenAI

# Set up environment variables
os.environ["OPENAI_API_KEY"] = "your-openai-api-key"
# Using DuckDuckGo search tool for ease of demonstration
from langchain_community.tools import DuckDuckGoSearchRun
search_tool = DuckDuckGoSearchRun()

# Define the LLM
llm = ChatOpenAI(model="gpt-4o-mini", temperature=0.3)

# 1. Define Agents
researcher = Agent(
    role='Lead Fact Researcher',
    goal='Search the web to extract verified facts and statistics about the given topic.',
    backstory='You are a meticulous investigative researcher who cross-checks all facts. You only report data that is backed by credible sources.',
    verbose=True,
    allow_delegation=False,
    tools=[search_tool],
    llm=llm
)

writer = Agent(
    role='Expert Tech Copywriter',
    goal='Write a structured, engaging article based ONLY on the provided research.',
    backstory='You are an award-winning writer. You take dry, raw technical data and synthesize it into clear, storytelling blog posts.',
    verbose=True,
    allow_delegation=False,
    llm=llm
)

editor = Agent(
    role='Chief SEO Editor',
    goal='Critique drafts, verify SEO standards, and confirm readability.',
    backstory='You are an editor with an eye for detail. If a draft doesn\'t include subheadings or fails keyword requirements, you send it back with clear directions.',
    verbose=True,
    allow_delegation=True, # Allows editor to talk back to the writer
    llm=llm
)

# 2. Define Tasks
research_task = Task(
    description='Research the topic: "The Impact of Quantum Computing on Cybersecurity in 2026". Collect 5 key facts and statistics.',
    expected_output='A markdown list of 5 verified facts with citations.',
    agent=researcher
)

write_task = Task(
    description='Using the researched facts, write a 500-word blog post. Organize with subheadings.',
    expected_output='A complete, beautifully formatted markdown draft blog post.',
    agent=writer
)

edit_task = Task(
    description='Audit the written blog post. Ensure it is at least 400 words, contains subheadings, and incorporates keyword "cybersecurity". If it fails, delegate back to writer to fix.',
    expected_output='A finalized, proofread blog post ready for publishing.',
    agent=editor
)

# 3. Assemble the Crew
tech_crew = Crew(
    agents=[researcher, writer, editor],
    tasks=[research_task, write_task, edit_task],
    process=Process.sequential, # Tasks execute one after the other
    verbose=True
)

# 4. Kick off the team!
result = tech_crew.kickoff()
print("########## TEAM OUTPUT ##########")
print(result)
```

How CrewAI Orchestrates This


In this sequential layout, `tech_crew.kickoff()` fires first the `research_task`. Under the hood, CrewAI formats the researcher's goal and backstory into a system message, invokes the search tool, collects the markdown list, and prepends it to the `write_task` context. The writer reads the prompt, drafts the content, and passes it to the editor. The editor evaluates it and, using the `allow_delegation` flag, can message the writer if changes are needed.



Implementation 2: Building with LangGraph


If you want absolute control over the flow, inputs, outputs, and routing, you should build a State Machine in LangGraph.


Step 1: Install Dependencies
pip install langgraph langchain-core langchain-openai
Step 2: Write the Python Code
Create a file named `graph_team.py`:

import os
from typing import TypedDict, List
from langchain_openai import ChatOpenAI
from langchain_core.messages import BaseMessage, HumanMessage, SystemMessage
from langgraph.graph import StateGraph, END

# Set up API keys
os.environ["OPENAI_API_KEY"] = "your-openai-api-key"
model = ChatOpenAI(model="gpt-4o-mini", temperature=0.2)

# 1. Define the Shared State Schema
# Every node in the graph reads from and writes to this State object.
class AgentState(TypedDict):
    topic: str
    research_notes: str
    draft: str
    editor_feedback: str
    revision_count: int
    final_output: str

# 2. Define the Nodes (The functions representing our Agents)
def researcher_node(state: AgentState):
    print("[Researcher] Gathering facts...")
    prompt = f"Find 3 key facts about the topic: {state['topic']}. Provide a summarized markdown bulleted list."
    response = model.invoke([HumanMessage(content=prompt)])
    return {
        "research_notes": response.content,
        "revision_count": 0
    }

def writer_node(state: AgentState):
    print(f"[Writer] Drafting post (Revision {state.get('revision_count', 0) + 1})...")
    
    # Construct prompt with research facts and feedback if it exists
    feedback_context = f"\nEditor Feedback to address:\n{state['editor_feedback']}" if state.get('editor_feedback') else ""
    prompt = f"""
    Write a 300-word blog post on the topic: '{state['topic']}' 
    using these facts:
    {state['research_notes']}
    {feedback_context}
    
    Ensure you include the word 'cybersecurity' and use clean markdown subheadings.
    """
    response = model.invoke([HumanMessage(content=prompt)])
    return {
        "draft": response.content,
        "revision_count": state.get('revision_count', 0) + 1
    }

def editor_node(state: AgentState):
    print("[Editor] Critiquing draft...")
    prompt = f"""
    Analyze the following blog draft:
    ---
    {state['draft']}
    ---
    
    You must check for two criteria:
    1. Does it contain the word 'cybersecurity'?
    2. Is it at least 250 words?
    
    Respond in JSON format with two keys:
    'status': 'APPROVED' or 'REJECTED'
    'feedback': 'Your detailed critique if rejected, or empty string if approved.'
    """
    response = model.invoke([SystemMessage(content="You are a strict editor. Output JSON only."), HumanMessage(content=prompt)])
    
    # Parse the LLM evaluation (simple JSON parse or regex fallback)
    import json
    import re
    cleaned_res = re.search(r'\{.\}', response.content, re.DOTALL).group(0)
    eval_data = json.loads(cleaned_res)
    
    return {
        "editor_feedback": eval_data.get('feedback', ''),
        "final_output": state['draft'] if eval_data.get('status') == 'APPROVED' else ""
    }

# 3. Define the Router Edge (Decision logic)
# This dictates whether we route to the Writer or to the END node.
def route_after_edit(state: AgentState):
    if state["final_output"]:
        print("[Editor] Draft approved!")
        return "approved"
    
    # Guard against infinite loops (limit revisions to 3)
    if state.get("revision_count", 0) >= 3:
        print("[System] Max revisions reached. Stopping.")
        return "max_revisions"
        
    print(f"[Editor] Draft rejected. Feedback: {state['editor_feedback']}")
    return "rejected"

# 4. Build the StateGraph
workflow = StateGraph(AgentState)

# Add Nodes
workflow.add_node("Researcher", researcher_node)
workflow.add_node("Writer", writer_node)
workflow.add_node("Editor", editor_node)

# Connect Edges
workflow.set_entry_point("Researcher")
workflow.add_edge("Researcher", "Writer")
workflow.add_edge("Writer", "Editor")

# Add Conditional Edges from the Editor Node
workflow.add_conditional_edges(
    "Editor",
    route_after_edit,
    {
        "approved": END,
        "rejected": "Writer",       # Loop back to writer!
        "max_revisions": END
    }
)

# Compile Graph
app = workflow.compile()

# 5. Run the Graph Team
initial_input = {"topic": "The Impact of Quantum Computing on Cybersecurity in 2026"}
final_state = app.invoke(initial_input)

print("\n########## FINAL PUBLISHED POST ##########")
print(final_state["draft"])

Why the LangGraph Design is Powerful

1. Explicit State: Every state change (updating `revision_count`, saving `editor_feedback`) is typed and predictable. There is no guessing.

2. Deterministic Cycles: Unlike CrewAI where the model decides when to talk back, here the routing code (`route_after_edit`) decides. This prevents token runaway by enforcing a `max_revisions` limit.

3. Save Points (Checkpoints): You can pause execution after `editor_node`, inspect `editor_feedback`, and wait for a human to hit "Approve" before routing back to the writer. This is called Human-in-the-Loop.



Production Patterns: Making Teams Reliable


Building a local script is the first step. Moving a multi-agent team to a production environment (like a customer support dashboard or automated content generator) introduces several engineering hurdles.


1. Stopping Infinite Loops (The Runaway Agent)


It is remarkably easy for two agents to get stuck in an feedback loop.


- Writer writes draft -> Editor rejects it for spelling -> Writer rewrites it but makes a spacing error -> Editor rejects it again.


If you don't limit this, the agents will cycle continuously, costing hundreds of dollars in API tokens in minutes.


- The Safeguard: Always track a counter (like `revision_count` in our LangGraph example) inside your shared state. Set a hard limit (e.g., 3 revisions). If reached, either drop out, fallback to a simpler task, or alert a human supervisor.


2. State Isolation vs. Shared Memory


Should every agent see the entire conversation history?


- If Agent A searches the web and reads a 5,000-word page, sending that entire page content to Agent B and Agent C will balloon your context window and spike costs.

- The Safeguard: Only pass the synthesized results between agents. Use a typed state object to restrict what data flows down the line. Let the Researcher store a summarized `research_notes` string, rather than passing the raw HTML transcripts.


3. Human-in-the-Loop (HITL) Checkpoints


For business-critical tasks (such as sending emails to customers or executing database writes), you should never rely 100% on autonomous agents.

- The Safeguard: Use LangGraph’s native checkpointing system. When the graph hits a critical edge:

1. Save the state of the graph to a database (e.g., PostgreSQL).

2. Send a notification (Slack, Email) to a human reviewer with a UI dashboard showing the draft.

3. Pause the thread.

4. Once the human clicks "Approve" or edits the text, update the state database and resume execution where the graph left off.


4. Model Tiering for Cost Optimization


Using high-tier models (like GPT-4o or Claude 3.5 Sonnet) for every node in your graph is expensive.

- The Safeguard: Assign cheaper, faster models (like `gpt-4o-mini` or Claude 3 Haiku) to low-cognitive tasks like extracting bullet points or verifying simple criteria. Save the premium reasoning models for complex synthesis, planning, or editing tasks.



Observability: Peeking Inside the Black Box


When a multi-agent team fails, it fails silently. You will simply get a final output that is garbage, without knowing which agent made the initial mistake. To debug agent systems, you need specialized tracing tools:

LangSmith: Specifically designed for LangChain and LangGraph. It visualizes the entire execution graph tree. You can click on any node, see the raw prompt sent to the LLM, view the exact JSON payload returned, inspect tool calls, and analyze latency.

Phoenix / Arize: Open-source LLM tracing platforms that integrate via OpenTelemetry.

OpenLLMetry: A tool to monitor token usage and tracing in microservice architectures. Before launching your system, integrate a tracing tool by adding its configuration variables to your environment setup. This is equivalent to having a debugger attached to your multi-agent team.


Conclusion & Next Steps


Building a multi-agent team shifts your mindset from Prompt Engineering to Software Engineering. You are no longer trying to craft the perfect sentences to make a single model behave. Instead, you are building a software program where LLMs act as micro-decisions engines linked by standard routing logic, code-based guardrails, and persistent databases. If you are starting out:

1. Start with CrewAI to quickly validate your ideas. Define a basic 2-agent sequential crew to see if the LLMs can handle the collaboration.

2. Once you need to implement cycles, strict routing, human approvals, or cost optimizations, refactor your team into a stateful LangGraph structure.

3. Integrate tracing from Day 1 to inspect how your agents think, and prevent runaway loops by locking down your state boundaries. Multi-agent architecture is the key to unlocking true enterprise value from AI. Start dividing tasks, specialize your workers, and build system nodes that run predictably.



Explore More about AI Agents from Codersarts


If you enjoyed mastering AI orchestration and want to dive deeper into production-ready LLM pipelines, autonomous agents, and advanced retrieval architectures, explore our latest engineering guides:




Ready to Build Production-Grade AI Agents?


At Codersarts, we help startups and enterprises bridge the gap between fragile AI prototypes and resilient, deterministic visual automation. Whether you are looking to deploy secure, self-hosted workflows or scale cognitive agent architectures, our team can help you build reliable systems engineered for real-world scale.


What We Can Build Together:


  • Enterprise AI Agents: Custom visual workflows that seamlessly integrate cognitive LLM reasoning with your existing enterprise software (CRMs, ERPs, and internal databases).

  • Deterministic Tool Engineering: Designing robust n8n sub-workflows for data mutation, calendar management, and multi-step transactional logic.

  • Voice & Omnichannel Agents: Powering telephone and messaging lines by connecting n8n to voice engines like Vapi, Retell, or Bland AI.

  • On-Premise & HIPAA-Compliant AI: Self-hosted n8n infrastructure paired with open-source LLMs (via Ollama/vLLM) to ensure absolute data privacy and compliance.

  • Advanced RAG Pipelines: Custom chunking strategy optimization, vector database schema design (Supabase, Pinecone, Qdrant), and reranking integration.


From visual canvas prototyping to enterprise-scale deployment—we build AI systems that don't just chat, but act.


Explore more AI engineering insights and projects at: https://www.codersarts.com or connect with the Codersarts team to build your next AI solution.






 
 
 

Comments


bottom of page