<?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: Shahzaib S</title>
    <description>The latest articles on DEV Community by Shahzaib S (@shahzaib_dev).</description>
    <link>https://dev.to/shahzaib_dev</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.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3939917%2Fbc5d6129-36ea-4ace-abf6-ad4306dd4684.jpg</url>
      <title>DEV Community: Shahzaib S</title>
      <link>https://dev.to/shahzaib_dev</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/shahzaib_dev"/>
    <language>en</language>
    <item>
      <title>I Built a Support Bot That Knows When to Stop and Call a Human</title>
      <dc:creator>Shahzaib S</dc:creator>
      <pubDate>Mon, 05 Oct 2026 06:48:25 +0000</pubDate>
      <link>https://dev.to/shahzaib_dev/i-built-a-support-bot-that-knows-when-to-stop-and-call-a-human-4p34</link>
      <guid>https://dev.to/shahzaib_dev/i-built-a-support-bot-that-knows-when-to-stop-and-call-a-human-4p34</guid>
      <description>&lt;p&gt;Everyone has been stuck with a support bot that keeps saying "Sorry, I didn't understand that" while you get angrier and angrier.&lt;/p&gt;

&lt;p&gt;I wanted to build the opposite: a bot that answers what it can, and quietly steps aside when a real person is needed. It works on web, Discord, and WhatsApp, and the code is open source: &lt;a href="https://github.com/Shahzaib30/ai-support-agent" rel="noopener noreferrer"&gt;github.com/Shahzaib30/ai-support-agent&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The Big Picture
&lt;/h2&gt;

&lt;p&gt;The system has four layers. Customers talk to it from any channel, one FastAPI backend handles everything, a few services store state and send alerts, and monitoring watches it all.&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%2Fmedia.licdn.com%2Fdms%2Fimage%2Fv2%2FD4D12AQG6NuSpUnB4cw%2Farticle-inline_image-shrink_1500_2232%2FB4DaEKucWNIoAQ-%2F0%2F1791181310338%3Fe%3D2147483647%26v%3Dbeta%26t%3DhiPzR1WFen0wpQt02RQcBN1-GuqlYB3bci1-D6tvbJo" 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%2Fmedia.licdn.com%2Fdms%2Fimage%2Fv2%2FD4D12AQG6NuSpUnB4cw%2Farticle-inline_image-shrink_1500_2232%2FB4DaEKucWNIoAQ-%2F0%2F1791181310338%3Fe%3D2147483647%26v%3Dbeta%26t%3DhiPzR1WFen0wpQt02RQcBN1-GuqlYB3bci1-D6tvbJo" alt="AI support agent system architecture: channels, FastAPI core, infrastructure, monitoring" width="554" height="814"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Inside the FastAPI core there are three gates in front of the answer engine: a &lt;strong&gt;HITL gate&lt;/strong&gt; (human-in-the-loop, which checks whether a human is already handling the chat), an &lt;strong&gt;explicit escalation&lt;/strong&gt; check, and a &lt;strong&gt;sentiment escalation&lt;/strong&gt; check. PostgreSQL remembers conversations, Redis caches answers, and everything runs with one Docker Compose command.&lt;/p&gt;

&lt;h2&gt;
  
  
  How the Bot Finds Answers
&lt;/h2&gt;

