Most "AI SDR" tools are just spray-and-pray email blasters with a language model bolted on. They burn your domain reputation and annoy prospects.
A real AI SDR agent is different. It's a system that researches a lead, decides whether they're worth contacting, writes something a human would actually reply to, handles the back-and-forth, and drops a booked meeting on your calendar. All while you're asleep.
Here's how to build one that works.
The architecture
An AI SDR isn't one prompt. It's a pipeline of specialized steps, each with a single job:
- Enrichment - turn a name and company into context.
- Qualification - score the lead and kill the bad fits.
- Message generation - write a personalized first touch.
- Send + track - deliver and watch for replies.
- Reply handling - classify intent and respond.
- Booking - hand off to a calendar link when there's interest.
Treat each as a discrete function. This makes the agent debuggable and stops the LLM from hallucinating its way through five jobs at once.
Step 1: Enrich before you write anything
Bad personalization is worse than none. "I noticed you work at [Company]" fools no one. You need real signals: recent funding, a job posting, a tech stack change, a LinkedIn post.
def enrich_lead(lead):
company = lead["company_domain"]
signals = {
"funding": get_funding_news(company),
"hiring": get_open_roles(company),
"tech_stack": detect_tech(company),
"recent_posts": get_linkedin_activity(lead["linkedin"]),
}
# Drop empty signals so the model doesn't invent them
return {k: v for k, v in signals.items() if v}
Feed only real signals into the prompt. If enrichment returns nothing meaningful, the lead shouldn't get a personalized line at all - fall back to a segment-level angle instead of faking specificity.
Step 2: Qualify ruthlessly
Your AI SDR's value isn't sending more email. It's sending fewer, better emails to people who might buy. Use the LLM as a judgment layer.
def qualify(lead, signals, icp):
prompt = f"""
Ideal customer profile: {icp}
Lead: {lead['title']} at {lead['company']}
Signals: {signals}
Score 0-100 for fit. Return JSON:
{{"score": int, "reason": str, "angle": str}}
Be strict. Score below 40 if the title or company size is off.
"""
result = call_llm(prompt, json_mode=True)
return result
Anything under your threshold gets discarded or routed to a nurture list. The angle field becomes the hook for the message - the single most relevant reason to reach out.
Step 3: Write like a human, not a template
The first email has one job: earn a reply. Keep it short, reference one real signal, and make the ask tiny.
def write_email(lead, angle):
prompt = f"""
Write a cold email to {lead['first_name']}, {lead['title']}.
Hook: {angle}
Rules:
- Under 90 words
- No corporate jargon, no "I hope this finds you well"
- One specific observation, one clear value point
- End with a soft question, not a hard pitch
- Sound like a founder, not a marketing team
"""
return call_llm(prompt)
Run the output through a quick quality gate: reject anything with "synergy," "revolutionize," or more than one exclamation mark. Small guardrails keep the model honest.
Step 4: Handle the reply - this is where the money is
Anyone can automate sending. The agent earns its keep by managing responses without a human in the loop. Classify every reply first:
def classify_reply(text):
prompt = f"""
Classify this email reply into one:
INTERESTED, NOT_NOW, OBJECTION, WRONG_PERSON, UNSUBSCRIBE
Reply: "{text}"
Return only the label.
"""
return call_llm(prompt).strip()
HANDLERS = {
"INTERESTED": send_booking_link,
"OBJECTION": handle_objection,
"NOT_NOW": schedule_followup,
"WRONG_PERSON": ask_for_referral,
"UNSUBSCRIBE": mark_suppressed,
}
def process(reply):
HANDLERS[classify_reply(reply.text)](reply)
When intent is positive, the agent offers times immediately - either by proposing slots from a calendar API or dropping a scheduling link. No lag, no "a rep will get back to you." The gap between interest and booking is where deals die.
Step 5: Close the loop with booking
Wire the INTERESTED path to your calendar. Use a Cal.com or Google Calendar API to fetch open slots and confirm the meeting programmatically, then write it to your CRM so a human takes over prepared, not cold.
def send_booking_link(reply):
slots = get_open_slots(days=5)
msg = draft_scheduling_email(reply.lead, slots)
send(reply.lead, msg)
crm.update(reply.lead, stage="meeting_pending")
Guardrails that keep you out of the spam folder
- Rate limits. Warm up domains. Cap sends per mailbox per day (start at 30-40).
- Suppression list. Never re-contact opt-outs or existing customers.
- Human review queue. Route ambiguous or high-value replies to a person.
- Kill switch. If bounce rate spikes, pause automatically.
The realistic picture
An AI SDR won't replace your best closer. It replaces the tedious top of the funnel - research, first touch, follow-up, and initial qualification - so humans spend their time on live conversations instead of copy-pasting.
Built right, it runs overnight and hands you a calendar full of qualified meetings by morning. Built lazily, it's a reputation-destroying spam cannon.
The difference is entirely in the qualification and reply-handling layers. Send less. Respond fast. Let judgment, not volume, do the work.
Originally published at getmichaelai.com
Top comments (0)