Autonomous AI AgentsModule 5

5.3Capstone: Deploy a Multi-Agent Business Automation

40 min 10 code blocks Practice Lab Quiz (4Q)

Capstone: Deploy a Multi-Agent Business Automation

Yeh final lesson hai, bhai. Ab tak tumne agents banana seekha, frameworks master kiye, aur production patterns samjhe. Ab sab kuch ek real-world multi-agent system mein combine karo jo tumhara business automate kare — 24/7, bina tumhare intervention ke. This capstone walks you through building, connecting, deploying, and monitoring a 5-agent lead processing pipeline.

The Capstone Challenge

Build a multi-agent system that handles a complete business workflow:

code
Lead comes in → Agent qualifies it → Agent researches the company
→ Agent drafts a personalized email → Agent schedules follow-up
→ Agent reports results

FIVE AGENTS, ONE PIPELINE:

[Google Sheet]                    [SMTP + CRM]
     │                                 ▲
     ▼                                 │
┌──────────┐  ┌──────────┐  ┌──────────┐  ┌──────────┐  ┌──────────┐
│ Agent 1   │→│ Agent 2   │→│ Agent 3   │→│ Agent 4   │→│ Agent 5   │
│ Lead      │  │ Company   │  │ Email     │  │ Send &    │  │ Weekly    │
│ Intake    │  │ Research  │  │ Drafter   │  │ Schedule  │  │ Reporter  │
│           │  │           │  │           │  │           │  │           │
│ Gemini    │  │ Claude    │  │ Claude    │  │ Python    │  │ Gemini    │
│ Flash     │  │ Haiku     │  │ Sonnet    │  │ + SMTP    │  │ Flash     │
│           │  │           │  │           │  │           │  │           │
│ ~$0.00    │  │ ~$0.001   │  │ ~$0.005   │  │ Free      │  │ ~$0.001   │
│ per lead  │  │ per lead  │  │ per lead  │  │           │  │ per week  │
└──────────┘  └──────────┘  └──────────┘  └──────────┘  └──────────┘

System Architecture in Detail

Agent 1 — Lead Intake (Gemini Flash)

Monitors a Google Sheet or webhook for new leads. Validates and normalizes the data.

python
# agents/lead_intake.py
import gspread
from google.oauth2.service_account import Credentials
from google import genai

class LeadIntakeAgent:
    """Watches Google Sheet for new leads, validates them."""

    def __init__(self, sheet_id, gemini_key):
        self.client = genai.Client(api_key=gemini_key)
        creds = Credentials.from_service_account_file("credentials.json")
        self.gc = gspread.authorize(creds)
        self.sheet = self.gc.open_by_key(sheet_id).sheet1

    def get_new_leads(self):
        """Fetch rows where 'status' column is empty."""
        records = self.sheet.get_all_records()
        return [r for r in records if not r.get("status")]

    def validate_lead(self, lead):
        """Use Gemini Flash to validate and normalize lead data."""
        prompt = f"""Validate this business lead:
Name: {lead.get('name')}
Company: {lead.get('company')}
Email: {lead.get('email')}
Website: {lead.get('website')}

Check:
1. Is the email format valid?
2. Does the company name seem real?
3. Extract the industry if possible.
Return JSON: {{"valid": true/false, "email_valid": true/false,
"industry": "...", "issues": []}}"""

        response = self.client.models.generate_content(
            model="gemini-2.5-flash",
            contents=prompt
        )
        return response.text

    def process(self):
        leads = self.get_new_leads()
        validated = []
        for lead in leads:
            result = self.validate_lead(lead)
            if result.get("valid"):
                validated.append({**lead, **result})
                self.update_status(lead["row"], "validated")
        return validated

Agent 2 — Company Researcher (Claude Haiku)

Takes validated leads and builds company profiles using web data.

python
# agents/researcher.py
import anthropic
import requests