&lt;p&gt;Most RAG bots search once and hope. Mine runs every question through six stages:&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%2Fmedia.licdn.com%2Fdms%2Fimage%2Fv2%2FD4D12AQHm9Gh87y-OoA%2Farticle-inline_image-shrink_1000_1488%2FB4DaEKvJzrKsAI-%2F0%2F1791181496345%3Fe%3D2147483647%26v%3Dbeta%26t%3Dtw9ABnb6GyGW_Zppon9NIFRhFH-DF5FezwsY9l-YUFQ" 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%2Fmedia.licdn.com%2Fdms%2Fimage%2Fv2%2FD4D12AQHm9Gh87y-OoA%2Farticle-inline_image-shrink_1000_1488%2FB4DaEKvJzrKsAI-%2F0%2F1791181496345%3Fe%3D2147483647%26v%3Dbeta%26t%3Dtw9ABnb6GyGW_Zppon9NIFRhFH-DF5FezwsY9l-YUFQ" alt="RAG pipeline: query condenser, hybrid search, fusion, reranker, generation" width="980" height="1000"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;The question arrives.&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A query condenser rewrites it.&lt;/strong&gt; Customers say things like "what about sale items?", which means nothing alone. A DeepSeek step turns follow-ups into standalone questions first.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Two searches run at once.&lt;/strong&gt; FAISS with BGE-small embeddings finds passages by meaning. BM25 finds passages by exact words. Each returns its top 20.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Reciprocal Rank Fusion&lt;/strong&gt; merges them into one list of 20 candidates.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A cross-encoder reranks them.&lt;/strong&gt; It reads the question and each passage together, and only the top 5 move on.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;DeepSeek writes the answer&lt;/strong&gt; using those 5 chunks, the chat history, and long-term memory.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Why two searches? Vector search understands meaning but is weak on exact things like prices, emails, and phone numbers. Ask "What does the Pro plan cost?" and it may return a nice passage about pricing in general instead of the one with the number. BM25 is the opposite. Together they cover each other's weak spots, and for questions about fixed facts, hybrid clearly beat vector search alone.&lt;/p&gt;

&lt;h2&gt;
  
  
  When Does the Bot Give Up?
&lt;/h2&gt;

&lt;p&gt;There are two triggers, and I built them differently on purpose.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. The customer is clearly upset (checked by an LLM)
&lt;/h3&gt;

&lt;p&gt;Every message goes to the DeepSeek API with a strict prompt that replies in JSON, a label and a score from -1.0 to 1.0:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Rules:
- negative: customer is CLEARLY angry, frustrated, or complaining
- neutral: casual phrases, short responses, confusion, greetings
- positive: happy, satisfied, thankful

"oh no" → neutral
"wtf" → neutral (not clearly angry enough)
"this is terrible I want a refund NOW" → negative

Reply ONLY with JSON: {"label": ..., "score": ...}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The examples are what make it work. People say "oh no" and "wtf" casually, so those count as neutral. Only clear anger counts as negative.&lt;/p&gt;

&lt;p&gt;One angry message doesn't trigger anything. The bot escalates after &lt;strong&gt;three negative messages in a row&lt;/strong&gt;, so a customer who calms down isn't punished for an early bad moment.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. The customer asks for a human (plain code, no LLM)
&lt;/h3&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;wants_human&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="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;bool&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;text&lt;/span&gt; &lt;span class="o"&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;lower&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;any&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;HUMAN_REQUEST_PHRASES&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# "talk to a human", "real person", "live agent", ...
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If the message contains a phrase like "talk to a human" or "real person," the bot escalates immediately. An API call to understand "I want a human" would cost money and time for no gain, so a simple phrase list does the job for free.&lt;/p&gt;

&lt;p&gt;That became my main rule: &lt;strong&gt;use an LLM when you need judgment, and plain code when the rule is clear.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  One Conversation, Three States
&lt;/h2&gt;

&lt;p&gt;Before answering anything, the HITL gate checks what state the conversation is in:&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%2Fmedia.licdn.com%2Fdms%2Fimage%2Fv2%2FD4D12AQE9hE5SDj3zdw%2Farticle-inline_image-shrink_1000_1488%2FB4DaEKv5hfHsAI-%2F0%2F1791181691894%3Fe%3D2147483647%26v%3Dbeta%26t%3DN1ONDWHP__ZyNTYqw60MvPhCsofoXCe8tMS7YY-iynY" 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%2Fmedia.licdn.com%2Fdms%2Fimage%2Fv2%2FD4D12AQE9hE5SDj3zdw%2Farticle-inline_image-shrink_1000_1488%2FB4DaEKv5hfHsAI-%2F0%2F1791181691894%3Fe%3D2147483647%26v%3Dbeta%26t%3DN1ONDWHP__ZyNTYqw60MvPhCsofoXCe8tMS7YY-iynY" alt="HITL flow: AI Active, Human Pending, Human Active" width="879" height="1000"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;AI Active:&lt;/strong&gt; normal RAG flow, the bot answers.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Human Pending:&lt;/strong&gt; an escalation was sent but no human has replied yet. If nobody answers within 5 minutes, the bot takes the chat back so the customer isn't left hanging.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Human Active:&lt;/strong&gt; a human is handling it, so the bot stays quiet and forwards the customer's messages to the agent. The customer never gets two answers.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When the case is resolved, the customer goes straight back to chatting with the AI.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Slack Side
&lt;/h2&gt;

