<?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: Exson Joseph</title>
    <description>The latest articles on DEV Community by Exson Joseph (@exson_joseph).</description>
    <link>https://dev.to/exson_joseph</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%2F2975695%2Fee103607-92e2-4354-a216-3038c1a0da5d.png</url>
      <title>DEV Community: Exson Joseph</title>
      <link>https://dev.to/exson_joseph</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/exson_joseph"/>
    <language>en</language>
    <item>
      <title>Crafting Conversational Experiences: A Generative UI Portfolio Built with Gemini</title>
      <dc:creator>Exson Joseph</dc:creator>
      <pubDate>Sat, 03 Jan 2026 11:26:22 +0000</pubDate>
      <link>https://dev.to/exson_joseph/crafting-conversational-experiences-a-generative-ui-portfolio-built-with-gemini-3c18</link>
      <guid>https://dev.to/exson_joseph/crafting-conversational-experiences-a-generative-ui-portfolio-built-with-gemini-3c18</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for the &lt;a href="https://dev.to/challenges/new-year-new-you-google-ai-2025-12-31"&gt;New Year, New You Portfolio Challenge Presented by Google AI&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  About Me
&lt;/h2&gt;

&lt;p&gt;My name is Exson Joseph. I'm a AI Engineer and Full-Stack Developer with over 2 years of experience building AI-powered products from end-to-end. I'm skilled at turning ideas into working products, from problem definition and feature design to full-stack implementation and deployment. This portfolio is a showcase of my skills and projects, presented in a unique and interactive way.&lt;/p&gt;

&lt;h2&gt;
  
  
  Portfolio
&lt;/h2&gt;

&lt;p&gt;

&lt;/p&gt;
&lt;div class="ltag__cloud-run"&gt;
  &lt;iframe height="600px" src="https://exson-frontend-119055976588.us-central1.run.app/"&gt;
  &lt;/iframe&gt;
&lt;/div&gt;




&lt;h2&gt;
  
  
  How I Built It
&lt;/h2&gt;

&lt;p&gt;This portfolio is a full-stack application designed to be an interactive and engaging.&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Frontend&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Framework&lt;/strong&gt;: Next.js (with React and TypeScript)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Styling&lt;/strong&gt;: Tailwind CSS&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Animations&lt;/strong&gt;: Framer Motion&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;UI&lt;/strong&gt;: A custom-built chatbot interface that allows users to ask questions in natural language.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

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

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Framework&lt;/strong&gt;: Node.js with Express&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Database&lt;/strong&gt;: MongoDB with Mongoose for conversation history.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;AI&lt;/strong&gt;: Google's &lt;strong&gt;Gemini 2.5 Flash&lt;/strong&gt; model through the &lt;code&gt;@google/genai&lt;/code&gt; SDK.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;This project consists of two services a Next.js frontend and a Node.js backend both are deployed in Google Cloud Run.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I'm Most Proud Of
&lt;/h2&gt;

&lt;p&gt;I'm most proud of creating a portfolio that goes beyond a static page. The chatbot interface, powered by Google's Gemini model, allows for a truly interactive and personal experience. I'm particularly excited about the "Generative UI" concept, where the AI has direct control over the user interface, making the portfolio feel alive and intelligent. This project was a great opportunity to combine my skills in full-stack development and generative AI to build something unique and memorable.&lt;/p&gt;

</description>
      <category>devchallenge</category>
      <category>googleaichallenge</category>
      <category>portfolio</category>
      <category>gemini</category>
    </item>
    <item>
      <title>A Guide to HITL, HOTL, and HOOTL Workflows</title>
      <dc:creator>Exson Joseph</dc:creator>
      <pubDate>Wed, 24 Dec 2025 17:54:11 +0000</pubDate>
      <link>https://dev.to/exson_joseph/a-guide-to-hitl-hotl-and-hootl-workflows-4p4n</link>
      <guid>https://dev.to/exson_joseph/a-guide-to-hitl-hotl-and-hootl-workflows-4p4n</guid>
      <description>&lt;p&gt;In the rush to automate everything with Large Language Models (LLMs), many make a critical mistake they treat AI as a binary choice either a human does the work, or the machine does.&lt;/p&gt;

&lt;p&gt;In reality, the most successful AI implementations exist on a spectrum of human intervention. We call these HITL (&lt;strong&gt;Human-in-the-Loop&lt;/strong&gt;), HOTL (&lt;strong&gt;Human-on-the-Loop&lt;/strong&gt;), and HOOTL (&lt;strong&gt;Human-out-of-the-Loop&lt;/strong&gt;).&lt;/p&gt;

&lt;p&gt;Choosing the wrong workflow can lead to either a "bottleneck" (too much human interference) or "hallucination disasters" (too much machine autonomy). Here is everything you need to know about these three pillars of AI architecture.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Human-in-the-Loop (HITL)
&lt;/h2&gt;