class CompanyResearchAgent:
    """Researches companies and builds profiles for email personalization."""

    def __init__(self, claude_key):
        self.client = anthropic.Anthropic(api_key=claude_key)

    def research(self, lead):
        """Build a company profile from available data."""
        # Fetch website content (basic scrape)
        website_text = self._fetch_website(lead["website"])

        prompt = f"""Research this company for a cold outreach campaign:

Company: {lead['company']}
Website: {lead['website']}
Industry: {lead.get('industry', 'Unknown')}

Website content (first 2000 chars):
{website_text[:2000]}

Build a profile with:
1. Company description (2 sentences)
2. Products/services offered
3. Estimated company size (small/medium/large)
4. 3 potential pain points we could solve
5. Technology they appear to use (from website)
6. Personalization hooks (recent news, awards, job postings)

Return JSON format."""

        response = self.client.messages.create(
            model="claude-haiku-4-5-20251001",
            max_tokens=1000,
            messages=[{"role": "user", "content": prompt}]
        )
        return response.content[0].text

    def _fetch_website(self, url):
        try:
            r = requests.get(url, timeout=10, headers={
                "User-Agent": "Mozilla/5.0"
            })
            # Strip HTML tags for plain text
            from bs4 import BeautifulSoup
            return BeautifulSoup(r.text, "html.parser").get_text()[:3000]
        except:
            return "Website unavailable"

Agent 3 — Email Drafter (Claude Sonnet)

Uses company profiles to draft personalized cold emails following the AIDA framework.

python
# agents/email_drafter.py

class EmailDrafterAgent:
    """Drafts personalized cold emails using company research."""

    AIDA_PROMPT = """Write a cold email using the AIDA framework:

RECIPIENT:
Name: {name}
Company: {company}
Industry: {industry}

COMPANY PROFILE:
{profile}

SENDER:
We offer: {services}
Our value: {value_prop}

REQUIREMENTS:
- Attention: Open with a specific insight about THEIR company (not generic)
- Interest: Connect their pain point to our solution
- Desire: Include a brief case study or result (if available)
- Action: Clear, low-friction CTA (15-min call, not "buy now")
- Length: Under 150 words (busy executives don't read novels)
- Tone: Professional but warm (not corporate robot)
- Subject line: Under 50 chars, curiosity-driven

Return JSON:
{{"subject": "...", "body": "...", "qc_score": 1-10}}"""

    def draft(self, lead, profile):
        response = self.client.messages.create(
            model="claude-sonnet-4-6",
            max_tokens=500,
            messages=[{"role": "user", "content": self.AIDA_PROMPT.format(
                name=lead["name"], company=lead["company"],
                industry=lead.get("industry", ""),
                profile=profile,
                services="AI automation and SEO services",
                value_prop="Save 20+ hours/week with AI workflows"
            )}]
        )
        result = json.loads(response.content[0].text)

        # QC Gate: reject emails scoring below 7/10
        if result.get("qc_score", 0) < 7:
            return self.draft(lead, profile)  # Retry once
        return result

Agent 4 — Scheduler (Python + SMTP)

Sends emails and schedules follow-ups.

python
# agents/scheduler.py
import smtplib
from email.mime.text import MIMEText
from datetime import datetime, timedelta

class SchedulerAgent:
    """Sends emails via SMTP and schedules follow-ups."""

    def __init__(self, smtp_user, smtp_pass):
        self.smtp_user = smtp_user
        self.smtp_pass = smtp_pass

    def send_email(self, to_email, subject, body):
        msg = MIMEText(body, "plain")
        msg["Subject"] = subject
        msg["From"] = self.smtp_user
        msg["To"] = to_email

        with smtplib.SMTP("smtp.gmail.com", 587) as server:
            server.starttls()
            server.login(self.smtp_user, self.smtp_pass)
            server.send_message(msg)
        return True

    def schedule_followup(self, lead, days=3):
        """Log follow-up to CRM (Google Sheet) for later processing."""
        followup_date = (datetime.now() + timedelta(days=days)).isoformat()
        self.crm.append_row([
            lead["email"], lead["company"],
            followup_date, "pending_followup"
        ])

    def process(self, lead, email_data):
        sent = self.send_email(lead["email"], email_data["subject"], email_data["body"])
        if sent:
            self.log_to_crm(lead, "email_sent")
            self.schedule_followup(lead, days=3)
        return sent