&lt;p&gt;Sending the alert was the easy part. When either trigger fires, the bot posts to an &lt;code&gt;#escalations&lt;/code&gt; channel in Slack with the customer, the channel, the reason, the sentiment score, and the conversation ID:&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%2Fmedia.licdn.com%2Fdms%2Fimage%2Fv2%2FD4D12AQED8P_tR5yeZQ%2Farticle-inline_image-shrink_400_744%2FB4DaEKwLL.GsAM-%2F0%2F1791181768295%3Fe%3D2147483647%26v%3Dbeta%26t%3D4eBo5HkYDeQf2Ib5g8O3AvbvKkVvR8OigZPPdTxwfDg" 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%2Fmedia.licdn.com%2Fdms%2Fimage%2Fv2%2FD4D12AQED8P_tR5yeZQ%2Farticle-inline_image-shrink_400_744%2FB4DaEKwLL.GsAM-%2F0%2F1791181768295%3Fe%3D2147483647%26v%3Dbeta%26t%3D4eBo5HkYDeQf2Ib5g8O3AvbvKkVvR8OigZPPdTxwfDg" alt="Slack escalation alert and reply thread" width="744" height="353"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A human replies in the thread, and no special format is needed. The customer's new messages also show up in that thread, so the whole conversation lives in one place. To hand the chat back to the bot, the human types &lt;code&gt;resolved&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Hard Half: Getting the Reply Back to the Customer
&lt;/h2&gt;

&lt;p&gt;Reading a Slack reply and delivering it to someone on Discord was the tricky part. I solved it with an n8n workflow:&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%2Fmedia.licdn.com%2Fdms%2Fimage%2Fv2%2FD4D12AQHYwdQRtzI2XQ%2Farticle-inline_image-shrink_1500_2232%2FB4DaEKzhIzGsAQ-%2F0%2F1791182641285%3Fe%3D2147483647%26v%3Dbeta%26t%3DlqD-F5EwWsZNB-91DOkXdUQa82VKGo6iZxTaVsQBOuM" 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%2Fmedia.licdn.com%2Fdms%2Fimage%2Fv2%2FD4D12AQHYwdQRtzI2XQ%2Farticle-inline_image-shrink_1500_2232%2FB4DaEKzhIzGsAQ-%2F0%2F1791182641285%3Fe%3D2147483647%26v%3Dbeta%26t%3DlqD-F5EwWsZNB-91DOkXdUQa82VKGo6iZxTaVsQBOuM" alt="n8n workflow: Slack trigger, user check, extract, resolved branch" width="1254" height="534"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Slack Trigger&lt;/strong&gt; fires on a new message in the thread.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Is real user reply&lt;/strong&gt; checks it's a person and not the bot's own message.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Extract conversation_id and message&lt;/strong&gt; pulls out the two things the API needs.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Is resolved&lt;/strong&gt; branches:

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Yes:&lt;/strong&gt; an API call resolves the conversation in PostgreSQL.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No:&lt;/strong&gt; an API call (&lt;code&gt;/human_reply&lt;/code&gt;) stores the reply.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;On the Discord side, a small bot checks the API every 5 seconds and DMs any new human reply to the customer. Here's what the customer sees:&lt;/p&gt;

