<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Aimen Kerrour</title>
    <description>The latest articles on DEV Community by Aimen Kerrour (@kaymen99).</description>
    <link>https://dev.to/kaymen99</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F2655594%2Fe98e52de-361a-4502-ba29-c55cb6aef4a8.jpeg</url>
      <title>DEV Community: Aimen Kerrour</title>
      <link>https://dev.to/kaymen99</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/kaymen99"/>
    <language>en</language>
    <item>
      <title>I Built an AI Marketing Ads Generator with VEO3 That Creates Videos in Minutes</title>
      <dc:creator>Aimen Kerrour</dc:creator>
      <pubDate>Sun, 27 Jul 2025 12:40:31 +0000</pubDate>
      <link>https://dev.to/kaymen99/create-viral-ai-marketing-ads-for-almost-nothing-with-veo3-3o35</link>
      <guid>https://dev.to/kaymen99/create-viral-ai-marketing-ads-for-almost-nothing-with-veo3-3o35</guid>
      <description>&lt;p&gt;If you’ve been following the AI space or just scrolling through Twitter in the last couple of days, you’ve probably seen those &lt;strong&gt;Google VEO3-generated ads&lt;/strong&gt; popping up everywhere. And for good reason. These things look &lt;strong&gt;amazing&lt;/strong&gt; — and if no one told you, you’d &lt;strong&gt;never guess they were made by AI&lt;/strong&gt;. Marketing videos that used to cost &lt;strong&gt;hundreds of thousands of dollars&lt;/strong&gt; are now being made for &lt;strong&gt;literally under a dollar&lt;/strong&gt; using AI.&lt;/p&gt;

&lt;p&gt;As someone who doesn’t know much about marketing or design 😅, I was curious to see what I could come up with myself. So I built a &lt;strong&gt;simple app&lt;/strong&gt; that lets anyone start generating these AI videos in &lt;strong&gt;seconds&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;▶️ &lt;strong&gt;See the ad I generated in seconds&lt;/strong&gt; for &lt;em&gt;“Mercedes F1 Car Launch”&lt;/em&gt; — made entirely with Google VEO3. &lt;strong&gt;You won’t believe it’s AI&lt;/strong&gt;:&lt;/p&gt;

&lt;p&gt;  &lt;iframe src="https://www.youtube.com/embed/jodrXBd4DRo"&gt;
  &lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;So if you've been curious about the AI video generation space but haven't had a chance to build with it yet, this tutorial is for you 😅. I'll walk you through exactly how to built an &lt;strong&gt;AI video generation system&lt;/strong&gt; that creates professional marketing ads in minutes&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Here's what you'll learn:&lt;/strong&gt;&lt;br&gt;
• &lt;strong&gt;VEO3 prompt engineering&lt;/strong&gt; - The secret structured formats that unlock Google's VEO3 hidden potential&lt;br&gt;
• &lt;strong&gt;Cost-effective AI ad videos&lt;/strong&gt; - How to create $10,000+ quality videos for under $1 each&lt;br&gt;
• &lt;strong&gt;Automated marketing ads workflow&lt;/strong&gt; - Build your own app that generates marketing ads without the hassle&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The best part?&lt;/strong&gt; You don't need to be a video expert or have a massive budget. Just willingness to experiment with this new AI tools that are literally changing the game right now.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Let's dive in 🚀&lt;/strong&gt;&lt;/p&gt;



&lt;blockquote&gt;
&lt;p&gt;🚀 &lt;strong&gt;Want to try it out?&lt;/strong&gt; Test the live demo: &lt;a href="https://veo3-ads-generator.streamlit.app/" rel="noopener noreferrer"&gt;VEO3 Ads Generator&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;🤔 &lt;strong&gt;New to Google's VEO3 video generation?&lt;/strong&gt; Check my previous post: &lt;a href="https://dev.to/kaymen99/turn-any-topic-into-viral-ai-videos-using-googles-veo3-model-c03"&gt;Turn Any Topic into Viral AI Videos Using Google's VEO3 Model&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;


&lt;h2&gt;
  
  
  🎬 What Are These Viral VEO3 Ads?
&lt;/h2&gt;

&lt;p&gt;If you've been on Twitter lately, you've probably seen these incredibly realistic marketing videos popping up everywhere:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;IKEA furniture assembly ads that look professionally shot
&lt;iframe class="tweet-embed" id="tweet-1946530151434428639-463" src="https://platform.twitter.com/embed/Tweet.html?id=1946530151434428639"&gt;
&lt;/iframe&gt;

  // Detect dark theme
  var iframe = document.getElementById('tweet-1946530151434428639-463');
  if (document.body.className.includes('dark-theme')) {
    iframe.src = "https://platform.twitter.com/embed/Tweet.html?id=1946530151434428639&amp;amp;theme=dark"
  }



&lt;/li&gt;
&lt;li&gt;Tesla car commercials with cinematic quality
&lt;iframe class="tweet-embed" id="tweet-1947055581778563570-383" src="https://platform.twitter.com/embed/Tweet.html?id=1947055581778563570"&gt;
&lt;/iframe&gt;

  // Detect dark theme
  var iframe = document.getElementById('tweet-1947055581778563570-383');
  if (document.body.className.includes('dark-theme')) {
    iframe.src = "https://platform.twitter.com/embed/Tweet.html?id=1947055581778563570&amp;amp;theme=dark"
  }



&lt;/li&gt;
&lt;li&gt;Sneaker launch videos that rival Nike's production value
&lt;iframe class="tweet-embed" id="tweet-1947007723024928771-568" src="https://platform.twitter.com/embed/Tweet.html?id=1947007723024928771"&gt;
&lt;/iframe&gt;

  // Detect dark theme
  var iframe = document.getElementById('tweet-1947007723024928771-568');
  if (document.body.className.includes('dark-theme')) {
    iframe.src = "https://platform.twitter.com/embed/Tweet.html?id=1947007723024928771&amp;amp;theme=dark"
  }



&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;The secret?&lt;/strong&gt; These aren't traditional video productions. They're AI-generated using &lt;strong&gt;Google's VEO3&lt;/strong&gt; model, and they're created using specially formatted prompts that unlock VEO3's hidden potential.&lt;/p&gt;
&lt;h2&gt;
  
  
  🔍 The Magic Behind Structured Prompts
&lt;/h2&gt;

&lt;p&gt;What makes these ads so effective isn't just &lt;strong&gt;VEO3&lt;/strong&gt; itself - it's the &lt;strong&gt;structured prompt format&lt;/strong&gt; that creators discovered. Instead of simple text descriptions, these prompts use markup languages like YAML and JSON:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# YAML Format Example&lt;/span&gt;
&lt;span class="na"&gt;scene&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Close-up&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;of&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;hands&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;assembling&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;IKEA&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;furniture"&lt;/span&gt;
&lt;span class="na"&gt;character&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Person&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;in&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;casual&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;clothing,&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;focused&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;expression"&lt;/span&gt;
&lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Modern&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;living&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;room,&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;natural&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;lighting"&lt;/span&gt;
&lt;span class="na"&gt;camera&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Handheld,&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;intimate&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;perspective"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"scene"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Luxury car driving through mountain roads"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"character"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Confident driver, hands on steering wheel"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"lighting"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Golden hour, dramatic shadows"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"audio"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Engine purr, wind through windows"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This structured approach works because VEO3 was trained on the entire internet - and the internet runs on structured data formats like these. When you feed VEO3 a properly formatted prompt, it understands exactly what you want.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Choose Google VEO3 for Marketing Ad Generation?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Cost-effective&lt;/strong&gt;: Create professional ads for under $1 vs $10,000+ traditional production&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Speed&lt;/strong&gt;: Generate marketing videos in minutes instead of weeks&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Scalability&lt;/strong&gt;: Produce multiple video variations instantly&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Accessibility&lt;/strong&gt;: No video editing skills required - though you need to be a little creative 😅&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  🛠️ Building The Ads Video Generation
&lt;/h2&gt;

&lt;p&gt;I built a simple system that automates the entire video generation workflow. Here's how it works:&lt;/p&gt;

&lt;h3&gt;
  
  
  1️⃣ Prompt Library Management
&lt;/h3&gt;

&lt;p&gt;I started by diving deep into Twitter to collect any good prompts I could find from the community (Thanks to everyone for sharing them publicly!). There are tons of people experimenting with VEO3 designs right now, so I probably missed a lot of amazing prompts out there! &lt;/p&gt;

&lt;p&gt;To make them all work together in a standard format, I converted everything into JSON and compiled a small prompt library that we can use as reference for our ad creative generation:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Each prompt is a Python dict with structured data
&lt;/span&gt;&lt;span class="n"&gt;amazon_gamer_room&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;name&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Amazon Gamer Room Setup&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;scene&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Close-up of hands unboxing gaming gear&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;character&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Gamer in casual hoodie, excited expression&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;environment&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Modern bedroom, RGB lighting, gaming setup&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;camera&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Handheld, first-person perspective&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;lighting&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Colorful RGB ambiance, dramatic shadows&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;audio&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Unboxing sounds, excited breathing&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;📚 &lt;strong&gt;Want to see all the prompts?&lt;/strong&gt; Check out the &lt;a href="https://github.com/kaymen99/viral-ai-vids" rel="noopener noreferrer"&gt;complete VEO3 prompt library on GitHub&lt;/a&gt; - there are prompts for IKEA, Tesla, Nike, Jeep, and many more!&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  2️⃣ AI-Powered VEO3 Prompt Generation
&lt;/h3&gt;

&lt;p&gt;The core of the system is an AI agent that takes a brand brief and transforms it using inspiration from the prompt library:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;generate_veo3_video_prompt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ad_idea&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;inspiration_prompt&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;Generate a VEO3-optimized prompt based on user idea and inspiration&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;

    &lt;span class="n"&gt;system_prompt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;
    Edit a structured prompt object (JSON) based on the provided user creative idea.  

    # Instructions:
    - Adapt the inspiration prompt to the user creative direction including style, room, background, elements, motion, ending, text, keywords
    - Do not modify any part of the structure unless the user explicitly requests it.
    - Maintain original structure and intention unless asked otherwise.

    # **Output**: Your response should be in the following structure:

    {
        &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;title&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;: &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Title of the video&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;,
        &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;prompt&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;: &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Prompt for the video&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;
    }
    &lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;

    &lt;span class="n"&gt;user_message&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;
    Create a VEO3 prompt for this ad idea: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;ad_idea&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;

    Follow and get instructions directly from this prompt: 
    &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;inspiration_prompt&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;
    &lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;

    &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;ainvoke_llm&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;gpt-4.1&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;system_prompt&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;system_prompt&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;user_message&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;user_message&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;temperature&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mf"&gt;0.3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;response_format&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;VideoDetails&lt;/span&gt;  &lt;span class="c1"&gt;# Structured output
&lt;/span&gt;    &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;💡 Pro tip&lt;/strong&gt;: I use structured output to make the LLM return both the ad title and the video prompt in a consistent format:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;VideoDetails&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;TypedDict&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Annotated&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Title of the video&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="n"&gt;prompt&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Annotated&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Prompt for the video&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This ensures we always get clean, structured data that's easy to work with.&lt;/p&gt;

&lt;h3&gt;
  
  
  3️⃣ VEO3 Integration via Kie AI
&lt;/h3&gt;

&lt;p&gt;There are lots of ways to use &lt;strong&gt;Google's VEO3&lt;/strong&gt; model currently, but the best one I found is &lt;strong&gt;Kie AI&lt;/strong&gt;. They offer great pricing and don't require a subscription, so it's perfect for testing:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;start_video_generation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;prompt&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;aspect_ratio&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;16:9&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;veo3_fast&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;Submit video generation request to Kie AI&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;

    &lt;span class="n"&gt;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://api.kie.ai/v1/video/generate&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;

    &lt;span class="n"&gt;payload&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;prompt&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;prompt&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;model&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;aspect_ratio&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;aspect_ratio&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;headers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Authorization&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Bearer &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;environ&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;KIE_API_TOKEN&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Content-Type&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;application/json&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status_code&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;taskId&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nc"&gt;Exception&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Failed to start generation: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;📌 &lt;strong&gt;What we need to provide to Kie AI:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Prompt&lt;/strong&gt;: The structured video description we generated&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Model&lt;/strong&gt;: Either &lt;code&gt;veo3_fast&lt;/code&gt; (cheaper/faster) or &lt;code&gt;veo3&lt;/code&gt; (higher quality/more expensive)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Aspect ratio&lt;/strong&gt;: &lt;code&gt;16:9&lt;/code&gt; for horizontal or &lt;code&gt;9:16&lt;/code&gt; for vertical videos&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyix8kxoqwnacxo4w1ity.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyix8kxoqwnacxo4w1ity.png" alt="Google VEO3 Video generator"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  4️⃣ Automated Video Generation
&lt;/h3&gt;

&lt;p&gt;The system handles the complete workflow automatically:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;run_workflow&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;inputs&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;Complete video generation workflow&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="c1"&gt;# 1. Generate optimized prompt
&lt;/span&gt;        &lt;span class="n"&gt;video_details&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;generate_veo3_video_prompt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="n"&gt;inputs&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ad_idea&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; 
            &lt;span class="n"&gt;inputs&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;inspiration_prompt&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="c1"&gt;# 2. Submit to VEO3
&lt;/span&gt;        &lt;span class="n"&gt;taskid&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;start_video_generation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="n"&gt;video_details&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;prompt&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;inputs&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;aspect_ratio&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
            &lt;span class="n"&gt;inputs&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;model&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="c1"&gt;# 3. Wait for completion
&lt;/span&gt;        &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;wait_for_completion&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;taskid&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="c1"&gt;# 4. Log and return results
&lt;/span&gt;        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;status&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;completed&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;video_url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;response&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{}).&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;resultUrls&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[])[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;title&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;video_details&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;title&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;prompt&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;video_details&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;prompt&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;video_url&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;video_url&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="nb"&gt;Exception&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Workflow error: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nf"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  🎨 Streamlit App
&lt;/h2&gt;

&lt;p&gt;I know some people just want to test the power of the model and don't care about the code 😄, so I built a Streamlit web app that allows to get started easily, you just need to setup your API keys and you're good to go:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Streamlit app for easy video generation
&lt;/span&gt;&lt;span class="n"&gt;st&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;title&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;🎬 AI Video Generator&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# User inputs
&lt;/span&gt;&lt;span class="n"&gt;video_idea&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;st&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;text_area&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Describe your video concept:&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;selected_prompt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;st&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;selectbox&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Choose prompt inspiration:&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;prompt_options&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;aspect_ratio&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;st&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;selectbox&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Aspect ratio:&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;16:9&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;9:16&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;span class="n"&gt;model&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;st&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;selectbox&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Model:&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;veo3_fast&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;veo3&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;st&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;button&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;🎬 Generate Video&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="n"&gt;st&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;spinner&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Generating your video...&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;asyncio&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;run_workflow&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ad_idea&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;video_idea&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;inspiration_prompt&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;selected_prompt&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;prompt&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;aspect_ratio&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;aspect_ratio&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;model&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;model&lt;/span&gt;
        &lt;span class="p"&gt;}))&lt;/span&gt;

        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;st&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;success&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;✅ Video generated successfully!&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;st&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;video&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;video_url&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  💰 Cost Breakdown
&lt;/h2&gt;

&lt;p&gt;The economics are incredible:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;VEO3 Fast&lt;/strong&gt;: ~$0.40 per video (or $2 per video with the higher quality &lt;strong&gt;VEO3&lt;/strong&gt;)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;GPT-4 for prompt generation&lt;/strong&gt;: ~$0.02 per request&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Total cost per video&lt;/strong&gt;: under $0.50&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Compare this to traditional video production costs of $10,000-$100,000+ and the value proposition is obvious.&lt;/p&gt;

&lt;h2&gt;
  
  
  📊 Keeping Track of Everything
&lt;/h2&gt;

&lt;p&gt;One thing I found super helpful was that all the videos and prompts generated are automatically saved to an Excel file, so you can review them whenever you want. This creates a nice history of:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Video titles&lt;/strong&gt; and &lt;strong&gt;prompts&lt;/strong&gt; that were generated&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Direct links&lt;/strong&gt; to the video files&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Generation timestamps&lt;/strong&gt; for tracking&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Model settings&lt;/strong&gt; used (VEO3 fast vs VEO3)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Aspect ratios&lt;/strong&gt; chosen&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This way, you can easily go back and see what worked well, reuse successful prompts, or share specific videos with others. It's like having a personal library of all your AI-generated content!&lt;/p&gt;




&lt;h2&gt;
  
  
  🔗 Try It Yourself
&lt;/h2&gt;

&lt;p&gt;If you want to try it &lt;strong&gt;right now&lt;/strong&gt;, you can use the &lt;strong&gt;free app I deployed&lt;/strong&gt; here:&lt;br&gt;
👉 &lt;a href="https://veo3-ads-generator.streamlit.app/" rel="noopener noreferrer"&gt;Try AI Marketing video generation with VEO3&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;But if you prefer to check out the code and run it on your own machine, here’s how to get started:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1-&lt;/strong&gt; Clone the repository from &lt;a href="https://github.com/kaymen99/viral-ai-vids" rel="noopener noreferrer"&gt;🌐 GitHub&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2-&lt;/strong&gt; Install the required dependencies:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cd viral-ai-vids/video-ads-generation
python -m venv venv
source venv/bin/activate  # On Windows: venv\Scripts\activate
pip install -r requirements.txt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;3-&lt;/strong&gt; Create a .env file and add your API keys:&lt;/p&gt;

&lt;p&gt;First, &lt;a href="https://kie.ai" rel="noopener noreferrer"&gt;create an account on Kie AI&lt;/a&gt;. as I said before, their platform currently offers the best pricing options for accessing the VEO3 model. Once registered, generate your API key from your Kie AI dashboard.&lt;/p&gt;

&lt;p&gt;For AI models, I usually use &lt;a href="https://openrouter.ai" rel="noopener noreferrer"&gt;OpenRouter&lt;/a&gt; to access various LLMs in one place — but you can use any other provider like OpenAI, Claude, or DeepSeek, since LangChain supports them all.&lt;/p&gt;

&lt;p&gt;Now, create a .env file and add your API keys:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;KIE_API_TOKEN=your_kie_ai_token_here
OPENROUTER_API_KEY=your_openrouter_key_here  # For LLM access
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;4-&lt;/strong&gt; Run the script directly:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;python main.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;5-&lt;/strong&gt; Or if you prefer a more user-friendly interface, run the Streamlit app:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;streamlit run streamlit_app.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The app will open in your browser where you can:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;📝 Add your API keys&lt;/li&gt;
&lt;li&gt;💡 Enter your video idea&lt;/li&gt;
&lt;li&gt;🎨 Choose prompt inspiration from the library&lt;/li&gt;
&lt;li&gt;⚙️ Select VEO3 model and aspect ratio&lt;/li&gt;
&lt;li&gt;🎬 Generate professional marketing videos&lt;/li&gt;
&lt;li&gt;📥 Download the video&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fe1xc58icjaa4cd1clh3q.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fe1xc58icjaa4cd1clh3q.png" alt="Google VEO3 Marketing Ads Generator"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  🚀 What This Means for Everyone
&lt;/h2&gt;

&lt;p&gt;We're witnessing a &lt;strong&gt;massive shift&lt;/strong&gt; in content creation. The ability to create &lt;strong&gt;professional-quality video content for under a dollar&lt;/strong&gt; changes everything:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Small businesses&lt;/strong&gt; can now &lt;strong&gt;compete with major brands&lt;/strong&gt; without huge budgets&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Content creators&lt;/strong&gt; can experiment freely without &lt;strong&gt;financial constraints&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Marketing agencies&lt;/strong&gt; can scale video services without &lt;strong&gt;massive overhead&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And we're just getting started! Right now we're limited to &lt;strong&gt;8-second videos&lt;/strong&gt;, but that's temporary. The &lt;strong&gt;models are improving rapidly&lt;/strong&gt;, and the community keeps discovering &lt;strong&gt;new creative techniques&lt;/strong&gt; daily.&lt;/p&gt;

&lt;p&gt;The real exciting part? &lt;strong&gt;This is just VEO3&lt;/strong&gt;. Imagine what's coming next!&lt;/p&gt;




&lt;h2&gt;
  
  
  🎬 Ready to Get Started?
&lt;/h2&gt;

&lt;p&gt;The barrier to entry is incredibly low - just a laptop, some API credits, and curiosity. While others are still figuring out how to use these tools manually, you could be generating professional marketing videos at scale.&lt;/p&gt;

&lt;p&gt;The question isn't whether AI will transform marketing - it's whether you'll be part of that transformation from the beginning.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;What do you think about this approach? Have you experimented with Google VEO3? Share your experiences in the comments below!&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>veo3</category>
      <category>tutorial</category>
      <category>videogeneration</category>
    </item>
    <item>
      <title>Turn Any Topic into Viral AI Videos Using Google’s VEO3 model</title>
      <dc:creator>Aimen Kerrour</dc:creator>
      <pubDate>Sun, 22 Jun 2025 23:55:13 +0000</pubDate>
      <link>https://dev.to/kaymen99/turn-any-topic-into-viral-ai-videos-using-googles-veo3-model-c03</link>
      <guid>https://dev.to/kaymen99/turn-any-topic-into-viral-ai-videos-using-googles-veo3-model-c03</guid>
      <description>&lt;p&gt;I've been hearing a lot about these &lt;strong&gt;new AI video models&lt;/strong&gt; that look &lt;strong&gt;incredibly realistic&lt;/strong&gt; lately. People are actually creating entire &lt;strong&gt;TikTok channels&lt;/strong&gt; based on them, and they look &lt;strong&gt;surprisingly good&lt;/strong&gt;! I never really tried them myself, so I wanted to check them out. I decided to start with &lt;strong&gt;Google's VEO3 model&lt;/strong&gt; that everyone seems to be talking about.&lt;/p&gt;

&lt;p&gt;Instead of manually creating prompts and videos one by one, I developed an &lt;strong&gt;AI automation&lt;/strong&gt; that will take &lt;strong&gt;any topic&lt;/strong&gt; you have and turn it into &lt;strong&gt;banger videos&lt;/strong&gt;. This way, I could quickly test the model's capabilities and see if it &lt;strong&gt;lives up to the hype&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;  &lt;iframe src="https://www.youtube.com/embed/f9V1hYXRFIA"&gt;
  &lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;By the end of this tutorial, you'll learn how to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Access and use &lt;strong&gt;Google’s VEO3 model&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Craft optimized prompts for &lt;strong&gt;Google VEO3&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Turn a simple topic into high-quality &lt;strong&gt;AI videos&lt;/strong&gt;!&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let's get started! 🚀&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;🔥 &lt;strong&gt;Get Code from &lt;a href="https://github.com/kaymen99/viral-ai-vids" rel="noopener noreferrer"&gt;Github&lt;/a&gt; now!&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  🤖 What is Google VEO3?
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;VEO3&lt;/strong&gt; is Google's latest &lt;strong&gt;text-to-video AI model&lt;/strong&gt; that's been creating waves across the internet. Released just a few weeks ago, it represents a giant leap forward in &lt;strong&gt;AI-generated video quality&lt;/strong&gt;. The videos it produces look &lt;strong&gt;shockingly realistic&lt;/strong&gt;—to the point where they're often indistinguishable from actual footage at first glance.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What makes VEO3 special compared to earlier models?&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Realistic human characters&lt;/strong&gt; with natural expressions, movements, and speech patterns&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Consistent environments&lt;/strong&gt; that maintain physical properties throughout the video&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Proper lighting and physics&lt;/strong&gt; that create a believable scene&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;High-resolution output&lt;/strong&gt; with smooth motion and transitions&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The current limitation is that videos are limited to &lt;strong&gt;8 seconds&lt;/strong&gt; in length, but even within that constraint, the results are &lt;strong&gt;impressive&lt;/strong&gt;. You've probably seen some &lt;strong&gt;VEO3-generated videos&lt;/strong&gt; on social media already — those &lt;strong&gt;viral clips&lt;/strong&gt; feature &lt;strong&gt;crazy realistic characters&lt;/strong&gt; like the &lt;strong&gt;Yeti vlogger&lt;/strong&gt; look almost &lt;strong&gt;too good to be AI-generated&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Don’t take my word for it — check it out yourself:&lt;/strong&gt; 👉 &lt;a href="https://www.tiktok.com/@yetivloglife" rel="noopener noreferrer"&gt;@yetivloglife on TikTok&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9aagpbwrp3bstn4y0otp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9aagpbwrp3bstn4y0otp.png" alt="AI-generated Tiktok content"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;YEP!&lt;/strong&gt;, that’s an &lt;strong&gt;AI-generated Yeti&lt;/strong&gt; running a vlog, with over &lt;strong&gt;356K followers&lt;/strong&gt; and videos reaching &lt;strong&gt;16 million+ views&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  ⚙️ How It Works?
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1️⃣ Generate Video Ideas
&lt;/h3&gt;

&lt;p&gt;The first step in our &lt;strong&gt;automation pipeline&lt;/strong&gt; is to &lt;strong&gt;generate creative video ideas&lt;/strong&gt; from a simple &lt;strong&gt;topic input&lt;/strong&gt;.&lt;br&gt;
Instead of manually brainstorming concepts, I created an &lt;strong&gt;AI agent&lt;/strong&gt; that handles this heavy lifting. &lt;/p&gt;

&lt;p&gt;It takes a topic (like &lt;strong&gt;"Alien food critic reviewing Earth cuisine"&lt;/strong&gt;) and transforms it into &lt;strong&gt;structured, creative video concepts&lt;/strong&gt;, complete with a &lt;strong&gt;catchy caption&lt;/strong&gt; and &lt;strong&gt;environmental context&lt;/strong&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;GENERATE_IDEAS_PROMPT&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;
You are an AI designed to generate 1 immersive, realistic idea based on a user-provided topic. Your output must be formatted as a JSON array (single line) and follow all the rules below exactly.

## RULES:

- Only return 1 idea at a time.
- The user will provide a key topic (e.g. &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;urban farming,&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt; &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;arctic survival,&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt; &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;street food in Vietnam&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;).