Agent 5 — Report Generator (Gemini Flash)

Compiles weekly stats and sends a WhatsApp summary.

python
# agents/reporter.py

class ReportAgent:
    """Generates weekly performance reports."""

    def generate_weekly(self, stats):
        prompt = f"""Generate a weekly outreach report summary:

Period: {stats['start_date']} to {stats['end_date']}
Leads processed: {stats['leads_processed']}
Emails sent: {stats['emails_sent']}
Replies received: {stats['replies']}
Meetings booked: {stats['meetings']}
Reply rate: {stats['reply_rate']}%

Generate a brief, upbeat WhatsApp-friendly summary (under 200 words).
Include: key wins, areas to improve, and suggested actions for next week.
Format with emojis for WhatsApp readability."""

        response = self.gemini.generate_content(
            model="gemini-2.5-flash", contents=prompt
        )
        return response.text

The Orchestrator — The Brain

The orchestrator coordinates all agents, handles errors, and manages the pipeline flow.

python
# orchestrator.py
import logging
from agents.lead_intake import LeadIntakeAgent
from agents.researcher import CompanyResearchAgent
from agents.email_drafter import EmailDrafterAgent
from agents.scheduler import SchedulerAgent
from agents.reporter import ReportAgent

logging.basicConfig(level=logging.INFO)
logger = logging.getLogger("orchestrator")

class Orchestrator:
    """Coordinates the 5-agent pipeline."""

    def __init__(self, config):
        self.intake = LeadIntakeAgent(config["sheet_id"], config["gemini_key"])
        self.researcher = CompanyResearchAgent(config["claude_key"])
        self.drafter = EmailDrafterAgent(config["claude_key"])
        self.scheduler = SchedulerAgent(config["smtp_user"], config["smtp_pass"])
        self.reporter = ReportAgent(config["gemini_key"])
        self.stats = {"leads": 0, "sent": 0, "errors": 0}

    def run_pipeline(self):
        """Process all new leads through the full pipeline."""
        leads = self.intake.process()
        logger.info(f"Processing {len(leads)} new leads")

        for lead in leads:
            try:
                # Stage 1: Research
                profile = self.researcher.research(lead)
                logger.info(f"Researched: {lead['company']}")

                # Stage 2: Draft email
                email = self.drafter.draft(lead, profile)
                if email.get("qc_score", 0) < 7:
                    logger.warning(f"QC failed for {lead['company']}, skipping")
                    self.intake.update_status(lead["row"], "qc_failed")
                    continue

                # Stage 3: Send & schedule
                sent = self.scheduler.process(lead, email)
                if sent:
                    self.stats["sent"] += 1
                    self.intake.update_status(lead["row"], "email_sent")
                    logger.info(f"Email sent to {lead['email']}")

            except Exception as e:
                logger.error(f"Pipeline failed for {lead.get('company')}: {e}")
                self.stats["errors"] += 1
                self.intake.update_status(lead["row"], f"error: {str(e)[:50]}")

        self.stats["leads"] += len(leads)

    def run_weekly_report(self):
        """Generate and send weekly performance report."""
        report = self.reporter.generate_weekly(self.stats)
        # Send via WATI or WhatsApp API
        logger.info(f"Weekly report generated: {report[:100]}...")
        return report

Error Recovery Patterns

code
ERROR HANDLING RULES:

Agent 2 (Research) fails:
├── Retry once with timeout increase
├── If still fails → use basic profile (company name + website only)
├── Mark lead as "partial_research" → human can enhance later
└── NEVER block the pipeline for one failed research

Agent 3 (Email Draft) fails or QC < 7:
├── Retry with slightly modified prompt (add "be more specific")
├── Maximum 2 retries
├── If still fails → skip this lead, flag for human review
└── NEVER send an email that scored below 7/10