&lt;p&gt;In an HITL workflow, the AI is a sophisticated assistant that cannot finish its task without a human "checkpoint."&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;When to use it:&lt;/strong&gt; &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  High-stakes legal or medical documents.&lt;/li&gt;
&lt;li&gt;  Creative writing where "voice" and "nuance" are vital.&lt;/li&gt;
&lt;li&gt;  Generating code for production systems.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Code Example
&lt;/h3&gt;

&lt;p&gt;In this example, Gemini writes a press release, but the script refuses to "publish" it until a human manually reviews and edits the text.&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;google&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;genai&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;dotenv&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;load_dotenv&lt;/span&gt;

&lt;span class="nf"&gt;load_dotenv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;override&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="n"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;genai&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Client&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="n"&gt;MODEL_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;gemini-2.5-flash&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;hitl_press_release&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="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;HITL: Human reviews and approves/edit AI output before finalizing.&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="n"&gt;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;Write a short press release for: &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="n"&gt;ai_draft&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;models&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;generate_content&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;MODEL_NAME&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;contents&lt;/span&gt;&lt;span class="o"&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;text&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="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;--- [ACTION REQUIRED] REVIEW AI DRAFT ---&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="n"&gt;ai_draft&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;feedback&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;input&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&lt;/span&gt;&lt;span class="s"&gt;Would you like to (1) Accept, (2) Rewrite, or (3) Edit manually? &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;feedback&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;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;final_output&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ai_draft&lt;/span&gt;
    &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="n"&gt;feedback&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;2&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;critique&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;input&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;What should the AI change? &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="nf"&gt;hitl_press_release&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="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="s"&gt;. Note: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;critique&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;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;final_output&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;input&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Paste your manually edited version here: &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="sh"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;[SUCCESS] Press release finalized and saved.&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;final_output&lt;/span&gt;

&lt;span class="nf"&gt;hitl_press_release&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Launch of a new sustainable coffee brand&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;
  
  
  2. Human-on-the-Loop (HOTL)
&lt;/h2&gt;

&lt;p&gt;In HOTL, the AI operates autonomously and at scale, but a human stands by a "dashboard" to monitor the outputs. The human doesn't approve every single item instead, they intervene only when they see the AI deviating from the goal.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;When to use it:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Live social media moderation.&lt;/li&gt;
&lt;li&gt;  Real-time customer support chatbots.&lt;/li&gt;
&lt;li&gt;  Monitoring industrial IoT sensors.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Code Example
&lt;/h3&gt;

&lt;p&gt;In this example, Gemini categorizes customer tickets. The human isn't asked for permission for every ticket, but they have a "Window of Intervention" to stop the process if the AI starts making mistakes.&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;google&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;genai&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;dotenv&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;load_dotenv&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;

&lt;span class="nf"&gt;load_dotenv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;override&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="n"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;genai&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Client&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="n"&gt;MODEL_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;gemini-2.5-flash&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;hotl_support_monitor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tickets&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;On-the-Loop: Human monitors AI decisions in real-time and can veto.&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="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;System active. Monitoring AI actions... (Press Ctrl+C to PAUSE/VETO)&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;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ticket&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;enumerate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tickets&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="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;models&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;generate_content&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;MODEL_NAME&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="n"&gt;contents&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;Categorize this ticket (Billing/Tech/Sales): &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;ticket&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;category&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="n"&gt;text&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="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;[Log &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;] Ticket: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;ticket&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="si"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;30&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;... -&amp;gt; Action: Tagged as &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;category&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;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;2&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;KeyboardInterrupt&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;[VETO] Human supervisor has paused the system on ticket: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;ticket&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;action&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;input&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Should we (C)ontinue or (S)kip this ticket? &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;action&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="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;s&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="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="k"&gt;pass&lt;/span&gt;

&lt;span class="n"&gt;tickets&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;My bill is too high&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;The app keeps crashing&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;How do I buy more?&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="nf"&gt;hotl_support_monitor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tickets&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  3. Human-out-of-the-Loop (HOOTL)
&lt;/h2&gt;

&lt;p&gt;The AI handles the entire process from start to finish. Human intervention only happens &lt;em&gt;after&lt;/em&gt; the fact during an audit or a weekly performance review. This is the goal for high-volume, low-risk tasks.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;When to use it:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Spam filtering.&lt;/li&gt;
&lt;li&gt;  Translating massive databases of product descriptions.&lt;/li&gt;
&lt;li&gt;  Basic data cleaning and formatting.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Code Example
&lt;/h3&gt;

&lt;p&gt;This script takes customer reviews and summarizes them into a report without ever stopping to ask a human for help.&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;google&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;genai&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;dotenv&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;load_dotenv&lt;/span&gt;