### The Idea must:
- Be under 13 words.
- Describe an interesting and viral-worthy moment, action, or event related to the provided topic.
- Can be as surreal as you can get, doesn&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;t have to be real-world!
- Involves a character.
&lt;/span&gt;&lt;span class="gp"&gt;
...&lt;/span&gt;
&lt;span class="sh"&gt;"""&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;generate_video_ideas&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;topic&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;count&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Generating ideas for topic: &lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;topic&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;...&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;user_message&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Generate &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;count&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; creative video ideas about: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;topic&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;

    &lt;span class="c1"&gt;# Use the AI invocation function with structured output
&lt;/span&gt;    &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;ainvoke_llm&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;gpt-4.1-mini&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;system_prompt&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;GENERATE_IDEAS_PROMPT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;user_message&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;user_message&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;response_format&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;IdeasList&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;temperature&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mf"&gt;0.7&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ideas&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;strong&gt;LLM&lt;/strong&gt; returns these ideas in a structured format using Pydantic models, which makes it easy to process the results&lt;/p&gt;

&lt;p&gt;For example, when I input the topic &lt;strong&gt;"Alien food critic reviewing Earth cuisine"&lt;/strong&gt; it might generate an idea like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Idea: "Tentacled alien grimaces tasting hot sauce for first time"
Environment: "Retro diner, neon lights, zoomed close-up, documentary style"
Caption: "Alien reviewer tries Earth's spiciest sauce! 👽 #alien #foodcritic #spicyfood #tastetest"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This approach gives us a continuous stream of fresh, creative ideas that would be perfect for viral short-form videos.&lt;/p&gt;

&lt;h3&gt;
  
  
  2️⃣ Generate VEO3 Video Prompt
&lt;/h3&gt;

&lt;p&gt;Once we have a &lt;strong&gt;creative idea&lt;/strong&gt;, we need to &lt;strong&gt;transform it into a specialized prompt&lt;/strong&gt; that works well with &lt;strong&gt;VEO3&lt;/strong&gt;. This isn't as simple as passing the raw idea to the model — &lt;strong&gt;VEO3 performs best&lt;/strong&gt; with &lt;strong&gt;highly detailed&lt;/strong&gt;, &lt;strong&gt;structured prompts&lt;/strong&gt; that follow certain patterns.&lt;/p&gt;

&lt;p&gt;That's why I created another &lt;strong&gt;AI agent&lt;/strong&gt; specifically designed to &lt;strong&gt;craft optimized VEO3 prompts&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;generate_veo3_video_prompt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;idea&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;environment&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;user_message&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;
    Create a V3 prompt for this idea: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;idea&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;
    Environment context: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;environment&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;
    &lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;

    &lt;span class="c1"&gt;# Use the AI invocation function
&lt;/span&gt;    &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;ainvoke_llm&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;gpt-4.1-mini&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;system_prompt&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;GENERATE_VIDEO_SCRIPT_PROMPT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;user_message&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;user_message&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;temperature&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mf"&gt;0.7&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;GENERATE_VIDEO_SCRIPT_PROMPT&lt;/code&gt; contains detailed instructions for creating cinematic, hyper-realistic video prompts. Here's a snippet of what it tells the AI:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;## REQUIRED STRUCTURE (FILL IN THE BRACKETS BELOW):

[Scene paragraph prompt here]

- **Main character:** [description of character]
- **They say:** [insert one line of dialogue, fits the scene and mood].
- **They** [describe a physical action or subtle camera movement, e.g. pans the camera, shifts position, glances around].
- **Time of Day:** [day / night / dusk / etc.]
- **Lens:** [describe lens]
- **Audio:** (implied) [ambient sounds, e.g. lion growls, wind, distant traffic, birdsong]
- **Background:** [brief restatement of what is visible behind them]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;strong&gt;prompt engineering&lt;/strong&gt; is quite specific and follows &lt;strong&gt;patterns that work well with VEO3&lt;/strong&gt;. For example, it instructs the AI to create &lt;strong&gt;selfie-style framing&lt;/strong&gt;, include &lt;strong&gt;just one character&lt;/strong&gt; (never named), specify a &lt;strong&gt;single line of dialogue&lt;/strong&gt;, and describe &lt;strong&gt;physical actions&lt;/strong&gt; and &lt;strong&gt;camera movements&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  3️⃣ Video Generation with &lt;strong&gt;Kie AI&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;For the actual video generation, there are multiple providers out there, but in this tutorial, I'm using &lt;a href="https://kie.ai" rel="noopener noreferrer"&gt;&lt;strong&gt;Kie AI&lt;/strong&gt;&lt;/a&gt;, which offers &lt;strong&gt;pay-as-you-go access&lt;/strong&gt; to the &lt;strong&gt;VEO3 model&lt;/strong&gt; at very reasonable prices. This is perfect for testing without committing to Google's &lt;strong&gt;expensive subscription&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;Kie AI&lt;/strong&gt; API generates videos in a &lt;strong&gt;three-step process&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;📤 &lt;strong&gt;Submit&lt;/strong&gt; a request including the AI model and video prompt&lt;/li&gt;
&lt;li&gt;⏳ &lt;strong&gt;Wait&lt;/strong&gt; for the video to be generated (which can take several minutes)&lt;/li&gt;
&lt;li&gt;🔗 &lt;strong&gt;Retrieve&lt;/strong&gt; the result with the video URL&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Their &lt;a href="https://docs.kie.ai/veo3-api/generate-veo-3-video" rel="noopener noreferrer"&gt;API docs&lt;/a&gt; makes it very easy to use:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;start_video_generation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;prompt&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="c1"&gt;# Prepare the payload for VEO3
&lt;/span&gt;        &lt;span class="n"&gt;payload_json&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dumps&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;prompt&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;prompt&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;model&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;veo3&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;

        &lt;span class="c1"&gt;# Set up headers with API token
&lt;/span&gt;        &lt;span class="n"&gt;headers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Content-Type&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;application/json&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Accept&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;application/json&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Authorization&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Bearer &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getenv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;KIE_API_TOKEN&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="c1"&gt;# Make the API request
&lt;/span&gt;        &lt;span class="n"&gt;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://api.kie.ai/api/v1/veo/generate&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
        &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;payload_json&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="c1"&gt;# Extract task ID from the response
&lt;/span&gt;        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status_code&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;taskId&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;data&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{}):&lt;/span&gt;
                &lt;span class="n"&gt;task_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;data&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;taskId&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
                &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Successfully submitted to Kie AI. Task ID: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;task_id&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;task_id&lt;/span&gt;

        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Error submitting to Kie AI: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;

    &lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="nb"&gt;Exception&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Error submitting to Kie AI: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nf"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After submitting the request, we receive a request id and we need to wait for the video to be generated. &lt;strong&gt;VEO3&lt;/strong&gt; can take several minutes to render a video, so I created a wait function that periodically checks the status:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;wait_for_completion&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;task_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;timeout_minutes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;start_time&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;time&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;timeout_seconds&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;timeout_minutes&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;60&lt;/span&gt;

    &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="c1"&gt;# Check if we've exceeded the timeout
&lt;/span&gt;        &lt;span class="n"&gt;elapsed&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;time&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;start_time&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;elapsed&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;timeout_seconds&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Timeout reached after &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;elapsed&lt;/span&gt;&lt;span class="si"&gt;:&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; seconds&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;error&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Timeout reached&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;status&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;timeout&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="c1"&gt;# Get the current status
&lt;/span&gt;        &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;get_video_status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;task_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;status&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;status&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;""&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;lower&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

        &lt;span class="c1"&gt;# If completed or error, return the result
&lt;/span&gt;        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;status&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;completed&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Kie AI video generation completed successfully&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;
        &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="n"&gt;status&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;failed&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Kie AI video generation failed: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;error&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;

        &lt;span class="c1"&gt;# Wait before checking again (adjust as needed)
&lt;/span&gt;        &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;30&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Finally, once the video is generated, the &lt;strong&gt;Kie AI API&lt;/strong&gt; returns a direct URL to the generated video, which can be viewed in any browser or embedded in a website.&lt;/p&gt;

&lt;h3&gt;
  
  
  4️⃣ Save Generated Videos
&lt;/h3&gt;

&lt;p&gt;To keep track of all the videos we generate, I used a simple &lt;strong&gt;Excel sheet&lt;/strong&gt;. It includes the &lt;strong&gt;video ideas&lt;/strong&gt;, &lt;strong&gt;captions&lt;/strong&gt;, &lt;strong&gt;prompts&lt;/strong&gt;, and of course, the &lt;strong&gt;video links&lt;/strong&gt;.&lt;br&gt;
This makes it easy to &lt;strong&gt;review&lt;/strong&gt; everything later and &lt;strong&gt;share&lt;/strong&gt; the videos with others.&lt;/p&gt;

&lt;p&gt;Now that we've explained how everything works, I'm sure you want to &lt;strong&gt;test it out&lt;/strong&gt; and generate your own &lt;strong&gt;crazy ideas&lt;/strong&gt; 🤯!&lt;br&gt;
But first, let's talk quickly about the &lt;strong&gt;cost&lt;/strong&gt; 💰 of using the &lt;strong&gt;VEO3 model&lt;/strong&gt;.&lt;/p&gt;
&lt;h2&gt;
  
  
  💰 Cost of Using VEO3
&lt;/h2&gt;

&lt;p&gt;The &lt;strong&gt;VEO3 model&lt;/strong&gt; is seriously impressive and delivers &lt;strong&gt;insane outputs&lt;/strong&gt;, but all that magic usually comes with a &lt;strong&gt;hefty price tag&lt;/strong&gt; 💸.&lt;/p&gt;

&lt;p&gt;To use it directly with a &lt;strong&gt;Google account&lt;/strong&gt;, you'd need to pay a steep &lt;strong&gt;$200/month&lt;/strong&gt; subscription fee 😬.&lt;/p&gt;

&lt;p&gt;Luckily, &lt;strong&gt;Kie AI&lt;/strong&gt; is currently the &lt;strong&gt;best platform&lt;/strong&gt; for using VEO3 — offering both &lt;strong&gt;access and affordability&lt;/strong&gt;. They give you two model options:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;VEO3 Full Quality&lt;/strong&gt; — $0.25/sec → about &lt;strong&gt;$2 for an 8-second video&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;VEO3 Fast&lt;/strong&gt; — just $0.05/sec → a crazy low &lt;strong&gt;$0.40 for 8 seconds&lt;/strong&gt; 😍&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6fw2walh7ssv02gqvu3s.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6fw2walh7ssv02gqvu3s.png" alt="Google VEO3 model pricing 2025"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We’ll be using the &lt;strong&gt;VEO3 Fast&lt;/strong&gt; model — it’s perfect for &lt;strong&gt;testing, playing around&lt;/strong&gt;, and unleashing creative ideas &lt;strong&gt;without breaking the bank&lt;/strong&gt;. &lt;/p&gt;

&lt;p&gt;The quality is slightly lower than the full model, but honestly, it still looks &lt;strong&gt;really damn good&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Hopefully, as the tech continues to evolve and &lt;strong&gt;competition ramps up&lt;/strong&gt;, we’ll see even better pricing!&lt;/p&gt;
&lt;h2&gt;
  
  
  🚀 Try It Out
&lt;/h2&gt;

&lt;p&gt;If you want to try this out for yourself, here's how to get started:&lt;/p&gt;

&lt;p&gt;1- &lt;strong&gt;Clone the repository&lt;/strong&gt; from &lt;a href="https://github.com/kaymen99/viral-ai-vids" rel="noopener noreferrer"&gt;🌐 GitHub&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;2- &lt;strong&gt;Install the required dependencies:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python &lt;span class="nt"&gt;-m&lt;/span&gt; venv venv
&lt;span class="nb"&gt;source &lt;/span&gt;venv/bin/activate  &lt;span class="c"&gt;# On Windows: venv\Scripts\activate&lt;/span&gt;
pip &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-r&lt;/span&gt; requirements.txt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;3- &lt;strong&gt;Create a .env file&lt;/strong&gt; and add your API keys:&lt;/p&gt;

&lt;p&gt;First, &lt;a href="https://kie.ai" rel="noopener noreferrer"&gt;&lt;strong&gt;create an account on Kie AI&lt;/strong&gt;&lt;/a&gt;. Their platform currently offers the &lt;strong&gt;best pricing options&lt;/strong&gt; for accessing the VEO3 model. Once registered, &lt;strong&gt;generate your API key&lt;/strong&gt; from your Kie AI dashboard.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fp7lz6qkm4sge2g1b4ihb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fp7lz6qkm4sge2g1b4ihb.png" alt="Kie AI video models"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For &lt;strong&gt;AI models&lt;/strong&gt;, I usually use &lt;a href="https://openrouter.ai" rel="noopener noreferrer"&gt;&lt;strong&gt;OpenRouter&lt;/strong&gt;&lt;/a&gt; to access various LLMs in one place — but you can use any other provider like &lt;strong&gt;OpenAI&lt;/strong&gt;, &lt;strong&gt;Claude&lt;/strong&gt;, or &lt;strong&gt;DeepSeek&lt;/strong&gt;, since &lt;strong&gt;Langchain&lt;/strong&gt; supports them all.&lt;/p&gt;

&lt;p&gt;Now, create a &lt;code&gt;.env&lt;/code&gt; file and add your API keys:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;KIE_API_TOKEN=your_kie_ai_token_here
OPENROUTER_API_KEY=your_openrouter_key_here  # For LLM access
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;4- Finally, &lt;strong&gt;update the main script&lt;/strong&gt; with your &lt;strong&gt;topic of interest&lt;/strong&gt; and set the &lt;strong&gt;number of videos&lt;/strong&gt; you want to generate (start with &lt;strong&gt;1&lt;/strong&gt; to test things out):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="c1"&gt;# Change this to whatever topic you'd like to explore
&lt;/span&gt;    &lt;span class="n"&gt;topic&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Dog playing piano in a jazz club&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;  &lt;span class="c1"&gt;# Your creative topic here
&lt;/span&gt;    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;run_workflow&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;topic&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;count&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;5- &lt;strong&gt;Run the script&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python main.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The script does all the work for you — it will:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;💡 &lt;strong&gt;Generate video ideas&lt;/strong&gt; automatically&lt;/li&gt;
&lt;li&gt;✍️ &lt;strong&gt;Create VEO3 prompts&lt;/strong&gt; based on those ideas&lt;/li&gt;
&lt;li&gt;🚀 &lt;strong&gt;Submit prompts&lt;/strong&gt; to &lt;strong&gt;Kie AI video generation&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;⏳ &lt;strong&gt;Wait for the videos&lt;/strong&gt; to be generated&lt;/li&gt;
&lt;li&gt;📁 Save everything — including &lt;strong&gt;video URLs&lt;/strong&gt; — to an &lt;strong&gt;Excel file&lt;/strong&gt; (&lt;code&gt;videos.xlsx&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;🔗 &lt;strong&gt;Click the URLs&lt;/strong&gt; to view your videos in any &lt;strong&gt;web browser&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So with just a single run, you’ll get a bunch of &lt;strong&gt;high-quality VEO3 videos&lt;/strong&gt; ready to go — no back-and-forth, no wasted time.&lt;/p&gt;

&lt;p&gt;▶️ &lt;strong&gt;Here’s an example&lt;/strong&gt; I got for &lt;em&gt;“meteorologist woman chasing tornado live on air”&lt;/em&gt; — generated entirely through the automation:&lt;br&gt;
&lt;em&gt;📽️ Watch the video&lt;/em&gt; &lt;/p&gt;

&lt;p&gt;  &lt;iframe src="https://www.youtube.com/embed/WrOCl0V1C3w"&gt;
  &lt;/iframe&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  🔧 Improvements
&lt;/h2&gt;

&lt;p&gt;I found this &lt;strong&gt;AI video generation&lt;/strong&gt; field really &lt;strong&gt;fascinating&lt;/strong&gt; and plan to continue exploring it. Here are some &lt;strong&gt;improvements&lt;/strong&gt; I'm considering for future versions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Experimenting with different VEO3 model variants&lt;/strong&gt; for optimal quality/cost balance&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Adding a way to directly upload&lt;/strong&gt; the generated videos to &lt;strong&gt;YouTube or TikTok&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And who knows — maybe I’ll even &lt;strong&gt;launch my own viral channel&lt;/strong&gt; with some &lt;strong&gt;crazy, original concept&lt;/strong&gt; like the &lt;strong&gt;Yeti vlogger&lt;/strong&gt;, but with my own twist! 🔥😄&lt;/p&gt;

&lt;h2&gt;
  
  
  🌎 Use Cases
&lt;/h2&gt;

&lt;p&gt;The output from &lt;strong&gt;VEO3 model&lt;/strong&gt; is really impressive and will be huge for many applications:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Content creation&lt;/strong&gt;: Generate videos for social media, websites, and presentations&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Marketing materials&lt;/strong&gt;: Create promotional videos and advertisements&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Educational content&lt;/strong&gt;: Produce instructional and explanatory videos&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Prototyping&lt;/strong&gt;: Rapid video concept development and testing&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Creative projects&lt;/strong&gt;: Artistic and experimental video generation&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Business presentations&lt;/strong&gt;: Professional video content for meetings and pitches&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Thanks to platforms like &lt;strong&gt;Kie AI&lt;/strong&gt; offering more affordable access, we're already seeing wider adoption. Early adopters who master these tools now will have a significant advantage as the technology continues to evolve.&lt;/p&gt;

&lt;h2&gt;
  
  
  🎯 Conclusion
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Google’s VEO3&lt;/strong&gt; is a major leap in &lt;strong&gt;AI video generation&lt;/strong&gt; 🎥. The videos it produces are &lt;strong&gt;incredibly realistic&lt;/strong&gt; and open the door to a whole new level of creativity for &lt;strong&gt;content creators&lt;/strong&gt;, &lt;strong&gt;marketers&lt;/strong&gt;, &lt;strong&gt;educators&lt;/strong&gt;, and beyond.&lt;/p&gt;

&lt;p&gt;While it &lt;strong&gt;used to be&lt;/strong&gt; pretty expensive for casual use 💸, platforms like &lt;strong&gt;Kie AI&lt;/strong&gt; are making it way more accessible — especially with the &lt;strong&gt;VEO3 Fast&lt;/strong&gt; model that delivers solid quality at a &lt;strong&gt;fraction of the cost&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;automation I shared&lt;/strong&gt; makes it even easier to &lt;strong&gt;experiment with VEO3&lt;/strong&gt; — handling everything from &lt;strong&gt;idea generation&lt;/strong&gt; to &lt;strong&gt;prompt writing&lt;/strong&gt; to &lt;strong&gt;video creation&lt;/strong&gt; in one streamlined workflow ⚙️.&lt;/p&gt;

&lt;p&gt;Have you tried &lt;strong&gt;VEO3&lt;/strong&gt; or any other &lt;strong&gt;AI video tools&lt;/strong&gt;?&lt;br&gt;
💬 What kind of videos would &lt;em&gt;you&lt;/em&gt; create with this tech? Let me know in the comments!&lt;/p&gt;




&lt;p&gt;&lt;em&gt;P.S. If you found this helpful, consider following me for more AI tutorials and experiments.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>veo3</category>
      <category>ai</category>
      <category>programming</category>
      <category>videogeneration</category>
    </item>
    <item>
      <title>How to Scrape Unlimited Google Maps Leads Using AI</title>
      <dc:creator>Aimen Kerrour</dc:creator>
      <pubDate>Mon, 16 Jun 2025 12:25:50 +0000</pubDate>
      <link>https://dev.to/kaymen99/how-to-scrape-unlimited-google-maps-leads-using-ai-4kem</link>
      <guid>https://dev.to/kaymen99/how-to-scrape-unlimited-google-maps-leads-using-ai-4kem</guid>
      <description>&lt;p&gt;Finding quality leads for your business is often expensive and time-consuming. Commercial lead generation tools can cost hundreds of dollars monthly, and manual research takes forever.&lt;/p&gt;

&lt;p&gt;In this guide, I'll walk you through building an AI-powered lead generation tool that scrapes business data from Google Maps at a fraction of the cost of commercial solutions. You'll learn how to extract business information, enhance it with AI scraping, and compile everything into ready-to-use lead lists — all for about &lt;strong&gt;$0.2 per 1000 leads&lt;/strong&gt;! 💰&lt;/p&gt;

&lt;p&gt;💡 &lt;strong&gt;See it in action!&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;  &lt;iframe src="https://www.youtube.com/embed/KDyxtmfZ3Bw"&gt;
  &lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;By the end, you'll have a powerful tool to generate leads for any business niche in any location. Whether you're running a marketing agency, doing sales outreach, or conducting market research, this tool will save you both time and money.&lt;/p&gt;

&lt;p&gt;Let's dive in! 🔥&lt;/p&gt;

&lt;p&gt;💡 Access the project in my &lt;a href="https://github.com/kaymen99/google-maps-lead-generator" rel="noopener noreferrer"&gt;Github repository&lt;/a&gt; now!&lt;/p&gt;

&lt;h2&gt;
  
  
  🤔 Why Build Another Lead Generation Tool?
&lt;/h2&gt;

&lt;p&gt;When I decided to start selling AI solutions for businesses, I needed up-to-date contact information and business details to conduct a successful outreach campaign. During my first look, I immediately noticed two clear options:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Having a subscription to a database provider like &lt;strong&gt;Apollo&lt;/strong&gt; or &lt;strong&gt;Zoominfo&lt;/strong&gt;, but for me this was too expensive as most of them charge $50-300/month&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The obvious second option is &lt;strong&gt;Manual research&lt;/strong&gt; which is completely free but for a good outreach at scale, it's incredibly time-consuming&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I made some research and found some good scrapers on Apify like &lt;a href="https://apify.com/compass/google-maps-extractor" rel="noopener noreferrer"&gt;Apify's Google Maps scrapers&lt;/a&gt; or even &lt;a href="https://apify.com/code_crafter/apollo-io-scraper" rel="noopener noreferrer"&gt;Apollo Lead scraper&lt;/a&gt; which offer a pay-per-use more affordable pricing model costing from $2-10 per 1000 results.&lt;/p&gt;

&lt;p&gt;This seemed good enough for me, but when I looked at the Apify Google Maps scraper, I noticed they were using a simple logic in the background - they get business details from the Google Maps API and then crawl each business details page to get more contact information. As I had experience with the Serper API, I thought why not try to build my own local business scraper tool.&lt;/p&gt;

&lt;p&gt;That's why I created this tool — to give you:&lt;/p&gt;

&lt;p&gt;🔹 &lt;strong&gt;Comprehensive data extraction&lt;/strong&gt; - Not just names and addresses, but emails and social profiles too&lt;br&gt;
🔹 &lt;strong&gt;Cost-efficiency&lt;/strong&gt; - About $0.2 per 1000 leads (50x cheaper than alternatives!)&lt;br&gt;
🔹 &lt;strong&gt;Full customization&lt;/strong&gt; - Search any business type in any location&lt;br&gt;
🔹 &lt;strong&gt;AI-powered enhancement&lt;/strong&gt; - Uses LLMs to intelligently extract contact information or other business details&lt;br&gt;
🔹 &lt;strong&gt;Ready-to-use format&lt;/strong&gt; - Export directly to Excel for immediate use in your campaigns&lt;/p&gt;
&lt;h2&gt;
  
  
  🛠️ How The Tool Works
&lt;/h2&gt;

&lt;p&gt;Our lead generator follows a three-step process that combines traditional API calls with AI-powered data enrichment:&lt;/p&gt;
&lt;h3&gt;
  
  
  1️⃣ Initial Data Collection
&lt;/h3&gt;

&lt;p&gt;First, we use the Serper Maps API to collect basic business information from Google Maps. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgn3ndqoirzv0iotwax6s.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgn3ndqoirzv0iotwax6s.png" alt="Serper Maps API"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is handled by our &lt;code&gt;search_places&lt;/code&gt; function, which formats and sends the API request:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;search_places&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;coords&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;num_pages&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;payload&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
    &lt;span class="n"&gt;lat&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;lon&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;coords&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;lat&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;coords&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;lon&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

    &lt;span class="c1"&gt;# Create payload for each page
&lt;/span&gt;    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;page&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;num_pages&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;q&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ll&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;@&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;lat&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;,&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;lon&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;,13z&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;# Format the location string for Serper API
&lt;/span&gt;            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;page&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;page&lt;/span&gt;
        &lt;span class="p"&gt;})&lt;/span&gt;

    &lt;span class="n"&gt;headers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;X-API-KEY&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getenv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;SERPER_API_KEY&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Content-Type&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;application/json&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c1"&gt;# Send request and return results
&lt;/span&gt;    &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://google.serper.dev/maps&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
        &lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
        &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dumps&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Also as you can notice, the Serper API requires specific longitude and latitude of the place we want to search for, so we can't directly provide a city name like "New York" for example. To get around this, we use the free Nominatim API which returns the coordinates of a place/city from its name. This is done using the &lt;code&gt;get_coordinates&lt;/code&gt; function:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_coordinates&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;city&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;
    Convert a city name to latitude and longitude coordinates.

    Args:
        city (str): Name of the city to geocode

    Returns:
        tuple: (latitude, longitude) if successful, (None, None) if not
    &lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://nominatim.openstreetmap.org/search&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
            &lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;q&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;city&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;format&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;json&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt; 
            &lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;User-Agent&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;USER_AGENTS&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;]}&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;lat&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;lat&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;lon&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;lon&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]}&lt;/span&gt;
        &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;
    &lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="nb"&gt;Exception&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Error getting coordinates: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Up to this point We get the basic business data - name, address, phone number, website URL, and reviews. But we need more information for effective outreach...&lt;/p&gt;

&lt;h3&gt;
  
  
  2️⃣ AI-Powered Data Enrichment
&lt;/h3&gt;

&lt;p&gt;The real magic happens in the data enrichment phase. For each business with a website, we:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Scrape the website content using Playwright&lt;/li&gt;
&lt;li&gt;Use AI (LLMs) to extract and analyze key contact information mainly email and social media links&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Here's how the business information processing works:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;process_businesses&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;excel_file&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="c1"&gt;# Load the Excel file into a DataFrame
&lt;/span&gt;    &lt;span class="n"&gt;df&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;file_path&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;load_excel_data&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;excel_file&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# Process each business
&lt;/span&gt;    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;row&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;tqdm&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;df&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;iterrows&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;desc&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Processing businesses&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;unit&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;business&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;name&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;""&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;website&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;""&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;location&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;address&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;""&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;continue&lt;/span&gt;

        &lt;span class="c1"&gt;# Get business info
&lt;/span&gt;        &lt;span class="n"&gt;info&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;get_business_info&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;location&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="c1"&gt;# Update the business information
&lt;/span&gt;        &lt;span class="nf"&gt;update_business_data&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;df&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;info&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For each business, we extract detailed information with our AI analysis function:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_business_info&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;business_url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;business_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;business_location&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="c1"&gt;# Scrape the main website
&lt;/span&gt;    &lt;span class="n"&gt;content&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;links&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;scrape_website&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;business_url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;extract_links&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;

    &lt;span class="n"&gt;social_links&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;find_relevant_links&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;links&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;emails&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;extract_emails_from_content&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;content&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# Analyze the identified links using AI
&lt;/span&gt;    &lt;span class="n"&gt;links_result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;analyze_business_links&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;social_links&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;business_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;business_location&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;business_url&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;emails&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;emails_result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;analyze_business_emails&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="n"&gt;emails&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;business_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;business_location&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;business_url&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# If no email found but we have a contact link, try scraping that too
&lt;/span&gt;    &lt;span class="nf"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;emails&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;social_links&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;contact&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;contact_url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;social_links&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;contact&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;contact_url&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;business_url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;contact_content&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;scrape_website&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;contact_url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;extract_links&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;False&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;emails&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;extract_emails_from_content&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;contact_content&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;emails&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="c1"&gt;# Re-analyze with new emails
&lt;/span&gt;                &lt;span class="n"&gt;emails_result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;analyze_business_emails&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                    &lt;span class="n"&gt;emails&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;business_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;business_location&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;business_url&lt;/span&gt;
                &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;facebook&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;links_result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;facebook&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;''&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;twitter&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;links_result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;twitter&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;''&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;instagram&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;links_result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;instagram&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;''&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;contact&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;links_result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;contact&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;''&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;email&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt; || &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;emails_result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;emails&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;''&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;🚀 &lt;strong&gt;What this function does:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Scrape the main website page&lt;/strong&gt; to extract all &lt;strong&gt;relevant links&lt;/strong&gt; and the &lt;strong&gt;page content&lt;/strong&gt;.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Analyze the identified links using AI&lt;/strong&gt; to determine the &lt;strong&gt;correct social media&lt;/strong&gt; and &lt;strong&gt;contact links&lt;/strong&gt;. &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Extract email addresses&lt;/strong&gt; from the page content using &lt;strong&gt;regex&lt;/strong&gt;.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Analyze the extracted emails using AI&lt;/strong&gt; to identify the &lt;strong&gt;valid email addresses&lt;/strong&gt;.
&lt;/li&gt;
&lt;li&gt;If &lt;strong&gt;no email is found&lt;/strong&gt; and there's a &lt;strong&gt;contact page link&lt;/strong&gt;, &lt;strong&gt;scrape that page&lt;/strong&gt; as well and &lt;strong&gt;extract any email addresses&lt;/strong&gt; from it.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Return a dictionary&lt;/strong&gt; containing the &lt;strong&gt;social media links&lt;/strong&gt;, &lt;strong&gt;contact links&lt;/strong&gt;, and the &lt;strong&gt;email addresses&lt;/strong&gt; found.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;💡 Pro Tip&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Instead of providing the &lt;strong&gt;full scraped page content&lt;/strong&gt; to the AI, we first use &lt;strong&gt;regex&lt;/strong&gt; to extract all the &lt;strong&gt;page links&lt;/strong&gt; and &lt;strong&gt;email addresses&lt;/strong&gt;. Then we instruct an &lt;strong&gt;AI agent&lt;/strong&gt; to identify which are the &lt;strong&gt;correct social media and contact links&lt;/strong&gt;, and which are the &lt;strong&gt;valid email addresses&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;This approach helps &lt;strong&gt;save money on LLM calls&lt;/strong&gt; and provides &lt;strong&gt;more accurate results&lt;/strong&gt; by reducing the chance of &lt;strong&gt;hallucinations&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;For example, for the email extraction we use the following regex pattern to identify all email addresses within the page content:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;EMAIL_PATTERN&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;re&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;compile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;r&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;extract_emails_from_content&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;
    Extracts email addresses from content.
    &lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="n"&gt;emails&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;lower&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;email&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;EMAIL_PATTERN&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;findall&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;content&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;list&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;emails&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then we use AI analysis to intelligently find the correct email addresses that match the business:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;analyze_business_emails&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;emails&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; 
    &lt;span class="n"&gt;business_name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
    &lt;span class="n"&gt;business_location&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
    &lt;span class="n"&gt;business_url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;
&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;system_prompt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;
Identify all relevant business contact emails. Prioritize general contact addresses (such as info@ or contact@) and emails of key personnel that use the business&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;s domain. Exclude department-specific ones (e.g., press, events) unless no main contact is available.

If no domain-based business emails are found, provide any available emails, including personal or free-domain addresses (e.g., Gmail, Yahoo) as fallback contacts.

## Business Information
- Business Name: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;business_name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;
- Business Location: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;business_location&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;
- Business Website URL: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;business_url&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;

**If only a single valid email is found, just return it.**
&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;

    &lt;span class="c1"&gt;# Create user message with all the context
&lt;/span&gt;    &lt;span class="n"&gt;user_message&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Potential emails: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nf"&gt;list&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;emails&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;

    &lt;span class="c1"&gt;# Invoke LLM to get structured response
&lt;/span&gt;    &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;ainvoke_llm&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getenv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;LLM_MODEL&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;gpt-4.1-mini&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="n"&gt;system_prompt&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;system_prompt&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;user_message&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;user_message&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;response_format&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;EmailsResponse&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;temperature&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mf"&gt;0.1&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  3️⃣ Data Export &amp;amp; Organization
&lt;/h3&gt;

&lt;p&gt;Finally, all the enhanced business data is saved back to the Excel file in a clean, organized format ready for your outreach campaigns.&lt;/p&gt;

&lt;p&gt;The whole flow is orchestrated by the &lt;code&gt;main&lt;/code&gt; function:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;location&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;search_query&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;num_pages&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;🔍 Starting lead generation for &lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;search_query&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt; in &lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;location&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;'"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# Step 1: Get coordinates from location
&lt;/span&gt;    &lt;span class="n"&gt;coords&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;get_coordinates&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;location&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;coords&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Could not get coordinates for the location. Exiting.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt;

    &lt;span class="c1"&gt;# Step 2: Search for places using Serper Maps API
&lt;/span&gt;    &lt;span class="n"&gt;places_data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;search_places&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;search_query&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;coords&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;num_pages&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;places_data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;No places found. Exiting.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt;

    &lt;span class="c1"&gt;# Step 3: Save places data to Excel
&lt;/span&gt;    &lt;span class="n"&gt;excel_filename&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;data_&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;search_query&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;_&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;location&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;_&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nf"&gt;get_current_date&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;.xlsx&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="nf"&gt;save_places_to_excel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;places_data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;excel_filename&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# Step 4: Process businesses to get detailed information and update Excel file
&lt;/span&gt;    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;process_businesses&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;excel_filename&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;📌 Serper Maps API Pagination&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;When using &lt;strong&gt;Serper Maps API&lt;/strong&gt;, each page of results contains 20 places, so to extract more than 20 places, we need to use the &lt;code&gt;num_pages&lt;/code&gt; parameter to specify the number of pages to fetch. For example, if we want to extract 100 places, we can set &lt;code&gt;num_pages=5&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  🚀 Features That Set This Tool Apart
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Multi-LLM Support&lt;/strong&gt; - Using OpenRouter for LLM calls gives you the freedom to use any AI model you prefer (OpenAI, Claude, DeepSeek) through a simple interface&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Full Control and Customization&lt;/strong&gt; - By default, the tool scrapes only the landing and contact page for each business, but you can change this behavior to crawl the entire website if you want and even extract other specific business details like products or services&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  💰 Cost Breakdown
&lt;/h2&gt;

&lt;p&gt;This tool is incredibly cost-efficient:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Service&lt;/th&gt;
&lt;th&gt;Cost Per 1000 Leads&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Serper Maps API&lt;/td&gt;
&lt;td&gt;~$0.15 (with free credits!)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;LLM API (OpenAI/Claude mini)&lt;/td&gt;
&lt;td&gt;~$0.05&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Total Cost&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;~$0.20&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Compare that to Apify's Google Maps scrapers at $5-10 per 1000 results, and you're saving up to &lt;strong&gt;50x on costs&lt;/strong&gt;!&lt;/p&gt;

&lt;h2&gt;
  
  
  🛠️ Setting Up Your Own Lead Generator
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Prerequisites
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Python 3.8+ installed&lt;/li&gt;
&lt;li&gt;Serper API key (&lt;a href="https://serper.dev/" rel="noopener noreferrer"&gt;Get one here&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;OpenRouter API key (&lt;a href="https://openrouter.ai/" rel="noopener noreferrer"&gt;Get one here&lt;/a&gt;) or your preferred LLM API key&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;💡 Serper API&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;When you register for a Serper API key, you get &lt;strong&gt;2500 free credits&lt;/strong&gt;. This will allow to test without any cost.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 1: Clone the Repository
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://github.com/kaymen99/google-maps-lead-generator
&lt;span class="nb"&gt;cd &lt;/span&gt;google-maps-lead-generator
pip &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-r&lt;/span&gt; requirements.txt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 2: Set Up Your Environment Variables
&lt;/h3&gt;

&lt;p&gt;Create a &lt;code&gt;.env&lt;/code&gt; file in the project root with your API keys:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;SERPER_API_KEY="your_serper_api_key"
OPENROUTER_API_KEY="your_openrouter_api_key"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;📌 AI Model Provider&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;You are not forced to use &lt;strong&gt;OpenRouter&lt;/strong&gt;, you can use any LLM provider you want, just change the &lt;code&gt;invoke_llm&lt;/code&gt; function in &lt;code&gt;src/utils.py&lt;/code&gt; to use your preferred LLM provider.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 3: Customize and Run
&lt;/h3&gt;

&lt;p&gt;Edit the parameters in &lt;code&gt;main.py&lt;/code&gt; to specify your target location, search query, and number of pages:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;__name__&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;__main__&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;location&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Toronto&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;  &lt;span class="c1"&gt;# Change to your target location
&lt;/span&gt;    &lt;span class="n"&gt;search_query&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Realtors&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;  &lt;span class="c1"&gt;# Change to your target business type
&lt;/span&gt;    &lt;span class="n"&gt;num_pages&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;  &lt;span class="c1"&gt;# Each page contains 20 results, increase for more leads
&lt;/span&gt;
    &lt;span class="c1"&gt;# Run main function
&lt;/span&gt;    &lt;span class="n"&gt;asyncio&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;location&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;search_query&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;num_pages&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then run the script:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python main.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 4: Streamlit UI
&lt;/h3&gt;

&lt;p&gt;To make the tool more accessible for non-technical users, I've created a simple Streamlit interface. This provides a clean, user-friendly way to generate leads without needing to touch any code.&lt;/p&gt;

&lt;p&gt;To use the Streamlit app, just run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;streamlit run app.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will open a browser window with an interface that includes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A sidebar where you can set your Serper API key and OpenRouter API key&lt;/li&gt;
&lt;li&gt;Options to select which LLM model you want to use for data enrichment&lt;/li&gt;
&lt;li&gt;The main panel where you can input your location, business type, and select the number of places to scrape&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmno71jsg06f8zws0bbl2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmno71jsg06f8zws0bbl2.png" alt="Google Maps Scraper UI"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After configuring your settings and clicking "Start Lead Generation", the tool will collect and enrich the data. When complete, you'll see a preview of the results and have the option to download the Excel file.&lt;/p&gt;

&lt;h2&gt;
  
  
  🌍 Real-World Use Cases
&lt;/h2&gt;

&lt;p&gt;This tool is perfect for:&lt;/p&gt;

&lt;p&gt;🔹 &lt;strong&gt;Sales Teams&lt;/strong&gt; - Generate qualified lead lists for targeted outreach&lt;br&gt;
🔹 &lt;strong&gt;Real Estate Agents&lt;/strong&gt; - Find property managers, contractors, or competing agents&lt;br&gt;
🔹 &lt;strong&gt;Marketing Agencies&lt;/strong&gt; - Build prospect lists for client acquisition&lt;br&gt;
🔹 &lt;strong&gt;Recruiters&lt;/strong&gt; - Identify potential companies to place candidates&lt;br&gt;
🔹 &lt;strong&gt;Market Researchers&lt;/strong&gt; - Analyze business density and distribution in specific areas&lt;/p&gt;

&lt;h2&gt;
  
  
  🎯 Final Thoughts
&lt;/h2&gt;

&lt;p&gt;Building your own lead generation tool gives you complete control over the process and drastically reduces costs. The combination of Serper Maps API and AI-powered enrichment provides a powerful, flexible solution that can adapt to your specific needs.&lt;/p&gt;

&lt;p&gt;I'd love to hear how you use this tool and what enhancements you'd like to see! Feel free to contribute to the project on GitHub or reach out with questions.&lt;/p&gt;

&lt;p&gt;💡 &lt;strong&gt;Want to learn more?&lt;/strong&gt; Follow my &lt;a href="https://dev.to/kaymen99"&gt;blog&lt;/a&gt; and check out my &lt;a href="https://github.com/kaymen99" rel="noopener noreferrer"&gt;Github&lt;/a&gt; for more AI project &amp;amp; tutorials!&lt;/p&gt;

&lt;p&gt;📖 &lt;strong&gt;Interested in AI scraping?&lt;/strong&gt; Check out my other tutorial: &lt;a href="https://dev.to/kaymen99/scrape-any-website-fast-and-cheap-with-crawl4ai-3fj1"&gt;Scrape Any Website Fast and Cheap with Crawl4AI&lt;/a&gt; to learn how to build your own custom scrapers in minutes!&lt;/p&gt;

&lt;p&gt;Happy lead hunting! 🚀&lt;/p&gt;

</description>
      <category>ai</category>
      <category>webscraping</category>
      <category>python</category>
      <category>llm</category>
    </item>
    <item>
      <title>AI Web Scraping Without Limits—Scrape Anything using Crawl4AI</title>
      <dc:creator>Aimen Kerrour</dc:creator>
      <pubDate>Tue, 11 Feb 2025 00:46:15 +0000</pubDate>
      <link>https://dev.to/kaymen99/scrape-any-website-fast-and-cheap-with-crawl4ai-3fj1</link>
      <guid>https://dev.to/kaymen99/scrape-any-website-fast-and-cheap-with-crawl4ai-3fj1</guid>
      <description>&lt;p&gt;&lt;strong&gt;Web scraping&lt;/strong&gt; is one of the most in-demand skills in AI and tech today. Companies are actively seeking professionals who can extract valuable data efficiently.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F54vb18mqu5589cesraq7.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F54vb18mqu5589cesraq7.jpg" alt="Web scraping" width="300" height="163"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In this guide, I’ll walk you through building an &lt;strong&gt;AI-powered web scraper&lt;/strong&gt; using &lt;strong&gt;Crawl4AI&lt;/strong&gt;, leveraging &lt;strong&gt;LLMs&lt;/strong&gt; to intelligently extract and process structured data from any website—whether you’re &lt;strong&gt;scraping leads, gathering research data, or building a custom dataset&lt;/strong&gt;, this will save you &lt;strong&gt;time and effort&lt;/strong&gt; ⏳.&lt;/p&gt;

&lt;p&gt;By the end, you’ll have a fully functional web scraper that can &lt;strong&gt;extract leads from&lt;/strong&gt; &lt;a href="https://www.yellowpages.ca/" rel="noopener noreferrer"&gt;&lt;strong&gt;YellowPages&lt;/strong&gt;&lt;/a&gt;, &lt;strong&gt;process them with AI&lt;/strong&gt;, and &lt;strong&gt;save the results to a CSV file&lt;/strong&gt;—all with minimal effort. &lt;/p&gt;

&lt;p&gt;And the best part? &lt;strong&gt;It costs practically nothing to run!&lt;/strong&gt; 💡&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Let’s dive in!&lt;/strong&gt; 🔥&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;💡 Access the project in my &lt;a href="https://github.com/kaymen99/llm-web-scraper" rel="noopener noreferrer"&gt;Github repository&lt;/a&gt; now!&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  🤖 &lt;strong&gt;What is Crawl4AI?&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Web scraping has come a long way, and &lt;a href="https://docs.crawl4ai.com/" rel="noopener noreferrer"&gt;&lt;strong&gt;Crawl4AI&lt;/strong&gt;&lt;/a&gt; is here to take it to the next level⚡&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Crawl4AI&lt;/strong&gt; is an &lt;strong&gt;open-source web crawling and scraping framework&lt;/strong&gt; designed for &lt;strong&gt;speed, scalability, and seamless integration with LLMs&lt;/strong&gt; (e.g., &lt;strong&gt;GPT-4o, Claude&lt;/strong&gt;). It combines &lt;strong&gt;traditional scraping methods&lt;/strong&gt; with &lt;strong&gt;AI-driven data extraction&lt;/strong&gt;, making it ideal for &lt;strong&gt;data pipelines, automation workflows, and AI agents&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F443p1p90arohdzodh7az.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F443p1p90arohdzodh7az.png" alt="Crawl4AI github repository" width="800" height="380"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  🔑 &lt;strong&gt;Key Features&lt;/strong&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;✅ &lt;strong&gt;LLM-Friendly Output&lt;/strong&gt; – Generates &lt;strong&gt;clean Markdown-formatted data&lt;/strong&gt;, perfect for &lt;strong&gt;retrieval-augmented generation (RAG)&lt;/strong&gt; and direct ingestion into LLMs.
&lt;/li&gt;
&lt;li&gt;✅ &lt;strong&gt;Smart Data Extraction&lt;/strong&gt; – Combines &lt;strong&gt;AI-powered parsing&lt;/strong&gt; with &lt;strong&gt;traditional methods&lt;/strong&gt; (&lt;strong&gt;CSS, XPath&lt;/strong&gt;) for maximum versatility.
&lt;/li&gt;
&lt;li&gt;✅ &lt;strong&gt;Advanced Browser Control&lt;/strong&gt; – Handles &lt;strong&gt;JavaScript-heavy websites&lt;/strong&gt; with &lt;strong&gt;proxy support, session management, and stealth scraping&lt;/strong&gt;.
&lt;/li&gt;
&lt;li&gt;✅ &lt;strong&gt;High Performance&lt;/strong&gt; – Supports &lt;strong&gt;parallel crawling&lt;/strong&gt; and &lt;strong&gt;chunk-based extraction&lt;/strong&gt; for &lt;strong&gt;efficient, scalable data collection&lt;/strong&gt;.
&lt;/li&gt;
&lt;li&gt;✅ &lt;strong&gt;Cost-Effective &amp;amp; Open-Source&lt;/strong&gt; – Eliminates the need for &lt;strong&gt;costly subscriptions&lt;/strong&gt; or &lt;strong&gt;expensive APIs&lt;/strong&gt;, offering &lt;strong&gt;full customization&lt;/strong&gt; and &lt;strong&gt;scalability&lt;/strong&gt; without breaking the bank.
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Crawl4AI empowers you to extract data intelligently, efficiently, and at scale&lt;/strong&gt;—unlocking new possibilities for &lt;strong&gt;automation and AI-driven workflows&lt;/strong&gt;. 💡&lt;/p&gt;

&lt;h2&gt;
  
  
  🛠️ What We Will Build
&lt;/h2&gt;

&lt;p&gt;Businesses and agencies often need access to &lt;strong&gt;local business information&lt;/strong&gt; to find potential clients, analyze competitors, or generate leads. Instead of manually searching directories, an &lt;strong&gt;AI scraper&lt;/strong&gt; can automate this process—saving time and effort.&lt;/p&gt;

&lt;p&gt;To showcase the power of &lt;strong&gt;AI web scraping&lt;/strong&gt; with &lt;strong&gt;Crawl4AI&lt;/strong&gt;, I chose to built a scraper that extracts &lt;strong&gt;local businesses information from Yellowpages&lt;/strong&gt;. 🏢📊&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhefmpsyt5kk4ajgd8cal.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhefmpsyt5kk4ajgd8cal.png" alt="Yellowpages scraper" width="800" height="387"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This scraper automatically &lt;strong&gt;navigates through listings&lt;/strong&gt;, collecting key details like:&lt;br&gt;&lt;br&gt;
🔹 &lt;strong&gt;Business Name&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
🔹 &lt;strong&gt;Address&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
🔹 &lt;strong&gt;Phone Number&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
🔹 &lt;strong&gt;Website &amp;amp; Additional Info&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Once extracted, the data is &lt;strong&gt;structured and saved into a CSV file&lt;/strong&gt;, making it easy to use for &lt;strong&gt;lead generation, market research, or business analytics&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;This project demonstrates how &lt;strong&gt;Crawl4AI + AI models&lt;/strong&gt; can &lt;strong&gt;quickly extract and process web data&lt;/strong&gt; with minimal effort. &lt;strong&gt;Let’s break down how it works!&lt;/strong&gt; 🚀&lt;/p&gt;


&lt;h2&gt;
  
  
  ⚙️ How It Works
&lt;/h2&gt;

&lt;p&gt;Before running our scraper, let's break down how the code works and give you a quick overview of how LLM-powered scraping with &lt;strong&gt;Crawl4AI&lt;/strong&gt; functions.&lt;/p&gt;

&lt;p&gt;(Don’t worry—I’ll keep it short and focus on the essential parts! 😉)&lt;/p&gt;
&lt;h3&gt;
  
  
  1️⃣ Browser Configuration
&lt;/h3&gt;

&lt;p&gt;First, we need to configure the browser settings. &lt;strong&gt;Crawl4AI&lt;/strong&gt; uses &lt;a href="https://playwright.dev/" rel="noopener noreferrer"&gt;&lt;strong&gt;Playwright&lt;/strong&gt;&lt;/a&gt; under the hood, so we get full control over how the browser behaves, including:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Headless mode&lt;/strong&gt; (whether the browser runs in the background)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Proxy settings&lt;/strong&gt; (to avoid getting blocked)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;User agents &amp;amp; timeouts&lt;/strong&gt; (to mimic real users)&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here’s how we define our browser configuration:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;crawl4ai&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;BrowserConfig&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_browser_config&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;BrowserConfig&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;BrowserConfig&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;browser_type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;chromium&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="c1"&gt;# Simulate a Chromium-based browser
&lt;/span&gt;        &lt;span class="n"&gt;headless&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="c1"&gt;# Run in headless mode (no UI)
&lt;/span&gt;        &lt;span class="n"&gt;verbose&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="c1"&gt;# Enable detailed logs for debugging
&lt;/span&gt;    &lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  2️⃣ Defining the LLM Extraction Strategy
&lt;/h3&gt;

&lt;p&gt;Now comes the &lt;strong&gt;AI part&lt;/strong&gt;! 🚀 &lt;strong&gt;Crawl4AI&lt;/strong&gt; allows us to use an &lt;a href="https://docs.crawl4ai.com/extraction/llm-strategies/" rel="noopener noreferrer"&gt;&lt;strong&gt;LLM extraction strategy&lt;/strong&gt;&lt;/a&gt; to tell the model exactly &lt;strong&gt;what&lt;/strong&gt; to extract from each page.&lt;/p&gt;

&lt;p&gt;Here’s how we define our strategy:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;llm_strategy&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;LLMExtractionStrategy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;provider&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;gemini/gemini-2.0-flash&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="c1"&gt;# LLM provider (Gemini, OpenAI, etc.)
&lt;/span&gt;    &lt;span class="n"&gt;api_token&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getenv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;GEMINI_API_KEY&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;  &lt;span class="c1"&gt;# API key for authentication
&lt;/span&gt;    &lt;span class="n"&gt;schema&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;BusinessData&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;model_json_schema&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;  &lt;span class="c1"&gt;# JSON schema of expected data
&lt;/span&gt;    &lt;span class="n"&gt;extraction_type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;schema&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="c1"&gt;# Use structured schema extraction
&lt;/span&gt;    &lt;span class="n"&gt;instruction&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Extract all business information: &lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;name&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;, &lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;address&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;, &lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;website&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;, &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
        &lt;span class="sh"&gt;"'&lt;/span&gt;&lt;span class="s"&gt;phone number&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt; and a one-sentence &lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;description&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt; from the content.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="n"&gt;input_format&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;markdown&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="c1"&gt;# Define input format
&lt;/span&gt;    &lt;span class="n"&gt;verbose&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="c1"&gt;# Enable logging for debugging
&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;📌 Structuring the Output&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;To ensure the extracted data follows a consistent structure, we use a &lt;strong&gt;Pydantic model&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;pydantic&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;BaseModel&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Field&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;BusinessData&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;BaseModel&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Field&lt;/span&gt;&lt;span class="p"&gt;(...,&lt;/span&gt; &lt;span class="n"&gt;description&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;The business name.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;address&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Field&lt;/span&gt;&lt;span class="p"&gt;(...,&lt;/span&gt; &lt;span class="n"&gt;description&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;The business address.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;phone_number&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Field&lt;/span&gt;&lt;span class="p"&gt;(...,&lt;/span&gt; &lt;span class="n"&gt;description&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;The business phone number.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;website&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Field&lt;/span&gt;&lt;span class="p"&gt;(...,&lt;/span&gt; &lt;span class="n"&gt;description&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;The business website URL.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Field&lt;/span&gt;&lt;span class="p"&gt;(...,&lt;/span&gt; &lt;span class="n"&gt;description&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;A short description of the business.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;💡 &lt;strong&gt;Why use Pydantic?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;It ensures the LLM returns &lt;strong&gt;structured data&lt;/strong&gt; that we can easily validate and process.&lt;/p&gt;

&lt;p&gt;📍 &lt;strong&gt;Multiple LLM Choices&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;You noticed that in the LLM strategy, I chose to use the &lt;strong&gt;Gemini 2.0 Flash&lt;/strong&gt; LLM. However, as Crawl4AI is built on &lt;a href="https://www.litellm.ai/" rel="noopener noreferrer"&gt;&lt;strong&gt;LiteLLM&lt;/strong&gt;&lt;/a&gt;, you can swap it with &lt;strong&gt;OpenAI, Claude, DeepSeek, Groq&lt;/strong&gt;, or &lt;strong&gt;any other supported LLM!&lt;/strong&gt; &lt;em&gt;(See the full list&lt;/em&gt; &lt;a href="https://github.com/BerriAI/litellm/blob/main/model_prices_and_context_window.json" rel="noopener noreferrer"&gt;&lt;em&gt;here&lt;/em&gt;&lt;/a&gt;&lt;em&gt;).&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  3️⃣ Scraping the web page
&lt;/h3&gt;

&lt;p&gt;Now that we have the browser and LLM strategy set up, we need a function to &lt;strong&gt;scrape each page&lt;/strong&gt; and extract business details:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;fetch_and_process_page&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;crawler&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;AsyncWebCrawler&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;page_number&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;base_url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;css_selector&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;llm_strategy&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;LLMExtractionStrategy&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;session_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;seen_names&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Set&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Tuple&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;dict&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="nb"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;

    &lt;span class="n"&gt;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;base_url&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;page_number&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;page_number&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Loading page &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;page_number&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;...&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# Fetch page content with the extraction strategy
&lt;/span&gt;    &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;crawler&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;arun&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nc"&gt;CrawlerRunConfig&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="n"&gt;cache_mode&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;CacheMode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;BYPASS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="c1"&gt;# No cached data
&lt;/span&gt;            &lt;span class="n"&gt;extraction_strategy&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;llm_strategy&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="c1"&gt;# Define extraction method
&lt;/span&gt;            &lt;span class="n"&gt;css_selector&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;css_selector&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="c1"&gt;# Target specific page elements
&lt;/span&gt;            &lt;span class="n"&gt;session_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;session_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="c1"&gt;# Unique ID for the session
&lt;/span&gt;        &lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# Parse extracted content
&lt;/span&gt;    &lt;span class="n"&gt;extracted_data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;loads&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;extracted_content&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# Process extracted businesses
&lt;/span&gt;    &lt;span class="n"&gt;all_businesses&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;business&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;extracted_data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nf"&gt;is_duplicated&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;business&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;name&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;seen_names&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
            &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Duplicate business &lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;business&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;name&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt; found. Skipping.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;continue&lt;/span&gt;  &lt;span class="c1"&gt;# Avoid duplicates
&lt;/span&gt;
        &lt;span class="n"&gt;seen_names&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;business&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;name&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
        &lt;span class="n"&gt;all_businesses&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;business&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;all_businesses&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;No valid businesses found on page &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;page_number&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;[],&lt;/span&gt; &lt;span class="bp"&gt;False&lt;/span&gt;

    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Extracted &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;all_businesses&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; businesses from page &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;page_number&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;all_businesses&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="bp"&gt;False&lt;/span&gt;  &lt;span class="c1"&gt;# Continue crawling
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This function:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Includes&lt;/strong&gt; the necessary &lt;strong&gt;LLM strategy&lt;/strong&gt; and &lt;strong&gt;CSS selector&lt;/strong&gt; in the crawler config.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Loads the webpage&lt;/strong&gt; by calling the &lt;code&gt;arun&lt;/code&gt; method.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Extracts business details&lt;/strong&gt; using the LLM strategy.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Filters duplicates&lt;/strong&gt; to prevent redundant data.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Returns&lt;/strong&gt; a list of all collected local businesses.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;💡 &lt;strong&gt;Pro Tip&lt;/strong&gt;  &lt;/p&gt;

&lt;p&gt;The &lt;code&gt;session_id&lt;/code&gt; helps maintain consistent browsing behavior across pagination - crucial for websites that track user sessions!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;🔍 Targeting the Right Data with CSS Selectors&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;To help the LLM focus on the relevant sections of the page, we use &lt;strong&gt;CSS selectors&lt;/strong&gt;. These selectors allow us to pinpoint specific HTML elements that contain the desired data, ensuring a smoother and cleaner extraction for the LLM.&lt;/p&gt;

&lt;p&gt;📸 The screenshot below shows the HTML structure of a Yellow Pages listing, where we can use CSS selectors to extract business details precisely.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7ov4sh0ysnhw89ur9o14.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7ov4sh0ysnhw89ur9o14.png" alt="Web Scraping - CSS Selectors" width="800" height="390"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h3&gt;
  
  
  4️⃣ Putting Everything Together
&lt;/h3&gt;

&lt;p&gt;Scraping just one page isn’t enough—we want to &lt;strong&gt;crawl all businesses listings&lt;/strong&gt;. So let’s tie everything together into a &lt;strong&gt;full web crawling workflow&lt;/strong&gt;! 🎯&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;crawl_yellowpages&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;
    Main function to scrape business data.
    &lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="c1"&gt;# Initialize configurations
&lt;/span&gt;    &lt;span class="n"&gt;browser_config&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;get_browser_config&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;llm_strategy&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;get_llm_strategy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;llm_instructions&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;SCRAPER_INSTRUCTIONS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="c1"&gt;# Extraction instructions
&lt;/span&gt;        &lt;span class="n"&gt;output_format&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;BusinessData&lt;/span&gt;  &lt;span class="c1"&gt;# Output schema
&lt;/span&gt;    &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;session_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;crawler_session&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;

    &lt;span class="c1"&gt;# Initialize state variables
&lt;/span&gt;    &lt;span class="n"&gt;page_number&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
    &lt;span class="n"&gt;all_records&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
    &lt;span class="n"&gt;seen_names&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="c1"&gt;# Start the web crawler session
&lt;/span&gt;    &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="nc"&gt;AsyncWebCrawler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;browser_config&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;crawler&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;records&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;no_results_found&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetch_and_process_page&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                &lt;span class="n"&gt;crawler&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="n"&gt;page_number&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="n"&gt;BASE_URL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="n"&gt;CSS_SELECTOR&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="n"&gt;llm_strategy&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="n"&gt;session_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="n"&gt;seen_names&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="p"&gt;)&lt;/span&gt;

            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;no_results_found&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;No more records found. Stopping crawl.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="k"&gt;break&lt;/span&gt;

            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;records&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;No records extracted from page &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;page_number&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="k"&gt;break&lt;/span&gt;  

            &lt;span class="n"&gt;all_records&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;extend&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;records&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;page_number&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;  &lt;span class="c1"&gt;# Move to the next page
&lt;/span&gt;
            &lt;span class="c1"&gt;# Stop after a maximum number of pages
&lt;/span&gt;            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;page_number&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;MAX_PAGES&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="k"&gt;break&lt;/span&gt;

            &lt;span class="c1"&gt;# Pause to prevent rate limits
&lt;/span&gt;            &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;asyncio&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# Save extracted data
&lt;/span&gt;    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;all_records&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="nf"&gt;save_data_to_csv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;records&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;all_records&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;data_struct&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;BusinessData&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;filename&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;businesses_data.csv&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;No records found.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# Show LLM usage stats
&lt;/span&gt;    &lt;span class="n"&gt;llm_strategy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;show_usage&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;🚀 &lt;strong&gt;What this function does:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Sets up the &lt;strong&gt;browser &amp;amp; LLM strategy&lt;/strong&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Invokes &lt;code&gt;fetch_and_process_page&lt;/code&gt; to scrape the local businesses data for each page&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Runs a while loop and uses &lt;strong&gt;pagination&lt;/strong&gt; to scrape multiple pages.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Saves all extracted &lt;strong&gt;businesses data to a CSV file&lt;/strong&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Displays &lt;strong&gt;LLM usage statistics&lt;/strong&gt; to track input/output tokens count for cost estimate.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;With just a few steps, we've built a powerful AI scraper that can extract local business listings! Now, let’s put it to the test and see it in action. ⚡🔍&lt;/strong&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  🔥 Try It Out!
&lt;/h2&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;🛠 Step 1: Clone the Project&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;To get started, clone the &lt;a href="https://github.com/kaymen99/local-rag-researcher-deepseek" rel="noopener noreferrer"&gt;GitHub repository&lt;/a&gt; and install the necessary dependencies (preferably in a virtual environment):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Clone the repository from GitHub  &lt;/span&gt;
git clone https://github.com/kaymen99/llm-web-scraper  
&lt;span class="nb"&gt;cd &lt;/span&gt;llm-web-scraper  

&lt;span class="c"&gt;# Create a virtual environment to manage dependencies  &lt;/span&gt;
python &lt;span class="nt"&gt;-m&lt;/span&gt; venv venv  

&lt;span class="c"&gt;# Activate the virtual environment  &lt;/span&gt;
&lt;span class="nb"&gt;source &lt;/span&gt;venv/bin/activate &lt;span class="c"&gt;# On macOS/Linux&lt;/span&gt;
&lt;span class="c"&gt;# On Windows: venv\Scripts\activate  &lt;/span&gt;

&lt;span class="c"&gt;# Install the required dependencies from the requirements.txt&lt;/span&gt;
pip &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-r&lt;/span&gt; requirements.txt 

&lt;span class="c"&gt;# Install playwright browsers &lt;/span&gt;
playwright &lt;span class="nb"&gt;install&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  &lt;strong&gt;🛠 Step 2: Set Up Your Environment Variables&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Create a &lt;code&gt;.env&lt;/code&gt; file in the root directory with the following content:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;GEMINI_API_KEY=your_gemini_api_key_here
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;💡 &lt;strong&gt;Tip:&lt;/strong&gt; You can use any LLM supported by &lt;a href="https://www.litellm.ai/" rel="noopener noreferrer"&gt;&lt;strong&gt;LiteLLM&lt;/strong&gt;&lt;/a&gt;—just ensure you provide the correct API key!&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;🛠 Step 3: Customize the Scraper (Optional)&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Inside the project directory, you'll find a &lt;a href="http://config.py" rel="noopener noreferrer"&gt;&lt;code&gt;config.py&lt;/code&gt;&lt;/a&gt; file where you can modify key settings, such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;The &lt;strong&gt;website URL&lt;/strong&gt; to scrape.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The &lt;strong&gt;LLM provider&lt;/strong&gt; being used.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The &lt;strong&gt;maximum number of pages&lt;/strong&gt; to crawl.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Scraper instructions.&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For example, to scrape different types of businesses, update the &lt;code&gt;BASE_URL&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# - Plumbers in Vancouver: "https://www.yellowpages.ca/search/si/{page_number}/Plumbers/Vancouver+BC"
# - Restaurants in Montreal: "https://www.yellowpages.ca/search/si/{page_number}/Restaurants/Montreal+QC"
&lt;/span&gt;&lt;span class="n"&gt;BASE_URL&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://www.yellowpages.ca/search/si/{page_number}/Dentists/Toronto+ON&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To switch to a different LLM provider, update these lines:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;LLM_MODEL&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;gpt-4o-mini&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="n"&gt;API_TOKEN&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getenv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;OPENAI_API_KEY&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  &lt;strong&gt;🛠 Step 4: Run the Scraper&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Start the crawler with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python main.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The program will:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Scrape &lt;strong&gt;local businesses listings&lt;/strong&gt; page by page.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Save all extracted data to &lt;code&gt;businesses_data.csv&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Display &lt;strong&gt;LLM tokens usage statistics&lt;/strong&gt; after completion.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;📸 &lt;strong&gt;See the results:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/D4S6JNCS8kM"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;🚀 Go on, give it a spin and watch it in action!&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;💰 Cost Breakdown&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;I chose the &lt;strong&gt;Gemini-2.0 Flash&lt;/strong&gt; LLM from Google for my AI scraper. Let's take a look at the token usage:  &lt;/p&gt;

&lt;p&gt;📸 &lt;strong&gt;Screenshot:&lt;/strong&gt;  &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1ijjcyqq8erk02tefpkq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1ijjcyqq8erk02tefpkq.png" alt="AI web scraper cost breakdown" width="543" height="374"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;From the usage data, we can see that the scraper processes approximately &lt;strong&gt;13,000 input tokens&lt;/strong&gt; and &lt;strong&gt;2,000 output tokens&lt;/strong&gt; per page. Let’s calculate how much it costs to scrape a &lt;strong&gt;single Yellow Pages&lt;/strong&gt; entry using our AI scraper:  &lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;strong&gt;Usage&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Tokens Used&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Pricing (per 1M tokens)&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Cost&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Input Tokens&lt;/td&gt;
&lt;td&gt;13,000&lt;/td&gt;
&lt;td&gt;$0.10&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;$0.0013&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Output Tokens&lt;/td&gt;
&lt;td&gt;2,000&lt;/td&gt;
&lt;td&gt;$0.40&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;$0.0008&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Total Cost&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;15,000&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;—&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;$0.0021&lt;/strong&gt; (≈ $0.002)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;So, the cost for scraping a &lt;strong&gt;single page&lt;/strong&gt; is &lt;strong&gt;only ~$0.002&lt;/strong&gt;—practically &lt;strong&gt;free!&lt;/strong&gt; 💸&lt;/p&gt;

&lt;h2&gt;
  
  
  🌍 Use Cases
&lt;/h2&gt;

&lt;p&gt;Our &lt;strong&gt;AI web scraper&lt;/strong&gt; isn’t just a tool—it’s a &lt;strong&gt;game-changer&lt;/strong&gt; for automating web data collection. Here’s how it can be applied:  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;🎯 Lead Generation&lt;/strong&gt; – &lt;strong&gt;Extract business details&lt;/strong&gt; like &lt;strong&gt;emails, phone numbers, and addresses&lt;/strong&gt; to build &lt;strong&gt;targeted outreach lists&lt;/strong&gt; effortlessly.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;📊 Market Research&lt;/strong&gt; – &lt;strong&gt;Analyze trends, customer behavior, and industry insights&lt;/strong&gt; by gathering &lt;strong&gt;real-time data&lt;/strong&gt; from various sources.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;⚔️ Competitor Analysis&lt;/strong&gt; – &lt;strong&gt;Monitor pricing, services, and customer reviews&lt;/strong&gt; to stay ahead in your industry.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;🤖 AI Data Enrichment&lt;/strong&gt; – &lt;strong&gt;Leverage LLMs&lt;/strong&gt; to &lt;strong&gt;clean, categorize, and enhance&lt;/strong&gt; scraped data for &lt;strong&gt;deeper insights&lt;/strong&gt;.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;📚 Research &amp;amp; Analysis&lt;/strong&gt; – &lt;strong&gt;Extract structured data&lt;/strong&gt; from &lt;strong&gt;directories, reports, and publications&lt;/strong&gt; to fuel &lt;strong&gt;business or academic studies&lt;/strong&gt;.
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Whether you’re a &lt;strong&gt;marketer, researcher, or developer&lt;/strong&gt;, this &lt;strong&gt;AI scraper streamlines data extraction—fast, efficient, and automated!&lt;/strong&gt; 🚀&lt;/p&gt;

&lt;h2&gt;
  
  
  🎯 &lt;strong&gt;Final Thoughts&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;🎉 &lt;strong&gt;Congrats!&lt;/strong&gt; You've successfully built your own &lt;strong&gt;AI-powered scraper&lt;/strong&gt; using &lt;strong&gt;Crawl4AI&lt;/strong&gt;, giving you the ability to collect as many potential leads as you need for your &lt;strong&gt;business or clients&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;This scraper is &lt;strong&gt;highly adaptable&lt;/strong&gt;—just &lt;strong&gt;plug in the website&lt;/strong&gt; and specify the &lt;strong&gt;data you want to extract&lt;/strong&gt;, then let it do the rest! 🚀&lt;/p&gt;

&lt;p&gt;💡 &lt;strong&gt;Got ideas to improve it?&lt;/strong&gt; Drop them in the comments!&lt;/p&gt;

&lt;p&gt;👉 &lt;strong&gt;Want to learn more?&lt;/strong&gt; Follow my &lt;a href="https://dev.to/kaymen99"&gt;&lt;strong&gt;blog&lt;/strong&gt;&lt;/a&gt; and check out my &lt;a href="https://github.com/kaymen99" rel="noopener noreferrer"&gt;&lt;strong&gt;GitHub&lt;/strong&gt;&lt;/a&gt; for more &lt;strong&gt;AI projects &amp;amp; tutorials&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Happy scraping!&lt;/strong&gt; 🔥&lt;/p&gt;

</description>
      <category>ai</category>
      <category>python</category>
      <category>tutorial</category>
      <category>agenticai</category>
    </item>
    <item>
      <title>Build a Local RAG Researcher with DeepSeek R1</title>
      <dc:creator>Aimen Kerrour</dc:creator>
      <pubDate>Fri, 07 Feb 2025 00:13:37 +0000</pubDate>
      <link>https://dev.to/kaymen99/build-your-own-local-rag-researcher-with-deepseek-r1-11m</link>
      <guid>https://dev.to/kaymen99/build-your-own-local-rag-researcher-with-deepseek-r1-11m</guid>
      <description>&lt;p&gt;You’ve probably heard of &lt;strong&gt;DeepSeek R1&lt;/strong&gt;, the powerful Chinese reasoning LLM that’s detouring OpenAI’s dominance in the AI world. And let’s be honest—you’ve likely seen tons of tutorials on &lt;strong&gt;chatting with PDFs&lt;/strong&gt; using its local versions. But… that’s where most of them stop.&lt;/p&gt;

&lt;p&gt;So, I thought—&lt;strong&gt;why not go beyond that?&lt;/strong&gt; 🚀&lt;/p&gt;

&lt;p&gt;What if you had a &lt;strong&gt;local RAG researcher&lt;/strong&gt; that:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Questions your local documents 📄&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Performs web searches 🌍&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Generates structured reports in &lt;strong&gt;your&lt;/strong&gt; format 📝&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;💡 &lt;strong&gt;See for yourself!&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/fYqbk8OFHS8"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;By the end of this guide, you’ll learn:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;🔹 &lt;strong&gt;Why&lt;/strong&gt; you need a local RAG researcher&lt;br&gt;&lt;br&gt;
🔹 &lt;strong&gt;How&lt;/strong&gt; to use &lt;strong&gt;local&lt;/strong&gt; &lt;strong&gt;DeepSeek R1&lt;/strong&gt; models with &lt;strong&gt;Ollama&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
🔹 &lt;strong&gt;How&lt;/strong&gt; to run your own &lt;strong&gt;fully local&lt;/strong&gt; RAG researcher&lt;/p&gt;

&lt;p&gt;So… &lt;strong&gt;are you ready to level up your AI research game?&lt;/strong&gt; Let’s dive in! ⏳💡&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;🔥 Explore the project in my &lt;a href="https://github.com/kaymen99/local-rag-researcher-deepseek" rel="noopener noreferrer"&gt;Github repository&lt;/a&gt; now!&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;
  
  
  Do You &lt;em&gt;Really&lt;/em&gt; Need a Local RAG Researcher? 🤔
&lt;/h2&gt;

&lt;p&gt;You already know the perks of local LLMs—&lt;strong&gt;privacy, zero ongoing costs, offline access, and full control over the models&lt;/strong&gt;. But why take it a step further with a &lt;strong&gt;local RAG researcher&lt;/strong&gt;?&lt;/p&gt;

&lt;p&gt;Let’s look at two simple cases:&lt;/p&gt;

&lt;p&gt;📌 &lt;strong&gt;Your boss asks for a report&lt;/strong&gt; on the company’s progress using internal documents.&lt;br&gt;&lt;br&gt;
📌 &lt;strong&gt;You want to analyze your personal finances&lt;/strong&gt; and get a tailored report with insights.&lt;/p&gt;

&lt;p&gt;In both cases, sending sensitive data to a cloud AI isn’t an option unless you &lt;em&gt;want&lt;/em&gt; your finances leaked 💸 or your boss furious 😡.&lt;/p&gt;

&lt;p&gt;Sure, you could chat with your documents using a local model, but you'd still &lt;strong&gt;waste time manually compiling a final report&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;🔹 &lt;strong&gt;That's where your local RAG researcher comes in.&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Just tell it &lt;strong&gt;what&lt;/strong&gt; you need and &lt;strong&gt;how&lt;/strong&gt; the report should be structured, and it will:&lt;/p&gt;

&lt;p&gt;✅ Generate relevant research queries&lt;br&gt;&lt;br&gt;
✅ Retrieve key insights from your docs&lt;br&gt;&lt;br&gt;
✅ Perform web searches for real-time data (&lt;strong&gt;&lt;em&gt;if enabled!&lt;/em&gt;&lt;/strong&gt;)&lt;br&gt;&lt;br&gt;
✅ Summarize everything into a structured report&lt;/p&gt;

&lt;p&gt;🚀 And it does all this &lt;strong&gt;entirely on your local machine&lt;/strong&gt;.&lt;/p&gt;


&lt;h2&gt;
  
  
  Why Use DeepSeek R1? 🧠
&lt;/h2&gt;

&lt;p&gt;When DeepSeek released their top-tier &lt;a href="https://www.deepseek.com/" rel="noopener noreferrer"&gt;&lt;strong&gt;DeepSeek R1&lt;/strong&gt;&lt;/a&gt; model, they didn't stop at just one breakthrough. Instead, they took it a step further by developing a series of distilled models—smaller, open-source LLMs built on top of existing architectures like &lt;strong&gt;LLaMA&lt;/strong&gt; and &lt;strong&gt;Qwen&lt;/strong&gt;. These models were fine-tuned using reasoning datasets generated by the larger DeepSeek R1 model.&lt;/p&gt;

&lt;p&gt;In other words, the big &lt;strong&gt;671b parameters DeepSeek R1&lt;/strong&gt; model served as a &lt;strong&gt;teacher model&lt;/strong&gt;, transferring its reasoning abilities to these smaller versions through carefully curated training datasets. This method allowed them to retain strong reasoning capabilities while being much more lightweight and efficient.💡&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;And the results?&lt;/strong&gt; 🔥&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Faoe9e4g5row898kvibyc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Faoe9e4g5row898kvibyc.png" alt="Deepseek R1 local models" width="595" height="233"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;📊 &lt;strong&gt;Just look at the&lt;/strong&gt; &lt;a href="https://arxiv.org/abs/2501.12948" rel="noopener noreferrer"&gt;&lt;strong&gt;table above&lt;/strong&gt;&lt;/a&gt;—a trained &lt;strong&gt;LLaMA 70B model&lt;/strong&gt; from DeepSeek already &lt;strong&gt;outperforms OpenAI’s o1-mini&lt;/strong&gt; in reasoning tasks. &lt;strong&gt;That’s huge!&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;But what’s even more exciting?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If you don’t have a powerful GPU, these &lt;strong&gt;smaller models change everything&lt;/strong&gt;. You can now &lt;strong&gt;run the DeepSeek-R1-14B&lt;/strong&gt; &lt;strong&gt;model&lt;/strong&gt; on your own machine and still achieve reasoning performance &lt;strong&gt;comparable to OpenAI’s O1-mini&lt;/strong&gt;, while also being &lt;strong&gt;much more powerful than the latest GPT-4o and Claude Sonnet-3.5 models&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;This means &lt;strong&gt;powerful, private, and cost-free reasoning models&lt;/strong&gt;—all accessible from your local setup. 🚀&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;💡 The possibilities are endless, and they’re now in your hands.&lt;/strong&gt;&lt;/p&gt;


&lt;h2&gt;
  
  
  &lt;strong&gt;Researcher Agent Architecture&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;(If you can't wait to test it out, skip to setup—we won't tell! 😉)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Before setting up the RAG researcher, let’s take a quick look at how it’s built 🔍.&lt;/p&gt;
&lt;h3&gt;
  
  
  &lt;strong&gt;Local ChromaDB Vector Store&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;As with any &lt;strong&gt;RAG application&lt;/strong&gt;, we need a vector database for search. Once you upload your files (PDFs, TXT, MD, or CSV) from the UI, we follow these standard steps:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;1. Load the Documents:&lt;/strong&gt; We use &lt;a href="https://python.langchain.com/docs/integrations/document_loaders" rel="noopener noreferrer"&gt;&lt;strong&gt;LangChain loaders&lt;/strong&gt;&lt;/a&gt; to handle different file formats easily.
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Import libraries
&lt;/span&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;process_uploaded_files&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;uploaded_files&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="bp"&gt;...&lt;/span&gt;

    &lt;span class="c1"&gt;# Choose the appropriate loader
&lt;/span&gt;    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;file_extension&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;csv&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;loader&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;CSVLoader&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;temp_file_path&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="n"&gt;file_extension&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;txt&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;md&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
        &lt;span class="n"&gt;loader&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;TextLoader&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;temp_file_path&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="n"&gt;file_extension&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;pdf&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;loader&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;PDFPlumberLoader&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;temp_file_path&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;continue&lt;/span&gt;
    &lt;span class="bp"&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;💡 &lt;strong&gt;Tip:&lt;/strong&gt; Experimenting with different file types or chunking strategies? Just swap in a new loader or splitter logic to suit your needs!&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;2. Chunk the Documents:&lt;/strong&gt; We split each document into smaller, semantically meaningful chunks.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;3. Create the Vector Database:&lt;/strong&gt; We use a local &lt;a href="https://huggingface.co/spaces/mteb/leaderboard" rel="noopener noreferrer"&gt;&lt;strong&gt;HuggingFace&lt;/strong&gt;&lt;/a&gt; embedding model to convert document chunks into vector representations, then store them in the local &lt;a href="https://docs.trychroma.com/docs/overview/introduction" rel="noopener noreferrer"&gt;&lt;strong&gt;Chroma&lt;/strong&gt;&lt;/a&gt; database.&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;add_documents&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;documents&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;embeddings&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;HuggingFaceEmbeddings&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="c1"&gt;# Process the new documents
&lt;/span&gt;    &lt;span class="n"&gt;semantic_text_splitter&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;SemanticChunker&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;embeddings&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;documents&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;semantic_text_splitter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;split_documents&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;documents&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# Create embeddings and store in vector DB
&lt;/span&gt;    &lt;span class="n"&gt;vectorstore&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Chroma&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;embedding_function&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;embeddings&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;vectorstore&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add_documents&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;documents&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;vectorstore&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;🔑 &lt;strong&gt;Key Point:&lt;/strong&gt; Semantic chunking splits text based on meaning rather than just character count, improving accuracy when fetching relevant snippets later.&lt;/p&gt;


&lt;h2&gt;
  
  
  &lt;strong&gt;Researcher Agent&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;(Don’t worry—we’ll keep this quick. But trust me, you’ll want to see how it works. ✨)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Our researcher agent is an &lt;strong&gt;adaptive RAG pipeline&lt;/strong&gt; built using &lt;strong&gt;LangGraph&lt;/strong&gt;. Let’s break down how it transforms your instructions into polished reports.&lt;/p&gt;
&lt;h3&gt;
  
  
  &lt;strong&gt;Core Workflow&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;The agent functions as a &lt;strong&gt;state machine&lt;/strong&gt; that manages research generation, document retrieval, and synthesis.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F238zi9owr33igt3ldohk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F238zi9owr33igt3ldohk.png" alt="Langgraph RAG researcher agent" width="542" height="428"&gt;&lt;/a&gt;&lt;/p&gt;


&lt;h3&gt;
  
  
  &lt;strong&gt;Step 1: Generate Search Queries&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;The agent starts by analyzing the provided instructions and generating &lt;strong&gt;precise research queries&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;generate_research_queries&lt;/span&gt;&lt;span class="p"&gt;(...):&lt;/span&gt;  
    &lt;span class="n"&gt;query_writer_prompt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;RESEARCH_QUERY_WRITER_PROMPT&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;max_queries&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;max_queries&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;date&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;datetime&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;datetime&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;strftime&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;%Y/%m/%d %H:%M&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# Using a local DeepSeek R1 model with Ollama
&lt;/span&gt;    &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;invoke_ollama&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;deepseek-r1:7b&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;system_prompt&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;query_writer_prompt&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;user_prompt&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Generate research queries for this user instruction: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;user_instructions&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;output_format&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;Queries&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We provide the reasoning model with the &lt;strong&gt;current date&lt;/strong&gt; and the &lt;strong&gt;maximum number of queries&lt;/strong&gt;, letting it handle the rest:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;RESEARCH_QUERY_WRITER_PROMPT&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;You are an expert Research Query Writer specializing in designing precise and effective queries to fulfill user research tasks.

Your goal is to generate the necessary queries to complete the user&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;s research goal based on their instructions. Ensure the queries are concise, relevant, and avoid redundancy.

Your output must be a JSON object containing a single key &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;queries&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;:
{{ &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;queries&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;: [&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Query 1&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;, &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Query 2&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;,...] }}

# NOTE:
* You can generate up to {max_queries} queries, but only as many as needed to effectively address the user&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;s research goal.
* **Today is: {date}**
&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;💡 &lt;strong&gt;Tip:&lt;/strong&gt; You can adjust the number of search queries directly from the UI.&lt;/p&gt;




&lt;h3&gt;
  
  
  &lt;strong&gt;Step 2: Process Queries&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Once generated, queries are processed in &lt;strong&gt;parallel&lt;/strong&gt; for speed. Each query runs through a &lt;strong&gt;mini-research subgraph&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;query_search_subgraph&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add_edge&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;START&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;retrieve_rag_documents&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;query_search_subgraph&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add_edge&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;retrieve_rag_documents&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;evaluate_retrieved_documents&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;query_search_subgraph&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add_conditional_edges&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;evaluate_retrieved_documents&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;route_research&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;query_search_subgraph&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add_edge&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;web_research&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;summarize_query_research&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;query_search_subgraph&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add_edge&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;summarize_query_research&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;END&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here’s how it works:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Retrieve Documents&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Fetches the top &lt;strong&gt;3&lt;/strong&gt; most relevant snippets from &lt;strong&gt;ChromaDB&lt;/strong&gt; using similarity search.&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;retrieve_rag_documents&lt;/span&gt;&lt;span class="p"&gt;(...):&lt;/span&gt;  
    &lt;span class="n"&gt;vectorstore_retriever&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;vectorstore&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;as_retriever&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;search_type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;similarity&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;search_kwargs&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;k&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;  
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;retrieved_documents&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;documents&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Relevance Check&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
A &lt;strong&gt;secondary reasoning agent&lt;/strong&gt; evaluates whether the retrieved documents actually answer the query (relevant or not).&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;evaluate_retrieved_documents&lt;/span&gt;&lt;span class="p"&gt;(...):&lt;/span&gt;  
    &lt;span class="n"&gt;evaluation_prompt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;RELEVANCE_EVALUATOR_PROMPT&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;format&lt;/span&gt;&lt;span class="p"&gt;(...)&lt;/span&gt;
    &lt;span class="n"&gt;evaluation&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;invoke_ollama&lt;/span&gt;&lt;span class="p"&gt;(...)&lt;/span&gt;  &lt;span class="c1"&gt;# "Are these docs useful? Yes/No"  
&lt;/span&gt;    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;are_documents_relevant&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;evaluation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;is_relevant&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Adaptive Routing&lt;/strong&gt;      &lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;✅ &lt;strong&gt;Relevant?&lt;/strong&gt; → Move to summarization.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;❌ &lt;strong&gt;Irrelevant?&lt;/strong&gt; → Launch &lt;strong&gt;web search&lt;/strong&gt; (if enabled).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;😔 &lt;strong&gt;No web search?&lt;/strong&gt; → Skip the query.&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;route_research&lt;/span&gt;&lt;span class="p"&gt;(...):&lt;/span&gt;  
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;are_documents_relevant&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;  
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;summarize_query_research&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;  
    &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="n"&gt;enable_web_search&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;  
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;web_research&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;  
    &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;__end__&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;⚠️ &lt;strong&gt;Note:&lt;/strong&gt; Web research uses the &lt;a href="https://tavily.com/" rel="noopener noreferrer"&gt;&lt;strong&gt;Tavily API&lt;/strong&gt;&lt;/a&gt; to gather high-quality sources (academic papers, verified blogs).&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Summarize Research Findings&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
A summarizer agent compiles a &lt;strong&gt;concise, focused summary&lt;/strong&gt; based on retrieved documents or web search results for each query.&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;summarize_query_research&lt;/span&gt;&lt;span class="p"&gt;(...):&lt;/span&gt;  
     &lt;span class="n"&gt;summary_prompt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;SUMMARIZER_PROMPT&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;format&lt;/span&gt;&lt;span class="p"&gt;(...)&lt;/span&gt;

     &lt;span class="n"&gt;summary&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;invoke_ollama&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
         &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;deepseek-r1:7b&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
         &lt;span class="n"&gt;system_prompt&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;summary_prompt&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
         &lt;span class="n"&gt;user_prompt&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Generate a research summary for this query: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
     &lt;span class="p"&gt;)&lt;/span&gt;
     &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;search_summaries&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;summary&lt;/span&gt;&lt;span class="p"&gt;]}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;We instruct the summarizer agent to craft an objective summary of the key findings while skipping irrelevant facts:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt; &lt;span class="n"&gt;SUMMARIZER_PROMPT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;Your goal is to generate a focused, evidence-based research summary from the provided documents.

 KEY OBJECTIVES:
 1. Extract and synthesize critical findings from each source
 2. Present key data points and metrics that support main conclusions
 3. Identify emerging patterns and significant insights
 4. Structure information in a clear, logical flow

 REQUIREMENTS:
 - Begin immediately with key findings - no introductions
 - Focus on verifiable data and empirical evidence
 - Keep the summary brief, avoid repetition and unnecessary details
 - Prioritize information directly relevant to the query

 Query:
 {query}

 Retrieved Documents:
 {docmuents}
 &lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;/ol&gt;




&lt;h3&gt;
  
  
  &lt;strong&gt;Step 3: Generate Final Report&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;The researcher compiles all findings into a well-structured report following the user-defined format.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;generate_final_answer&lt;/span&gt;&lt;span class="p"&gt;(...):&lt;/span&gt;  
    &lt;span class="n"&gt;report_structure&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;configurable&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;report_structure&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;""&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;answer_prompt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;REPORT_WRITER_PROMPT&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;instruction&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;user_instructions&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
        &lt;span class="n"&gt;report_structure&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;report_structure&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;information&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n\n&lt;/span&gt;&lt;span class="s"&gt;---&lt;/span&gt;&lt;span class="se"&gt;\n\n&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;search_summaries&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;invoke_ollama&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;deepseek-r1:7b&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;system_prompt&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;answer_prompt&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;user_prompt&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Generate a research summary using the provided information.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;final_answer&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;parse_output&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;)[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;response&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is the prompt that the report writer agent must follow:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;REPORT_WRITER_PROMPT&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;Your goal is to use the provided information to write a comprehensive and accurate report that answers all the user&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;s questions. 
The report must strictly follow the structure requested by the user.

USER INSTRUCTION:
{instruction}

REPORT STRUCTURE:
{report_structure}

PROVIDED INFORMATION:
{information}

# **CRITICAL GUIDELINES:**
- Adhere strictly to the structure specified in the user&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;s instruction.
- Start IMMEDIATELY with the summary content - no introductions or meta-commentary
- Focus ONLY on factual, objective information
- Avoid redundancy, repetition, or unnecessary commentary.
&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The crafted report appears in the UI, ready for you to review or copy.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Excited to see it in action? Let’s fire up the agent!&lt;/strong&gt; 🔥&lt;/p&gt;




&lt;h2&gt;
  
  
  &lt;strong&gt;How to Run It Yourself?&lt;/strong&gt;
&lt;/h2&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Tech Stack Used&lt;/strong&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://ollama.com" rel="noopener noreferrer"&gt;&lt;strong&gt;Ollama&lt;/strong&gt;&lt;/a&gt;: Runs the DeepSeek R1 model locally.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://www.langchain.com/langgraph" rel="noopener noreferrer"&gt;&lt;strong&gt;LangGraph&lt;/strong&gt;&lt;/a&gt;: Builds AI agents and defines the researcher's workflow.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://www.trychroma.com/" rel="noopener noreferrer"&gt;&lt;strong&gt;ChromaDB&lt;/strong&gt;&lt;/a&gt;: Local vector database for RAG-based retrieval.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://streamlit.io" rel="noopener noreferrer"&gt;&lt;strong&gt;Streamlit&lt;/strong&gt;&lt;/a&gt;: Provides a UI for interacting with the researcher.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhysq0m1qg92hrka38bo1.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhysq0m1qg92hrka38bo1.jpg" alt="Langgraph, Ollama, Deepseek, Streamlit" width="800" height="219"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h3&gt;
  
  
  🛠 &lt;strong&gt;Step 1: Install Ollama&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Ollama&lt;/strong&gt; is available for &lt;strong&gt;macOS, Linux, and Windows&lt;/strong&gt;. Follow these steps to install it:&lt;/p&gt;

&lt;p&gt;1️⃣ Visit the official Ollama download page.&lt;/p&gt;

&lt;p&gt;🔗 &lt;a href="https://ollama.ai/download" rel="noopener noreferrer"&gt;Download Ollama&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;2️⃣ Select your operating system (macOS, Linux, or Windows).&lt;/p&gt;

&lt;p&gt;3️⃣ Click the &lt;strong&gt;Download&lt;/strong&gt; button.&lt;/p&gt;

&lt;p&gt;4️⃣ Follow the system-specific installation instructions.&lt;/p&gt;

&lt;p&gt;📸 &lt;strong&gt;Screenshot:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqs9lptdmi6a3kk2wkr3j.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqs9lptdmi6a3kk2wkr3j.png" alt="Install Ollama" width="800" height="388"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h3&gt;
  
  
  🛠 &lt;strong&gt;Step 2: Run DeepSeek R1 Locally&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Once &lt;strong&gt;Ollama&lt;/strong&gt; is installed, you can run &lt;strong&gt;DeepSeek R1&lt;/strong&gt; models. There are multiple options depending on your system’s capabilities.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fg6mmy9bv8rie1thy2enb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fg6mmy9bv8rie1thy2enb.png" alt="Ollama DeepSeek R1 models" width="800" height="574"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For this researcher agent, I used the &lt;strong&gt;7B model&lt;/strong&gt;, but you can choose the &lt;strong&gt;1.5B model&lt;/strong&gt; or even larger ones if your machine can handle them!&lt;/p&gt;

&lt;p&gt;🔹 &lt;strong&gt;Pull the DeepSeek R1 Model&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
To download the &lt;strong&gt;1.5B parameter model&lt;/strong&gt;, run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ollama pull deepseek-r1:1.5b
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;🔹 &lt;strong&gt;Run DeepSeek R1&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Once downloaded, you can interact with the model using:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ollama run deepseek-r1:1.5b
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;🔑 &lt;strong&gt;Key Point:&lt;/strong&gt; Larger models (e.g., &lt;strong&gt;32B&lt;/strong&gt;, &lt;strong&gt;70B&lt;/strong&gt;) provide better reasoning and research quality but require significant RAM.&lt;/p&gt;




&lt;h3&gt;
  
  
  🛠 &lt;strong&gt;Step 3: Set Up the RAG Researcher with Streamlit&lt;/strong&gt;
&lt;/h3&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;1️⃣ Clone the Project&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;To run the researcher agent, clone the &lt;a href="https://github.com/kaymen99/local-rag-researcher-deepseek" rel="noopener noreferrer"&gt;GitHub repository&lt;/a&gt; and install the required dependencies (preferably in a virtual environment):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://github.com/kaymen99/local-rag-researcher-deepseek
&lt;span class="nb"&gt;cd &lt;/span&gt;local-rag-researcher-deepseek
python &lt;span class="nt"&gt;-m&lt;/span&gt; venv venv
&lt;span class="nb"&gt;source &lt;/span&gt;venv/bin/activate  &lt;span class="c"&gt;# On Windows use `venv\Scripts\activate`&lt;/span&gt;
pip &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-r&lt;/span&gt; requirements.txt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  &lt;strong&gt;2️⃣ Set Up Web Search API (Optional)&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;&lt;em&gt;(Skip this if you don't want to use web search.)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The researcher agent uses the &lt;a href="https://tavily.com/" rel="noopener noreferrer"&gt;&lt;strong&gt;Tavily API&lt;/strong&gt;&lt;/a&gt; for web search. You’ll need an API key (they give a lot of free credit—basically FREE). Add it to your &lt;strong&gt;.env&lt;/strong&gt; file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ini"&gt;&lt;code&gt;&lt;span class="c"&gt;# Tavily API key for SearchTool
&lt;/span&gt;&lt;span class="py"&gt;TAVILY_API_KEY&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"tvly-..."&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  &lt;strong&gt;3️⃣ Launch the Streamlit App&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;I've already built a &lt;strong&gt;Streamlit UI&lt;/strong&gt; for the researcher agent (check &lt;a href="http://app.py" rel="noopener noreferrer"&gt;&lt;code&gt;app.py&lt;/code&gt;&lt;/a&gt;). It allows you to configure the agent, upload documents, and see real-time updates.&lt;/p&gt;

&lt;p&gt;To launch the app, run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;streamlit run app.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;📸 &lt;strong&gt;Screenshot:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5llwafueg8zqbujujb4m.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5llwafueg8zqbujujb4m.png" alt="RAG Researcher Streamlit UI" width="800" height="397"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;🔹 &lt;strong&gt;Visualize in LangGraph Studio&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Since the researcher is built with &lt;strong&gt;LangGraph&lt;/strong&gt;, you can visualize its workflow in &lt;strong&gt;LangGraph Studio&lt;/strong&gt;. (You'll need a &lt;strong&gt;free LangSmith account&lt;/strong&gt; for this)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pip &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-U&lt;/span&gt; &lt;span class="s2"&gt;"langgraph-cli[inmem]"&lt;/span&gt;
langgraph dev
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;📸 &lt;strong&gt;Screenshot:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fo2bdg8kaw7qxbuxk56nu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fo2bdg8kaw7qxbuxk56nu.png" alt="Langgraph studio" width="800" height="431"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  🚀 &lt;strong&gt;Test It Out!&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Upload your documents and provide research instructions—the agent will handle the rest!&lt;/strong&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Real-World Use Cases 🌍
&lt;/h2&gt;

&lt;p&gt;A &lt;strong&gt;local RAG researcher&lt;/strong&gt; with reasoning power isn’t just a cool project—it’s a game-changer for handling private, sensitive data. Here’s how it can be used in real scenarios:  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;🏥 Healthcare &amp;amp; Medical Research&lt;/strong&gt;: Analyze patient files, summarize research papers, and generate reports—all while keeping data secure.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;🔐 Cybersecurity &amp;amp; Threat Analysis&lt;/strong&gt;: Process vulnerability reports, security logs, and risk assessments without exposing sensitive information.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;💰 Financial Insights &amp;amp; Business Reports&lt;/strong&gt;: Review personal or company financials, uncover spending patterns, and generate structured reports privately.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;🚀 Product Development &amp;amp; Innovation&lt;/strong&gt;: Summarize internal R&amp;amp;D docs, analyze customer feedback, and generate insights for new product strategies.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;🏢 Corporate Management&lt;/strong&gt;: Retrieve and summarize internal reports, meeting notes, and technical documents for faster decision-making.
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And the best part? &lt;strong&gt;Everything stays local.&lt;/strong&gt; No cloud processing, no data leaks—just secure, AI-powered research. 🚀&lt;/p&gt;




&lt;h2&gt;
  
  
  &lt;strong&gt;Customizations 🛠️&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;🔹 &lt;strong&gt;Add Custom Report Structures&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;By default, the researcher uses a &lt;strong&gt;"standard"&lt;/strong&gt; report structure, but you can customize it.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Add new structures inside the &lt;code&gt;report_structures&lt;/code&gt; folder in the project root directory.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Select your preferred structure from the UI.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;🔹 &lt;strong&gt;Use external LLM Providers&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;By default, the researcher uses &lt;strong&gt;Ollama&lt;/strong&gt; and the local &lt;strong&gt;DeepSeek R1 models&lt;/strong&gt;, but you can easily switch to external LLM providers like &lt;strong&gt;OpenAI, Claude, or even the larger Cloud-based DeepSeek R1 models&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;To change providers:&lt;/p&gt;

&lt;p&gt;1️⃣ Uncomment the relevant code in &lt;a href="https://github.com/kaymen99/local-rag-researcher-deepseek/blob/main/src/assistant/graph.py" rel="noopener noreferrer"&gt;&lt;code&gt;assistant/graph.py&lt;/code&gt;&lt;/a&gt;.&lt;br&gt;&lt;br&gt;
2️⃣ Add the necessary API keys to your &lt;strong&gt;.env&lt;/strong&gt; file.&lt;/p&gt;




&lt;h2&gt;
  
  
  &lt;strong&gt;Final Thoughts&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;✅ You’ve successfully set up your &lt;strong&gt;local RAG researcher&lt;/strong&gt; with &lt;strong&gt;DeepSeek R1 &amp;amp; Ollama&lt;/strong&gt;!&lt;br&gt;&lt;br&gt;
✅ Your &lt;strong&gt;AI researcher&lt;/strong&gt; is up and running—ready to analyze private data and generate your structured reports!&lt;br&gt;&lt;br&gt;
✅ Built with &lt;strong&gt;LangGraph&lt;/strong&gt;, it’s fully customizable—add a reflection step, connect it to databases, or extend its capabilities to fit your needs!&lt;/p&gt;

&lt;p&gt;💡 &lt;strong&gt;Want to learn more?&lt;/strong&gt; Follow my &lt;a href="https://dev.to/kaymen99"&gt;blog&lt;/a&gt; and check out my &lt;a href="https://github.com/kaymen99" rel="noopener noreferrer"&gt;Github&lt;/a&gt; for more AI project &amp;amp; tutorials!&lt;/p&gt;

&lt;p&gt;📖 &lt;strong&gt;Also, don’t miss my guide to reasoning LLMs!&lt;/strong&gt; Check out &lt;a href="https://dev.to/kaymen99/reasoning-llms-explained-how-deepseek-r-1-and-openai-o1-are-solving-ais-hardest-problems-1m76"&gt;Understanding Reasoning LLMs: DeepSeek R1 &amp;amp; OpenAI o1 Demystified&lt;/a&gt; to learn how these models really work!&lt;/p&gt;

</description>
      <category>ai</category>
      <category>rag</category>
      <category>deepseek</category>
      <category>agenticai</category>
    </item>
    <item>
      <title>Understanding Reasoning AI: How DeepSeek R1 &amp; OpenAI o3/o1 Work</title>
      <dc:creator>Aimen Kerrour</dc:creator>
      <pubDate>Sun, 26 Jan 2025 14:18:35 +0000</pubDate>
      <link>https://dev.to/kaymen99/reasoning-llms-explained-how-deepseek-r-1-and-openai-o1-are-solving-ais-hardest-problems-1m76</link>
      <guid>https://dev.to/kaymen99/reasoning-llms-explained-how-deepseek-r-1-and-openai-o1-are-solving-ais-hardest-problems-1m76</guid>
      <description>&lt;p&gt;The &lt;strong&gt;AI landscape is evolving at breakneck speed&lt;/strong&gt;. We’ve grown accustomed to chat models like &lt;strong&gt;GPT-4o&lt;/strong&gt; and &lt;strong&gt;Claude Sonnet 3.5&lt;/strong&gt;—masters of fast, intuitive responses. They write emails, crack jokes, and explain quantum physics in plain English. But when faced with debugging a &lt;strong&gt;500-line script&lt;/strong&gt; or &lt;strong&gt;optimizing a supply chain&lt;/strong&gt;, their limits become clear. These models excel at conversational tasks but struggle with problems that demand &lt;strong&gt;slow, deliberate reasoning&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;With the recent release of &lt;strong&gt;DeepSeek’s R1&lt;/strong&gt; and &lt;strong&gt;OpenAI’s o1/o3&lt;/strong&gt; models, we are witnessing the rise of &lt;strong&gt;reasoning LLMs&lt;/strong&gt;—a new class of AI designed not just to chat but to &lt;strong&gt;think&lt;/strong&gt;. These models take a &lt;strong&gt;methodical, step-by-step approach&lt;/strong&gt; to tackle &lt;strong&gt;complex math problems&lt;/strong&gt;, &lt;strong&gt;debug code&lt;/strong&gt;, and &lt;strong&gt;analyze medical data&lt;/strong&gt; with precision. They represent a shift from &lt;strong&gt;“autocomplete on steroids”&lt;/strong&gt; to &lt;strong&gt;deliberate problem-solving machines&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Let’s explore &lt;strong&gt;how these reasoning models work&lt;/strong&gt;, &lt;strong&gt;why they’re different&lt;/strong&gt;, and &lt;strong&gt;how they’re reshaping AI’s role&lt;/strong&gt; in solving the toughest challenges.&lt;/p&gt;




&lt;h2&gt;
  
  
  &lt;strong&gt;Understanding Reasoning LLM Models&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;To grasp why reasoning models like &lt;strong&gt;DeepSeek R1&lt;/strong&gt; and &lt;strong&gt;OpenAI’s o1/o3&lt;/strong&gt; are revolutionary, we need to start with the foundation: &lt;strong&gt;next-word prediction&lt;/strong&gt;, the engine powering most chat models today.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;The Power (and Limits) of Next-Word Prediction&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Models like &lt;strong&gt;GPT-4o&lt;/strong&gt; and &lt;strong&gt;Claude Sonnet 3.5&lt;/strong&gt; are trained to predict the next token (word or subword) in a sequence. This simple objective forces them to learn grammar, world knowledge, and even basic reasoning—all at once.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.youtube.com/watch?v=yhpjpNXJDco&amp;amp;t=786s" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzx8kk0dtl12bxwmxtoxe.jpg" alt="Jason Wei: Scaling Paradigms for Large Language Models" width="800" height="261"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This approach scales remarkably well. As models grow larger and datasets expand, they unlock &lt;strong&gt;emergent abilities&lt;/strong&gt;—skills like translation or arithmetic that weren’t explicitly programmed. GPT-3, for instance, couldn’t reliably solve math problems, but GPT-4 improved significantly.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;But there’s a catch&lt;/strong&gt;: next-word prediction is &lt;strong&gt;System 1 thinking&lt;/strong&gt;—fast, intuitive, but shallow. It uses the &lt;em&gt;same computational effort&lt;/em&gt; for easy tasks (&lt;em&gt;“What’s 2+2?”&lt;/em&gt;) and hard ones (&lt;em&gt;“Prove Fermat’s Last Theorem”&lt;/em&gt;). When faced with complex reasoning, it often guesses plausibly rather than calculating methodically.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;The Chain-of-Thought Workaround&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;To address this limitation, researchers introduced the concept of &lt;strong&gt;chain-of-thought (CoT) prompting&lt;/strong&gt; in 2022. This technique leverages &lt;strong&gt;prompt engineering&lt;/strong&gt; to guide models into &lt;strong&gt;explicitly revealing their intermediary reasoning steps or internal thoughts&lt;/strong&gt;, nudging them toward &lt;strong&gt;System 2 thinking&lt;/strong&gt;—slower, more deliberate, and logical reasoning.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8cydz16uzb7tlyjsmpp2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8cydz16uzb7tlyjsmpp2.png" alt="Chain of Thought Prompting" width="800" height="425"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;By generating intermediate tokens (like algebraic steps), the model “stores” partial solutions, mimicking human problem-solving.&lt;/p&gt;

&lt;p&gt;This hack improved performance on math, coding, and logic tasks—but it was still a band-aid. &lt;strong&gt;Models weren’t &lt;em&gt;trained&lt;/em&gt; to reason this way; they were just &lt;em&gt;prompted&lt;/em&gt; to&lt;/strong&gt;.&lt;/p&gt;




&lt;h3&gt;
  
  
  &lt;strong&gt;The New Paradigm: Reinforcement Learning Meets Chain-of-Thought&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Reasoning LLMs like &lt;strong&gt;DeepSeek R1&lt;/strong&gt; and &lt;strong&gt;OpenAI’s o1/o3&lt;/strong&gt; go further. Instead of relying on prompting tricks, they’re &lt;em&gt;trained from the ground up&lt;/em&gt; using &lt;strong&gt;reinforcement learning over chain-of-thought trajectories&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Let's explain how it works!&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;First, let’s introduce &lt;strong&gt;Reinforcement Learning (RL)&lt;/strong&gt; for those who might be unfamiliar with it. It’s a &lt;strong&gt;machine learning paradigm&lt;/strong&gt; where an agent learns to make decisions through &lt;strong&gt;trial and error&lt;/strong&gt;, receiving rewards for good actions and penalties for bad ones. Think of it like training a dog—you reinforce the behaviors you want to encourage with &lt;strong&gt;rewards&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;In the world of &lt;strong&gt;conversational AI&lt;/strong&gt;, RL plays a pivotal role. You’ve likely come across terms like &lt;strong&gt;RLHF (Reinforcement Learning from Human Feedback)&lt;/strong&gt; and &lt;strong&gt;RLAIF (Reinforcement Learning from AI Feedback)&lt;/strong&gt;. These techniques fine-tune models like &lt;strong&gt;GPT-4o&lt;/strong&gt; or &lt;strong&gt;Claude&lt;/strong&gt; to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Align outputs with human preferences (e.g., polite, helpful).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Avoid harmful or nonsensical responses.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For example, &lt;strong&gt;RLHF&lt;/strong&gt; might nudge a model toward drafting &lt;strong&gt;concise&lt;/strong&gt;, well-structured email responses while steering it away from &lt;strong&gt;rambling&lt;/strong&gt; or &lt;strong&gt;off-topic&lt;/strong&gt; content. However, it’s important to note that these techniques focus on &lt;strong&gt;style and safety&lt;/strong&gt;, not necessarily on improving &lt;strong&gt;reasoning correctness&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;How RL Transforms Reasoning Models&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;With reasoning LLMs, RL is applied differently. Instead of aligning with human preferences, it’s used to &lt;em&gt;train models to generate verified, correct solutions&lt;/em&gt;. Here’s how:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Training Data with Ground Truth&lt;/strong&gt;:

&lt;ul&gt;
&lt;li&gt;Datasets contain problems with &lt;strong&gt;explicitly correct answers&lt;/strong&gt; (e.g., solved math equations, bug-free code).
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Example:&lt;/strong&gt; A Python script that calculates Fibonacci numbers, verified by unit tests.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Generate Multiple Trajectories&lt;/strong&gt;:

&lt;ul&gt;
&lt;li&gt;For each problem, the model produces &lt;strong&gt;dozens of potential solutions&lt;/strong&gt; (trajectories), including intermediate reasoning steps.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Example:&lt;/strong&gt; 10 different ways to derive the solution to &lt;em&gt;“Solve 3x + 5 = 20”&lt;/em&gt;, some correct, some flawed.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Grader/Verifier&lt;/strong&gt;:

&lt;ul&gt;
&lt;li&gt;A &lt;strong&gt;verifier&lt;/strong&gt; (e.g., code executor, equation solver) checks each trajectory.&lt;/li&gt;
&lt;li&gt;Correct solutions get a reward; incorrect ones get nothing or get a penalty.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Policy Optimization&lt;/strong&gt;:

&lt;ul&gt;
&lt;li&gt;The ultimate goal of RL is to learn the best policy, so the model’s weights are adjusted to favor high-reward trajectories. &lt;/li&gt;
&lt;li&gt;Over time, it internalizes patterns that lead to verified answers which reinforces correct reasoning.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;The Process in Action&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;Let’s break down a training step for a coding problem:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Input&lt;/strong&gt;: &lt;em&gt;“Write a Python function to calculate Fibonacci numbers.”&lt;/em&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Model Generates&lt;/strong&gt;: 20 potential solutions with different algorithms (recursive, iterative).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Grader Tests&lt;/strong&gt;: Each solution against unit tests (e.g., &lt;code&gt;fib(5) must return 5&lt;/code&gt;).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Reward&lt;/strong&gt;: Only bug-free code that passes tests gets a reward.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Policy Update&lt;/strong&gt;: The model learns to prioritize efficient, test-passing code.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This method, described in OpenAI’s &lt;a href="https://openai.com/index/learning-to-reason-with-llms/" rel="noopener noreferrer"&gt;Learning to Reason with LLMs&lt;/a&gt; blog post and Nathan Lambert’s &lt;a href="https://www.youtube.com/watch?v=skT89EvIjrc" rel="noopener noreferrer"&gt;breakdown&lt;/a&gt;, turns the model into a &lt;strong&gt;self-improving problem-solver&lt;/strong&gt;.&lt;/p&gt;




&lt;h3&gt;
  
  
  &lt;strong&gt;A New Scaling Law: Quality Over Quantity&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;In the past 2 years, LLM progress followed a predictable formula:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;bigger models + more data = better performance&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;But this paradigm is hitting diminishing returns. Training data is becoming scarce (e.g., high-quality text is finite), and doubling model size no longer guarantees proportional gains.&lt;/p&gt;

&lt;p&gt;Reasoning models like &lt;strong&gt;OpenAI’s o1&lt;/strong&gt; and &lt;strong&gt;DeepSeek R1&lt;/strong&gt; rewrite this playbook. Their performance scales not with raw data volume, but with &lt;strong&gt;how compute is allocated to verify reasoning quality&lt;/strong&gt;. This introduces a new scaling law:&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;What the Data Shows&lt;/strong&gt;
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;As shown from OpenAI's o1 model training, reasoning models &lt;strong&gt;improve steadily with more compute allocated to verifying trajectories&lt;/strong&gt;. Unlike traditional training (where gains plateau), iterative refinement of reasoning paths yields continuous improvements.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://openai.com/index/learning-to-reason-with-llms/" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fepi0qa59hhq5t3zviru1.jpg" alt="OpenAI O1 training accuracy evolution over time chart" width="639" height="359"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Additionally at test time, allowing models like DeepSeek R1 to &lt;strong&gt;use more tokens for “thinking”&lt;/strong&gt; (e.g., generating longer chain-of-thought steps) directly boosts accuracy. This mirrors human problem-solving—more time spent deliberating often leads to better solutions.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://github.com/deepseek-ai/DeepSeek-R1/blob/main/DeepSeek_R1.pdf" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8z4zdpk7nsgzsc5af4gk.png" alt="Deepseek R1 Training chart" width="800" height="516"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;Why This Matters&lt;/strong&gt;
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Smaller Models, Bigger Impact&lt;/strong&gt;: A 7B-parameter reasoning model can outperform a 70B-parameter generalist on niche tasks (e.g., medical coding analysis) by focusing compute on verification, not memorization.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Escape the Data Bottleneck&lt;/strong&gt;: Instead of scraping the internet for more text, these models extract value from smaller, high-quality datasets (e.g., verified math problems).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Flexible Compute Tradeoffs&lt;/strong&gt;: Users can “dial up” accuracy by allowing more reasoning steps (tokens) or “dial down” for faster, cheaper outputs.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Future of Reasoning models&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Today’s reasoning models are &lt;strong&gt;still in their infancy&lt;/strong&gt;, yet they’re already achieving what took traditional LLMs years to master. Benchmarks like &lt;strong&gt;GPQA&lt;/strong&gt;—a grueling test of complex, “Google-proof” reasoning—are being saturated &lt;strong&gt;10x faster&lt;/strong&gt; than older models could manage.&lt;/p&gt;

&lt;p&gt;And this is just the beginning!&lt;/p&gt;

&lt;p&gt;With the recent surge of &lt;strong&gt;DeepSeek R1&lt;/strong&gt; and a multitude of open-source reasoning models like &lt;strong&gt;Llama-3-Reason&lt;/strong&gt; and &lt;strong&gt;Mistral-Math&lt;/strong&gt;, more researchers and developers are diving into this field. This collective momentum promises &lt;strong&gt;rapid advancements—not in years, but potentially within months&lt;/strong&gt;. The era of &lt;strong&gt;deliberate, step-by-step reasoning&lt;/strong&gt; has just begun, and its potential to &lt;strong&gt;reshape problem-solving&lt;/strong&gt; is boundless.&lt;/p&gt;




&lt;h2&gt;
  
  
  &lt;strong&gt;How to Use Reasoning LLM Models&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;(Inspired by&lt;/em&gt; &lt;a href="https://www.latent.space/p/o1-skill-issue" rel="noopener noreferrer"&gt;&lt;em&gt;Latent Space’s “Missing Manual” for OpenAI o1&lt;/em&gt;&lt;/a&gt;&lt;em&gt;)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Reasoning models like &lt;strong&gt;OpenAI’s o1&lt;/strong&gt; or &lt;strong&gt;DeepSeek R1&lt;/strong&gt; demand a fundamentally different prompting than chat-first models like &lt;strong&gt;Claude&lt;/strong&gt; or &lt;strong&gt;GPT-4o&lt;/strong&gt;. Here’s how to use them effectively:&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;1. Provide Extensive Context&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Think of the model as a &lt;strong&gt;new hire&lt;/strong&gt;. It won’t ask for more details, so you need to give it everything upfront. Share as much context as possible—&lt;strong&gt;even more than you think is necessary&lt;/strong&gt;. For example:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Explain what you’ve already tried&lt;/strong&gt; and why it didn’t work.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Include relevant data&lt;/strong&gt;, like database schemas or company-specific terms.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Describe the problem space in detail.&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The more context you provide, the better the model can deliver &lt;strong&gt;accurate results&lt;/strong&gt; without unnecessary back-and-forth.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.latent.space/p/o1-skill-issue" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftv1g483v9x25omynkbad.jpg" alt="How to Prompt OpenAI o1 model" width="800" height="665"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;2. Focus on the Outcome, Not the Process&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Instead of telling the model &lt;strong&gt;how&lt;/strong&gt; to solve a problem, focus on &lt;strong&gt;what you want as the final result&lt;/strong&gt;. Be specific about your goals:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Do you need a &lt;strong&gt;complete file&lt;/strong&gt;, a &lt;strong&gt;list of options&lt;/strong&gt;, or a &lt;strong&gt;detailed explanation&lt;/strong&gt;?&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Let the model handle the reasoning and planning—it’s &lt;strong&gt;designed to do that for you&lt;/strong&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;3. Understand Their Strengths and Limitations&lt;/strong&gt;
&lt;/h3&gt;

&lt;h4&gt;
  
  
  ✅ &lt;strong&gt;What They Can Do&lt;/strong&gt;
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Generate Complete Files:&lt;/strong&gt; They can one-shot entire files (or multiple files) with minimal errors, following your existing patterns.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Explain Complex Concepts:&lt;/strong&gt; They excel at breaking down difficult topics with &lt;strong&gt;clear examples&lt;/strong&gt;, almost like writing an article.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Provide Structured Outputs:&lt;/strong&gt; They can create detailed comparisons, pros/cons lists, or multiple plans for architectural decisions.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Hallucinate Less:&lt;/strong&gt; They are generally more accurate, especially with niche tasks like &lt;strong&gt;bespoke query languages&lt;/strong&gt; or &lt;strong&gt;medical differential diagnoses&lt;/strong&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  ❌ &lt;strong&gt;What They Can’t Do (Yet)&lt;/strong&gt;
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Write in Specific Styles:&lt;/strong&gt; They tend to default to an academic or corporate tone, struggling to adapt to unique voices.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Build Entire Applications:&lt;/strong&gt; While great at one-shotting features, they require &lt;strong&gt;significant iteration&lt;/strong&gt; to create a full SaaS or complex app.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;By following these tips, you can &lt;strong&gt;unlock the full potential&lt;/strong&gt; of reasoning models and achieve &lt;strong&gt;faster, more accurate results&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  &lt;strong&gt;Practical Use Cases&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Reasoning models excel at tasks that require deep thinking and structured problem-solving. Here are some of their applications:&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;Coding&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;As mentioned earlier, these models are able to generate multiple code files in a single step with minimal errors. For example, &lt;a href="https://www.youtube.com/@ColeMedin" rel="noopener noreferrer"&gt;&lt;strong&gt;Cole Madin&lt;/strong&gt;&lt;/a&gt; demonstrated how &lt;strong&gt;DeepSeek R1&lt;/strong&gt; was used within &lt;a href="https://github.com/stackblitz-labs/bolt.diy" rel="noopener noreferrer"&gt;&lt;strong&gt;Bolt.diy&lt;/strong&gt;&lt;/a&gt; to &lt;strong&gt;build a complete chat interface for an AI agent&lt;/strong&gt;, delivering outstanding results compared to &lt;strong&gt;Claude-Sonnet-3.5&lt;/strong&gt; on the first attempt.&lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/-GmEIqi0yNE"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;Planning in Workflows and Agents&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;Reasoning models are highly effective in upfront planning for agent-based workflows, outlining detailed steps for execution by traditional agents.&lt;/p&gt;

&lt;p&gt;Unify used &lt;strong&gt;OpenAI's o1 model&lt;/strong&gt; to create their &lt;a href="https://blog.langchain.dev/unify-launches-agents-for-account-qualification-using-langgraph-and-langsmith/" rel="noopener noreferrer"&gt;AI agents for account qualification using LangGraph&lt;/a&gt;, the model was used to generate detailed, step-by-step plans and identify potential challenges. It effectively expanded on user queries, even with minimal input, making it ideal for strategic planning and further research tasks.&lt;/p&gt;


&lt;div class="crayons-card c-embed text-styles text-styles--secondary"&gt;
      &lt;div class="c-embed__cover"&gt;
        &lt;a href="https://blog.langchain.dev/unify-launches-agents-for-account-qualification-using-langgraph-and-langsmith/" class="c-link s:max-w-50 align-middle" rel="noopener noreferrer"&gt;
          &lt;img alt="" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.langchain.dev%2Fcontent%2Fimages%2Fsize%2Fw1200%2F2024%2F10%2F3.-PlanningAgent-LangGraph.png" height="613" class="m-0" width="800"&gt;
        &lt;/a&gt;
      &lt;/div&gt;
    &lt;div class="c-embed__body"&gt;
      &lt;h2 class="fs-xl lh-tight"&gt;
        &lt;a href="https://blog.langchain.dev/unify-launches-agents-for-account-qualification-using-langgraph-and-langsmith/" rel="noopener noreferrer" class="c-link"&gt;
          Unify Launches Agents for Account Qualification using LangGraph and LangSmith
        &lt;/a&gt;
      &lt;/h2&gt;
      &lt;div class="color-secondary fs-s flex items-center"&gt;
          &lt;img alt="favicon" class="c-embed__favicon m-0 mr-2 radius-0" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.langchain.dev%2Fcontent%2Fimages%2Fsize%2Fw256h256%2F2024%2F03%2FTwitter_ProfilePicture.png" width="256" height="256"&gt;
        blog.langchain.dev
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;


&lt;h4&gt;
  
  
  &lt;strong&gt;Deep Research and Reflection&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;As research assistants, these models excel at analyzing academic papers, summarizing key findings, and generating comprehensive reports.&lt;/strong&gt; They are also highly effective at reflecting on and analyzing search results or large sets of documents, enabling them to extract critical insights or identify overlooked details.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Langchain&lt;/strong&gt; has posted an excellent tutorial on how to &lt;strong&gt;set up your own local research assistant using&lt;/strong&gt; &lt;strong&gt;DeepSeek-R1&lt;/strong&gt;, making it easier than ever to leverage these powerful tools for academic and research purposes.&lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/sGUjmyfof4Q"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;Data Analysis&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;Advanced reasoning models have proven to be invaluable for analyzing complex datasets, including those in highly specialized fields like medicine and finance. These models uncover patterns, extract actionable insights, and streamline decision-making processes.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://tocanan.ai/aireportpro-openai-o1-financial-media-intelligence/" rel="noopener noreferrer"&gt;&lt;strong&gt;Enhancing Financial and Media Analysis Using OpenAI’s o1 Model in AiReportPro&lt;/strong&gt;&lt;/a&gt;&lt;strong&gt;:&lt;/strong&gt; explores how the o1 model transforms financial and media analysis, empowering businesses with real-time intelligence for better strategic decisions.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://arxiv.org/html/2409.15277v1" rel="noopener noreferrer"&gt;&lt;strong&gt;A Preliminary Study of o1 in Medicine: Are We Closer to an AI Doctor?&lt;/strong&gt;&lt;/a&gt;&lt;strong&gt;:&lt;/strong&gt; investigates the potential of OpenAI’s o1 model in medical applications, assessing its capability to support healthcare professionals through diagnostic and predictive analytics.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;Newsfeeds Analysis&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;Reasoning models are powerful tools for analyzing &lt;strong&gt;news&lt;/strong&gt; and &lt;strong&gt;social media&lt;/strong&gt;, identifying trends, and surfacing relevant information. For example, the &lt;a href="https://www.firecrawl.dev/" rel="noopener noreferrer"&gt;&lt;strong&gt;Firecrawl team&lt;/strong&gt;&lt;/a&gt; developed the &lt;strong&gt;o1 Trend Finder&lt;/strong&gt;, a tool powered by the &lt;em&gt;o1 model&lt;/em&gt;. It efficiently filters &lt;strong&gt;critical insights&lt;/strong&gt; from news feeds, providing users with &lt;strong&gt;targeted updates&lt;/strong&gt; that matter most.&lt;/p&gt;

&lt;p&gt;&lt;iframe class="tweet-embed" id="tweet-1874145916116222198-230" src="https://platform.twitter.com/embed/Tweet.html?id=1874145916116222198"&gt;
&lt;/iframe&gt;

  // Detect dark theme
  var iframe = document.getElementById('tweet-1874145916116222198-230');
  if (document.body.className.includes('dark-theme')) {
    iframe.src = "https://platform.twitter.com/embed/Tweet.html?id=1874145916116222198&amp;amp;theme=dark"
  }



&lt;/p&gt;




&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;We’ve seen how reasoning LLMs like &lt;strong&gt;DeepSeek R1&lt;/strong&gt; and &lt;strong&gt;OpenAI o1/o3&lt;/strong&gt; are flipping the script. No longer just "fast talkers" these models slow down, break problems into steps, and verify solutions like meticulous problem-solvers. By combining &lt;strong&gt;chain-of-thought&lt;/strong&gt; logic with &lt;strong&gt;reinforcement learning&lt;/strong&gt;, they’re tackling tasks that once stumped traditional chatbots—debugging code, cracking math proofs, or untangling complex data.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;This isn’t just an upgrade—it’s a fundamental shift!&lt;/strong&gt; &lt;strong&gt;Reasoning models&lt;/strong&gt; prove that AI can do more than mimic human conversation; it can mirror our deliberate, step-by-step thinking. But here’s the kicker:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;Does this mean we’re edging closer to AGI?&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;While they’re still far from human-like general intelligence, their ability to learn verified reasoning patterns hints at a future where AI doesn’t just answer—it understands.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;So, where do you think we’re headed with ever smarter LLMs? Share your thoughts below!&lt;/strong&gt; 🌟🤔&lt;/p&gt;

</description>
      <category>ai</category>
      <category>deepseek</category>
      <category>learning</category>
      <category>openai</category>
    </item>
    <item>
      <title>AI Voice Agents in 2025: A Comprehensive Guide</title>
      <dc:creator>Aimen Kerrour</dc:creator>
      <pubDate>Thu, 09 Jan 2025 10:20:27 +0000</pubDate>
      <link>https://dev.to/kaymen99/ai-voice-agents-in-2025-a-comprehensive-guide-3kl</link>
      <guid>https://dev.to/kaymen99/ai-voice-agents-in-2025-a-comprehensive-guide-3kl</guid>
      <description>&lt;p&gt;&lt;strong&gt;Did you know that 62% of potential customers are lost before they even hear a response?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Studies reveal that most callers won’t try again if their first attempt goes unanswered. Businesses across industries face this challenge—whether it's handling high call volumes, managing inquiries, or qualifying leads. &lt;strong&gt;The result? Missed opportunities, lost revenue, and weakened customer trust.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;But what if you could answer every call, every time?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The good news is, you can. In 2025, &lt;strong&gt;AI voice agents&lt;/strong&gt; are revolutionizing customer interactions. These intelligent systems ensure &lt;strong&gt;no call goes unanswered&lt;/strong&gt;, providing instant support, 24/7 availability, and seamless customer experiences.&lt;/p&gt;

&lt;p&gt;In this post, we'll explore the world of &lt;strong&gt;AI voice agents&lt;/strong&gt;: what they are, how they work, the benefits they offer, and how you can build and deploy them for your business.&lt;/p&gt;




&lt;h2&gt;
  
  
  What Are Voice AI Agents?
&lt;/h2&gt;

&lt;p&gt;Voice AI agents are systems that use &lt;strong&gt;artificial intelligence (AI)&lt;/strong&gt; to listen, understand, and respond to people in a natural and conversational way. These agents can do tasks like answering questions, giving information, booking appointments, and triggering actions—all in real-time.&lt;/p&gt;

&lt;h3&gt;
  
  
  How Do They Work?
&lt;/h3&gt;

&lt;p&gt;To achieve this, voice AI agents rely on one of two main design architectures:&lt;/p&gt;

&lt;h4&gt;
  
  
  1. &lt;strong&gt;Modular Architecture&lt;/strong&gt; (Traditional Method)
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fz3bfld7gx3nimexdtd25.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fz3bfld7gx3nimexdtd25.png" alt="Diagram illustrating traditional AI voice agent pipeline stages: Speech-to-Text (STT), LLM (AI) processing, and Text-to-Speech (TTS)." width="800" height="342"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This method breaks down the interaction into separate components, each handling a specific task:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Speech-to-Text (STT):&lt;/strong&gt; Translates the caller’s voice into written text.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Text Processing by an AI Chat Agent:&lt;/strong&gt; A text-based AI agent, powered by a large language model (LLM), processes the text input. It uses integrated tools to fetch information, manage tasks like booking appointments, or triggering actions.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Text-to-Speech (TTS):&lt;/strong&gt; Converts the agent's generated text response back into natural-sounding speech, which is then sent to the caller.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  2. &lt;strong&gt;Unified Architecture&lt;/strong&gt; (Direct Method)
&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;Introduced in late 2024 with OpenAI's Realtime API&lt;/strong&gt;, this method combines everything into one step:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;A &lt;strong&gt;standalone AI agent&lt;/strong&gt; handles everything from speech input to speech output.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The agent is backed by an LLM that directly processes audio input, performs the required analysis (e.g., calling tools or retrieving data), and generates an appropriate audio response without intermediate text-based steps.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Which One Is Better?
&lt;/h4&gt;

&lt;p&gt;The &lt;strong&gt;modular architecture&lt;/strong&gt; is cheaper but can be slower because different parts need to work together. On the other hand, using &lt;strong&gt;OpenAI's Realtime API&lt;/strong&gt; offers a faster, more seamless experience, though it comes at a higher cost.&lt;/p&gt;

&lt;h2&gt;
  
  
  Types of Voice AI Agents
&lt;/h2&gt;

&lt;p&gt;AI voice agents are designed for different purposes, and understanding these differences is key. &lt;strong&gt;There are two main types: inbound and outbound.&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Inbound Agents
&lt;/h3&gt;

&lt;p&gt;These agents are like your virtual receptionists, handling incoming calls and requests. They're designed to field inquiries, provide information, and assist customers who are reaching out to a business. Here's how they're being used:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Customer Support:&lt;/strong&gt; Handling common issues like password resets and order tracking, while seamlessly directing complex problems to human agents.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Appointment Scheduling:&lt;/strong&gt; Allowing customers to easily book, reschedule, or cancel appointments for services like medical consultations or car repairs.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Answering FAQs:&lt;/strong&gt; Providing instant answers to frequently asked questions about business hours, locations, product details, or return policies.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Order Taking/Processing:&lt;/strong&gt; Guiding customers through placing new orders or making reservations, simplifying the process.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvzbblmtb572lrigh2e9s.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvzbblmtb572lrigh2e9s.png" alt="AI Voice agents types and use cases: Outbound vs Inbound" width="800" height="320"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Outbound Agents
&lt;/h3&gt;

&lt;p&gt;These agents are proactive, reaching out to customers on behalf of a business. They're used for various purposes, from marketing and sales to reminders and follow-ups. Here are some examples:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Lead Qualification:&lt;/strong&gt; Contacting potential customers to gauge interest, gather information, and schedule appointments for qualified leads with sales reps.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Reminders:&lt;/strong&gt; Sending automated reminders to customers about upcoming appointments or overdue payments, reducing no-shows and improving cash flow.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Surveys and Feedback:&lt;/strong&gt; Conducting customer satisfaction surveys to gather feedback and identify areas for improvement.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Reactivating Cold Leads:&lt;/strong&gt; Reaching out to old leads that have gone cold, rekindling interest and identifying potential opportunities.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Promotional Calls:&lt;/strong&gt; Informing customers about special offers, discounts, or new product launches.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;By understanding the different types of AI voice agents and their capabilities, you can start to see the many ways they can be used to improve efficiency and customer experience, creating new opportunities for both businesses and developers.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Building AI Voice Agents: Tools and Approaches&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Creating your own &lt;strong&gt;voice AI agent&lt;/strong&gt; might seem daunting at first, &lt;strong&gt;but it has become surprisingly accessible&lt;/strong&gt;. There are different approaches to suit various skill levels and project needs, and you don't even need deep coding knowledge to build a fully custom and highly reliable voice agent.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Let's explore the options you can use!&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;No-Code Platforms: The Fastest Way to Get Started&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;No-code platforms are revolutionizing the way &lt;strong&gt;voice AI agents&lt;/strong&gt; are built, offering the quickest and easiest path to development.&lt;/p&gt;

&lt;p&gt;These platforms act as an orchestration layer, seamlessly handling the complex background processes of your agent. This includes connecting to various voice service providers like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://deepgram.com/" rel="noopener noreferrer"&gt;&lt;strong&gt;Deepgram&lt;/strong&gt;&lt;/a&gt; for highly accurate speech-to-text (STT).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://elevenlabs.io/" rel="noopener noreferrer"&gt;&lt;strong&gt;ElevenLabs&lt;/strong&gt;&lt;/a&gt; for realistic text-to-speech (TTS), generating natural-sounding voices.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;They also simplify integration with leading:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Large Language Models (LLMs)&lt;/strong&gt;: such as OpenAI's GPT models, Claude, Google's Gemini, or open source ones like those from Meta LLAMA or Mistral, to power your agent's understanding and responses.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Telephony Providers&lt;/strong&gt;: Enabling your agent to make and receive phone calls through services like &lt;a href="https://www.twilio.com" rel="noopener noreferrer"&gt;Twilio&lt;/a&gt; or &lt;a href="https://telnyx.com/" rel="noopener noreferrer"&gt;Telnyx&lt;/a&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;By managing these connections, no-code platforms provide a visual interface where you can focus on what matters most:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Designing your agent's personality and conversation flow.&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Defining the specific actions your agent should take.&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Adding the tools that your agent will need.&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Instead of getting bogged down in technical complexities, you can concentrate on crafting the user experience and ensuring your agent meets your specific goals.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Core Features&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;No-code voice AI platforms&lt;/strong&gt; typically offer a set of essential features that make them powerful tools for building voice agents:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffvpvlyg8dy9qbosncrxr.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffvpvlyg8dy9qbosncrxr.png" alt="No-code voice AI agent builder platforms features." width="698" height="542"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Multi-Language Support:&lt;/strong&gt; Supports multiple languages, making it perfect for businesses that serve diverse customer bases.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Knowledge Base Creation:&lt;/strong&gt; Allowing you to upload custom files with domain-specific information, enabling the agent to provide more accurate and contextually relevant responses.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Tool Integrations:&lt;/strong&gt; Offering built-in tools like call transfers and end-call functionality, as well as supporting external integrations through webhooks to connect with custom servers or third-party services like &lt;a href="http://Make.com" rel="noopener noreferrer"&gt;Make.com&lt;/a&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Endpointing:&lt;/strong&gt; Accurately detecting when a user has finished speaking to manage turn-taking smoothly.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Interruptions (Barge-in):&lt;/strong&gt; Handling interruptions intelligently, differentiating between genuine interjections and simple acknowledgments.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Background Noise Management:&lt;/strong&gt; Filtering out background noise to ensure clear communication and focus on the primary speaker.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Backchanneling:&lt;/strong&gt; Incorporating subtle cues like "uh-huh" and "got it" to create a more natural and engaging conversation flow.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Call Transcriptions &amp;amp; Post-call Analysis:&lt;/strong&gt; Providing detailed call transcripts and often generating summaries, determining call success, or extracting key information.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Popular No-Code Platforms: Vapi and Retell AI
&lt;/h3&gt;

&lt;p&gt;Several platforms are at the forefront of no-code &lt;strong&gt;voice AI development&lt;/strong&gt;, with &lt;strong&gt;Vapi&lt;/strong&gt; and &lt;strong&gt;Retell AI&lt;/strong&gt; being two of the most prominent.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://vapi.ai/" rel="noopener noreferrer"&gt;&lt;strong&gt;VAPI&lt;/strong&gt;&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://vapi.ai/" rel="noopener noreferrer"&gt;Vapi&lt;/a&gt; offers a highly customizable platform for building voice AI agents, where you can select your preferred providers for STT, LLM, and TTS, offering flexibility and control.&lt;/p&gt;

&lt;p&gt;In addition to the core features, Vapi boasts:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Wide LLM Support:&lt;/strong&gt; You assistant can use a vast range of LLMs, including OpenAI models, Claude, Gemini, Groq, and others.
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnaen9djea0zee82wliqo.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnaen9djea0zee82wliqo.png" alt="Vapi AI assistant builder" width="800" height="431"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Multiple Voice Providers:&lt;/strong&gt; has integrations with ElevenLabs, Deepgram, Cartesia, OpenAI voices, etc.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6gz3s4sisgt1n1czpmkg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6gz3s4sisgt1n1czpmkg.png" alt="VAPI AI voice models" width="800" height="431"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;GHL/Make Tools Integration:&lt;/strong&gt; Vapi allows direct integration with &lt;strong&gt;GoHighLevel&lt;/strong&gt; workflows and &lt;a href="http://Make.com" rel="noopener noreferrer"&gt;&lt;strong&gt;Make.com&lt;/strong&gt;&lt;/a&gt; scenarios, enabling you to trigger these automations using voice commands within your agent.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F69agihqfzkg9ap7vh1t1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F69agihqfzkg9ap7vh1t1.png" alt="VAPI AI tools creator" width="800" height="430"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Squads:&lt;/strong&gt; The ability to create teams of specialized agents that can handle different parts of a complex workflow and easily transfer calls between them.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcqwy2tl5kr6pu1y03a12.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcqwy2tl5kr6pu1y03a12.png" alt="VAPI AI squads builder" width="800" height="583"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Conversation Flow—Blocks (Beta):&lt;/strong&gt; A new feature designed to improve conversation flow by breaking it down into smaller, manageable prompts, reducing errors and hallucinations. This provides more control and reliability, like a "checklist for conversations."&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://www.retellai.com/" rel="noopener noreferrer"&gt;&lt;strong&gt;Retell AI&lt;/strong&gt;&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://www.retellai.com/" rel="noopener noreferrer"&gt;Retell AI&lt;/a&gt; prioritizes creating highly responsive voice agents with minimal latency, making them ideal for real-time conversations.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fltqz66yql15qdjox9gwx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fltqz66yql15qdjox9gwx.png" alt="RETELL AI assistants" width="800" height="273"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;While similar to VAPI in its capabilities, Retell AI's current LLMs model support is limited to &lt;strong&gt;OpenAI's GPT-4o and Anthropic's Claude&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2py8mykfmvzvjtnmhsaw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2py8mykfmvzvjtnmhsaw.png" alt="RETELL AI Agents" width="800" height="430"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;OpenAI Realtime API Support&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Both VAPI and Retell AI allow you to use the OpenAI Realtime API (speech-to-speech model) directly without having to interact with OpenAI, which simplify further the development of low latency voice agents.&lt;/p&gt;

&lt;h3&gt;
  
  
  Advantages &amp;amp; Disadvantages of No-Code
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Advantages:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Speed:&lt;/strong&gt; Launch your agent in minutes or hours, not days or weeks.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Ease of Use:&lt;/strong&gt; Minimal to no coding experience is required, and server management is handled by the platform, making it very user-friendly.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Accessibility:&lt;/strong&gt; Ideal for entrepreneurs, marketers, and anyone without a strong technical background.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Disadvantages:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Latency &amp;amp; Reliability:&lt;/strong&gt; Both &lt;a href="http://Vapi.ai" rel="noopener noreferrer"&gt;Vapi.ai&lt;/a&gt; and Retell AI rely on external API providers, which can &lt;strong&gt;result in delays of 3–4 seconds&lt;/strong&gt;, affecting call quality. This is especially problematic for enterprise use.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Limited Customization:&lt;/strong&gt; You may encounter restrictions based on the platform's built-in features.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Platform Cost:&lt;/strong&gt; Subscription fees or usage-based pricing are common, so factor these costs into your budget.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Code-Based Solutions
&lt;/h3&gt;

&lt;p&gt;For developers seeking full control over their voice agents and requiring highly customized solutions, code-based approaches are ideal. These involve writing code to manage every aspect of the voice agent, from natural language processing (NLP) to handling voice input and output.&lt;/p&gt;

&lt;p&gt;There are two primary approaches:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Building your agent from scratch.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Using frameworks like &lt;strong&gt;LiveKit&lt;/strong&gt; to simplify development.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Option 1: Build From Scratch&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;For building from scratch one would be use programming languages like &lt;strong&gt;Python or Node.js&lt;/strong&gt;. This allows you to create highly customized voice agents tailored to specific needs.&lt;/p&gt;

&lt;p&gt;You'll be responsible for handling all aspects of the agent's logic, including:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Connecting to &lt;strong&gt;speech-to-text (STT)&lt;/strong&gt; and &lt;strong&gt;text-to-speech (TTS)&lt;/strong&gt; providers.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Communicating with large language models (&lt;strong&gt;LLMs&lt;/strong&gt;) via APIs and managing conversational state in memory.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Integrating with telephony providers like &lt;strong&gt;Twilio or Telnyx&lt;/strong&gt; for inbound and outbound calls.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Implementing advanced features such as background noise removal, interruption handling, and backchanneling.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This list is not exhaustive—many additional aspects must be considered.&lt;/p&gt;

&lt;p&gt;For instance, when interacting with different APIs and providers managing latency is critical since high delays can severely impact user experience. &lt;strong&gt;No one wants a voice agent with a 10-second delay!&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If you are interested in using the &lt;strong&gt;OpenAI Realtime API&lt;/strong&gt;, multiple tutorials are available for developing low-latency voice agents.&lt;/p&gt;

&lt;p&gt;For example, &lt;strong&gt;Twilio&lt;/strong&gt; provides various &lt;a href="https://www.twilio.com/en-us/blog/twilio-openai-realtime-api-launch-integration" rel="noopener noreferrer"&gt;articles and videos&lt;/a&gt; about building inbound and outbound AI callers using the &lt;strong&gt;OpenAI Realtime API&lt;/strong&gt; with &lt;strong&gt;Python or Node.js.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fuvwcy0qmg3zap48opdmh.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fuvwcy0qmg3zap48opdmh.png" alt="Twilio OpenAI Tutorials" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;If you prefer Python for example, you can explore:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://www.twilio.com/en-us/blog/voice-ai-assistant-openai-realtime-api-python" rel="noopener noreferrer"&gt;Build an AI Voice Assistant with Twilio Voice, the OpenAI Realtime API, and Python&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://www.twilio.com/en-us/blog/outbound-calls-python-openai-realtime-api-voice" rel="noopener noreferrer"&gt;Outbound Calling with Twilio Voice, the OpenAI Realtime API, and Python&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Option 2: Using LiveKit&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;If you want to avoid managing the complexities of real-time voice communication and provider integrations, consider using &lt;strong&gt;LiveKit&lt;/strong&gt;, a framework for building programmable, multimodal AI agents in &lt;strong&gt;Python or Node.js&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F912nhb9101lcqax5kaef.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F912nhb9101lcqax5kaef.png" alt="LiveKit voice AI platform" width="800" height="448"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;LiveKit&lt;/strong&gt; simplifies development by handling much of the heavy lifting. It operates as a stateful, long-running process, connecting to the &lt;strong&gt;LiveKit&lt;/strong&gt; network via &lt;strong&gt;WebRTC&lt;/strong&gt; for ultra-low-latency, real-time communication.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdl41ocnnntimrbt0uwdi.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdl41ocnnntimrbt0uwdi.png" alt="LiveKit voice AI Agents architecture" width="800" height="445"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;LiveKit is the equivalent of VAPI or Retell AI in the coding world!&lt;/strong&gt; It offers capabilities similar to those no-code platforms, including:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Managing &lt;strong&gt;STT&lt;/strong&gt; and &lt;strong&gt;TTS&lt;/strong&gt; conversions.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Connecting with LLMs and handling turn detection and interruptions via &lt;strong&gt;Voice Activity Detection (VAD)&lt;/strong&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Easy integration with telephony providers like &lt;strong&gt;Twilio and Telnyx&lt;/strong&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Supporting the use of &lt;strong&gt;OpenAI Realtime API&lt;/strong&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Plus many others features which you can see for yourself in the their extensive &lt;a href="https://docs.livekit.io/agents/" rel="noopener noreferrer"&gt;Documentation&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Advantages &amp;amp; Disadvantages of Code-Based Solutions
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Advantages:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Ultimate Flexibility:&lt;/strong&gt; Design your agent exactly how you want, without limitations.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Full Control:&lt;/strong&gt; Manage every aspect of functionality and data handling.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Innovative Solutions:&lt;/strong&gt; Build unique and differentiated voice experiences.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Disadvantages:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Steep Learning Curve:&lt;/strong&gt; Requires strong programming skills and a deep understanding of AI and APIs.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Time-Consuming:&lt;/strong&gt; Building from scratch demands significant time and effort.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Maintenance Overhead:&lt;/strong&gt; You’re responsible for ongoing code maintenance and updates.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  4. The Future of AI Voice Agents in 2025
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Folw6ua5dbsks4l30tgn5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Folw6ua5dbsks4l30tgn5.png" alt="Voice AI Agents in 2025" width="800" height="457"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2025 is shaping up to be a pivotal year for AI voice agents&lt;/strong&gt;, as they become &lt;strong&gt;essential tools&lt;/strong&gt; for businesses of all sizes. Industries such as &lt;strong&gt;retail, healthcare, finance, and real estate&lt;/strong&gt; are leading the way, leveraging voice agents for &lt;strong&gt;customer support, lead generation, and operational efficiency.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Surveys suggest that &lt;strong&gt;70% of businesses&lt;/strong&gt; plan to adopt voice AI technology by the end of 2025. This growth is fueled by &lt;strong&gt;rapid advancements in AI models&lt;/strong&gt;, which promise &lt;strong&gt;reduced costs&lt;/strong&gt; and &lt;strong&gt;improved performance&lt;/strong&gt;, enabling more &lt;strong&gt;powerful and accessible&lt;/strong&gt; AI agents.&lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;widespread adoption&lt;/strong&gt; of &lt;strong&gt;voice AI&lt;/strong&gt; is creating a surge in demand for experts who can &lt;strong&gt;build, deploy, and optimize&lt;/strong&gt; these systems. &lt;strong&gt;Entrepreneurs and developers&lt;/strong&gt; who invest in mastering this technology today are &lt;strong&gt;well-positioned&lt;/strong&gt; to tap into a &lt;strong&gt;rapidly expanding market.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Beyond offering voice AI as a service, businesses can explore &lt;strong&gt;niche opportunities&lt;/strong&gt;, such as developing &lt;strong&gt;industry-specific agents&lt;/strong&gt; or providing &lt;strong&gt;value-added features&lt;/strong&gt; like &lt;strong&gt;analytics, voice personalization, and CRM integrations.&lt;/strong&gt; The possibilities are vast, and the &lt;strong&gt;potential rewards are significant.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  5. How to Get Started with AI Voice Agents
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Ready to start exploring the power of AI voice agents?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Getting started is easier than you might think. Here's a step-by-step guide to help you launch your first voice agent:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsbt64mivd662aufzc2ra.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsbt64mivd662aufzc2ra.png" alt="AI Voice Agents Creation Steps" width="800" height="405"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;1- Identify a Niche:&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;Don’t try to boil the ocean.&lt;/strong&gt; Focus on a specific industry or a clearly defined problem where a voice agent can deliver &lt;strong&gt;significant value.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;For example, you could start by &lt;strong&gt;automating appointment scheduling&lt;/strong&gt; for a dental practice or creating a &lt;strong&gt;lead qualification agent&lt;/strong&gt; for a real estate agency. Specializing allows you to &lt;strong&gt;build expertise&lt;/strong&gt; and &lt;strong&gt;tailor your solution&lt;/strong&gt; for maximum impact.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Start small, focus on a specific use case, and scale as you gain more experience and confidence.&lt;/strong&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;2- Choose Your Tools:&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;Select platforms aligned with your technical skills and project requirements.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;No-Code Platforms:&lt;/strong&gt; If you're new to AI or prefer a visual development approach, consider using no-code platforms like &lt;a href="http://Vapi.ai" rel="noopener noreferrer"&gt;&lt;strong&gt;Vapi.ai&lt;/strong&gt;&lt;/a&gt; or &lt;strong&gt;Retell AI.&lt;/strong&gt; They offer &lt;strong&gt;user-friendly interfaces&lt;/strong&gt;, &lt;strong&gt;pre-built integrations&lt;/strong&gt;, and handle much of the technical complexity. Start with these to get familiar with the technology and its capabilities.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Code-Based Solutions:&lt;/strong&gt; For developers who want &lt;strong&gt;complete control&lt;/strong&gt; and customization, building with frameworks like &lt;strong&gt;LiveKit&lt;/strong&gt; offers ultimate flexibility.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;3- Design Your Agent Instructions:&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;As with all AI use cases, you must excel in &lt;strong&gt;prompt engineering&lt;/strong&gt; and providing &lt;strong&gt;clear instructions&lt;/strong&gt; to your agent.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Define the Persona:&lt;/strong&gt; Give your agent a &lt;strong&gt;distinct personality&lt;/strong&gt; that aligns with your brand and target audience.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Outline the Conversation Flow:&lt;/strong&gt; Clearly explain the &lt;strong&gt;key questions, responses, and decision points&lt;/strong&gt; the agent should follow.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Specify the Tools:&lt;/strong&gt; Detail the tools your agent should use, such as &lt;strong&gt;CRM integrations, knowledge bases, or external APIs.&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Use Examples:&lt;/strong&gt; Provide &lt;strong&gt;sample conversations&lt;/strong&gt; to demonstrate how the agent should handle different scenarios.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;4- Train Your Agent:&lt;/strong&gt;
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Real-World Conversations:&lt;/strong&gt; Use transcripts of &lt;strong&gt;actual customer interactions&lt;/strong&gt; to make the agent more natural and effective.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;FAQs:&lt;/strong&gt; Train your agent on &lt;strong&gt;frequently asked questions&lt;/strong&gt; to ensure &lt;strong&gt;accurate and consistent answers.&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Industry-Specific Data:&lt;/strong&gt; If you're building a niche agent, provide data relevant to that &lt;strong&gt;industry&lt;/strong&gt; to improve its expertise.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;5- Deploy and Test:&lt;/strong&gt;
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Integrate:&lt;/strong&gt; Connect your agent to your existing &lt;strong&gt;phone systems, website,&lt;/strong&gt; or other channels.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Run User Tests:&lt;/strong&gt; Gather feedback from &lt;strong&gt;real users&lt;/strong&gt; to identify areas for improvement.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Iterate:&lt;/strong&gt; Continuously refine your agent based on &lt;strong&gt;user feedback&lt;/strong&gt; and &lt;strong&gt;performance data.&lt;/strong&gt; Deploying is not the end; it's an &lt;strong&gt;ongoing process of improvement.&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;By following these steps, you can create a &lt;strong&gt;powerful AI voice agent&lt;/strong&gt; that enhances customer experience, streamlines operations, and drives business growth.&lt;/p&gt;




&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;🎉 &lt;strong&gt;Congratulations on taking your first step into the exciting world of voice AI agents!&lt;/strong&gt; Now that you’ve seen their potential, it’s time to take action.&lt;/p&gt;

&lt;p&gt;📚 &lt;strong&gt;Next Steps:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Check out this &lt;a href="https://www.youtube.com/watch?v=mXN7FCXoSTU&amp;amp;list=PLw8LDUDYUIIFOlCAnifRomf6vtARfU1jR" rel="noopener noreferrer"&gt;&lt;strong&gt;YouTube playlist&lt;/strong&gt;&lt;/a&gt; for step-by-step tutorials on building voice AI agents.&lt;/li&gt;
&lt;li&gt;Learn how to pitch and sell your AI voice solutions to businesses with &lt;a href="https://www.youtube.com/watch?v=PmaWoRWL5qk" rel="noopener noreferrer"&gt;&lt;strong&gt;this guide&lt;/strong&gt;&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;✨ The future is voice-driven, and you have the tools to shape it. Start building your voice AI projects today and share your journey in the comments below! &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What excites you most about voice AI? Let’s discuss!&lt;/strong&gt; 🔥&lt;/p&gt;

</description>
      <category>ai</category>
      <category>learning</category>
      <category>tutorial</category>
      <category>programming</category>
    </item>
    <item>
      <title>Build the Ultimate AI Email Automation with AI Agents, RAG, and LangGraph</title>
      <dc:creator>Aimen Kerrour</dc:creator>
      <pubDate>Sun, 05 Jan 2025 16:13:21 +0000</pubDate>
      <link>https://dev.to/kaymen99/boost-customer-support-ai-agents-langgraph-and-rag-for-email-automation-21hj</link>
      <guid>https://dev.to/kaymen99/boost-customer-support-ai-agents-langgraph-and-rag-for-email-automation-21hj</guid>
      <description>&lt;p&gt;In the age of instant gratification, customer support is no longer a department, it's the entire company.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Did you know that 86% of customers will churn after just one bad experience?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Traditional support teams are overwhelmed, struggling to manage endless email queues.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fch35bc1myxbsfprfkrpn.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fch35bc1myxbsfprfkrpn.jpeg" alt="Too many emails meme" width="600" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;But the game is changing. &lt;strong&gt;Large Language Models (LLMs) and AI Agents&lt;/strong&gt; are transforming customer service, enabling businesses to meet rising expectations with speed and precision. Studies show that &lt;strong&gt;AI can boost customer satisfaction by 15–25% and cut costs by 20–40%&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The era of manual email processing is over. &lt;strong&gt;AI automation&lt;/strong&gt; is here to deliver the fast, high-quality support your customers demand.&lt;/p&gt;

&lt;p&gt;In this technical guide, we’ll explore how I built an &lt;a href="https://github.com/kaymen99/langgraph-email-automation" rel="noopener noreferrer"&gt;AI Customer Support Email Automation System&lt;/a&gt; using &lt;strong&gt;LangGraph&lt;/strong&gt;, &lt;strong&gt;LangChain&lt;/strong&gt;, and &lt;strong&gt;RAG&lt;/strong&gt; to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Monitor emails 24/7 and deliver rapid responses&lt;/strong&gt; to customer inquiries.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Leverage &lt;strong&gt;AI agents&lt;/strong&gt; to intelligently sort emails into categories and craft tailored responses.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Use &lt;strong&gt;Retrieval-Augmented Generation (RAG)&lt;/strong&gt; to provide precise answers to product and service questions.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Let's dive in!&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;AI Email Automation with LangGraph and RAG&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;To better understand the &lt;strong&gt;AI Email Automation system&lt;/strong&gt; I built, it's helpful to first introduce the core technologies that power it: &lt;a href="https://python.langchain.com/docs/introduction/" rel="noopener noreferrer"&gt;&lt;strong&gt;LangChain&lt;/strong&gt;&lt;/a&gt;, &lt;a href="https://langchain-ai.github.io/langgraph/" rel="noopener noreferrer"&gt;&lt;strong&gt;LangGraph&lt;/strong&gt;&lt;/a&gt;, and &lt;strong&gt;Retrieval-Augmented Generation (RAG)&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;LangChain and LangGraph&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;LangChain&lt;/strong&gt; is a framework for developing AI applications using different &lt;strong&gt;LLMs (like GPT-4o, Google Gemini, LLAMA3)&lt;/strong&gt; and &lt;strong&gt;LangGraph&lt;/strong&gt; is built on top of it, extending its capabilities by adding the ability to coordinate multiple chains (or actors) across multiple steps of computation in a cyclic manner.&lt;/p&gt;

&lt;p&gt;Think of &lt;strong&gt;LangGraph&lt;/strong&gt; as the workflow orchestrator. It excels at managing complex, multi-step processes by representing them as a graph—a network of interconnected nodes. This allows for flexible and dynamic interactions, enabling the system to adapt to various scenarios and user inputs.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsc6peygt49kj5268xtsy.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsc6peygt49kj5268xtsy.png" alt="Flowchart of a Langgraph AI agent with RAG" width="305" height="405"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;What is RAG?&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;You’ve likely heard of &lt;strong&gt;Retrieval-Augmented Generation (RAG)&lt;/strong&gt;, but let me briefly explain its role. Most LLMs are trained periodically on large public datasets, meaning they often lack recent information or access to private data unavailable during training.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;RAG&lt;/strong&gt; addresses this limitation by &lt;strong&gt;connecting LLMs to external data sources&lt;/strong&gt;. It retrieves relevant information from a knowledge base (such as company documents, websites, or FAQs) and uses that data to generate accurate and contextually appropriate responses. In essence, it’s like equipping the AI with a reference library to consult before answering.&lt;/p&gt;

&lt;p&gt;Alright, now that we've covered the basics of LangChain, LangGraph, and RAG, &lt;strong&gt;let's see what this system can actually do!&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;High-Level System Overview&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;The automation system operates by continuously monitoring the agency's inbox, categorizing emails, generating tailored responses, and ensuring quality before sending them. Below is a visual representation of the process:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fprm63tygxdw0o2jw389g.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fprm63tygxdw0o2jw389g.png" alt="Flowchart of an AI-powered Email Automation system" width="652" height="1052"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;A. Email Monitoring and Categorization&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Using the &lt;strong&gt;Gmail API&lt;/strong&gt;, the system actively monitors the agency's inbox. New emails are immediately identified and categorized by the &lt;strong&gt;AI classification agent&lt;/strong&gt; into four key classes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Customer Complaint:&lt;/strong&gt; Emails detailing dissatisfaction or issues.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Product Inquiry:&lt;/strong&gt; Emails requesting information about offerings.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Customer Feedback:&lt;/strong&gt; Emails providing general opinions, suggestions, or praise.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Unrelated:&lt;/strong&gt; Emails irrelevant to the agency’s operations, which are ignored.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;B. Dynamic Response Generation&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;The response process adapts based on the email's category:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Complaints and Feedback:&lt;/strong&gt; These emails are routed directly to an &lt;strong&gt;AI writer agent&lt;/strong&gt;, which generates personalized responses acknowledging the customer’s concerns or expressing gratitude for their feedback. &lt;strong&gt;RAG (Retrieval-Augmented Generation)&lt;/strong&gt; is not required for these cases.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Product Inquiries:&lt;/strong&gt; For these emails, we use &lt;strong&gt;RAG&lt;/strong&gt; to retrieve accurate and up-to-date information from the agency’s &lt;strong&gt;knowledge base&lt;/strong&gt; (e.g., product documentation, FAQs). This information is then used by the &lt;strong&gt;AI writer agent&lt;/strong&gt; to craft a comprehensive and precise response.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;C. AI Quality Assurance&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Every email undergoes quality checks before being sent. An &lt;strong&gt;AI proofreader agent&lt;/strong&gt; ensures:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Formatting:&lt;/strong&gt; The email is visually appealing and easy to read.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Relevance:&lt;/strong&gt; The response directly addresses the customer’s queries or concerns.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Tone:&lt;/strong&gt; The tone aligns with the agency’s professional and brand-specific standards.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;D. Automated Email Dispatch&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Once an email passes the quality assurance stage, it is promptly sent to the customer, ensuring swift and efficient communication.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;How It Works: Step-by-Step Breakdown&lt;/strong&gt;
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Setting Up the Knowledge Base for RAG
&lt;/h3&gt;

&lt;p&gt;Since our system relies on &lt;strong&gt;Retrieval-Augmented Generation (RAG)&lt;/strong&gt;, we need a well-prepared knowledge base containing information about the agency. This will help us provide accurate and relevant answers to customer inquiries about products and services.&lt;/p&gt;

&lt;p&gt;For this project, I've already created a sample agency profile using &lt;strong&gt;ChatGPT&lt;/strong&gt;. To use it, we'll follow the standard steps for setting up a &lt;strong&gt;RAG knowledge base&lt;/strong&gt;:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Load the Documents:&lt;/strong&gt; We'll start by loading the agency documents.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Chunk the Documents:&lt;/strong&gt; We'll then split the document into smaller, manageable chunks. This is important because large segments can be difficult for &lt;strong&gt;LLMs&lt;/strong&gt; to process effectively.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Generate Embeddings:&lt;/strong&gt; We'll use an &lt;strong&gt;embedding model&lt;/strong&gt; to convert each chunk into a vector representation.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Create a Vector Database:&lt;/strong&gt; Finally, we'll create a vector database to store these embeddings.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;To keep things simple for this project, I've used &lt;a href="https://www.trychroma.com/" rel="noopener noreferrer"&gt;&lt;strong&gt;Chroma DB&lt;/strong&gt;&lt;/a&gt;, a local vector database, along with &lt;a href="https://ai.google.dev/api/embeddings" rel="noopener noreferrer"&gt;&lt;strong&gt;Google's embedding model&lt;/strong&gt;&lt;/a&gt;. For production environments, you might consider more scalable solutions like &lt;a href="https://www.pinecone.io/" rel="noopener noreferrer"&gt;&lt;strong&gt;Pinecone&lt;/strong&gt;&lt;/a&gt; &lt;strong&gt;or&lt;/strong&gt; &lt;a href="https://qdrant.tech/" rel="noopener noreferrer"&gt;&lt;strong&gt;Qdrant&lt;/strong&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Here's the code that accomplishes this setup:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;langchain_community.document_loaders&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;TextLoader&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;langchain_text_splitters&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;RecursiveCharacterTextSplitter&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;langchain_google_genai&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;ChatGoogleGenerativeAI&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;GoogleGenerativeAIEmbeddings&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;langchain_chroma&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Chroma&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;langchain_core.prompts&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;ChatPromptTemplate&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;langchain_core.runnables&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;RunnablePassthrough&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;langchain_core.output_parsers&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;StrOutputParser&lt;/span&gt;

&lt;span class="c1"&gt;# Loading Docs
&lt;/span&gt;&lt;span class="n"&gt;loader&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;TextLoader&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;./data/agency.txt&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;docs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;loader&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;load&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="c1"&gt;# Split document into chuncks
&lt;/span&gt;&lt;span class="n"&gt;doc_splitter&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;RecursiveCharacterTextSplitter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;chunk_size&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;300&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;chunk_overlap&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;doc_chunks&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;doc_splitter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;split_documents&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;docs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# Creating vector embeddings
&lt;/span&gt;&lt;span class="n"&gt;embeddings&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;GoogleGenerativeAIEmbeddings&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;models/embedding-001&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;# Updated model name
&lt;/span&gt;&lt;span class="n"&gt;vectorstore&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Chroma&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;from_documents&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;doc_chunks&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;embeddings&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;persist_directory&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;db&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# Semantic vector search retriever
&lt;/span&gt;&lt;span class="n"&gt;vectorstore_retriever&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;vectorstore&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;as_retriever&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;search_kwargs&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;k&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With the knowledge base set up, we can now visualize the core of the system: the &lt;strong&gt;automation graph&lt;/strong&gt; built with &lt;strong&gt;LangGraph&lt;/strong&gt;. Here's how it looks:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# load inbox emails
&lt;/span&gt;&lt;span class="n"&gt;workflow&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set_entry_point&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;load_emails&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# check if there are new emails to process
&lt;/span&gt;&lt;span class="n"&gt;workflow&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add_edge&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;load_emails&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;is_email_inbox_empty&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;workflow&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add_conditional_edges&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;is_email_inbox_empty&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;nodes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;check_new_emails&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;process&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;categorize_email&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;empty&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;END&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# route email based on category
&lt;/span&gt;&lt;span class="n"&gt;workflow&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add_conditional_edges&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;categorize_email&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;nodes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;route_email_based_on_category&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;product related&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;construct_rag_queries&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;not product related&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;email_writer&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;# Feedback or Complaint
&lt;/span&gt;        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;unrelated&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;skip_unrelated_email&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# pass constructed queries to RAG chain to get information
&lt;/span&gt;&lt;span class="n"&gt;workflow&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add_edge&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;construct_rag_queries&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;retrieve_from_rag&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;# give information to writer agent to write the email
&lt;/span&gt;&lt;span class="n"&gt;workflow&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add_edge&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;retrieve_from_rag&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;email_writer&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;# proofread the generated email
&lt;/span&gt;&lt;span class="n"&gt;workflow&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add_edge&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;email_writer&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;email_proofreader&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;# check if email is sendable or not, if not rewrite the email
&lt;/span&gt;&lt;span class="n"&gt;workflow&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add_conditional_edges&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;email_proofreader&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;nodes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;must_rewrite&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;send&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;send_email&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;rewrite&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;email_writer&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# check if there are still emails to be processed
&lt;/span&gt;&lt;span class="n"&gt;workflow&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add_edge&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;send_email&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;is_email_inbox_empty&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;workflow&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add_edge&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;skip_unrelated_email&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;is_email_inbox_empty&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Let's explore each part of this automation separately!&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;1. Email Monitoring&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;The process begins with continuous monitoring of the agency's &lt;strong&gt;Gmail inbox&lt;/strong&gt;. This is achieved using the &lt;strong&gt;Gmail API&lt;/strong&gt;, which allows the system to regularly check for new emails.&lt;/p&gt;

&lt;p&gt;I built a special class &lt;code&gt;GmailToolsClass&lt;/code&gt; to handle everything related to Gmail. &lt;strong&gt;You can check out the full code in&lt;/strong&gt; &lt;a href="https://github.com/kaymen99/langgraph-email-automation/blob/main/src/tools/GmailTools.py" rel="noopener noreferrer"&gt;my Github&lt;/a&gt;. For now, let's focus on how it &lt;strong&gt;fetches new emails&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;GmailToolsClass&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;service&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;_get_gmail_service&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;fetch_unanswered_emails&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;max_results&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="c1"&gt;# 1. Get recent emails
&lt;/span&gt;            &lt;span class="n"&gt;recent_emails&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fetch_recent_emails&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;max_results&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;recent_emails&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;

            &lt;span class="c1"&gt;# 2. Get draft replies to filter out already answered threads
&lt;/span&gt;            &lt;span class="n"&gt;drafts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fetch_draft_replies&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
            &lt;span class="n"&gt;threads_with_drafts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;draft&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;threadId&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;draft&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;drafts&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

            &lt;span class="c1"&gt;# 3. Process each new email
&lt;/span&gt;            &lt;span class="n"&gt;seen_threads&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
            &lt;span class="n"&gt;unanswered_emails&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
            &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;email&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;recent_emails&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="n"&gt;thread_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;threadId&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
                &lt;span class="c1"&gt;# Skip if thread was seen before or has a draft reply
&lt;/span&gt;                &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;thread_id&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;seen_threads&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;thread_id&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;threads_with_drafts&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                    &lt;span class="n"&gt;seen_threads&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;thread_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                    &lt;span class="n"&gt;email_info&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;_get_email_info&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;id&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
                    &lt;span class="c1"&gt;# Skip if email is sent from the agency (not received)
&lt;/span&gt;                    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;_should_skip_email&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;email_info&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
                        &lt;span class="k"&gt;continue&lt;/span&gt;
                    &lt;span class="n"&gt;unanswered_emails&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;email_info&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;unanswered_emails&lt;/span&gt;

        &lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="nb"&gt;Exception&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;An error occurred: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;fetch_recent_emails&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;max_results&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;Fetches emails from the last 8 hours.&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
        &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="c1"&gt;# Query emails from the last 8 hours
&lt;/span&gt;            &lt;span class="n"&gt;now&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;datetime&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
            &lt;span class="n"&gt;delay&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;now&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nf"&gt;timedelta&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;hours&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;after_timestamp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;delay&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;timestamp&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
            &lt;span class="n"&gt;before_timestamp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;now&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;timestamp&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
            &lt;span class="n"&gt;query&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;after:&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;after_timestamp&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; before:&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;before_timestamp&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;

            &lt;span class="n"&gt;results&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;service&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;users&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;list&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                &lt;span class="n"&gt;userId&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;me&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;maxResults&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;max_results&lt;/span&gt;
            &lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;execute&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
            &lt;span class="n"&gt;messages&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;results&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;messages&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[])&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;messages&lt;/span&gt;

        &lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="nb"&gt;Exception&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;An error occurred while fetching emails: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;error&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;

    &lt;span class="c1"&gt;# ... other methods ...
&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;_get_email_info&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;msg_id&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;message&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;service&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;users&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="n"&gt;userId&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;me&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;msg_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;format&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;full&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
        &lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;execute&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

        &lt;span class="n"&gt;payload&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;payload&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{})&lt;/span&gt;
        &lt;span class="n"&gt;headers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;header&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;name&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;lower&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="n"&gt;header&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;value&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;header&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;headers&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[])}&lt;/span&gt;

        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;id&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;msg_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;threadId&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;threadId&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;messageId&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;message-id&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;references&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;references&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;""&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;sender&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;from&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Unknown&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;subject&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;subject&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;No Subject&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;body&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;_get_email_body&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Ok what’s going on inside&lt;/strong&gt; &lt;code&gt;fetch_unanswered_emails&lt;/code&gt; ?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;We use &lt;code&gt;fetch_recent_emails&lt;/code&gt; to retrieve emails from the &lt;strong&gt;past 8 hours&lt;/strong&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Draft replies are checked to &lt;strong&gt;avoid loading already-answered emails&lt;/strong&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;We loop over all new emails to gather key details &lt;strong&gt;(sender, subject, body)&lt;/strong&gt;, making sure to skip any emails sent by the agency itself.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;2. Email Categorization&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Once new emails are detected, an &lt;strong&gt;AI agent categorize&lt;/strong&gt; them into four predefined categories: "Customer Complaint", "Product Inquiry", "Customer Feedback" or "Unrelated".&lt;/p&gt;

&lt;p&gt;Below are the instructions used for the &lt;strong&gt;AI categorization agent&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;CATEGORIZE_EMAIL_PROMPT&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;
# **Role:**

You are a highly skilled customer support specialist working for a SaaS company specializing in AI agent design. Your expertise lies in understanding customer intent and meticulously categorizing emails to ensure they are handled efficiently.

# **Instructions:**

1. Review the provided email content thoroughly.
2. Use the following rules to assign the correct category:
   - **product_enquiry**: When the email seeks information about a product feature, benefit, service, or pricing.
   - **customer_complaint**: When the email communicates dissatisfaction or a complaint.
   - **customer_feedback**: When the email provides feedback or suggestions regarding a product or service.
   - **unrelated**: When the email content does not match any of the above categories.

# **EMAIL CONTENT:**
{email}

# **Notes:**

* Base your categorization strictly on the email content provided; avoid making assumptions or overgeneralizing.
&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then we call this agent in the &lt;code&gt;categorize_email&lt;/code&gt; node of our graph:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;categorize_email&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;GraphState&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;GraphState&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;Categorizes the current email using the categorize_email agent.&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="c1"&gt;# Get the last email
&lt;/span&gt;    &lt;span class="n"&gt;current_email&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;emails&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;agents&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;categorize_email&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;invoke&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;email&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;current_email&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Email category: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;category&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;email_category&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;category&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;current_email&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;current_email&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  &lt;strong&gt;3. Response Generation&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;The system generates responses differently depending on the email's category:&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;a. Complaints and Feedback:&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;For emails categorized as complaints or feedback, the &lt;strong&gt;AI writer agent&lt;/strong&gt; is directly tasked with crafting a personalized response. The &lt;strong&gt;writer agent&lt;/strong&gt; is instructed to be empathetic, professional, and to ensure its responses align with the agency's brand voice:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;EMAIL_WRITER_PROMPT&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;
# **Role:**  

You are a professional email writer working as part of the customer support team at a SaaS company specializing in AI agent development. Your role is to draft thoughtful and friendly emails that effectively address customer queries based on the given category and relevant information.  

# **Tasks:**  

1. Use the provided email category, subject, content, and additional information to craft a professional and helpful response.  
2. Ensure the tone matches the email category, showing empathy, professionalism, and clarity.  
3. Write the email in a structured, polite, and engaging manner that addresses the customer’s needs.  
&lt;/span&gt;&lt;span class="gp"&gt;
...&lt;/span&gt;

&lt;span class="s"&gt;Write the email in the following format:  
   Dear [Customer Name],  

   [Email body responding to the query, based on the category and information provided.]  

   Best regards,  
   The Agentia Team    
   - Replace `[Customer Name]` with “Customer” if no name is provided.  
   - Ensure the email is friendly, concise, and matches the tone of the category.  

3. If a feedback is provided, use it to improve the email while ensuring it still aligns with the predefined guidelines.  

# **Notes:**  

* Return only the final email without any additional explanation or preamble.  
* Always maintain a professional and empathetic tone that aligns with the context of the email.  
* If the information provided is insufficient, politely request additional details from the customer.  
* Make sure to follow any feedback provided when crafting the email.  
&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here's how the &lt;code&gt;write_draft_email&lt;/code&gt; function uses this prompt to create a draft:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;write_draft_email&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;GraphState&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;GraphState&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;Writes a draft email based on the current email and retrieved information.&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="c1"&gt;# Get messages history for current email
&lt;/span&gt;    &lt;span class="n"&gt;writer_messages&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;writer_messages&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[])&lt;/span&gt;

    &lt;span class="c1"&gt;# Write email
&lt;/span&gt;    &lt;span class="n"&gt;draft_result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;agents&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;email_writer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;invoke&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;email_category&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;email_category&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;email_content&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;current_email&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;retrieved_documents&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;retrieved_documents&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="c1"&gt;# Empty for feedback or complaint
&lt;/span&gt;        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;history&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;writer_messages&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="n"&gt;email&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;draft_result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;email&lt;/span&gt;
    &lt;span class="n"&gt;trials&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;trials&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;

    &lt;span class="c1"&gt;# Append writer's draft to the message list
&lt;/span&gt;    &lt;span class="n"&gt;writer_messages&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;**Draft &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;trials&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;:**&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;generated_email&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;trials&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;trials&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;writer_messages&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;writer_messages&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We keep track of the writer agent's message history (&lt;code&gt;writer_messages&lt;/code&gt;) and the number of drafting attempts (&lt;code&gt;trials&lt;/code&gt;) for reasons that will become clear in the next section.&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;b. Product Inquiries:&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;For &lt;strong&gt;emails categorized as product inquiries&lt;/strong&gt;, the system will use &lt;strong&gt;RAG&lt;/strong&gt; to provide accurate and detailed answers.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Query Construction:&lt;/strong&gt; The first step is to transform the customer's email into specific queries that can be used to search the internal knowledge base. This is done using the below prompt:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;GENERATE_RAG_QUERIES_PROMPT&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;
# **Role:**

You are an expert at analyzing customer emails to extract their intent and construct the most relevant queries for internal knowledge sources.

# **Context:**

You will be given the text of an email from a customer. This email represents their specific query or concern. Your goal is to interpret their request and generate precise questions that capture the essence of their inquiry.

# **Instructions:**

1. Carefully read and analyze the email content provided.
2. Identify the main intent or problem expressed in the email.
3. Construct up to three concise, relevant questions that best represent the customer’s intent or information needs.
4. Include only relevant questions. Do not exceed three questions.
5. If a single question suffices, provide only that.

# **EMAIL CONTENT:**
{email}

# **Notes:**

* Focus exclusively on the email content to generate the questions; do not include unrelated or speculative information.
* Ensure the questions are specific and actionable for retrieving the most relevant answer.
* Use clear and professional language in your queries.
&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The node &lt;code&gt;construct_rag_queries&lt;/code&gt; calls this &lt;strong&gt;AI agent&lt;/strong&gt; to generate queries:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;construct_rag_queries&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;GraphState&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;GraphState&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;Constructs RAG queries based on the email content.&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="n"&gt;email_content&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;current_email&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="n"&gt;body&lt;/span&gt;
    &lt;span class="n"&gt;query_result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;agents&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;design_rag_queries&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;invoke&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;email&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;email_content&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;rag_queries&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;query_result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;queries&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;2. Information Retrieval and Response Generation:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Next, RAG uses these queries to search through the knowledge base. The retrieved information serves as context for a specialized &lt;strong&gt;QA AI agent&lt;/strong&gt;, which synthesizes accurate responses to each query:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;GENERATE_RAG_ANSWER_PROMPT&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;
# **Role:**

You are a highly knowledgeable and helpful assistant specializing in question-answering tasks.

# **Context:**

You will be provided with pieces of retrieved context relevant to the user&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;s question. This context is your sole source of information for answering.

# **Instructions:**

1. Carefully read the question and the provided context.
2. Analyze the context to identify relevant information that directly addresses the question.
3. Formulate a clear and precise response based only on the context. Do not infer or assume information that is not explicitly stated.
4. If the context does not contain sufficient information to answer the question, respond with: &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;I don&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;t know.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;
5. Use simple, professional language that is easy for users to understand.

# **Question:**
{question}

# **Context:**
{context}

# **Notes:**

* Stay within the boundaries of the provided context; avoid introducing external information.
* If multiple pieces of context are relevant, synthesize them into a cohesive and accurate response.
* Prioritize user clarity and ensure your answers directly address the question without unnecessary elaboration.
&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;retrieve_from_rag&lt;/code&gt; node retrieves information for each query and assembles the answers:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;retrieve_from_rag&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;GraphState&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;GraphState&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;Retrieves information from internal knowledge based on RAG questions.&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="n"&gt;final_answer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;""&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;query&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;rag_queries&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
        &lt;span class="n"&gt;rag_result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;agents&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;generate_rag_answer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;invoke&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;final_answer&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;query&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;rag_result&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n\n&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;retrieved_documents&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;final_answer&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;All queries with their respective answers are saved in &lt;code&gt;retrieved_documents&lt;/code&gt; which is then used by the &lt;strong&gt;AI writer agent&lt;/strong&gt; as context to craft the final email response, ensuring it is both comprehensive and accurate.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;4. Quality Assurance: Making Sure Emails are Perfect&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Before any email is sent, it undergoes a thorough quality check by an AI proofreader agent. The agent reviews each email for proper &lt;strong&gt;formatting&lt;/strong&gt;, &lt;strong&gt;relevance to customer inquiries&lt;/strong&gt;, and a professional, &lt;strong&gt;brand-consistent tone.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;AI proofreader agent&lt;/strong&gt; is guided by the below prompt that outlines its responsibilities:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;EMAIL_PROOFREADER_PROMPT&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;
# **Role:**

You are an expert email proofreader working for the customer support team at a SaaS company specializing in AI agent development. Your role is to analyze and assess replies generated by the writer agent to ensure they accurately address the customer&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;s inquiry, adhere to the company&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;s tone and writing standards, and meet professional quality expectations.

# **Context:**

You are provided with the **initial email** content written by the customer and the **generated email** crafted by the our writer agent.

# **Instructions:**

1. Analyze the generated email for:
   - **Accuracy**: Does it appropriately address the customer’s inquiry based on the initial email and information provided?
   - **Tone and Style**: Does it align with the company’s tone, standards, and writing style?
   - **Quality**: Is it clear, concise, and professional?
2. Determine if the email is:
   - **Sendable**: The email meets all criteria and is ready to be sent.
   - **Not Sendable**: The email contains significant issues requiring a rewrite.
3. Only judge the email as &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;not sendable&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt; (`send: false`) if lacks information or inversely contains irrelevant ones that would negatively impact customer satisfaction or professionalism.
4. Provide actionable and clear feedback for the writer agent if the email is deemed &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;not sendable.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;

---

# **INITIAL EMAIL:**
{initial_email}

# **GENERATED REPLY:**
{generated_email}

---

# **Notes:**

* Be objective and fair in your assessment. Only reject the email if necessary.
* Ensure feedback is clear, concise, and actionable.
&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;verify_generated_email&lt;/code&gt; node calls the &lt;strong&gt;proofreader agent&lt;/strong&gt; to check the email:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;verify_generated_email&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;GraphState&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;GraphState&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;Verifies the generated email using the proofreader agent.&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Fore&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;YELLOW&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Verifying generated email...&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;Style&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RESET_ALL&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;review&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;agents&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;email_proofreader&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;invoke&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;initial_email&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;current_email&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;generated_email&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;generated_email&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;

    &lt;span class="c1"&gt;# Store feedback if email is not good
&lt;/span&gt;    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;review&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;send&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;writer_messages&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;writer_messages&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[])&lt;/span&gt;
        &lt;span class="n"&gt;writer_messages&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;**Proofreader Feedback:**&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;review&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;feedback&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;sendable&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;review&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;send&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;writer_messages&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;writer_messages&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Here's how it works:&lt;/strong&gt; The function provides both the customer's original email and the drafted response to the &lt;strong&gt;AI proofreader agent&lt;/strong&gt;, which either approves the email (&lt;code&gt;sendable: True&lt;/code&gt;) or rejects it (&lt;code&gt;sendable: False&lt;/code&gt;) with feedback. If it's rejected, the feedback is saved to &lt;code&gt;writer_messages&lt;/code&gt; list so the &lt;strong&gt;AI writer agent&lt;/strong&gt; can use it to improve the response.&lt;/p&gt;

&lt;p&gt;To prevent the system from getting stuck in an infinite loop (which can happen if the necessary information to answer the email is not present in the knowledge base), we only give it three tries (&lt;code&gt;trials = 3&lt;/code&gt;) to get it right. If it still can't produce a good email after three attempts, we flag it for a human to review. This makes sure that every email sent out is high quality.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;5. Email Dispatch&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Finally, once the email has passed all quality checks, it's ready to be sent. The system uses the &lt;strong&gt;Gmail API&lt;/strong&gt; to automatically send the finalized reply to the customer.&lt;/p&gt;

&lt;p&gt;There are two options available, the first is to &lt;strong&gt;create a draft email for human review&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;create_draft_response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;GraphState&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;GraphState&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;Creates a draft response in Gmail.&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Fore&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;YELLOW&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Creating draft email...&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;Style&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RESET_ALL&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;gmail_tools&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create_draft_reply&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;current_email&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;generated_email&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;retrieved_documents&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;""&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;trials&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The second is to &lt;strong&gt;send the email directly&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;send_email_response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;GraphState&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;GraphState&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;Sends the email response directly using Gmail.&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Fore&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;YELLOW&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Sending email...&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;Style&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RESET_ALL&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;gmail_tools&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send_reply&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;current_email&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;generated_email&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;retrieved_documents&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;""&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;trials&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;What happens next?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;After sending the email or creating a draft, the system loops back to the beginning to check for any new emails. This keeps the process going, ensuring all customer emails are handled quickly and efficiently, until the inbox is empty.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Benefits and Impact&lt;/strong&gt;
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Improved Customer Experience:&lt;/strong&gt; Provides quick, tailored responses that make customers feel valued.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Efficiency Boost:&lt;/strong&gt; Dramatically reduces the time spent on email management.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Team Productivity:&lt;/strong&gt; Frees up support teams to focus on complex tasks and strategic initiatives.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Accuracy Guaranteed:&lt;/strong&gt; RAG ensures every response is backed by reliable information.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Real-World Applications&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;This &lt;strong&gt;email automation system&lt;/strong&gt; offers versatile solutions for various industries:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Marketing Agencies:&lt;/strong&gt; Handles client emails, automates reporting, and answers questions quickly, letting teams focus on creative work.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;E-commerce:&lt;/strong&gt; Answers product questions, helps with order updates, and collects feedback to improve customer experiences.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Tech Companies:&lt;/strong&gt; Responds to common technical issues, provides customer support, and organizes feedback from beta testers.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Education:&lt;/strong&gt; Helps with student inquiries, guides them through enrollment, and supports administrative tasks.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The system is flexible and works well for any business that wants to handle emails more effectively and improve communication with customers.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Conclusion&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;This &lt;strong&gt;AI email automation system&lt;/strong&gt;, built with &lt;strong&gt;LangChain&lt;/strong&gt;, &lt;strong&gt;LangGraph&lt;/strong&gt;, and RAG, helps businesses improve customer support by:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Responding to emails faster.&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Improving customer satisfaction.&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Making operations more efficient.&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;🎯 &lt;strong&gt;Want to try it out?&lt;/strong&gt; Check out the full project on my &lt;a href="https://github.com/kaymen99/langgraph-email-automation" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt; for the code, setup instructions, and tips to customize it for your own business. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Have questions or ideas? 💬 Let me know in the comments!&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>python</category>
      <category>rag</category>
      <category>agenticai</category>
    </item>
    <item>
      <title>AI Agents + LangGraph: The Winning Formula for Sales Outreach Automation</title>
      <dc:creator>Aimen Kerrour</dc:creator>
      <pubDate>Sat, 04 Jan 2025 12:55:53 +0000</pubDate>
      <link>https://dev.to/kaymen99/how-ai-automation-can-transform-your-sales-outreach-strategy-aop</link>
      <guid>https://dev.to/kaymen99/how-ai-automation-can-transform-your-sales-outreach-strategy-aop</guid>
      <description>&lt;p&gt;&lt;strong&gt;Sales success starts with great lead research&lt;/strong&gt;—but let’s face it, the process can feel like an uphill battle. Sifting through endless tabs, chasing down decision-makers, and piecing together insights from company websites can quickly turn into a &lt;strong&gt;time-consuming grind&lt;/strong&gt;. And after all that effort, many outreach attempts still miss the mark, lacking the &lt;strong&gt;personal touch&lt;/strong&gt; needed to stand out and make a real connection.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbixmomnrpxpw2ocxezlu.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbixmomnrpxpw2ocxezlu.jpeg" alt="sales outreach struggle" width="225" height="225"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In a sales world that moves at lightning speed, &lt;strong&gt;efficiency isn’t just a nice-to-have—it’s a must-have&lt;/strong&gt;. By automating the most tedious tasks, sales teams can reclaim their time and focus on what truly matters: building genuine relationships and &lt;strong&gt;closing more deals&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;In this technical guide, we’ll explore how I build an &lt;a href="https://github.com/kaymen99/sales-outreach-automation-langgraph" rel="noopener noreferrer"&gt;&lt;strong&gt;AI outreach automation&lt;/strong&gt;&lt;/a&gt; for a &lt;strong&gt;marketing agency&lt;/strong&gt; that:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Gathers insights from LinkedIn, websites, and social media,&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Automatically evaluates and qualifies leads, and&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Generates tailored outreach materials that help you stand out in crowded inboxes.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Let’s get started!&lt;/strong&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  &lt;strong&gt;Why Sales Outreach Needs AI Automation?&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Sales outreach is crucial for business success&lt;/strong&gt;, yet many teams face challenges due to outdated methods. Here are key reasons why automation is essential:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Time-consuming research&lt;/strong&gt; limits sales professionals to manual data gathering, reducing time for actual lead engagement.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Inconsistent qualification&lt;/strong&gt; occurs when processes rely on incomplete data or subjective decisions.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Lack of personalization&lt;/strong&gt; makes generic outreach efforts easy to ignore, diminishing client engagement.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Scalability issues&lt;/strong&gt; arise as manual processes struggle to keep up with growing outreach demands.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Missed opportunities&lt;/strong&gt; happen when leads slip through the cracks due to delayed follow-ups or incomplete insights.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Simplifying Lead Outreach with AI Automation
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0xfws6ott38pa81voqas.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0xfws6ott38pa81voqas.jpeg" alt="Flowchart of an AI-powered Sales outreach automation system" width="800" height="308"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To tackle the complexities of lead research, qualification, and outreach for an &lt;strong&gt;AI marketing agency&lt;/strong&gt; (&lt;strong&gt;ElevateAI&lt;/strong&gt;), I created a fully automated system that use multiple &lt;strong&gt;AI agents&lt;/strong&gt; to accelerate and streamline the entire process. Here’s a high-level breakdown:&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;High-Level Overview&lt;/strong&gt;
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;CRM Integration&lt;/strong&gt;: Connects with platforms like &lt;strong&gt;HubSpot, Airtable, and Google Sheets&lt;/strong&gt; to streamline lead data access and synchronization.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Lead Research&lt;/strong&gt;: Gathers insights on leads and their company, including:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;LinkedIn data&lt;/strong&gt; (profile, roles, company size, industry).&lt;/li&gt;
&lt;li&gt;Company &lt;strong&gt;website&lt;/strong&gt;, &lt;strong&gt;blogs&lt;/strong&gt;, and &lt;strong&gt;social media activities&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Recent company news&lt;/strong&gt; for relevant outreach.&lt;/li&gt;
&lt;li&gt;Identification of &lt;strong&gt;challenges&lt;/strong&gt; and &lt;strong&gt;opportunities&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;&lt;p&gt;&lt;strong&gt;Analysis Reports&lt;/strong&gt;: Create detailed analysis reports using AI from all gathered information, helping sales teams better understand the lead and make informed decisions.&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;&lt;strong&gt;Lead Qualification&lt;/strong&gt;: Scores leads based on factors like online presence, industry fit, and growth potential.&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;&lt;strong&gt;Personalized Outreach&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Custom Outreach Report&lt;/strong&gt;: Generate a company audit report that outlines the challenges identified, how your services can address them, and highlights relevant case studies.&lt;/li&gt;
&lt;li&gt;Craft a &lt;strong&gt;personalized email&lt;/strong&gt; using all collected insights, including a link to the custom outreach report, to engage the lead effectively.&lt;/li&gt;
&lt;li&gt;Generate custom &lt;strong&gt;interview scripts&lt;/strong&gt; to facilitate productive calls and meetings with the lead.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;&lt;p&gt;&lt;strong&gt;Data Management&lt;/strong&gt;: All generated research reports are saved to &lt;strong&gt;Google Drive&lt;/strong&gt; and CRM is updated with the collected data for easy access.&lt;/p&gt;&lt;/li&gt;

&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Key Benefits&lt;/strong&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Automated Lead Research&lt;/strong&gt;: Gathers insights from LinkedIn, websites, social media, and more, ensuring thorough lead evaluation.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Higher Reply Rates &amp;amp; Conversions&lt;/strong&gt;: Attach detailed audit reports to outreach emails, increasing the likelihood of positive responses.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Time-Saving &amp;amp; Improved Efficiency&lt;/strong&gt;: Automates research and report generation, freeing up time and streamlining team efforts.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Technical Deep Dive&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;To build this automation, I used &lt;strong&gt;Langgraph&lt;/strong&gt; and &lt;strong&gt;LangChain&lt;/strong&gt;. Langgraph facilitates the development of complex workflows, while LangChain enables integration with different LLMs (Google Gemini, GPT-4o, and LLaMA 3). We use the power of LLMs to interpret insights, generate analytical reports, craft personalized outreach materials, and qualify leads.&lt;/p&gt;

&lt;p&gt;Below is a glimpse of the automation graph structure developed using &lt;strong&gt;Langgraph&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Entry point of the graph
&lt;/span&gt;&lt;span class="n"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set_entry_point&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;get_new_leads&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add_edge&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;fetch_linkedin_profile_data&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;review_company_website&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add_edge&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;review_company_website&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;collect_company_information&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add_edge&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;collect_company_information&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;analyze_blog_content&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add_edge&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;collect_company_information&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;analyze_social_media_content&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add_edge&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;collect_company_information&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;analyze_recent_news&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add_edge&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;analyze_recent_news&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;generate_digital_presence_report&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add_edge&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;generate_digital_presence_report&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;generate_full_lead_research_report&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add_edge&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;generate_full_lead_research_report&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;score_lead&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add_conditional_edges&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;score_lead&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;nodes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;check_if_qualified&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;qualified&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;generate_custom_outreach_report&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="c1"&gt;# Proceed if lead is qualified
&lt;/span&gt;        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;not qualified&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;save_reports_to_google_docs&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;  &lt;span class="c1"&gt;# Save reports and exit if lead is unqualified 
&lt;/span&gt;    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;# Outreach material creation
&lt;/span&gt;&lt;span class="n"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add_edge&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;generate_custom_outreach_report&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;create_outreach_materials&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add_edge&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;create_outreach_materials&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;generate_personalized_email&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add_edge&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;create_outreach_materials&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;generate_interview_script&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add_edge&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;generate_personalized_email&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;save_reports_to_google_docs&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;# Save reports and update the CRM
&lt;/span&gt;&lt;span class="n"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add_edge&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;save_reports_to_google_docs&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;update_CRM&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Now, let’s break down each component of this automation in detail:&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Fetching Leads from CRM&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;The process begins with extracting lead information (e.g., name, email, phone number) from CRM platforms such as &lt;strong&gt;Airtable, HubSpot, or Google Sheets&lt;/strong&gt;. The system connects to these platforms using a standardized class structure, ensuring seamless integration and making it easy to extend support for new CRMs without disrupting the automation.&lt;/p&gt;

&lt;p&gt;Here’s an example of how it connects to &lt;strong&gt;Airtable&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;AirtableLeadLoader&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;LeadLoaderBase&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;access_token&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;base_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;table_name&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="c1"&gt;# Use the access_token instead of api_key
&lt;/span&gt;        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;table&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Table&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;access_token&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;base_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;table_name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;fetch_records&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;lead_ids&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;status_filter&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;NEW&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;
        Fetches leads from Airtable. If lead IDs are provided, fetch those specific records.
        Otherwise, fetch leads matching the given status.
        &lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;lead_ids&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;leads&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
            &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;lead_id&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;lead_ids&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="n"&gt;record&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;table&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lead_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;record&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                    &lt;span class="c1"&gt;# Merge id and fields into a single dictionary
&lt;/span&gt;                    &lt;span class="n"&gt;lead&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;id&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;record&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;id&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;record&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;fields&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{})}&lt;/span&gt;
                    &lt;span class="n"&gt;leads&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lead&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;leads&lt;/span&gt;
        &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="c1"&gt;# Fetch leads by status filter (based on "Status" field)
&lt;/span&gt;            &lt;span class="c1"&gt;# You can choose your own field for filter with different naming
&lt;/span&gt;            &lt;span class="n"&gt;records&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;table&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;all&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;formula&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nf"&gt;match&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Status&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;status_filter&lt;/span&gt;&lt;span class="p"&gt;}))&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
                &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;id&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;record&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;id&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;record&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;fields&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{})}&lt;/span&gt;
                &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;record&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;records&lt;/span&gt;
            &lt;span class="p"&gt;]&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;update_record&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;lead_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;updates&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;dict&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;Updates a record in Airtable&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
        &lt;span class="c1"&gt;# Fetch the current record to ensure it exists and get its fields
&lt;/span&gt;        &lt;span class="n"&gt;record&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;table&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lead_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;record&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nc"&gt;ValueError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Record with ID &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;lead_id&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; not found.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="c1"&gt;# Merge current fields with updates, adding any new fields
&lt;/span&gt;        &lt;span class="n"&gt;current_fields&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;record&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;fields&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{})&lt;/span&gt;
        &lt;span class="n"&gt;updated_fields&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;current_fields&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;updates&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="c1"&gt;# Update the record in Airtable
&lt;/span&gt;        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;table&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lead_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;updated_fields&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this example, the &lt;code&gt;fetch_records&lt;/code&gt; function retrieves new leads based on their status, while the &lt;code&gt;update_record&lt;/code&gt; function saves any insights gathered during the outreach process directly into the CRM.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Enriching Lead Profiles via LinkedIn&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Once the basic lead information is retrieved, the system enhances their profiles by gathering insights from LinkedIn. This involves finding and &lt;strong&gt;scraping LinkedIn profiles&lt;/strong&gt; for both the lead and their company.&lt;/p&gt;

&lt;p&gt;Here’s how the system retrieves company details:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;research_lead_company&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;linkedin_url&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="c1"&gt;# Scrape company LinkedIn profile
&lt;/span&gt;    &lt;span class="n"&gt;company_page_content&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;scrape_linkedin&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;linkedin_url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;data&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;company_page_content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;LinkedIn profile not found&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;

    &lt;span class="c1"&gt;# Structure collected information about company
&lt;/span&gt;    &lt;span class="n"&gt;company_profile&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;company_page_content&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;data&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;company_name&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;company_profile&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;company_name&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;''&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;description&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;company_profile&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;description&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;''&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;year_founded&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;company_profile&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;year_founded&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;''&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;industries&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;company_profile&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;industries&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[]),&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;specialties&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;company_profile&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;specialties&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;''&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;employee_count&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;company_profile&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;employee_count&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;''&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;social_metrics&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;follower_count&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;company_profile&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;follower_count&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;locations&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;company_profile&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;locations&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[])&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;What’s happening here?&lt;/strong&gt; The function scrapes the company’s &lt;strong&gt;LinkedIn profile&lt;/strong&gt; to extracts key details such as industry, company size, and description.&lt;/p&gt;

&lt;p&gt;A similar approach is used to gather details about the &lt;strong&gt;lead’s professional background, including their roles, skills, and experience&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Scraping the Company Website&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;The automation goes a step further by &lt;strong&gt;scraping the company’s website&lt;/strong&gt; to gather deeper insights. This is done using the following function, which scrapes a URL and converts its HTML content into markdown, making it more readable for LLMs:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;scrape_website_to_markdown&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;headers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;User-Agent&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.77 Safari/537.36&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Accept-Language&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;en-US,en;q=0.5&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Accept-Encoding&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;gzip, deflate&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c1"&gt;# Make the HTTP request
&lt;/span&gt;    &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status_code&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nc"&gt;Exception&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Failed to fetch the URL. Status code: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status_code&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# Parse the HTML
&lt;/span&gt;    &lt;span class="n"&gt;soup&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;BeautifulSoup&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;html.parser&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;html_content&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;soup&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;prettify&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; 

    &lt;span class="c1"&gt;# Convert HTML to markdown
&lt;/span&gt;    &lt;span class="n"&gt;h&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;html2text&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;HTML2Text&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;h&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ignore_links&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;False&lt;/span&gt;
    &lt;span class="n"&gt;h&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ignore_images&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;
    &lt;span class="n"&gt;h&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ignore_tables&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;
    &lt;span class="n"&gt;markdown_content&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;h&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;handle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;html_content&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# Clean up excess newlines
&lt;/span&gt;    &lt;span class="n"&gt;markdown_content&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;re&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sub&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;r&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;\n{3,}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n\n&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;markdown_content&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;markdown_content&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;markdown_content&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;strip&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;markdown_content&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We then use AI to summarize the website content, focusing on key information such as the company's mission, products, and services. Additionally, it extracts relevant links, including those to social media accounts and blogs.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;WEBSITE_ANALYSIS_PROMPT&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;
The provided webpage content is scraped from: {main_url}.

# Tasks

## 1- Summarize webpage content:
Write a 1500-word comprehensive summary in markdown format about the content of the webpage, 
focusing on relevant information related to the company mission, products, and services.

## 2- Extract and categorize the following links:
1. Blog URL: Extract the main blog URL of the company. 
2. Social Media Links: Extract links to the company&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;s YouTube, Twitter, and Facebook profiles.

# IMPORTANT:
* Ensure the summary is organized in markdown format.
* Ensure that only the specified categories of links are included. 
* If a link is not found, its value is an empty string.
* If the link is relative (e.g., &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/blog&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;), prepend it with {main_url} to form an absolute URL.
&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If the company operates a blog, we also scrape it and use an AI agent to extract relevant insights, such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Total Number of Blog Posts&lt;/strong&gt;: Measures the volume of published content.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Posting Frequency&lt;/strong&gt;: Identifies patterns (e.g., consistent, irregular, or inactive).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Key Themes and Topics&lt;/strong&gt;: Highlights recurring subjects and main themes.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Analyzing Social Media Metrics&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;To better understand the company’s social media presence, we examine its activity on popular platforms such as &lt;strong&gt;Facebook, Twitter, YouTube, and TikTok&lt;/strong&gt;. This involves scraping key metrics—posts, videos, followers, and more—followed by AI analysis to generate detailed reports on content themes, engagement levels, and actionable opportunities for improvement.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Example: Analyzing YouTube Performance&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;For &lt;strong&gt;YouTube&lt;/strong&gt;, the following function is used to collect key statistics from a company’s channel:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_youtube_stats&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;channel_url&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;
    Collects statistics and metadata from a company&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;s YouTube channel.
    &lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="n"&gt;channel_name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;extract_channel_name&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;channel_url&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;channel_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;get_channel_id_by_name&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;channel_name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;get_channel_videos_stats&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;channel_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;total_videos&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;total_videos&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;subscriber_count&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;subscriber_count&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;average_views&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;average_views&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;recent_videos&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;title&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;video&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;title&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;published_at&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;video&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;published_at&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]}&lt;/span&gt;
            &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;video&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;last_15_videos&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This function retrieves key details, including:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Total number of videos&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Subscriber count&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Average views per video&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Details of recent videos&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The gathered data is passed to an &lt;strong&gt;AI marketing agent&lt;/strong&gt; instructed to generate a detailed analysis report:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;YOUTUBE_ANALYSIS_PROMPT&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;
# **Role:**
You are a Professional Marketing Analyst specializing in evaluating YouTube channel 
performance and identifying actionable insights to improve content strategies.

---

# **Task:**
Analyze the provided YouTube channel&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;s content and generate a detailed performance report. 
This report will evaluate the channel&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;s activity, relevance to the company’s services, 
and opportunities for improvement.

# **Specifics:**
Your report will include the following sections:

## **Channel Summary:**
* **Number of Videos:** Count of videos provided for analysis.  
* **Activity:** Describe the frequency of uploads (e.g., consistent, irregular, or inactive).  
* **Engagement:** Summarize key engagement metrics (e.g., average views, likes, and comments 
per video).  
* **Summary of Topics:** Highlight the main themes and subjects covered.  
* **Examples:** List five representative video titles and descriptions.  

## **Scoring:**
Evaluate the channel in these categories: **Volume of Videos**, **Upload Activity**, 
**Engagement Levels**, **Relevance to the Company’s Services**  
Combine these to calculate a total performance score.

## **Opportunities for Improvement:**
* Identify content gaps or underexplored topics.  
* Suggest new themes and innovative content formats (e.g., shorts, live streams, tutorials).  

## **Action Plan:**
Provide actionable recommendations to boost engagement, relevance, and activity.
&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This analysis evaluates the channel’s activity, audience engagement, and alignment with the company’s goals. It also provides targeted strategies to enhance visibility, improve content relevance, and boost engagement&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Recent News Review&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;In the final step of our research, we use the &lt;strong&gt;Google News API&lt;/strong&gt; to fetch the latest news and announcements related to the company. This step provides valuable insights into the company’s recent initiatives, achievements, and potential challenges:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_recent_news&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;company&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="c1"&gt;# Define the payload and headers for the request
&lt;/span&gt;    &lt;span class="n"&gt;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://google.serper.dev/news&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="n"&gt;payload&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dumps&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;q&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;company&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;num&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;tbs&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;qdr:y&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="n"&gt;headers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;X-API-KEY&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getenv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;SERPER_API_KEY&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Content-Type&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;application/json&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c1"&gt;# Make the POST request to the API
&lt;/span&gt;    &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# Check if the response is successful
&lt;/span&gt;    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status_code&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;news&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;news&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[])&lt;/span&gt;

        &lt;span class="c1"&gt;# Prepare the string to return
&lt;/span&gt;        &lt;span class="n"&gt;news_string&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;""&lt;/span&gt;
        &lt;span class="n"&gt;news&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;reverse&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;  &lt;span class="c1"&gt;# Reverse the list to get the most recent news first
&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;news&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;title&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;title&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;snippet&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;snippet&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;date&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;date&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;link&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;link&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;news_string&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Title: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;title&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;Snippet: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;snippet&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;Date: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;date&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;URL: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;link&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="se"&gt;\n\n&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;

        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;news_string&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Error fetching news: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status_code&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  &lt;strong&gt;Reports Generation&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Each step of the analysis culminates in a detailed, &lt;strong&gt;AI-generated report&lt;/strong&gt;. These reports serve two primary purposes:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Empowering Sales Teams&lt;/strong&gt;: By providing rich insights to facilitate more informed and personalized engagements.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Supporting Outreach Preparation&lt;/strong&gt;: By offering a clear foundation for crafting tailored materials for outreach.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The reports include the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Lead Profile Report:&lt;/strong&gt; Generated from LinkedIn and company website data, detailing the lead’s professional background and company information.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Blog Analysis Report:&lt;/strong&gt; Insights extracted from blog content to highlight themes, posting frequency, and engagement.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Social Media Analysis Reports:&lt;/strong&gt; Detailed evaluations for each social media platform, covering activity, engagement, and strategic opportunities.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Recent News Analysis:&lt;/strong&gt; A summary of the latest news, emphasizing recent achievements and challenges.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Digital Presence Report:&lt;/strong&gt; Combines insights from blogs, news articles, and social media to provide a holistic view of the company’s online presence.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Global Research Report:&lt;/strong&gt; Consolidates findings from all reports into a comprehensive document for internal use.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All reports are saved locally and synchronized to &lt;strong&gt;Google Docs&lt;/strong&gt;, ensuring easy access and collaboration among team members.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Lead Qualification&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Once the research process is complete, the next step is to &lt;strong&gt;qualify the lead&lt;/strong&gt;. This is also done using an AI agent, which analyzes the comprehensive reports generated previously and determines if the lead is qualified against predefined criteria.&lt;/p&gt;

&lt;p&gt;Given that I built this system for an &lt;strong&gt;AI marketing agency&lt;/strong&gt;, the lead qualification requirements are based on that. Here is a glimpse of the &lt;strong&gt;AI lead scoring&lt;/strong&gt; prompt:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;SCORE_LEAD_PROMPT&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;
# **Role &amp;amp; Task**  
You are an expert lead scorer for **ElevateAI Marketing Solutions**, tasked with evaluating and scoring leads based on their digital presence, social media activity, industry fit, company scale, and marketing strategy.  

# **Scoring Criteria**  
- **Digital Presence:** Blog activity and website quality.  
- **Social Media Activity:** Platform presence, engagement rates, and posting frequency.  
- **Industry Fit:** Relevance to target industries and use of AI/automation.  
- **Company Scale:** Growth signals and alignment with ElevateAI&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;s focus.  
- **Marketing Strategy:** Use of tools and consistency in messaging.  
- **Pain Points &amp;amp; ROI:** Identifiable challenges and potential ROI from ElevateAI solutions.  

# **Output**  
Provide a final score (1–10) based on these criteria, with no additional explanation.
&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For this implementation I choose to consider that if a lead gets a score &lt;strong&gt;7.0 or above&lt;/strong&gt; is considered qualified, marking them as high-priority for our outreach efforts.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Preparing Outreach Materials&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;For &lt;strong&gt;qualified leads&lt;/strong&gt;, the system crafts personalized outreach materials to maximize engagement:&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Custom Outreach Report&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;For every qualified lead, we task an &lt;strong&gt;AI writer agent&lt;/strong&gt; to generate a &lt;strong&gt;Custom Outreach Report&lt;/strong&gt;—a dynamic, data-driven presentation showcasing how &lt;strong&gt;ElevateAI&lt;/strong&gt; can address their unique challenges.&lt;/p&gt;

&lt;p&gt;The outreach report includes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Business Overview:&lt;/strong&gt; A concise profile of the lead’s company, detailing their industry, core offerings, and competitive position.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Challenges Identified:&lt;/strong&gt; A breakdown of specific pain points in their current marketing or business strategy, such as limited digital presence, low engagement rates, or operational inefficiencies.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;AI-Powered Solutions:&lt;/strong&gt; Customized recommendations that leverage &lt;strong&gt;ElevateAI’s&lt;/strong&gt; capabilities, highlighting how our solutions align with their business goals.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Tangible Results:&lt;/strong&gt; Real-world impact examples, drawn from our knowledge base using &lt;strong&gt;Retrieval-Augmented Generation (RAG)&lt;/strong&gt;. These examples feature case studies from similar businesses, showcasing measurable outcomes, such as improved ROI, increased customer retention, or enhanced operational efficiency.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Clear Call-to-Action (CTA):&lt;/strong&gt; A compelling CTA, such as scheduling a free consultation or demo, encouraging leads to take the next step in the sales funnel.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here’s a sample of a &lt;strong&gt;Custom Outreach Report&lt;/strong&gt; created for Relevance AI for example:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftvtrnbmappbsjp197c50.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftvtrnbmappbsjp197c50.png" alt="AI generated Sales Outreach Report Example" width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;You can also view the&lt;/strong&gt; &lt;a href="https://docs.google.com/document/d/1vDHDGDSPOcx4g_LyjK-cpG4undB1DyJqUJB6F_15gFA/edit?tab=t.0#heading=h.itn39tty5pur" rel="noopener noreferrer"&gt;&lt;strong&gt;Full Report&lt;/strong&gt;&lt;/a&gt; &lt;strong&gt;if you want!&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Personalized Email &amp;amp; Interview Script&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;For each qualified lead, we use another &lt;strong&gt;AI email writer agent&lt;/strong&gt; to craft a &lt;strong&gt;highly personalized email&lt;/strong&gt; designed to address their &lt;strong&gt;specific needs and challenges&lt;/strong&gt;. The email highlights the &lt;strong&gt;value ElevateAI can deliver&lt;/strong&gt;, includes a link to the &lt;strong&gt;custom outreach report&lt;/strong&gt;, and emphasizes measurable benefits such as &lt;strong&gt;increased ROI&lt;/strong&gt;, &lt;strong&gt;enhanced customer engagement&lt;/strong&gt;, or &lt;strong&gt;operational efficiencies&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;To support sales teams, the system also generates an &lt;strong&gt;interview script&lt;/strong&gt; rooted in &lt;strong&gt;SPIN selling principles&lt;/strong&gt;. This script includes &lt;strong&gt;strategic, open-ended questions&lt;/strong&gt; to guide discussions, uncover the lead’s &lt;strong&gt;pain points&lt;/strong&gt;, and position ElevateAI’s solutions as the &lt;strong&gt;ideal fit&lt;/strong&gt; for their &lt;strong&gt;business objectives&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Save to CRM&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Once the system processes a lead, all generated data is &lt;strong&gt;saved back to the CRM&lt;/strong&gt;, including report links, the lead's score, and their updated status.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fa110e9p9nu3u09zus6zf.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fa110e9p9nu3u09zus6zf.jpeg" alt="Airtable CRM for Sales Automation" width="800" height="251"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Make It Your Own
&lt;/h2&gt;

&lt;p&gt;While this &lt;strong&gt;AI outreach automation&lt;/strong&gt; was specifically designed and configured for the needs of &lt;strong&gt;an AI marketing agency&lt;/strong&gt;, it's fully &lt;strong&gt;customizable&lt;/strong&gt; to fit any business. Here's the flexibility you get:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Your CRM:&lt;/strong&gt; Integrates with whatever CRM you use.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Custom Reports:&lt;/strong&gt; Choose which reports to generate (e.g., prioritize social media, skip blog analysis) and modify their structure to focus on the data you need.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Your Ideal Lead:&lt;/strong&gt; Adjust lead scoring criteria to match your target audience.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Your Brand Voice:&lt;/strong&gt; Tailor email templates and interview scripts to your own business.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Expand as Needed:&lt;/strong&gt; Add data sources, AI models, or outreach channels.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It's a powerful, flexible automation ready to be customized for your unique outreach strategy.&lt;/p&gt;




&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Sales outreach&lt;/strong&gt; doesn’t have to be exhausting. With &lt;strong&gt;AI automation and AI agents&lt;/strong&gt;, you can move from generic emails and manual research to hyper-personalized, data-driven strategies.&lt;/p&gt;

&lt;p&gt;You've just seen how to use &lt;strong&gt;LangGraph&lt;/strong&gt; and &lt;strong&gt;LangChain&lt;/strong&gt; to build a &lt;strong&gt;sales automation system&lt;/strong&gt; that can transform your sales outreach by:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Saving time&lt;/strong&gt; on manual research.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Boosting conversions&lt;/strong&gt; with hyper-personalized strategies.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Streamlining workflows&lt;/strong&gt; for smarter, more efficient processes.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;🎯 &lt;strong&gt;Want to learn more?&lt;/strong&gt; Check out the full project on my &lt;strong&gt;&lt;a href="https://github.com/kaymen99/sales-outreach-automation-langgraph" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;&lt;/strong&gt; and take your sales game to the next level! 🚀&lt;/p&gt;

</description>
      <category>ai</category>
      <category>python</category>
      <category>langchain</category>
      <category>agenticai</category>
    </item>
    <item>
      <title>All You Need to Know About AI Agents: A Full Guide</title>
      <dc:creator>Aimen Kerrour</dc:creator>
      <pubDate>Sat, 04 Jan 2025 12:37:19 +0000</pubDate>
      <link>https://dev.to/kaymen99/all-you-need-to-know-about-ai-agents-a-full-guide-1p6i</link>
      <guid>https://dev.to/kaymen99/all-you-need-to-know-about-ai-agents-a-full-guide-1p6i</guid>
      <description>&lt;p&gt;&lt;strong&gt;Generative AI agents&lt;/strong&gt; are a hot topic, with many claiming they'll revolutionize the world. But what exactly are they?&lt;/p&gt;

&lt;p&gt;In this post, we'll demystify generative AI agents and explore real-world examples of their application. By the end, you'll understand:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;What a generative AI agent is&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;How AI agents differ from AI automation&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Keys to design effective AI agents&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Equipping AI agents with tools&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  &lt;strong&gt;What is a Generative AI Agent?&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Generative AI agents&lt;/strong&gt; combine two key components:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Generative AI (Large Language Models or LLMs e.g. &lt;strong&gt;chatGPT&lt;/strong&gt;, &lt;strong&gt;LLAMA3&lt;/strong&gt;).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Traditional AI Agents (AI-driven decision-making).&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3nxm8949898f4s4bvrxq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3nxm8949898f4s4bvrxq.png" alt="What is an AI agent?" width="760" height="355"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Generative AI agents&lt;/strong&gt; use large language models (&lt;strong&gt;LLMs&lt;/strong&gt;) like &lt;strong&gt;GPT-4&lt;/strong&gt; or &lt;strong&gt;Llama3&lt;/strong&gt; as their "&lt;strong&gt;brain&lt;/strong&gt;" to decide which actions to take or tools to use to achieve a specific goal.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;AI agents are often confused with AI automation, but they're distinct concepts.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fl61wjs0fc6c8wcxjpntv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fl61wjs0fc6c8wcxjpntv.png" alt="Comparison between AI agent and AI automation" width="602" height="494"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To &lt;strong&gt;differentiate&lt;/strong&gt; between them, ask yourself:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Yes → AI agent&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;No → AI automation&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Can the AI system learn from its interactions with the environment to make better decisions?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Let's compare a standard chatbot with an AI sales agent:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Standard Website Chatbot:&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
&lt;li&gt;Responds to predefined questions&lt;/li&gt;
&lt;li&gt;Provides scripted answers&lt;/li&gt;
&lt;li&gt;Can't adapt beyond its programming&lt;/li&gt;
&lt;/ul&gt;

&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;AI Sales Agent:&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
&lt;li&gt;Accesses detailed product information&lt;/li&gt;
&lt;li&gt;Uses a recommendation tool based on customer preferences&lt;/li&gt;
&lt;li&gt;Handles payment processing&lt;/li&gt;
&lt;li&gt;Manages meeting schedules&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For example if a customer interacts with the &lt;strong&gt;AI sales agent&lt;/strong&gt; looking for a new laptop. The agent can:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Asks about the customer's needs (e.g., for gaming, work, or casual use)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Uses its &lt;strong&gt;product database&lt;/strong&gt; to find matching laptops&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Recommends&lt;/strong&gt; laptops based on the customer's budget and requirements&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Answers questions about specs and features&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Processes the payment&lt;/strong&gt; when the customer decides to buy&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Schedules&lt;/strong&gt; a follow-up for setup assistance&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Throughout this interaction, the &lt;strong&gt;AI agent&lt;/strong&gt; adapts its responses based on the customer's &lt;strong&gt;feedback&lt;/strong&gt;, making it more effective than a &lt;strong&gt;standard chatbot&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Now that we understand what are AI agents, let's see how we can build them.&lt;/p&gt;




&lt;h2&gt;
  
  
  &lt;strong&gt;How to Design Effective AI Agents&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Designing effective AI agents involves several key considerations:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Identity&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Narrow scope&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Memory&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Planning&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Access to external tools&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;We’ll dive into each below.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. &lt;strong&gt;Identity&lt;/strong&gt;:
&lt;/h3&gt;

&lt;p&gt;The &lt;strong&gt;role or persona&lt;/strong&gt; you assign to an AI agent significantly influences the quality of its responses.&lt;/p&gt;

&lt;p&gt;Consider these two prompts and their answers:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;What is an LLM?&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;You are a sarcastic teenager explaining AI to your grandparents. What is an LLM?&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvsjegprthysca3puypau.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvsjegprthysca3puypau.png" alt="chatGPT different answers based on AI agent roles" width="800" height="554"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In the second prompt, the brief identity assignment led &lt;strong&gt;ChatGPT&lt;/strong&gt; to adopt the persona of a sarcastic teenager explaining AI to their grandparents, transforming its response in several ways:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Content:&lt;/strong&gt; The information presented was more casual and humorous.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Writing Style:&lt;/strong&gt; The tone became more conversational and relatable.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Humor:&lt;/strong&gt; The response included sarcasm to entertain and engage.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Comprehension Level:&lt;/strong&gt; The explanation was simplified and analogies were used.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Technical Detail:&lt;/strong&gt; The answer was less formal and more accessible.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Understanding and carefully crafting the identity and context for each AI agent is essential.&lt;/p&gt;

&lt;p&gt;Regularly experiment to determine the most effective identity for your specific requirements.&lt;/p&gt;

&lt;p&gt;For instance, an AI agent designed as a customer service representative should be friendly and empathetic, while a technical support agent should channel their inner tech wizard, complete with geeky charm.&lt;/p&gt;

&lt;p&gt;You wouldn’t want your tech support agent cracking jokes about why the computer crossed the road, would you?&lt;/p&gt;

&lt;h3&gt;
  
  
  2. &lt;strong&gt;Narrow Scope&lt;/strong&gt;:
&lt;/h3&gt;

&lt;p&gt;Research consistently shows that LLMs excel when given &lt;strong&gt;clear, specific tasks&lt;/strong&gt; rather than broad, open-ended ones.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Overloading&lt;/strong&gt; an agent with excessive information or context can reduce accuracy and increase the risk of generating false responses or &lt;strong&gt;hallucinations&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The secret is to maintain a sharply focused scope for each agent.&lt;/p&gt;

&lt;p&gt;Give each agent a &lt;strong&gt;single, well-defined objective&lt;/strong&gt;. Avoid creating a “jack of all trades” agent. Instead, aim for a master of one.&lt;/p&gt;

&lt;p&gt;Rather than depending on one agent to tackle multiple complex tasks, build a team of specialized agents, each with a distinct area of expertise.&lt;/p&gt;

&lt;p&gt;For example, in an AI-driven customer service system, you could organize your team as follows:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;One agent handles initial query classification&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Another agent retrieves relevant information from your knowledge base&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;A third agent crafts personalized responses based on the information gathered&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This focused approach not only boosts performance of the agents but also increases output quality and decreases hallucinations.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. &lt;strong&gt;Memory&lt;/strong&gt;:
&lt;/h3&gt;

&lt;p&gt;Memory is key to making AI agents effective in the real world.&lt;/p&gt;

&lt;p&gt;Just like human memory, &lt;strong&gt;AI memory&lt;/strong&gt; lets agents remember past actions and results, think about their performance, and use these insights to make better choices in the future.&lt;/p&gt;

&lt;p&gt;Memory helps agents get better over time and adapt to new situations.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Short-term memory&lt;/strong&gt; acts like a blank slate, starting fresh with each new task.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Long-term memory&lt;/strong&gt;, stored usually in databases, keeps track of past experiences. After finishing a task, the agent reflects on its work and saves useful information for future use.&lt;/p&gt;

&lt;p&gt;When faced with a new challenge, agents can use this stored knowledge to make smarter and more effective decisions.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fntxh82rsqa0clq4a3835.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fntxh82rsqa0clq4a3835.png" alt="The required components for creating a good AI agent" width="794" height="524"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  4. &lt;strong&gt;Planning&lt;/strong&gt;:
&lt;/h3&gt;

&lt;p&gt;Not every task can be broken down into simple steps from the beginning. Some goals need a more flexible approach to handle unexpected issues and adapt to changing circumstances.&lt;/p&gt;

&lt;p&gt;With &lt;strong&gt;strategic planning&lt;/strong&gt;, agents can handle complex tasks by figuring out the necessary steps as they go.&lt;/p&gt;

&lt;p&gt;For example, a &lt;strong&gt;travel booking agent&lt;/strong&gt; planning a multi-city trip won't give up if a flight is full. The agent will look for other flights, consider different routes or airlines, and even check options like changing travel dates or nearby airports to meet the client's needs.&lt;/p&gt;

&lt;p&gt;By letting agents assess their goals, review available options, and plan their actions, you improve their ability to manage complex situations and provide effective solutions.&lt;/p&gt;

&lt;p&gt;In practice, adding the simple &lt;strong&gt;"Think step by step"&lt;/strong&gt; statement to the agent will hugely improve its response.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. &lt;strong&gt;Tools&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;LLMs are limited to the data they were trained on, which can restrict their ability to provide real time information, &lt;strong&gt;as many of us have seen with ChatGPT&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;To address this, agents can be &lt;strong&gt;equipped with tools&lt;/strong&gt; that allow them to interact with the external world.&lt;/p&gt;

&lt;p&gt;These tools might include &lt;strong&gt;APIs&lt;/strong&gt;, &lt;strong&gt;databases&lt;/strong&gt;, and other services that help them search the internet, collect data, or perform specific actions.&lt;/p&gt;

&lt;p&gt;Just as with defining an agent’s scope, it’s important not to &lt;strong&gt;overwhelm&lt;/strong&gt; your agents with too many tools.&lt;/p&gt;

&lt;p&gt;Provide each agent with only the essential tools needed to achieve its goal. Too many tools can be confusing, making it hard for the agent to know which one to use and leading to errors or mixed-up information.&lt;/p&gt;

&lt;p&gt;In the next section, we’ll explore how to integrate these tools with your agents in more detail.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;In summary&lt;/strong&gt;, when creating an agent, consider the following:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Identity:&lt;/strong&gt; The role you assign to an AI agent affects its response quality, so tailor the persona to match the task.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Narrow Scope:&lt;/strong&gt; Focus each agent on a single task to improve accuracy and reduce errors, avoiding a &lt;strong&gt;“jack of all trades”&lt;/strong&gt; approach.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Memory:&lt;/strong&gt; Use memory to help agents remember past actions and learn from them, enhancing their future performance.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Planning:&lt;/strong&gt; Allow agents to dynamically plan and adapt their approach to complex tasks, improving their flexibility and effectiveness.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Tools:&lt;/strong&gt; Equip agents with essential tools for their tasks, but avoid overwhelming them with too many options to prevent confusion and errors.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  How to Equip AI Agents with Tools
&lt;/h2&gt;

&lt;p&gt;AI agents can use tools by leveraging a concept called &lt;strong&gt;function calling&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Function calling&lt;/strong&gt; means giving an &lt;strong&gt;LLM&lt;/strong&gt; access to &lt;strong&gt;external functions&lt;/strong&gt; to interact with the real world.&lt;/p&gt;

&lt;p&gt;It works like this:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;The user asks the LLM, &lt;strong&gt;"What's the current weather in Barcelona?"&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The LLM decides it needs &lt;strong&gt;weather data&lt;/strong&gt;, so it calls a &lt;strong&gt;weather data tool&lt;/strong&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The weather data tool fetches and returns the current weather information for Barcelona.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The LLM uses this weather information to provide an accurate response to the user.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;As the name suggests, tools are normal programming functions being called by the LLM. They can be created in several ways:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Coding them &lt;strong&gt;from scratch&lt;/strong&gt;, for example, using a programming language like &lt;strong&gt;Python&lt;/strong&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Using builtin tools from established frameworks like &lt;a href="https://python.langchain.com/v0.2/docs/integrations/tools/" rel="noopener noreferrer"&gt;&lt;strong&gt;Langchain&lt;/strong&gt;&lt;/a&gt; or &lt;a href="https://docs.llamaindex.ai/en/stable/module_guides/deploying/agents/tools/" rel="noopener noreferrer"&gt;&lt;strong&gt;Llama Index&lt;/strong&gt;&lt;/a&gt;&lt;strong&gt;.&lt;/strong&gt; Below are some of the tools available in &lt;strong&gt;Langchain&lt;/strong&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Alpha Vantage&lt;/th&gt;
&lt;th&gt;Google Finance&lt;/th&gt;
&lt;th&gt;OpenWeatherMap&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;ArXiv&lt;/td&gt;
&lt;td&gt;Google Jobs&lt;/td&gt;
&lt;td&gt;Passio NutritionAI&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;AWS Lambda&lt;/td&gt;
&lt;td&gt;Google Places&lt;/td&gt;
&lt;td&gt;PubMed&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Azure Container Apps dynamic sessions&lt;/td&gt;
&lt;td&gt;Google Scholar&lt;/td&gt;
&lt;td&gt;Python REPL&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Shell (bash)&lt;/td&gt;
&lt;td&gt;Google Search&lt;/td&gt;
&lt;td&gt;Reddit Search&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Bearly Code Interpreter&lt;/td&gt;
&lt;td&gt;Google Serper&lt;/td&gt;
&lt;td&gt;Requests&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Bing Search&lt;/td&gt;
&lt;td&gt;Google Trends&lt;/td&gt;
&lt;td&gt;Tavily Search&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Dall-E Image Generator&lt;/td&gt;
&lt;td&gt;HuggingFace Hub Tools&lt;/td&gt;
&lt;td&gt;SearchApi&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;DataForSEO&lt;/td&gt;
&lt;td&gt;SerpAPI&lt;/td&gt;
&lt;td&gt;Semantic Scholar API Tool&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;DuckDuckGo Search&lt;/td&gt;
&lt;td&gt;Ionic Shopping Tool&lt;/td&gt;
&lt;td&gt;SQL Database&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Eleven Labs Text2Speech&lt;/td&gt;
&lt;td&gt;Exa Search&lt;/td&gt;
&lt;td&gt;Twilio&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;File System&lt;/td&gt;
&lt;td&gt;NVIDIA Riva: ASR and TTS&lt;/td&gt;
&lt;td&gt;Wikipedia&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Google Cloud Text-to-Speech&lt;/td&gt;
&lt;td&gt;Oracle AI Vector Search: Generate Summary&lt;/td&gt;
&lt;td&gt;Wolfram Alpha&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Google Drive&lt;/td&gt;
&lt;td&gt;Passio NutritionAI&lt;/td&gt;
&lt;td&gt;Yahoo Finance News&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Google Finance&lt;/td&gt;
&lt;td&gt;Polygon Stock Market API Tools&lt;/td&gt;
&lt;td&gt;
&lt;a href="http://You.com" rel="noopener noreferrer"&gt;You.com&lt;/a&gt; Search&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Google Imagen&lt;/td&gt;
&lt;td&gt;PubMed&lt;/td&gt;
&lt;td&gt;YouTube&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;ul&gt;
&lt;li&gt;Using a &lt;strong&gt;no-code platform&lt;/strong&gt; like &lt;a href="https://app.relevanceai.com/" rel="noopener noreferrer"&gt;&lt;strong&gt;Relevance AI&lt;/strong&gt;&lt;/a&gt;, which comes with various built-in tools and simplified templates to develop custom ones.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftvb7rt59xw03s3zse9rf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftvb7rt59xw03s3zse9rf.png" alt="Relevance AI tools and AI agents" width="800" height="452"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When designing an AI agent, you must provide it with all the necessary tools to achieve its tasks.&lt;/p&gt;

&lt;p&gt;For example, an AI agent tasked with &lt;strong&gt;sales prospecting&lt;/strong&gt; should be equipped with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Research tools:&lt;/strong&gt; to enrich lead information by accessing LinkedIn or social media profiles.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Scraping tools:&lt;/strong&gt; to collect additional details from the lead's company websites.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Emailing tools:&lt;/strong&gt; to send a personalized email to the lead.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;CRM tools:&lt;/strong&gt; to record the lead in the database for future follow-up.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;An important thing to keep in mind while building these tools is &lt;strong&gt;error handling&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;When an agent calls a tool, it expects to get a correct response. But what if the tool throws an error or exception?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Should the agent stop?&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Should the agent try again?&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;You don't want your entire app to crash because of that!&lt;/strong&gt; So you need to consider the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Your tools must have robust error handling.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;They must provide helpful error messages to your agent (who may decide on a new plan).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Enable your agent to perform multiple tries if the first call fails.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;strong&gt;In summary&lt;/strong&gt;, tools are crucial for your AI agent:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;They allow him to &lt;strong&gt;interact&lt;/strong&gt; with the real world and perform tasks effectively.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;They must be well-designed and robust to ensure your agent can &lt;strong&gt;handle errors gracefully&lt;/strong&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;They should be &lt;strong&gt;tailored&lt;/strong&gt; to the agent's specific tasks to maximize efficiency and effectiveness.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  &lt;strong&gt;What's Next?&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;In this article, we explored &lt;strong&gt;what AI agents are and how to design them effectively&lt;/strong&gt;. You also discovered the key &lt;strong&gt;differences between AI agents and AI automation&lt;/strong&gt; and learned &lt;strong&gt;how to equip your AI agents with the right tools&lt;/strong&gt; to boost their performance.&lt;/p&gt;

&lt;p&gt;🚀 &lt;strong&gt;Ready to take your AI skills to the next level?&lt;/strong&gt;&lt;br&gt;
Check out my &lt;strong&gt;&lt;a href="https://github.com/kaymen99" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;&lt;/strong&gt; for hands-on projects, builds, and experiments in AI automation and AI agent development!&lt;/p&gt;

</description>
      <category>ai</category>
      <category>agenticai</category>
      <category>learning</category>
      <category>tutorial</category>
    </item>
  </channel>
</rss>