Agent 4 (Send) fails:
├── If SMTP error → retry after 60 seconds
├── If "too many requests" → queue for next batch
├── If invalid email → mark lead as "bad_email"
└── Track bounce rate — if > 5%, check email validation

General rules:
├── Every error is logged with timestamp + lead details
├── Errors don't crash the pipeline — they skip and continue
├── Daily error count: if > 20% of leads error → alert human
└── Weekly: review all "qc_failed" and "error" leads manually

Deployment on a VPS

Setup Guide

code
OPTION 1: Contabo VPS (PKR 1,200-1,500/month)
├── 4 vCPU, 8 GB RAM, 200 GB SSD
├── Location: EU (low latency to Google/Anthropic APIs)
├── Setup: Ubuntu 22.04, Python 3.11+

OPTION 2: DigitalOcean Droplet (PKR 1,400/month)
├── 2 vCPU, 4 GB RAM, 80 GB SSD
├── Location: Singapore (closer to Pakistan)
├── $7/month with GitHub Student Pack (free)

DEPLOYMENT STEPS:
1. SSH into VPS
2. Install Python + dependencies:
   $ apt update && apt install python3.11 python3-pip -y
   $ pip install anthropic google-genai gspread requests beautifulsoup4

3. Upload project files:
   $ scp -r business-automation/ user@vps:/home/user/

4. Set up environment variables:
   $ nano /home/user/business-automation/.env
   CLAUDE_KEY=sk-ant-...
   GEMINI_KEY=AI...
   SMTP_USER=yourbot@gmail.com
   SMTP_PASS=app-password-here

5. Create systemd service for auto-restart:
   $ sudo nano /etc/systemd/system/leadbot.service
   [Unit]
   Description=Lead Processing Bot
   After=network.target

   [Service]
   ExecStart=/usr/bin/python3 /home/user/business-automation/main.py
   Restart=always
   RestartSec=60
   User=user
   WorkingDirectory=/home/user/business-automation
   EnvironmentFile=/home/user/business-automation/.env

   [Install]
   WantedBy=multi-user.target

6. Enable and start:
   $ sudo systemctl enable leadbot
   $ sudo systemctl start leadbot

7. Set up Telegram alerts for errors:
   $ pip install python-telegram-bot
   # Add Telegram alert in orchestrator error handler

Cost Analysis for Pakistan

code
MONTHLY COSTS (100 leads/day system):

Infrastructure:
├── VPS (Contabo):                    PKR 1,500
├── Domain (optional):                PKR 200
└── Subtotal:                         PKR 1,700

AI APIs:
├── Gemini Flash (intake + reports):  Free tier
├── Claude Haiku (research):          ~$3/month = PKR 840
├── Claude Sonnet (drafting):         ~$8/month = PKR 2,240
└── Subtotal:                         PKR 3,080

Email:
├── Gmail (500/day free):             Free
├── OR SendGrid (100/day free):       Free
├── OR SendGrid paid (40K/month):     PKR 500
└── Subtotal:                         PKR 0-500

═══════════════════════════════════════════════════
TOTAL:                                PKR 4,780-5,280/month
═══════════════════════════════════════════════════

COMPARISON:
├── Human SDR (Sales Dev Rep):        PKR 50,000-80,000/month
├── Your bot:                         PKR 5,000/month
├── Savings:                          90-94%
└── Bot works 24/7, no sick days, no Eid holidays, no burnout

ROI CALCULATION:
├── If system books 2 meetings/month
├── You close 1 client at PKR 50,000
├── Monthly revenue: PKR 50,000
├── Monthly cost: PKR 5,000
└── ROI: 10x (1,000% return)

Your Deliverables