&lt;span class="nf"&gt;load_dotenv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;override&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="n"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;genai&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Client&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="n"&gt;MODEL_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;gemini-2.5-flash&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;hootl_batch_processor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data_list&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;Human-out-of-the-Loop: AI processes batch independently; human reviews final report.&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="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Starting HOOTL process: &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;data_list&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; items to process.&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_report&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;item&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;data_list&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;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;models&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;generate_content&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;MODEL_NAME&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;contents&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;Extract key sentiment (Happy/Sad/Neutral): &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;item&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;final_report&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;data&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;sentiment&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="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="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;final_report&lt;/span&gt;

&lt;span class="n"&gt;reviews&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;Great food!&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;Slow service&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;Expensive but worth it&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&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;hootl_batch_processor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;reviews&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;Final 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;report&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Which one should you build?
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Workflow&lt;/th&gt;
&lt;th&gt;Interaction Level&lt;/th&gt;
&lt;th&gt;Human Effort&lt;/th&gt;
&lt;th&gt;Latency (Speed)&lt;/th&gt;
&lt;th&gt;Risk Tolerance&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;HITL&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Active&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;High&lt;/td&gt;
&lt;td&gt;Slow&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;Zero Tolerance&lt;/strong&gt; (High Risk)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;HOTL&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Passive&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Medium&lt;/td&gt;
&lt;td&gt;Medium&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;Managed Risk&lt;/strong&gt; (Scale + Safety)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;HOOTL&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;None&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Low&lt;/td&gt;
&lt;td&gt;Very Fast&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;Low Risk&lt;/strong&gt; (High Volume)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

</description>
      <category>ai</category>
      <category>architecture</category>
      <category>llm</category>
    </item>
    <item>
      <title>Strategies to Analyze Any Size Dataset with LLMs Beyond its Context Limit</title>
      <dc:creator>Exson Joseph</dc:creator>
      <pubDate>Tue, 18 Nov 2025 05:46:54 +0000</pubDate>
      <link>https://dev.to/exson_joseph/strategies-to-analyze-any-size-dataset-with-llms-beyond-its-context-limit-4i37</link>
      <guid>https://dev.to/exson_joseph/strategies-to-analyze-any-size-dataset-with-llms-beyond-its-context-limit-4i37</guid>
      <description>&lt;p&gt;You've connected your LLM to a SQL database using Model Context Protocol (MCP), run a query, and... oh no. Instead of the manageable 100 rows you expected, you get 50,000 records. Your LLM's context window can only handle a fraction of this data. What now?&lt;/p&gt;

&lt;p&gt;Here's how to fix this, starting with the most effective approaches.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Summary Approach
&lt;/h2&gt;

&lt;p&gt;Instead of dumping raw data, provide strategic summaries that give the LLM (and your users) the big picture.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;SELECT 
    COUNT(*) as total_records,
    AVG(sales_amount) as avg_sale,
    MIN(sales_amount) as min_sale,
    MAX(sales_amount) as max_sale,
    COUNT(DISTINCT customer_id) as unique_customers,
    SUM(sales_amount) as total_revenue
FROM sales_data 
WHERE date &amp;gt;= '2024-01-01';
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The LLM gets the complete statistical picture in a few dozen tokens instead of thousands. It can identify outliers, understand distributions, and ask intelligent follow-up questions.&lt;/p&gt;

&lt;h2&gt;
  
  
  Progressive Disclosure Pattern
&lt;/h2&gt;

&lt;p&gt;Think of this as a conversation rather than a data dump:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;High-level summary:&lt;/strong&gt; We have 50,000 sales records totaling $2.4M&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Key trends:&lt;/strong&gt; Sales are growing 15% month-over-month, with Electronics being the top category&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Segment analysis:&lt;/strong&gt; Let me analyze the top 10% of customers who drive 40% of revenue&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Deep dive:&lt;/strong&gt; Show me the actual transactions for our VIP customers last month&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Each step is context-aware and builds on previous understanding.&lt;/p&gt;

&lt;h2&gt;
  
  
  Intelligent Sampling
&lt;/h2&gt;

&lt;p&gt;Not all data points are created equal. Instead of random sampling, use strategic approaches:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;SELECT * FROM (
    SELECT *, 
           ROW_NUMBER() OVER (PARTITION BY category ORDER BY RANDOM()) as rn
    FROM products
) WHERE rn &amp;lt;= 10;  -- 10 from each category

-- Importance sampling: focus on what matters
SELECT * FROM customers 
ORDER BY lifetime_value DESC, last_purchase_date DESC
LIMIT 100;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Time-based Chunking
&lt;/h2&gt;

&lt;p&gt;Large datasets often have a time component. Use this to your advantage:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;SELECT 
    DATE_TRUNC('week', order_date) as week,
    COUNT(*) as order_count,
    AVG(order_amount) as avg_order_size
FROM orders
GROUP BY DATE_TRUNC('week', order_date)
ORDER BY week;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This helps identify trends, seasonality, and anomalies without overwhelming the context window.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Outlier-First Method
&lt;/h2&gt;

