<?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: Whoopit</title>
    <description>The latest articles on DEV Community by Whoopit (@whoopit_6002532f097189c66).</description>
    <link>https://dev.to/whoopit_6002532f097189c66</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%2F4170463%2Fd877e170-8b51-4c67-a9e8-89518e60141c.jpg</url>
      <title>DEV Community: Whoopit</title>
      <link>https://dev.to/whoopit_6002532f097189c66</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/whoopit_6002532f097189c66"/>
    <language>en</language>
    <item>
      <title>Adding AI Features to a Web App Without Making It Fragile</title>
      <dc:creator>Whoopit</dc:creator>
      <pubDate>Thu, 08 Oct 2026 10:51:03 +0000</pubDate>
      <link>https://dev.to/whoopit_6002532f097189c66/adding-ai-features-to-a-web-app-without-making-it-fragile-5ead</link>
      <guid>https://dev.to/whoopit_6002532f097189c66/adding-ai-features-to-a-web-app-without-making-it-fragile-5ead</guid>
      <description>&lt;p&gt;AI features are easy to demo and hard to run in production. Models time out, return malformed output, cost money on every call and sometimes answer with total confidence and no accuracy. Here is how to build them so the rest of your app stays dependable.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Keep model calls on the server
&lt;/h2&gt;

&lt;p&gt;Never call a model from the browser. Keep keys, prompts and provider logic behind your own API so you can add auth, rate limits, logging and provider changes without touching the client.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Constrain the output
&lt;/h2&gt;

&lt;p&gt;Ask for structured output and validate it before using it. A response that doesn't match the schema should be treated as a failure, not passed to the UI.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;zod&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;Reply&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;object&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;answer&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;string&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
  &lt;span class="na"&gt;confidence&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;enum&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;low&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;medium&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;high&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]),&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;ask&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;question&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;raw&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;callModel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;question&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;parsed&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Reply&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;safeParse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;raw&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;parsed&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;success&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;parsed&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;confidence&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;low&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;parsed&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;escalate&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;answer&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;I'm not sure about that. Let me pass you to a person.&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;confidence&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;low&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;escalate&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;callModel&lt;/code&gt; stands for a thin wrapper around your provider's SDK.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Ground answers in your own data
&lt;/h2&gt;

&lt;p&gt;For anything factual, retrieve the relevant content from your own documents or database and pass it to the model, with instructions to answer only from it. If nothing relevant is found, say so instead of guessing.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Plan for failure
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Set timeouts on every call&lt;/li&gt;
&lt;li&gt;Retry once with backoff, then fall back&lt;/li&gt;
&lt;li&gt;Provide a non-AI path: a form, a search box or a human handover&lt;/li&gt;
&lt;li&gt;Never block the main user flow on a model response if it can load afterwards&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  5. Control cost and load
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Cache repeated questions and expensive results&lt;/li&gt;
&lt;li&gt;Rate limit per user&lt;/li&gt;
&lt;li&gt;Cap input and output length&lt;/li&gt;
&lt;li&gt;Use a smaller model for simple tasks&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  6. Log everything you can
&lt;/h2&gt;

&lt;p&gt;Store the input, retrieved context, output and validation result for each call. Without that you can't debug a bad answer or measure improvement.&lt;/p&gt;

&lt;h2&gt;
  
  
  7. Test with real examples
&lt;/h2&gt;

&lt;p&gt;Keep a set of real questions with expected outcomes and run it whenever you change a prompt, model or retrieval step. A prompt tweak that fixes one case often breaks another.&lt;/p&gt;

&lt;h2&gt;
  
  
  8. Treat personal data carefully
&lt;/h2&gt;

&lt;p&gt;Decide what is sent to the provider, what is stored and for how long, and how a user's data is deleted. In the UK, UK GDPR applies as soon as personal data is involved.&lt;/p&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;Treat the model as an unreliable but useful dependency: validate what comes out, have a fallback, watch the cost and keep a record of what it did.&lt;/p&gt;

