Multi-Agent — When Multiple Agents Work Together

Episode 5 22 min

Introduction: One Agent Is Not Enough

So far in this series, we have learned to build an Agent that thinks, uses tools, has memory, and plans. But there is a problem: some tasks are too heavy for a single Agent.

For instance, imagine building a complete application. One Agent would need to handle UI design, backend coding, testing, and deployment. It is very hard for one Agent to be an expert in all of these.

The solution? Multiple Agents, each with their own specialty, working together. Like a real team of people. This is Multi-Agent Systems.

Why Multi-Agent?

Several key reasons:

1. Specialization

An Agent that only knows coding writes better code than one that does coding, design, and management all at once. Just like in the real world: a dedicated frontend developer paired with a backend developer outperforms one person who knows both halfway.

2. Parallelization

Multiple Agents can work on different parts simultaneously. This speeds up the overall work.

3. Complexity Management

Instead of one giant prompt with 100 instructions, each Agent has one clear responsibility. Simpler, more understandable, more debuggable.

4. Reliability

If one Agent fails, others can continue the work. Like a team where if one member is sick, others compensate.

Pattern 1: Orchestrator

The most common pattern. A main Agent (Orchestrator) distributes tasks among specialist Agents and collects the results.

class OrchestratorAgent:
    def __init__(self):
        self.client = OpenAI()
        self.specialists = {
            "coder": CoderAgent(),
            "reviewer": ReviewerAgent(),
            "tester": TesterAgent(),
            "writer": DocumentationAgent(),
        }

    def solve(self, task: str) -> str:
        # 1. Analyze task and assign Agents
        plan = self._create_plan(task)

        # 2. Assign and execute
        results = {}
        for step in plan:
            agent_name = step["assigned_to"]
            agent = self.specialists[agent_name]

            # Pass context from previous steps
            context = self._get_step_context(step, results)
            result = agent.execute(step["task"], context)
            results[step["id"]] = result

            print(f"[{agent_name}] {step['task']}")
            print(f"  <- {result[:100]}...\n")

        # 3. Compile final result
        return self._compile_final(task, results)

Pattern 2: Debate

In this pattern, two or more Agents discuss and debate a topic. Each has their own perspective and tries to convince the others. The final result emerges from combining viewpoints.

This pattern is especially good for complex decision-making:

class DebateSystem:
    def __init__(self):
        self.client = OpenAI()

    def debate(self, topic: str, rounds: int = 3) -> str:
        # Two Agents with different perspectives
        agent_a_prompt = f"You are in favor of {topic}. Make strong arguments. Be logical."
        agent_b_prompt = f"You are critical of {topic}. Highlight problems and risks. Be logical."

        debate_history = []

        for round_num in range(rounds):
            # Agent A speaks
            a_response = self._agent_speak(agent_a_prompt, topic, debate_history, "A")
            debate_history.append(f"Agent A: {a_response}")

            # Agent B responds
            b_response = self._agent_speak(agent_b_prompt, topic, debate_history, "B")
            debate_history.append(f"Agent B: {b_response}")

        # Final judge
        return self._judge(topic, debate_history)
Real-world application: The Debate pattern works great for software architecture decisions. For example, one Agent advocates Microservices and another advocates Monolith — the result of their debate is a comprehensive analysis.

Pattern 3: Pipeline

Like a factory assembly line. Each Agent performs one stage of the work and passes its output to the next Agent:

class AgentPipeline:
    def __init__(self):
        self.stages = [
            ("researcher", ResearchAgent()),
            ("writer", WriterAgent()),
            ("editor", EditorAgent()),
            ("fact_checker", FactCheckAgent()),
        ]

    def run(self, initial_input: str) -> str:
        current_output = initial_input

        for stage_name, agent in self.stages:
            print(f"Stage: {stage_name}")
            current_output = agent.process(current_output)
            print(f"  Output: {current_output[:100]}...\n")

        return current_output

Example: Content production

  1. Researcher: Researches the topic
  2. Writer: Writes an article from the research
  3. Editor: Edits the article
  4. Fact Checker: Verifies the information

Pattern 4: Supervisor

Similar to Orchestrator but with an important difference: the Supervisor only guides and does quality control. Agents make their own detailed decisions.