&lt;p&gt;![Discord DM: agent replies, case resolved, bot resumes](&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmedia.licdn.com%2Fdms%2Fimage%2Fv2%2FD4D12AQEPHFeCKY-B6g%2Farticle-inline_image-shrink_400_744%2FB4DaEKwdFbHcAM-%2F0%2F1791181840653%3Fe%3D2147483647%26v%3Dbeta%26t%3DjtD-WAvymbuV3r2aoFresvrNlH1yu6qxsn714WkyNHI" 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%2Fmedia.licdn.com%2Fdms%2Fimage%2Fv2%2FD4D12AQEPHFeCKY-B6g%2Farticle-inline_image-shrink_400_744%2FB4DaEKwdFbHcAM-%2F0%2F1791181840653%3Fe%3D2147483647%26v%3Dbeta%26t%3DjtD-WAvymbuV3r2aoFresvrNlH1yu6qxsn714WkyNHI" alt="Discord flow" width="744" height="350"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The customer's message is confirmed as sent to a support agent, the agent's replies appear in the chat, and once the case is resolved the bot says so and starts answering again.&lt;/p&gt;

&lt;h2&gt;
  
  
  Watching It Work
&lt;/h2&gt;

&lt;p&gt;A Grafana dashboard has six panels: total messages, total escalations, cache hit rate, average RAG response time, active conversations, and cache hits versus misses.&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%2Fmedia.licdn.com%2Fdms%2Fimage%2Fv2%2FD4D12AQEFRCSoh91O4w%2Farticle-inline_image-shrink_400_744%2FB4DaEKwmtAKIAM-%2F0%2F1791181879591%3Fe%3D2147483647%26v%3Dbeta%26t%3DC0oxqoamrXI5xzp3YEJHe2MkLc_LJ6HFT-xxB8aXIOM" 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%2Fmedia.licdn.com%2Fdms%2Fimage%2Fv2%2FD4D12AQEFRCSoh91O4w%2Farticle-inline_image-shrink_400_744%2FB4DaEKwmtAKIAM-%2F0%2F1791181879591%3Fe%3D2147483647%26v%3Dbeta%26t%3DC0oxqoamrXI5xzp3YEJHe2MkLc_LJ6HFT-xxB8aXIOM" alt="Grafana dashboard with six panels" width="744" height="349"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;LangSmith traces each request, so I can open any answer and see exactly what happened inside the pipeline:&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%2Fmedia.licdn.com%2Fdms%2Fimage%2Fv2%2FD4D12AQH-i-sQvbox6w%2Farticle-inline_image-shrink_400_744%2FB4DaEKwt6UJIAQ-%2F0%2F1791181908983%3Fe%3D2147483647%26v%3Dbeta%26t%3D78UskhFxnwyWDRD_eMzFaPeyjzKRkMULGgKXewEIeZg" 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%2Fmedia.licdn.com%2Fdms%2Fimage%2Fv2%2FD4D12AQH-i-sQvbox6w%2Farticle-inline_image-shrink_400_744%2FB4DaEKwt6UJIAQ-%2F0%2F1791181908983%3Fe%3D2147483647%26v%3Dbeta%26t%3D78UskhFxnwyWDRD_eMzFaPeyjzKRkMULGgKXewEIeZg" alt="LangSmith traces of the rag_pipeline" width="744" height="353"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In my test run (23 traces), answers took about 1.4 to 2.4 seconds end to end. Those numbers come from my own test conversations, not real customers.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I Learned
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Not everything needs an LLM.&lt;/strong&gt; Use it for judgment, like reading sentiment. Use plain code for clear rules, like phrase matching.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tracing saves hours.&lt;/strong&gt; LangSmith showed me what each request actually did, so I stopped guessing where things broke.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Connecting tools is most of the work.&lt;/strong&gt; Slack, Discord, n8n, and the database each have their own quirks, and the real effort goes into making them talk to each other.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Use n8n when you need a fast integration.&lt;/strong&gt; It makes tricky steps easy and keeps the workflow readable for other people. &lt;strong&gt;Skip it when you need deep customization, low latency, or custom logic.&lt;/strong&gt; For those, write code.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Try It or Hire Me
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Code:&lt;/strong&gt; &lt;a href="https://github.com/Shahzaib30/ai-support-agent" rel="noopener noreferrer"&gt;github.com/Shahzaib30/ai-support-agent&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Upwork:&lt;/strong&gt; &lt;a href="https://www.upwork.com/freelancers/~01774fb1bf81238658" rel="noopener noreferrer"&gt;My Upwork profile&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Linkedin:&lt;/strong&gt; &lt;a href="https://www.linkedin.com/in/s-shahzaib" rel="noopener noreferrer"&gt;My Linkedin profile&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I'm a Full Stack AI Engineer who builds AI agents, RAG systems, and automation. If you're building something similar, send me a message.&lt;/p&gt;

&lt;p&gt;What's the worst support bot you've ever dealt with? Tell me in the comments.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>rag</category>
      <category>python</category>
      <category>fastapi</category>
    </item>
    <item>
      <title>Why Your OpenAI Wrapper Is Costing Too Much (And How LangGraph Fixes It)</title>
      <dc:creator>Shahzaib S</dc:creator>
      <pubDate>Thu, 28 May 2026 08:36:57 +0000</pubDate>
      <link>https://dev.to/shahzaib_dev/why-your-openai-wrapper-is-costing-too-much-and-how-langgraph-fixes-it-3kk0</link>
      <guid>https://dev.to/shahzaib_dev/why-your-openai-wrapper-is-costing-too-much-and-how-langgraph-fixes-it-3kk0</guid>
      <description>&lt;p&gt;Many businesses rush into artificial intelligence by building a basic OpenAI wrapper. They connect a simple user interface to an API endpoint, upload a few documents, and call it an enterprise solution.&lt;/p&gt;

&lt;p&gt;Initially, the tool looks impressive. However, as user traffic grows, the monthly cloud bill spikes dramatically. Even worse, the chatbot starts repeating itself, hallucinating, or failing to complete multi-step workflows.&lt;/p&gt;

&lt;p&gt;If your company experiences soaring token usage and unpredictable chatbot behavior, you have a structural problem. A simple linear wrapper cannot handle complex enterprise operations efficiently.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Costly Reality of Basic AI Wrappers
&lt;/h2&gt;

&lt;p&gt;Standard OpenAI wrappers rely on a single, continuous prompt chain. Every single time a user asks a question, the entire chat history and every relevant document chunk must be sent back to the language model.&lt;/p&gt;

&lt;p&gt;This architecture causes major financial and operational inefficiencies.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Runaway Loop Costs: When a linear chatbot encounters an ambiguous user query, it frequently gets stuck in a loop. It repeatedly queries the LLM for clarification, burning through thousands of tokens in seconds.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Irrelevant Context Loading: Poorly designed Retrieval-Augmented Generation systems pull massive blocks of data from the vector database. Sending unoptimized context to the API forces you to pay premium prices for processing useless background text.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Lack of Native Memory: Without a robust system to track state, wrappers either pass massive text files to preserve memory or forget user details entirely. Both outcomes cost you money and lower client satisfaction.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To achieve reliable business automation without going bankrupt, you must replace linear code with a dynamic, self-correcting state machine.&lt;/p&gt;

&lt;h2&gt;
  
  
  How LangGraph Optimizes API Budgets
&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%2Fhkcueb8o4804cz5fuuxa.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%2Fhkcueb8o4804cz5fuuxa.png" alt="How LangGraph Optimizes API Budgets" width="800" height="807"&gt;&lt;/a&gt;&lt;br&gt;
LangGraph redefines agentic workflows by introducing cycles and strict state preservation. Instead of letting an LLM wander freely through a massive prompt, LangGraph breaks your business logic down into specific graph nodes and edges.&lt;/p&gt;

&lt;p&gt;An advanced LangGraph AI agent architecture optimizes your API budget through structural intelligence.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Controlled Routing&lt;/strong&gt;&lt;br&gt;
Your application does not need to use a costly model like GPT-4o for every trivial user interaction. A FastAPI backend powered by LangGraph evaluates incoming traffic immediately. Simple greetings or basic filtering tasks are handled by lightweight, low-cost models or hardcoded scripts. The system routes complex requests to premium models only when absolutely necessary.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Cyclic Self-Correction&lt;/strong&gt;&lt;br&gt;
If a tool output contains an error or missing data, the agent detects the anomaly before responding to the user. The system passes the incorrect output back to a validation node, allowing the model to correct its own work locally. This prevents the user from receiving broken data and eliminates the need for entirely new chat sessions.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Smart State Persistence&lt;/strong&gt;&lt;br&gt;
LangGraph utilizes database checkpointers, saving the precise conversational state into a secure database like PostgreSQL. The system loads only the exact data required for the current step, keeping prompt context windows incredibly tight and token costs exceptionally low.&lt;/p&gt;

&lt;h2&gt;
  
  
  Moving to Production-Grade AI Automation
&lt;/h2&gt;

&lt;p&gt;Deploying a professional AI agent requires moving past basic templates. By migrating to a robust &lt;a href="https://www.fiverr.com/s/P2zrwEA" rel="noopener noreferrer"&gt;FastAPI backend combined with LangGraph state tracking&lt;/a&gt;, you secure full control over your data workflows and your operational expenses. You gain a scalable system that captures leads, protects customer privacy, and executes complex tasks flawlessly.&lt;/p&gt;

&lt;p&gt;Stop paying for inefficient API loops that harm your business reputation. Invest in structured, token-conscious intelligence that scales alongside your company.&lt;/p&gt;

&lt;p&gt;Need an enterprise-ready AI Agent built with a cost-optimized architecture? Let's design your custom system workflows and state schemas. &lt;a href="https://www.fiverr.com/s/P2zrwEA" rel="noopener noreferrer"&gt;Click here to launch your advanced LangGraph AI Agent project today.&lt;/a&gt;&lt;/p&gt;

</description>
      <category>langgraph</category>
      <category>openai</category>
      <category>fastapi</category>
      <category>aiagents</category>
    </item>
    <item>
      <title>How to Build a Stateful AI Agent with FastAPI, LangGraph, and PostgreSQL.</title>
      <dc:creator>Shahzaib S</dc:creator>
      <pubDate>Tue, 19 May 2026 09:47:38 +0000</pubDate>
      <link>https://dev.to/shahzaib_dev/how-to-build-a-stateful-ai-agent-with-fastapi-langgraph-and-postgresql-5b45</link>
      <guid>https://dev.to/shahzaib_dev/how-to-build-a-stateful-ai-agent-with-fastapi-langgraph-and-postgresql-5b45</guid>
      <description>&lt;p&gt;Your AI demo worked perfectly in development.&lt;/p&gt;

&lt;p&gt;You opened a local notebook, wrote a clean prompt wrapper, and watched the model respond beautifully to your test queries. It felt like magic.&lt;/p&gt;

&lt;p&gt;Then production traffic hit.&lt;/p&gt;

&lt;p&gt;User sessions started losing memory. API latency exploded under concurrent requests. Long-running inference calls blocked your backend workers, and server restarts wiped active conversations entirely.&lt;/p&gt;

&lt;p&gt;This is why most enterprise AI systems fail after deployment. The problem is not the LLM. The problem is the architecture.&lt;/p&gt;

&lt;p&gt;In this article, I’ll show how to build a production-ready AI agent backend using FastAPI, LangGraph, and PostgreSQL to guarantee scale, memory, and reliability.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Core Problem: Why Stateless APIs Break AI Systems&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Standard web development relies on stateless APIs. A client sends a request, the server processes it, returns a response, and completely forgets the transaction ever happened.&lt;/p&gt;

&lt;p&gt;When you apply this stateless model to AI orchestration, everything breaks. Real humans do not talk to AI in linear paths. They ask a question, change their mind, trigger a tool, provide partial data, and expect the AI to maintain perfect context over hours or days.&lt;/p&gt;

&lt;p&gt;If you try to pass an ever-growing array of raw chat logs back and forth over the network on every click, you crush your server performance and waste thousands of dollars in token overhead.&lt;/p&gt;

&lt;p&gt;(Note: When I audit failing enterprise AI infrastructure for my clients, this stateless bottleneck is the #1 issue I have to fix.)&lt;/p&gt;

&lt;p&gt;To achieve production-grade stability, your AI infrastructure needs a cyclic graph state machine.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Solution: Stateful AI Architecture with LangGraph&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;To solve the state preservation problem, we need to abandon linear chains and adopt LangGraph.&lt;/p&gt;

&lt;p&gt;Unlike traditional frameworks that force data one way, LangGraph introduces a persistent state graph. This architecture allows us to define specific code execution steps as nodes and use conditional edges to evaluate what the agent should do next — including self-correction loops.&lt;/p&gt;

&lt;p&gt;Here is a look under the hood at a standard LangGraph workflow:&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%2F361jsicdpg93pgs2hi1n.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%2F361jsicdpg93pgs2hi1n.png" alt="LangGraph stateful workflow diagram showing router nodes, conditional edges, retrieval flow, and AI agent orchestration" width="770" height="682"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;LangGraph stateful workflow diagram showing router nodes, conditional edges, retrieval flow, and AI agent orchestration&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Code Implementation&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Instead of relying on a single massive prompt, we isolate logic into focused nodes. Here is a simplified snippet of how you compile a stateful graph:&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%2F27r7ahaxiw1e21028sgj.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%2F27r7ahaxiw1e21028sgj.png" alt="Python code example demonstrating LangGraph state graph compilation for a production-ready AI agent" width="619" height="641"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Python code example demonstrating LangGraph state graph compilation for a production-ready AI agent&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Scaling with an Async FastAPI AI Backend&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Even the best LangGraph agent will fail if your web server blocks threads. If you are using traditional synchronous frameworks (like standard Flask or Django), a single LLM API call taking 5 seconds will freeze your server for all other users.&lt;/p&gt;

&lt;p&gt;By wrapping our graph in a FastAPI AI backend, we utilize native asynchronous event loops.&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%2Fhrefq67zuve4op3wugc3.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%2Fhrefq67zuve4op3wugc3.png" alt="Async FastAPI webhook endpoint handling concurrent AI agent requests using background task processing" width="800" height="520"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Async FastAPI webhook endpoint handling concurrent AI agent requests using background task processing&lt;br&gt;
This guarantees that when a client’s system experiences a sudden traffic spike of 10,000 concurrent sessions, the server processes the network handshakes effortlessly without dropping webhooks.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Locking Down Persistent Conversational Memory (PostgreSQL)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;A stateful agent is only as stable as its underlying memory layer. If your server restarts mid-session, active memory vanishes.&lt;/p&gt;

&lt;p&gt;To prevent data loss, the LangGraph backend must be paired with persistent conversational memory. Every node transition, updated state parameter, and user token extraction is routed asynchronously into a PostgreSQL database.&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%2Fpfxqwuc91g3m3rpze1lf.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%2Fpfxqwuc91g3m3rpze1lf.png" alt="PostgreSQL checkpoint persistence setup for stateful conversational memory in a LangGraph AI backend" width="752" height="397"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;PostgreSQL checkpoint persistence setup for stateful conversational memory in a LangGraph AI backend&lt;br&gt;
If a connection drops, the system instantly looks up the thread_id in PostgreSQL, pulls the chronological chat history, and restores the exact operational state of the agent in milliseconds.&lt;/p&gt;

&lt;p&gt;(This specific PostgreSQL checkpointing setup recently allowed me to reduce response latency by over 40% for a multi-session customer support workflow).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Local Deployment vs. Cloud APIs&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;For enterprise teams with strict data privacy mandates, this architecture is completely decoupled.&lt;/p&gt;

&lt;p&gt;You can run this exact LangGraph and FastAPI setup using global cloud APIs (OpenAI GPT-4o, Anthropic Claude), or you can deploy it 100% locally and offline using open-source models via Ollama (Llama 3, Mistral) on private Linux droplets. The architecture stays the same; only the LLM endpoint changes.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Common Production Failures in AI Systems&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Most AI prototypes fail in production not because of poor models, but because of weak backend architecture.&lt;/p&gt;

&lt;p&gt;Here are the most common scaling failures I encounter when auditing enterprise AI systems:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Context Window Explosion&lt;/strong&gt;&lt;br&gt;
Many AI applications continuously append raw chat history into prompts. Over time, token usage becomes extremely expensive and response latency increases dramatically.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Stateless Memory Resets&lt;/strong&gt;&lt;br&gt;
Without persistent conversational memory, server restarts or failed sessions wipe active user context entirely.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Blocking LLM Calls&lt;/strong&gt;&lt;br&gt;
Synchronous backend frameworks freeze under long-running inference requests, causing webhook failures and severe concurrency bottlenecks.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. Race Conditions in Multi-User Sessions&lt;/strong&gt;&lt;br&gt;
When multiple requests hit the same workflow simultaneously, poorly designed agent systems can corrupt memory state or overwrite session variables.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;5. Unstructured Tool Orchestration&lt;/strong&gt;&lt;br&gt;
Linear chains struggle with retries, self-correction loops, and dynamic routing. This creates brittle AI behavior that breaks under real-world user interactions.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;6. Token Cost Escalation&lt;/strong&gt;&lt;br&gt;
Passing massive conversational payloads between the client and backend creates unnecessary token overhead and infrastructure costs.&lt;/p&gt;

&lt;p&gt;Production-ready AI systems require stateful orchestration, persistent memory, asynchronous execution, and reliable workflow routing from the beginning.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Final Thoughts:Don’t Build Wrappers, Build Systems&lt;/strong&gt;&lt;br&gt;
Brittle prompts and basic wrappers do not belong in production software. To deploy enterprise AI, you must treat your agents as robust, self-correcting software systems.&lt;/p&gt;

&lt;p&gt;By combining the asynchronous speed of FastAPI, the state-machine orchestration of LangGraph, and the persistent memory of PostgreSQL, you can build AI applications that actually scale.\&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;FAQ&lt;/strong&gt;&lt;br&gt;
&lt;strong&gt;Why is LangGraph better for production AI systems?&lt;/strong&gt;&lt;br&gt;
LangGraph supports cyclic workflows, persistent state management, and conditional routing logic. This makes it significantly more reliable for enterprise AI systems than traditional linear chains.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why use FastAPI for AI backends?&lt;/strong&gt;&lt;br&gt;
FastAPI provides asynchronous request handling, making it ideal for high-concurrency AI systems that process long-running LLM inference calls and webhook traffic.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why use PostgreSQL for conversational memory?&lt;/strong&gt;&lt;br&gt;
PostgreSQL provides durable, scalable, and recoverable state persistence for AI agents. It allows conversations to resume instantly even after crashes or server restarts.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Can this architecture run locally without cloud APIs?&lt;/strong&gt;&lt;br&gt;
Yes. The exact same architecture can run entirely offline using local LLMs through Ollama with models such as Llama 3 or Mistral.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What types of AI systems benefit from this architecture?&lt;/strong&gt;&lt;br&gt;
This setup is ideal for:&lt;/p&gt;

&lt;p&gt;AI customer support systems&lt;br&gt;
enterprise copilots&lt;br&gt;
AI sales agents&lt;br&gt;
RAG pipelines&lt;br&gt;
workflow automation tools&lt;br&gt;
multi-session conversational AI systems&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Is LangGraph better than standard LangChain for agents?&lt;/strong&gt;&lt;br&gt;
For complex stateful AI agents, LangGraph is generally more suitable because it supports cyclic execution, self-correction loops, and persistent workflow orchestration.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Need help building production-ready AI infrastructure?&lt;/strong&gt;&lt;br&gt;
If your team is struggling with AI latency, context loss, or scaling issues, I help startups and enterprises deploy scalable LangGraph agent systems. I specialize in:&lt;/p&gt;

&lt;p&gt;Persistent conversational memory schemas (PostgreSQL / Supabase)&lt;br&gt;
Async FastAPI backends optimized for high-traffic webhooks&lt;br&gt;
Custom RAG pipelines (ChromaDB / Pinecone)&lt;br&gt;
Local and cloud LLM orchestration (OpenAI, Claude, Ollama)&lt;br&gt;
&lt;strong&gt;Let’s build a reliable system:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;👉 &lt;a href="https://www.fiverr.com/s/R7eQQqV" rel="noopener noreferrer"&gt;View LangGraph deployment packages&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;👉 &lt;a href="https://www.upwork.com/freelancers/~01774fb1bf81238658" rel="noopener noreferrer"&gt;Hire me for custom AI engineering projects&lt;/a&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>langgraph</category>
      <category>agents</category>
      <category>python</category>
    </item>
  </channel>
</rss>