&lt;p&gt;Often, the most interesting insights live in the extremes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;SELECT *
FROM (
    SELECT *,
           (sales_amount - AVG(sales_amount) OVER()) / STDDEV(sales_amount) OVER() as z_score
    FROM sales_data
) WHERE ABS(z_score) &amp;gt; 3;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The goal isn't to show all your data, it's to derive insights from it. By using these strategies, you transform from someone who struggles with context limits to someone who delivers precise, actionable insights regardless of data size.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>llm</category>
      <category>mcp</category>
      <category>sql</category>
    </item>
    <item>
      <title>Scalable Character Insights from Novels Using Vector Search and LLMs</title>
      <dc:creator>Exson Joseph</dc:creator>
      <pubDate>Fri, 20 Jun 2025 02:31:41 +0000</pubDate>
      <link>https://dev.to/exson_joseph/scalable-character-insights-from-novels-using-vector-search-and-llms-1937</link>
      <guid>https://dev.to/exson_joseph/scalable-character-insights-from-novels-using-vector-search-and-llms-1937</guid>
      <description>&lt;p&gt;When dealing with &lt;strong&gt;small documents&lt;/strong&gt; say, 5 to 10 pages it's relatively straightforward to generate text embeddings, store them in a &lt;strong&gt;vector database&lt;/strong&gt;, and perform &lt;strong&gt;similarity search&lt;/strong&gt; to retrieve relevant content. This works well for basic use cases where you need to find simple facts, definitions, or short contextual passages.&lt;/p&gt;

&lt;p&gt;But what happens when the content isn’t a short article, but an entire &lt;strong&gt;novel series&lt;/strong&gt; like &lt;em&gt;Harry Potter&lt;/em&gt;? And what if your goal isn’t just to retrieve a paragraph, but to understand something &lt;strong&gt;deep and evolving&lt;/strong&gt; like a character's personality, motivations, or moral arc across multiple books?&lt;/p&gt;

&lt;p&gt;This introduces a number of challenges:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Volume of data&lt;/strong&gt;: Thousands of pages with rich narrative.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Contextual evolution&lt;/strong&gt;: A character may grow, change, or contradict themselves across different books.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Relevance and focus&lt;/strong&gt;: Not all scenes matter equally; many contain noise for this task.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To handle this effectively and efficiently, we need a multi-layered approach that combines the following techniques:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Smart Chunking&lt;/li&gt;
&lt;li&gt;Named Entity Recognition (NER)&lt;/li&gt;
&lt;li&gt;Vector Search with Metadata Filtering&lt;/li&gt;
&lt;li&gt;Retrieval-Augmented Generation (RAG)&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Smart Chunking
&lt;/h2&gt;

&lt;p&gt;Instead of naively splitting the text by fixed token lengths, we apply semantic chunking. This means breaking the text at natural boundaries like paragraphs, chapters, or scenes. Sliding windows can be used to preserve context across adjacent sections. This improves the quality of both retrieval and interpretation by keeping meaningful units of thought together.&lt;/p&gt;

&lt;h2&gt;
  
  
  Named Entity Recognition (NER)
&lt;/h2&gt;

&lt;p&gt;We use NER to automatically identify characters, locations, and other key entities throughout the text. This allows us to tag each chunk with metadata, such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Which characters are mentioned&lt;/li&gt;
&lt;li&gt;Dialogue vs. narration&lt;/li&gt;
&lt;li&gt;Scene context (e.g., setting or action)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;By doing this, we can filter the vector search to only include relevant portions of the text when analyzing a specific character.&lt;/p&gt;

&lt;h2&gt;
  
  
  Vector Search with Metadata Filtering
&lt;/h2&gt;

&lt;p&gt;Once the text is chunked and embedded, we store the vectors in a vector database (e.g., FAISS, Qdrant, or Weaviate). When a user query like:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;“What kind of person is Draco Malfoy?”&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;the system can:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Filter&lt;/strong&gt; the chunks to those that mention Draco Malfoy.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Search&lt;/strong&gt; within that filtered set using semantic similarity.&lt;/li&gt;
&lt;li&gt;Retrieve the most relevant passages for deeper analysis.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This drastically improves both performance and relevance compared to searching across the entire corpus.&lt;/p&gt;

&lt;h2&gt;
  
  
  Retrieval-Augmented Generation (RAG)
&lt;/h2&gt;

&lt;p&gt;Finally, the retrieved chunks are passed to a &lt;strong&gt;language model&lt;/strong&gt; using a Retrieval-Augmented Generation pipeline. Instead of just retrieving passages, the LLM is prompted to &lt;strong&gt;synthesize&lt;/strong&gt; an answer based on retrieved evidence.&lt;/p&gt;