&lt;p&gt;If you would rather have this built than build it yourself, &lt;a href="https://zeviqai.co.uk/services/ai-web-app-development" rel="noopener noreferrer"&gt;ZevIQ AI&lt;/a&gt; is a UK-based team that develops custom AI-powered web and app projects.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>ai</category>
      <category>architecture</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Building an AI Chatbot That Doesn't Make Things Up</title>
      <dc:creator>Whoopit</dc:creator>
      <pubDate>Thu, 08 Oct 2026 06:56:05 +0000</pubDate>
      <link>https://dev.to/whoopit_6002532f097189c66/building-an-ai-chatbot-that-doesnt-make-things-up-2ajn</link>
      <guid>https://dev.to/whoopit_6002532f097189c66/building-an-ai-chatbot-that-doesnt-make-things-up-2ajn</guid>
      <description>&lt;p&gt;Most AI chatbot projects don't fail because of the model. They fail because of everything around it: what it knows, what it's allowed to do, and what happens when it's wrong.&lt;/p&gt;

&lt;p&gt;Here is the architecture and the decisions that matter, whether you build it yourself or hire a team.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Define the scope before the stack
&lt;/h2&gt;

&lt;p&gt;Write down what the bot owns and what it must hand off. A narrow scope (tier-1 support, lead qualification, appointment booking) beats a general assistant every time. Escalation rules are part of the spec, not an afterthought.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Ground answers in your own data
&lt;/h2&gt;

&lt;p&gt;A raw LLM will answer confidently from general training data. For business use, answers should come from your content: FAQs, policy documents, product or course material.&lt;/p&gt;

&lt;p&gt;The usual pattern is retrieval-augmented generation (RAG):&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Split your documents into chunks and index them&lt;/li&gt;
&lt;li&gt;Retrieve the most relevant chunks for each user question&lt;/li&gt;
&lt;li&gt;Pass them to the model with instructions to answer only from that context&lt;/li&gt;
&lt;li&gt;Return "I don't know, here's a person who can help" when nothing relevant is found&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Step 4 is the one most projects skip, and it is what separates a trustworthy bot from a liability.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Add guardrails
&lt;/h2&gt;

&lt;p&gt;Decide in advance what the bot must refuse: off-topic requests, legal or medical advice, anything outside its knowledge base. Combine a clear system prompt with output checks, and test with adversarial questions before launch, not after.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Integrate, don't just converse
&lt;/h2&gt;

&lt;p&gt;A chatbot becomes useful when it can act:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Create or update a lead in your CRM&lt;/li&gt;
&lt;li&gt;Book a slot in a calendar&lt;/li&gt;
&lt;li&gt;Look up an order or record via API&lt;/li&gt;
&lt;li&gt;Open a ticket and attach the conversation&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Workflow tools such as n8n are a common way to wire this up without writing every integration by hand. Multi-channel deployment (website, WhatsApp, an LMS, internal tools) is mostly a matter of putting one backend behind several front ends.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. Build the human handover properly
&lt;/h2&gt;

&lt;p&gt;When the bot escalates, pass the full conversation history to the agent. Making a customer repeat themselves defeats the purpose of automating in the first place.&lt;/p&gt;

&lt;h2&gt;
  
  
  6. Log everything and review it
&lt;/h2&gt;

&lt;p&gt;Store conversations, and track:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Resolution rate&lt;/li&gt;
&lt;li&gt;Escalation rate&lt;/li&gt;
&lt;li&gt;Questions the bot couldn't answer&lt;/li&gt;
&lt;li&gt;User ratings&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Every unanswered question is a gap in your knowledge base. A monthly review loop is what keeps the bot improving after launch.&lt;/p&gt;

&lt;h2&gt;
  
  
  7. Treat data protection as a requirement
&lt;/h2&gt;

&lt;p&gt;If you operate in the UK, UK GDPR applies as soon as the bot handles personal data. Know what you collect, where it is stored, how long it is kept, and how a user can request deletion. This matters most in education, care and other sectors with sensitive data.&lt;/p&gt;

&lt;h2&gt;
  
  
  A sensible build order
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Knowledge audit&lt;/li&gt;
&lt;li&gt;Use case and escalation definition&lt;/li&gt;
&lt;li&gt;Build and train&lt;/li&gt;
&lt;li&gt;Integrations&lt;/li&gt;
&lt;li&gt;Testing with real conversations&lt;/li&gt;
&lt;li&gt;Launch with analytics&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If you'd rather have this built than build it yourself, &lt;a href="https://zeviqai.co.uk/services/ai-chatbot-development" rel="noopener noreferrer"&gt;ZevIQ AI&lt;/a&gt; is a UK-based team that develops custom chatbots connected to CRMs, ERPs, LMS platforms and knowledge bases.&lt;/p&gt;

</description>
      <category>chatbot</category>
      <category>automation</category>
      <category>webdev</category>
      <category>ai</category>
    </item>
  </channel>
</rss>