#DeliverableDescriptionVerification
1Working orchestratorCoordinates all 5 agents in sequenceRun with 5 test leads
2Error recoveryHandles failures gracefully (retry, skip, alert)Kill Agent 2 mid-run, verify pipeline continues
3Weekly reportGenerates real stats summaryRun reporter with sample data
4VPS deploymentRunning on a live server with auto-restartSSH in, verify systemd service running
5DocumentationCLAUDE.md or README explaining the systemAnother developer can understand and modify
Practice Lab

Practice Lab

Task 1: Build Agent 1 + Agent 2 Create the Lead Intake agent that reads from a Google Sheet (create a test sheet with 10 fake leads). Build the Company Researcher that takes a validated lead and returns a company profile. Connect them: Agent 1 output feeds directly into Agent 2.

Task 2: Build Agent 3 + QC Gate Create the Email Drafter with the AIDA prompt template. Implement the QC gate: if score < 7, retry once with modified prompt. Run 10 leads through and check: how many emails pass QC on first try? What's the average quality score?

Task 3: Full Pipeline Test Connect all 5 agents through the orchestrator. Run 10 test leads end-to-end. Deliberately cause errors (invalid email, unreachable website, API timeout) and verify error recovery works. Generate the weekly report from your test data.

Pakistan Case Study

Meet Hasan — runs a small digital marketing agency from Islamabad, 3-person team.

His problem: Spending 15 hours/week on lead generation manually. Googling companies, writing individual emails, following up. Could only contact 20-30 new prospects/week. Hit a ceiling at 5 clients because all his time went to prospecting instead of delivery.

His multi-agent system (built in 2 weekends):

Week 1: Built Agents 1-3 (intake, research, drafting)

  • Google Sheet as lead source (scraped company directories)
  • Claude Haiku for research, Sonnet for emails
  • QC gate: 82% of emails passed on first draft

Week 2: Built Agents 4-5 (scheduler, reporter) + deployed

  • Gmail SMTP for sending (500/day limit = more than enough)
  • Deployed on Contabo VPS (PKR 1,500/month)
  • Telegram alerts for errors and daily summary

Results after 3 months:

  • Leads processed: 100/day (was 5/day manually)
  • Emails sent: ~600/week (was 20-30/week)
  • Reply rate: 8.2% (industry average: 1-3%)
  • Meetings booked: 12/month (was 2/month)
  • New clients signed: 4 in 3 months (was 1 per quarter)
  • Revenue: PKR 200K/month → PKR 450K/month
  • Time on prospecting: 15 hours/week → 2 hours/week (reviewing replies)

Monthly bot cost: PKR 5,200 Additional monthly revenue: PKR 250,000 ROI: 4,800%

His key insight: "Mera bot 24/7 kaam karta hai. Jab main so raha hota hoon, woh leads process kar raha hota hai. Jab main client delivery pe focus karta hoon, woh naye clients la raha hota hai. Sab se badi cheez: email quality actually better hai because Claude AIDA framework consistently follow karta hai — main toh lazy ho ke generic emails bhejta tha."

Key Takeaways

  • Multi-agent systems decompose complex workflows into specialized, manageable roles
  • Use cheap models (Gemini Flash, Claude Haiku) for simple tasks — expensive models (Claude Sonnet) only where quality matters
  • The tiered model approach cuts AI costs by 80%+ while maintaining output quality
  • Error recovery is mandatory — individual agents fail, but the pipeline must survive
  • QC gates prevent bad outputs from reaching customers — never skip the quality check
  • PKR 5,000/month runs a system that replaces PKR 50,000+ of human labor (10x efficiency)
  • Deploy on a VPS with systemd for auto-restart — your bot should survive server reboots
  • Weekly reports keep you informed without requiring constant monitoring
  • The real ROI isn't cost savings — it's scaling from 20 prospects/week to 600 without hiring

Congratulations! You've completed the Autonomous Future course. You now have the skills to build AI agent systems that work while you sleep. The future belongs to those who build autonomous systems — go deploy yours.

Lesson Summary

Includes hands-on practice lab10 runnable code examples4-question knowledge check below

Multi-Agent Capstone Quiz

4 questions to test your understanding. Score 60% or higher to pass.