&lt;p&gt;This enables complex, context-aware answers like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Descriptions of a character’s evolving traits&lt;/li&gt;
&lt;li&gt;Contradictions in behavior across books&lt;/li&gt;
&lt;li&gt;Emotional or psychological profiling&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;Extracting character insights from massive narrative datasets like novel series requires more than just embedding text and running similarity search. It involves a thoughtful combination of:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Smart chunking&lt;/strong&gt; to preserve semantic structure&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;NER and metadata&lt;/strong&gt; for focused retrieval&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Vector search&lt;/strong&gt; to handle scale efficiently&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;RAG pipelines&lt;/strong&gt; to generate coherent, high-quality answers&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This approach scales well, offers flexibility, and can be adapted to a wide range of literary analysis or knowledge retrieval tasks.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>rag</category>
      <category>machinelearning</category>
      <category>vectordatabase</category>
    </item>
    <item>
      <title>Automating SQL Queries with LangChain and Gemini : A Step-by-Step Guide</title>
      <dc:creator>Exson Joseph</dc:creator>
      <pubDate>Wed, 02 Apr 2025 16:26:41 +0000</pubDate>
      <link>https://dev.to/exson_joseph/automating-sql-queries-with-langchain-and-gemini-a-step-by-step-guide-816</link>
      <guid>https://dev.to/exson_joseph/automating-sql-queries-with-langchain-and-gemini-a-step-by-step-guide-816</guid>
      <description>&lt;p&gt;&lt;a href="https://github.com/exson6969/langchain-sql" rel="noopener noreferrer"&gt;GitHub Repository&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Learn how to automate SQL query generation and execution using LangChain, Google Gemini AI, and MySQL. This guide walks you through setting up a seamless pipeline from transforming natural language questions into SQL queries to executing them and generating insightful answers.&lt;/p&gt;

&lt;h2&gt;
  
  
  Environment Setup
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Creating a Virtual Environment
&lt;/h3&gt;

&lt;p&gt;Isolate your project dependencies by creating a virtual environment:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;h3&gt;
  
  
  activate virtual environment
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;.\.venv\Scripts\activate
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Installing Required Packages
&lt;/h3&gt;

&lt;p&gt;Install the necessary Python packages:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;pip install mysql-connector-python langchain langchain-community langchain-google-genai python-dotenv
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Configuring Environment Variables
&lt;/h3&gt;

&lt;p&gt;Create a &lt;code&gt;.env&lt;/code&gt; file with your configuration:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;LANGSMITH_TRACING=true
LANGSMITH_ENDPOINT="https://api.smith.langchain.com"
LANGSMITH_API_KEY=your_langsmith_key
LANGSMITH_PROJECT="company-sql"
GOOGLE_API_KEY=your_google_api_key
SQL_HOST=your_db_host
SQL_USER=your_db_username
SQL_PASSWORD=your_db_password
SQL_DB_NAME=your_database_name
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Building the SQL Automation Pipeline
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Importing Required Modules
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;from langchain_google_genai import ChatGoogleGenerativeAI
from langchain_community.utilities import SQLDatabase
from langchain_community.tools.sql_database.tool import QuerySQLDatabaseTool
from langchain import hub
from dotenv import load_dotenv
import os
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;ChatGoogleGenerativeAI&lt;/code&gt; : To use Google's Gemini model.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;SQLDatabase&lt;/code&gt; : Manages database connections using SQL URI.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;QuerySQLDatabaseTool&lt;/code&gt; : Executes queries and retrieves results.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;hub&lt;/code&gt; : Accesses pre-defined prompts from LangChain Hub.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;load_dotenv&lt;/code&gt; : Manages environment variables.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;os&lt;/code&gt; : Accesses operating system functionality.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Loading Configuration
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;load_dotenv(override=True)

SQL_HOST=os.getenv("SQL_HOST")
SQL_USER=os.getenv("SQL_USER")
SQL_PASSWORD=os.getenv("SQL_PASSWORD")
SQL_DB_NAME=os.getenv("SQL_DB_NAME")
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This code loads sensitive configuration from your &lt;code&gt;.env&lt;/code&gt; file, keeping credentials secure and out of your source code.&lt;/p&gt;

&lt;h3&gt;
  
  
  Initializing Gemini AI Model
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;llm = ChatGoogleGenerativeAI(model="gemini-1.5-flash")
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We're using Google's &lt;code&gt;gemini-1.5-flash&lt;/code&gt; model, which offers excellent performance for SQL generation tasks while being cost-effective.&lt;/p&gt;

&lt;h3&gt;
  
  
  Establishing Database Connection
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;connection_Uri = f"mysql+mysqlconnector://{SQL_USER}:{SQL_PASSWORD}@{SQL_HOST}/{SQL_DB_NAME}"
db = SQLDatabase.from_uri(connection_Uri)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This creates a connection string and establishes a connection to your MySQL database using the credentials from your environment variables.&lt;/p&gt;

&lt;h2&gt;
  
  
  Core Functionality Implementation
&lt;/h2&gt;