class SupervisorAgent:
    def __init__(self):
        self.client = OpenAI()
        self.workers = {
            "analyst": AnalystAgent(),
            "developer": DeveloperAgent(),
            "qa": QAAgent(),
        }

    def manage(self, project: str) -> str:
        status = {"completed": [], "in_progress": None, "todo": []}

        # Define initial tasks
        tasks = self._plan_tasks(project)
        status["todo"] = tasks

        while status["todo"]:
            # Select next task
            task = status["todo"].pop(0)

            # Assign to appropriate Agent
            worker_name = self._assign_worker(task)
            worker = self.workers[worker_name]

            # Execute
            result = worker.execute(task)

            # Quality check
            quality_check = self._review_quality(task, result)

            if quality_check["approved"]:
                status["completed"].append({"task": task, "result": result})
                print(f"[Approved] {task[:50]}...")
            else:
                # Return for revision
                revised_task = f"{task}\n\nIssues: {quality_check['feedback']}"
                status["todo"].insert(0, revised_task)
                print(f"[Returned] {task[:50]}...")

        return self._compile_report(status["completed"])

Introduction to CrewAI

CrewAI is a Python framework for building Multi-Agent systems. The idea is simple: you define a "crew" of Agents, each with a specific role and task.

from crewai import Agent, Task, Crew

# Define Agents
researcher = Agent(
    role="Senior Researcher",
    goal="Conduct thorough and accurate research on technical topics",
    backstory="You are a researcher with 10 years of experience "
              "and high skill in finding accurate information.",
    verbose=True,
    llm="gpt-4o",
)

writer = Agent(
    role="Technical Writer",
    goal="Write clear and engaging technical content",
    backstory="You are a technical writer who can explain "
              "complex concepts simply.",
    verbose=True,
    llm="gpt-4o",
)

# Define Tasks
research_task = Task(
    description="Research {topic}. Find authoritative sources and list key points.",
    expected_output="Research report with key points and sources",
    agent=researcher,
)

writing_task = Task(
    description="Using the completed research, write a 1500-word technical article.",
    expected_output="Complete technical article",
    agent=writer,
    context=[research_task],
)

# Build Crew and run
crew = Crew(
    agents=[researcher, writer],
    tasks=[research_task, writing_task],
    verbose=True,
)

result = crew.kickoff(inputs={"topic": "RAG in Artificial Intelligence"})

Challenges of Multi-Agent Systems

1. Coordination

When multiple Agents work simultaneously, they must be coordinated. If Agent A modifies a file and Agent B also modifies the same file, you have a conflict.

2. Communication

Agents must be able to communicate with each other. What information gets exchanged? In what format? Better communication leads to better results.

3. Cost

Each Agent means additional API calls. A Multi-Agent system might cost 5 to 10 times more than a single Agent. You need to do the math.

4. Debugging

When the result is wrong, which Agent made the mistake? Debugging Multi-Agent systems is harder. Good logging is critical here.

When to Use Multi-Agent?

A simple rule:

  • Simple task (Q&A, calculation) -> One Agent is enough
  • Medium task (research + writing) -> Two-three Agent pipeline
  • Complex task (software project, comprehensive analysis) -> Orchestrator + specialist Agents
  • Decision-making (architecture, strategy) -> Debate pattern
Warning: Do not overuse Multi-Agent. If a single Agent can do the job well, there is no need for added complexity. KISS: Keep It Simple, Stupid!

The Future of Multi-Agent

Multi-Agent Systems are still in their early stages but advancing very quickly:

  • Agent Marketplaces: Places where you can find and combine ready-made Agents
  • Communication Standardization: Standard protocols for Agents to talk to each other (like MCP)
  • Self-organizing Agents: Agents that form teams and distribute tasks on their own
  • Agent Economy: An economy where Agents trade and collaborate with each other

Summary

  • Episode 1: What is an Agent — Agent vs Chatbot and the 4 core capabilities
  • Episode 2: Tool Use — when Agents can use real tools
  • Episode 3: Memory — short-term, long-term, and Vector DB
  • Episode 4: Planning — ReAct, CoT, task decomposition, Self-Reflection
  • Episode 5: Multi-Agent — when multiple Agents work together

These 5 concepts are the foundations of Agent building. By combining them, you can build Agents that truly accomplish complex tasks.

The world of Agents is changing very rapidly. Every week brings new tools, frameworks, and ideas. But if you master these foundations, you can easily learn any new tool — because they are all built on the same concepts.

Good luck!