&lt;h3&gt;
  
  
  SQL Query Generation
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;query_prompt_template = hub.pull("langchain-ai/sql-query-system-prompt")

def write_query(question: str):
    """Generate SQL query from the user's question."""
    prompt = query_prompt_template.invoke(
        {
            "dialect": db.dialect,
            "top_k": 10,
            "table_info": db.get_table_info(),
            "input": question,
        }
    )
    response = llm.invoke(prompt.to_string())

    extraction_prompt = """
    Please extract the SQL query from the following text and return only the SQL query without any additional characters or formatting:

    {response}

    SQL Query:
    """
    # Format the prompt with the actual response
    prompt = extraction_prompt.format(response=response)
    # Invoke the language model with the prompt
    parsed_query = llm.invoke(prompt)
    return parsed_query.content
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Pulls a specialized SQL generation prompt from LangChain Hub&lt;/li&gt;
&lt;li&gt;Formats the prompt with database schema information&lt;/li&gt;
&lt;li&gt;Sends the prompt to Gemini AI for query generation&lt;/li&gt;
&lt;li&gt;Uses a second prompt to extract just the SQL from the response&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Query Execution
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;def execute_query(query: str):
    """Execute the SQL query."""
    execute_query_tool = QuerySQLDatabaseTool(db=db)
    return execute_query_tool.invoke(query)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This function creates a query execution tool and runs the generated SQL against your database, returning the raw results.&lt;/p&gt;

&lt;h3&gt;
  
  
  Natural Language Answer Generation
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;def generate_answer(question: str, query: str, result: str):
    """Generate an answer using the query results."""
    prompt = (
        "Given the following user question, corresponding SQL query, "
        "and SQL result, answer the user question.\n\n"
        f'Question: {question}\n'
        f'SQL Query: {query}\n'
        f'SQL Result: {result}'
    )
    response = llm.invoke(prompt)
    return response.content
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This function takes the original question, generated SQL, and query results, then asks Gemini to formulate a human-friendly answer.&lt;/p&gt;

&lt;h3&gt;
  
  
  Putting It All Together
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;question = "Which employee is leading Project Gamma"

query = write_query(question)
result = execute_query(query)
answer = generate_answer(question,query, result )
print(answer)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Output&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Charlie Brown is the Marketing Lead for Project Gamma.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;p&gt;This implementation demonstrates how to create a powerful natural language interface for your SQL databases. By combining LangChain's orchestration capabilities with Gemini's advanced language understanding, you can build systems that make data accessible to non-technical users while maintaining the precision of SQL queries.&lt;/p&gt;

&lt;h2&gt;
  
  
  Complete Code
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;from langchain_google_genai import ChatGoogleGenerativeAI
from langchain_community.utilities import SQLDatabase
from langchain_community.tools.sql_database.tool import QuerySQLDatabaseTool
from langchain import hub
from dotenv import load_dotenv
import os

# Load environment variables
load_dotenv(override=True)

SQL_HOST=os.getenv("SQL_HOST")
SQL_USER=os.getenv("SQL_USER")
SQL_PASSWORD=os.getenv("SQL_PASSWORD")
SQL_DB_NAME=os.getenv("SQL_DB_NAME")

# Initialize the Gemini model
llm = ChatGoogleGenerativeAI(model="gemini-1.5-flash")

# Connect to the MySQL database
connection_Uri = f"mysql+mysqlconnector://{SQL_USER}:{SQL_PASSWORD}@{SQL_HOST}/{SQL_DB_NAME}"
db = SQLDatabase.from_uri(connection_Uri)

# Pull the SQL query prompt from LangChain Hub
query_prompt_template = hub.pull("langchain-ai/sql-query-system-prompt")


def write_query(question: str):
    """Generate SQL query from the user's question."""
    prompt = query_prompt_template.invoke(
        {
            "dialect": db.dialect,
            "top_k": 10,
            "table_info": db.get_table_info(),
            "input": question,
        }
    )
    response = llm.invoke(prompt.to_string())

    extraction_prompt = """
    Please extract the SQL query from the following text and return only the SQL query without any additional characters or formatting:

    {response}

    SQL Query:
    """
    # Format the prompt with the actual response
    prompt = extraction_prompt.format(response=response)
    # Invoke the language model with the prompt
    parsed_query = llm.invoke(prompt)
    return parsed_query.content

def execute_query(query: str):
    """Execute the SQL query."""
    execute_query_tool = QuerySQLDatabaseTool(db=db)
    return execute_query_tool.invoke(query)

def generate_answer(question: str, query: str, result: str):
    """Generate an answer using the query results."""
    prompt = (
        "Given the following user question, corresponding SQL query, "
        "and SQL result, answer the user question.\n\n"
        f'Question: {question}\n'
        f'SQL Query: {query}\n'
        f'SQL Result: {result}'
    )
    response = llm.invoke(prompt)
    return response.content

question = "Which employee is leading Project Gamma"
query = write_query(question)
result = execute_query(query)
answer = generate_answer(question,query, result )
print(answer)

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>sql</category>
      <category>llm</category>
      <category>gemini</category>
      <category>langchain</category>
    </item>
    <item>
      <title>FastAPI: A Comprehensive Guide</title>
      <dc:creator>Exson Joseph</dc:creator>
      <pubDate>Sat, 29 Mar 2025 19:30:35 +0000</pubDate>
      <link>https://dev.to/exson_joseph/fastapi-a-comprehensive-guide-22io</link>
      <guid>https://dev.to/exson_joseph/fastapi-a-comprehensive-guide-22io</guid>
      <description>&lt;p&gt;FastAPI is a modern, fast (high-performance), web framework for building APIs with Python 3.7+ based on standard Python type hints. In this guide, we'll walk through setting up FastAPI and implementing all the basic CRUD operations.&lt;/p&gt;

&lt;h2&gt;
  
  
  Installation and Setup
&lt;/h2&gt;

&lt;p&gt;First, let's set up a virtual environment and install FastAPI:&lt;/p&gt;

&lt;h2&gt;
  
  
  Create a virtual environment
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;python -m venv venv
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Activate the virtual environment
&lt;/h2&gt;

&lt;h3&gt;
  
  
  On Windows:
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;venv\Scripts\activate
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  On macOS/Linux:
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;source venv/bin/activate
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Install FastAPI with all dependencies
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;pip install "fastapi[standard]"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Basic FastAPI Application
&lt;/h2&gt;

&lt;p&gt;Let's create a movie API example instead of books. Create a file called &lt;code&gt;app.py&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;from fastapi import FastAPI

app = FastAPI()

MOVIES = [
    {"title": "Inception", "director": "Christopher Nolan", "genre": "sci-fi"},
    {"title": "The Shawshank Redemption", "director": "Frank Darabont", "genre": "drama"},
    {"title": "The Dark Knight", "director": "Christopher Nolan", "genre": "action"},
    {"title": "Pulp Fiction", "director": "Quentin Tarantino", "genre": "crime"},
    {"title": "Parasite", "director": "Bong Joon-ho", "genre": "drama"}
]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Running the Application
&lt;/h2&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;uvicorn app:app --reload
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;--reload&lt;/code&gt; flag enables auto-reload when you make code changes. &lt;/p&gt;

&lt;p&gt;Visit &lt;a href="http://127.0.0.1:8000/docs" rel="noopener noreferrer"&gt;http://127.0.0.1:8000/docs&lt;/a&gt; to see the interactive Swagger UI documentation.&lt;/p&gt;

&lt;h2&gt;
  
  
  Implementing CRUD Operations
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. GET Request (Read All)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@app.get('/movies')
async def read_all_movies():
    return MOVIES
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This endpoint returns the entire list of movies. The &lt;code&gt;@app.get&lt;/code&gt; decorator defines a GET request at the &lt;code&gt;/movies&lt;/code&gt; endpoint&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Path Parameters (Read One)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@app.get('/movies/{movie_title}')
async def get_movie(movie_title: str):
    for movie in MOVIES:
        if movie.get("title").casefold() == movie_title.casefold():
            return movie
    return {"error": "Movie not found"}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This endpoint retrieves a single movie by its title. The {movie_title} in the path is a path parameter that captures the movie title from the URL.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Query Parameters (Filtering)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@app.get('/movies/')
async def read_movies_by_genre(genre: str):
    movies_to_return = []
    for movie in MOVIES:
        if movie.get('genre').casefold() == genre.casefold():
            movies_to_return.append(movie)
    return movies_to_return if movies_to_return else {"message": "No movies found in this genre"}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This endpoint filters movies by genre using a query parameter. The genre parameter is passed in the URL as a query string (e.g., /movies/?genre=drama).&lt;/p&gt;

&lt;h3&gt;
  
  
  4. POST Request (Create)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;from fastapi import Body

@app.post('/movies/create_movie')
async def create_movie(new_movie=Body()):
    MOVIES.append(new_movie)
    return {"message": "Movie added successfully", "movie": new_movie}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This endpoint adds a new movie to the list. The Body dependency extracts the JSON body from the request, which contains the new movie's details.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. PUT Request (Update)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@app.put('/movies/update_movie')
async def update_movie(updated_movie=Body()):
    for i in range(len(MOVIES)):
        if MOVIES[i].get('title').casefold() == updated_movie.get('title').casefold():
            MOVIES[i] = updated_movie
            return {"message": "Movie updated successfully"}
    return {"error": "Movie not found"}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This endpoint updates an existing movie's details. It searches for the movie by title and replaces it with the updated movie data.&lt;/p&gt;

&lt;h3&gt;
  
  
  6. DELETE Request
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@app.delete('/movies/delete_movie/{movie_title}')
async def delete_movie(movie_title: str):
    for i in range(len(MOVIES)):
        if MOVIES[i].get('title').casefold() == movie_title.casefold():
            deleted_movie = MOVIES.pop(i)
            return {"message": "Movie deleted successfully", "deleted_movie": deleted_movie}
    return {"error": "Movie not found"}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This endpoint deletes a movie by its title. It searches for the movie and removes it from the list if found.&lt;/p&gt;

&lt;h2&gt;
  
  
  Best Practices
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Always use virtual environments&lt;/li&gt;
&lt;li&gt;Organize your code with routers as your app grows&lt;/li&gt;
&lt;li&gt;Add input validation using Pydantic models&lt;/li&gt;
&lt;li&gt;Implement proper error handling&lt;/li&gt;
&lt;li&gt;Consider adding authentication for production APIs&lt;/li&gt;
&lt;/ol&gt;

</description>
      <category>fastapi</category>
      <category>api</category>
      <category>programming</category>
      <category>backend</category>
    </item>
    <item>
      <title>Langgraph Visualization with get_graph</title>
      <dc:creator>Exson Joseph</dc:creator>
      <pubDate>Tue, 25 Mar 2025 18:10:16 +0000</pubDate>
      <link>https://dev.to/exson_joseph/langgraph-visualization-with-getgraph-5hdi</link>
      <guid>https://dev.to/exson_joseph/langgraph-visualization-with-getgraph-5hdi</guid>
      <description>&lt;p&gt;LangGraph is a library created to make it easier to create stateful, multi-agent applications that make use of Large Language Models (LLMs). By expressing complex agent operations as cyclic graphs, it makes it possible to create more dynamic and adaptable behaviors than conventional linear execution models. &lt;/p&gt;

&lt;p&gt;Creating and managing chat state graphs can be challenging, but with tools like StateGraph from the langgraph library, you can seamlessly build and visualize complex workflows. This post walks you through a simple example to illustrate how to define custom nodes and edges in a state graph and visualize it using multiple formats.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;p&gt;Before diving into the code, ensure you have the following Python libraries installed:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;pip install langgraph grandalf
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Building the Graph
&lt;/h2&gt;

&lt;p&gt;Here’s the core code that constructs a simple state graph, including custom nodes and transitions:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;from IPython.display import Image
from typing_extensions import TypedDict
from langgraph.graph import StateGraph, START, END

class State(TypedDict):
    "State to manage all chats"

class MyNode:
    "Custom Node"

# Initialize the graph builder with a state
builder = StateGraph(State)

# Add a custom node
builder.add_node("myNode", MyNode)

# Define the edges for transitions
builder.add_edge(START, "myNode")
builder.add_edge("myNode", END)

# Compile the graph
chat_graph = builder.compile()
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Mermaid PNG
&lt;/h2&gt;

&lt;p&gt;This can be rendered directly in a Jupyter Notebook using&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;IPython.display.Image

Image(chat_graph.get_graph().draw_mermaid_png())
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&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%2Fl05h8bhvwcx96ko030g2.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%2Fl05h8bhvwcx96ko030g2.png" alt=" " width="107" height="234"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  ASCII
&lt;/h2&gt;

&lt;p&gt;The ASCII output provides a minimal yet clear visualization of the node transitions.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;print(chat_graph.get_graph().draw_ascii())
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&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%2F8zz04fs6nzjifuk8jx82.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%2F8zz04fs6nzjifuk8jx82.png" alt=" " width="170" height="377"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Mermaid Code
&lt;/h2&gt;

&lt;p&gt;The draw_mermaid() function outputs the source code for a Mermaid&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;diagram.print(chat_graph.get_graph().draw_mermaid())
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;%%{init: {'flowchart': {'curve': 'linear'}}}%%
graph TD;
    __start__([&amp;lt;p&amp;gt;__start__&amp;lt;/p&amp;gt;]):::first
    myNode(myNode)
    __end__([&amp;lt;p&amp;gt;__end__&amp;lt;/p&amp;gt;]):::last
    __start__ --&amp;gt; myNode;
    myNode --&amp;gt; __end__;
    classDef default fill:#f2f0ff,line-height:1.2
    classDef first fill-opacity:0
    classDef last fill:#bfb6fc

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can copy the Mermaid code from the terminal and visit &lt;a href="https://mermaid.live/" rel="noopener noreferrer"&gt;mermaid.live&lt;/a&gt;. Paste the code into the Code section, and you will see the graph rendered under the Diagram section.&lt;/p&gt;

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

&lt;p&gt;StateGraph is a powerful tool for managing and visualizing state transitions in a chat workflow. By combining custom nodes, edges, and flexible visualization options, it simplifies the process of understanding and debugging complex state machines.&lt;/p&gt;

</description>
      <category>langchain</category>
      <category>llm</category>
      <category>beginners</category>
      <category>ai</category>
    </item>
  </channel>
</rss>
