<?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: Emma Schmidt</title>
    <description>The latest articles on DEV Community by Emma Schmidt (@emma_schmidt_).</description>
    <link>https://dev.to/emma_schmidt_</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%2F3450005%2Fcd01195d-0cef-48c0-9d0b-8033f6246f7e.jpeg</url>
      <title>DEV Community: Emma Schmidt</title>
      <link>https://dev.to/emma_schmidt_</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/emma_schmidt_"/>
    <language>en</language>
    <item>
      <title>The Vulnerability That Took Down Your Build Wasn't in Your Code</title>
      <dc:creator>Emma Schmidt</dc:creator>
      <pubDate>Wed, 19 Aug 2026 05:46:54 +0000</pubDate>
      <link>https://dev.to/emma_schmidt_/the-vulnerability-that-took-down-your-build-wasnt-in-your-code-kp9</link>
      <guid>https://dev.to/emma_schmidt_/the-vulnerability-that-took-down-your-build-wasnt-in-your-code-kp9</guid>
      <description>&lt;p&gt;You didn't write a single insecure line. You reviewed every pull request. Your own code is clean. And yet a routine dependency update just pulled in a compromised package three layers deep in your dependency tree, and now there's malicious code running in your CI pipeline that nobody on your team ever actually looked at. This isn't a hypothetical, it's the exact pattern behind a wave of real software &lt;strong&gt;&lt;a href="https://zignuts.com/ml-services/forecasting-models/supply-chain-forecasting?utm_source=seo&amp;amp;utm_medium=backlinks&amp;amp;utm_campaign=seo_referral&amp;amp;utm_id=8" rel="noopener noreferrer"&gt;supply chain&lt;/a&gt;&lt;/strong&gt; attacks that's made securing the dependency chain one of the most active DevSecOps priorities of the year, not a compliance checkbox anymore, but a genuine engineering discipline.&lt;/p&gt;

&lt;p&gt;Here's what's actually driving this, what a real defense looks like in practice, and how to start building it into a pipeline that doesn't already have it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why This Became Urgent Rather Than Theoretical
&lt;/h2&gt;

&lt;p&gt;For years, supply chain security lived in the "we should probably think about this someday" category for most teams. A few things changed that.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Attackers shifted their target.&lt;/strong&gt; Compromising one popular open-source package gives an attacker access to every downstream project that depends on it, which is a dramatically better return on effort than attacking one company directly&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Dependency trees have grown enormous and mostly invisible.&lt;/strong&gt; A modern project with a handful of direct dependencies can easily pull in hundreds of transitive ones, most of which nobody on the team has ever actually reviewed&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;CI/CD pipelines became a genuine attack surface of their own.&lt;/strong&gt; A compromised build step doesn't just affect one developer's machine, it can inject malicious code directly into what gets shipped to production&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Regulatory pressure caught up.&lt;/strong&gt; Software bill of materials requirements are increasingly showing up in vendor contracts and compliance frameworks, turning "do we know what's in our dependency tree" from a nice-to-have into a real audit question&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;AI-driven systems raised the stakes further.&lt;/strong&gt; As more production pipelines now include model training, &lt;strong&gt;&lt;a href="https://zignuts.com/llm-genai-services/fine-tuning?utm_source=seo&amp;amp;utm_medium=backlinks&amp;amp;utm_campaign=seo_referral&amp;amp;utm_id=8" rel="noopener noreferrer"&gt;fine-tuning&lt;/a&gt;&lt;/strong&gt;, and inference steps alongside traditional code, the same supply chain exposure now extends to model weights, training data sources, and the infrastructure feeding them&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What a Real Supply Chain Attack Actually Looks Like
&lt;/h2&gt;

&lt;p&gt;Understanding the shape of these attacks makes the defense make a lot more sense.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A maintainer's account on a popular package gets compromised, and a malicious update gets published under a trusted name&lt;/li&gt;
&lt;li&gt;A typosquatted package with a name one character off from a popular library gets installed by mistake during a routine &lt;code&gt;npm install&lt;/code&gt; or &lt;code&gt;pip install&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;A legitimate package gets acquired or handed off to a new maintainer who quietly introduces malicious code in a later version&lt;/li&gt;
&lt;li&gt;A build script inside a dependency runs arbitrary code during installation, before your own application code ever executes&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;None of these require your team to write a single insecure line. They exploit the trust baked into how modern dependency management works by default.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Core Defenses Worth Actually Building
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Software Bill of Materials (SBOM)&lt;/strong&gt;&lt;br&gt;
A structured, complete inventory of every dependency in your project, direct and transitive. Without this, you genuinely don't know what's actually running in production, which makes it impossible to respond quickly when a vulnerability in a specific package gets disclosed.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Dependency pinning and lockfiles&lt;/strong&gt;&lt;br&gt;
Pinning exact versions rather than accepting a range prevents a compromised update from silently flowing into your build the next time someone runs an install. Lockfiles should be committed and treated as part of your actual source of truth, not a generated afterthought.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Automated vulnerability scanning&lt;/strong&gt;&lt;br&gt;
Continuously checking your dependency tree against known vulnerability databases, ideally as part of CI, so a newly disclosed issue in something you already depend on gets flagged automatically rather than discovered by accident.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Provenance verification&lt;/strong&gt;&lt;br&gt;
Confirming that a package actually came from where it claims to have come from, using cryptographic signing where the ecosystem supports it, rather than trusting a package registry blindly.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Least-privilege CI pipelines&lt;/strong&gt;&lt;br&gt;
Build steps should only have access to exactly what they need. A compromised dependency running inside an overprivileged CI job can do far more damage than one running with tightly scoped permissions.&lt;/p&gt;

&lt;h2&gt;
  
  
  A Practical Starting Sequence
&lt;/h2&gt;

&lt;p&gt;You don't need to solve every layer of this at once. A reasonable order to tackle it in:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Generate an SBOM for your existing project&lt;/strong&gt; as a baseline, so you actually know what's in your dependency tree today&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Enable automated vulnerability scanning&lt;/strong&gt; in CI, so new issues surface automatically going forward&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Audit and commit your lockfiles&lt;/strong&gt;, closing the gap where version ranges could silently pull in something unexpected&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Review CI pipeline permissions&lt;/strong&gt;, scoping down anything with broader access than it actually needs&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Set a recurring cadence for dependency review&lt;/strong&gt;, not just reacting when something breaks or gets flagged&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Common Mistakes Worth Avoiding
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Treating an SBOM as a one-time compliance document instead of something that needs to stay current as dependencies change&lt;/li&gt;
&lt;li&gt;Scanning for vulnerabilities but never actually acting on what gets flagged, which makes the scanning theater rather than defense&lt;/li&gt;
&lt;li&gt;Assuming a popular, widely-used package is automatically safe, when popularity is exactly what makes a package an attractive target&lt;/li&gt;
&lt;li&gt;Giving CI pipelines broad, unscoped access "to make things easier," which turns a single compromised dependency into a much bigger incident&lt;/li&gt;
&lt;li&gt;Skipping this entirely for internal tools and side projects, when those often have the least oversight and the most direct access to sensitive systems&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  A Quick Self-Check
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Do you actually know every dependency in your project right now, including the transitive ones, or would you have to go find out?&lt;/li&gt;
&lt;li&gt;Is your CI pipeline scanning for known vulnerabilities automatically, or does that only happen when someone remembers to check?&lt;/li&gt;
&lt;li&gt;If a popular package you depend on were compromised tomorrow, how quickly could your team confirm whether you're affected?&lt;/li&gt;
&lt;li&gt;Do your CI build steps have more access than they actually need to do their job?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If more than one of those gave you pause, there's real, addressable exposure sitting in your pipeline right now.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why This Deserves Real Investment, Not a Checkbox
&lt;/h2&gt;

&lt;p&gt;Supply chain security tends to get deprioritized precisely because it's invisible until the day it isn't. Building this properly, real SBOM tooling, automated scanning wired into CI, scoped pipeline permissions, is genuinely cross-cutting work that touches DevOps, security, and every team shipping code, and it's easy to underestimate the ongoing maintenance this requires as dependencies constantly shift underneath a project. This is exactly where &lt;strong&gt;&lt;a href="https://zignuts.com/ai-services/enterprise-ai/ai-security-services?utm_source=seo&amp;amp;utm_medium=backlinks&amp;amp;utm_campaign=seo_referral&amp;amp;utm_id=8" rel="noopener noreferrer"&gt;AI security&lt;/a&gt;&lt;/strong&gt; and &lt;strong&gt;&lt;a href="https://zignuts.com/ai-services/enterprise-ai/ai-infrastructure-services?utm_source=seo&amp;amp;utm_medium=backlinks&amp;amp;utm_campaign=seo_referral&amp;amp;utm_id=8" rel="noopener noreferrer"&gt;AI infrastructure&lt;/a&gt;&lt;/strong&gt; work increasingly overlaps with traditional DevSecOps too, since teams running models in production now need the same rigor applied to &lt;strong&gt;&lt;a href="https://zignuts.com/ml-services/mlops/ml-ci-cd?utm_source=seo&amp;amp;utm_medium=backlinks&amp;amp;utm_campaign=seo_referral&amp;amp;utm_id=8" rel="noopener noreferrer"&gt;ML CI/CD&lt;/a&gt;&lt;/strong&gt; pipelines, model governance, and compliance around training data provenance that they'd apply to any other dependency chain. Getting this foundation right early, across both code and model infrastructure, is a lot cheaper than untangling it after an incident.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Takeaway
&lt;/h2&gt;

&lt;p&gt;The vulnerability that takes down your build was never guaranteed to be one your own team wrote. Most modern software is built on a foundation of trust in dependencies nobody on the team has actually reviewed, and that trust is exactly what attackers are exploiting at scale right now. Treating supply chain security as core infrastructure, not an afterthought, is quickly becoming table stakes rather than a nice-to-have.&lt;/p&gt;

&lt;p&gt;Has your team actually built out SBOM tooling and automated dependency scanning yet, or is this still sitting on the someday list? Curious how far along everyone actually is with this.&lt;/p&gt;

</description>
      <category>devsecops</category>
      <category>security</category>
      <category>cicd</category>
      <category>discuss</category>
    </item>
    <item>
      <title>7 AI Integration Mistakes I Keep Seeing Teams Make in 2026</title>
      <dc:creator>Emma Schmidt</dc:creator>
      <pubDate>Tue, 18 Aug 2026 05:32:29 +0000</pubDate>
      <link>https://dev.to/emma_schmidt_/7-ai-integration-mistakes-i-keep-seeing-teams-make-in-2026-djd</link>
      <guid>https://dev.to/emma_schmidt_/7-ai-integration-mistakes-i-keep-seeing-teams-make-in-2026-djd</guid>
      <description>&lt;p&gt;I don't write about &lt;strong&gt;&lt;a href="https://zignuts.com/ai-services/ai-integration?utm_source=seo&amp;amp;utm_medium=backlinks&amp;amp;utm_campaign=seo_referral&amp;amp;utm_id=8" rel="noopener noreferrer"&gt;AI integration&lt;/a&gt;&lt;/strong&gt; failures because they're rare.&lt;/p&gt;

&lt;p&gt;I write about them because I keep seeing the exact same ones, on different teams, in different industries, month after month.&lt;/p&gt;

&lt;p&gt;A mistake earns a spot on this list when I've watched it happen more than once. Not a one-off bad decision. A pattern.&lt;/p&gt;

&lt;p&gt;I've spent a lot of time this year looking closely at how companies actually bring AI into existing products, not the demo version, the real production version with real users and real data on the line.&lt;/p&gt;

&lt;p&gt;These are the seven mistakes that showed up again and again.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Treating AI Integration Like a Feature Flag&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Repository of thought: "we'll just bolt it on and see how it goes."&lt;/p&gt;

&lt;p&gt;I get why this feels reasonable. Ship fast, learn fast, iterate. But AI features aren't like a new button on a page. They touch data flow, user trust, and cost in ways a typical feature toggle doesn't.&lt;/p&gt;

&lt;p&gt;The teams that get burned here usually find out the hard way, weeks later, when the "quick add" needs a rewrite because nobody thought about:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Where the data actually comes from&lt;/li&gt;
&lt;li&gt;What happens when the model is wrong&lt;/li&gt;
&lt;li&gt;How much this costs at real usage volume&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;2. Skipping the "What Happens When It's Wrong" Conversation&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Every demo works. Every demo is cherry-picked, even unintentionally.&lt;/p&gt;

&lt;p&gt;The conversation that actually matters happens after the demo: what does the user see when the AI confidently gives a wrong answer? Is there a fallback? Is there a way to flag it? Does anyone even find out it happened?&lt;/p&gt;

&lt;p&gt;I've watched teams skip this conversation entirely and only have it for the first time after a customer complaint. That's the wrong order.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. No Evaluation Loop, Just Vibes&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;"It feels like it's working well" is not a metric.&lt;/p&gt;

&lt;p&gt;Teams that are serious about this build some kind of evaluation loop, a way to systematically check output quality against known good examples, before shipping and continuously after. Teams that skip this find out their AI feature quietly got worse three months in, and nobody noticed until a user did.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. Underestimating the Data Quality Problem&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This one isn't glamorous, which is probably why it gets skipped so often.&lt;/p&gt;

&lt;p&gt;AI integration is only as good as the data feeding it. I've seen teams spend weeks tuning a &lt;strong&gt;&lt;a href="https://zignuts.com/llm-genai-services/prompt-engineering/prompt-design-services?utm_source=seo&amp;amp;utm_medium=backlinks&amp;amp;utm_campaign=seo_referral&amp;amp;utm_id=8" rel="noopener noreferrer"&gt;prompt&lt;/a&gt;&lt;/strong&gt; to fix a problem that was actually a data quality issue the whole time. Messy, inconsistent, or outdated source data will sink an otherwise well-built integration every time.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;5. One Model, No Fallback&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Betting an entire feature on a single model provider with no fallback plan is a real, recurring pattern I keep seeing.&lt;/p&gt;

&lt;p&gt;What happens when that provider has an outage. What happens when pricing changes overnight. What happens when a model update shifts behavior in a way that breaks your carefully tuned prompts.&lt;/p&gt;

&lt;p&gt;Teams that plan for this from day one recover from disruptions in hours. Teams that don't scramble for days.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;6. Governance as an Afterthought&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This is the one that worries me most, because it's invisible until it's a real problem.&lt;/p&gt;

&lt;p&gt;Who's responsible for reviewing what the AI feature actually does. Who signs off on it touching sensitive data. Who's accountable if it produces something harmful or wrong in a regulated context. If nobody can answer these clearly, that's the actual gap, not a hypothetical one.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;7. Measuring the Wrong Thing&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;"We shipped an AI feature" isn't a success metric. Neither is "users are using it."&lt;/p&gt;

&lt;p&gt;The teams doing this well are measuring whether the feature actually improved the outcome it was supposed to improve, resolution time, task completion, accuracy against a real baseline. Everything else is activity dressed up as progress.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;A Quick Table, Because Patterns Are Easier to See This Way&lt;/strong&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Mistake&lt;/th&gt;
&lt;th&gt;What It Actually Costs You&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Bolting AI on like a feature flag&lt;/td&gt;
&lt;td&gt;Rework once real data and edge cases show up&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;No plan for wrong answers&lt;/td&gt;
&lt;td&gt;Trust erosion the first time a user hits one&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;No evaluation loop&lt;/td&gt;
&lt;td&gt;Silent quality drift nobody catches in time&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Ignoring data quality&lt;/td&gt;
&lt;td&gt;Wasted weeks tuning prompts that were never the real problem&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;No fallback model&lt;/td&gt;
&lt;td&gt;Full outages instead of graceful degradation&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;No governance ownership&lt;/td&gt;
&lt;td&gt;A real incident with no clear accountability&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Vanity metrics&lt;/td&gt;
&lt;td&gt;Confidently shipping something that isn't actually working&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;What I'd Tell a Team Starting This Today&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Slow down on the parts that feel boring. Data quality, evaluation, &lt;strong&gt;&lt;a href="https://zignuts.com/ai-services/enterprise-ai/ai-governance-consulting-services?utm_source=seo&amp;amp;utm_medium=backlinks&amp;amp;utm_campaign=seo_referral&amp;amp;utm_id=8" rel="noopener noreferrer"&gt;governance&lt;/a&gt;&lt;/strong&gt;, none of it is exciting, all of it is where the real risk actually lives.&lt;/p&gt;

&lt;p&gt;The AI part is usually not the hard part anymore. The hard part is everything around it, the parts that don't show up in a demo.&lt;/p&gt;

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

&lt;p&gt;None of these seven mistakes are exotic. They're not edge cases. They're the ordinary, predictable ways AI integration goes sideways when a team moves fast without slowing down for the boring, unglamorous parts.&lt;/p&gt;

&lt;p&gt;I don't think that's a knock on any team that's hit one of these. I've watched genuinely sharp engineers walk into every single one of them, because the pressure to ship fast is real and these mistakes are easy to make with the best of intentions.&lt;/p&gt;

&lt;p&gt;If you're integrating AI into a real product right now, I'd rather you catch these on paper than in production.&lt;/p&gt;

&lt;p&gt;Which of these have you actually run into? Curious how many of these seven are familiar to people reading this.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>discuss</category>
      <category>softwaredevelopment</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Top AI Coding Tools Every Developer Should Know in 2026</title>
      <dc:creator>Emma Schmidt</dc:creator>
      <pubDate>Mon, 17 Aug 2026 12:56:58 +0000</pubDate>
      <link>https://dev.to/emma_schmidt_/top-ai-coding-tools-every-developer-should-know-in-2026-51j4</link>
      <guid>https://dev.to/emma_schmidt_/top-ai-coding-tools-every-developer-should-know-in-2026-51j4</guid>
      <description>&lt;p&gt;A year ago, "AI coding assistant" mostly meant autocomplete on steroids. In 2026, that's no longer true. We've moved from &lt;strong&gt;inline suggestions&lt;/strong&gt; to &lt;strong&gt;&lt;a href="https://zignuts.com/agentic-ai-services?utm_source=seo&amp;amp;utm_medium=backlinks&amp;amp;utm_campaign=seo_referral&amp;amp;utm_id=8" rel="noopener noreferrer"&gt;agentic AI&lt;/a&gt;&lt;/strong&gt; tools that can plan a task, write across multiple files, run your test suite, and fix their own mistakes before you even open the diff.&lt;/p&gt;

&lt;p&gt;If you're a developer trying to figure out which tools are actually worth wiring into your workflow (and which are just hype), this guide breaks it down: what's changed, how to evaluate these tools, a side-by-side comparison, and a practical framework for adopting them on a real engineering team.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why This Shift Matters
&lt;/h2&gt;

&lt;p&gt;The jump from "autocomplete" to "agent" isn't just a marketing term. It changes &lt;em&gt;how&lt;/em&gt; you work:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Autocomplete-era tools&lt;/strong&gt; predicted the next few lines of code based on context.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Chat-era tools&lt;/strong&gt; let you ask questions and get code snippets back.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Agentic-era tools&lt;/strong&gt; take a goal ("add pagination to this &lt;strong&gt;&lt;a href="https://zignuts.com/ai-services/custom-ai-development/ai-api-development-services?utm_source=seo&amp;amp;utm_medium=backlinks&amp;amp;utm_campaign=seo_referral&amp;amp;utm_id=8" rel="noopener noreferrer"&gt;API&lt;/a&gt;&lt;/strong&gt; and update the tests"), break it into steps, execute those steps across your codebase, and self-correct using tool feedback like compiler errors or failing tests.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That last category is what's driving real productivity gains right now but it also introduces new questions around code review, security, and trust that teams need a process for, not just a tool.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to Evaluate an AI Coding Tool
&lt;/h2&gt;

&lt;p&gt;Before comparing specific products, it helps to have a checklist. Here's what actually matters when you're picking a tool for a team (not just a solo side project):&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Context window &amp;amp; codebase awareness&lt;/strong&gt;: Can it reason across your whole repo, or just the open file?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Agentic capability&lt;/strong&gt;: Can it execute multi-step tasks (run tests, fix errors, open a PR) or only suggest text?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;IDE / CLI fit&lt;/strong&gt;: Does it live where your team already works, or does it force a workflow change?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Security &amp;amp; data handling&lt;/strong&gt;: Where does your code go? Is there an enterprise/on-prem option?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cost model&lt;/strong&gt;: Per-seat, usage-based, or bundled into an existing subscription?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Review friction&lt;/strong&gt;: Does it produce diffs a human can review quickly, or large unreviewable rewrites?&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Comparison: Popular AI Coding Tools in 2026
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Tool&lt;/th&gt;
&lt;th&gt;Best For&lt;/th&gt;
&lt;th&gt;Works In&lt;/th&gt;
&lt;th&gt;Agentic?&lt;/th&gt;
&lt;th&gt;Notable Strength&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;GitHub Copilot&lt;/td&gt;
&lt;td&gt;General-purpose autocomplete + chat&lt;/td&gt;
&lt;td&gt;VS Code, JetBrains, GitHub.com&lt;/td&gt;
&lt;td&gt;Partial (Copilot Workspace)&lt;/td&gt;
&lt;td&gt;Deep GitHub/PR integration&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Claude Code&lt;/td&gt;
&lt;td&gt;Terminal-first, multi-file agentic coding&lt;/td&gt;
&lt;td&gt;CLI, VS Code, JetBrains&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Strong reasoning on large refactors&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cursor&lt;/td&gt;
&lt;td&gt;AI-native IDE experience&lt;/td&gt;
&lt;td&gt;Standalone editor (VS Code fork)&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Tight inline editing + chat loop&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Amazon Q Developer&lt;/td&gt;
&lt;td&gt;AWS-centric teams&lt;/td&gt;
&lt;td&gt;IDEs, AWS Console&lt;/td&gt;
&lt;td&gt;Partial&lt;/td&gt;
&lt;td&gt;Native AWS service knowledge&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Windsurf&lt;/td&gt;
&lt;td&gt;Agentic pair-programming&lt;/td&gt;
&lt;td&gt;Standalone editor&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;"Flow" mode for long tasks&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Tabnine&lt;/td&gt;
&lt;td&gt;Privacy-conscious teams&lt;/td&gt;
&lt;td&gt;Most major IDEs&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Self-hosted / on-prem options&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;em&gt;Note: this landscape moves fast pricing, features, and even product names shift every few months, so treat this as a snapshot rather than a permanent ranking. Always check the vendor's docs before committing a team to one.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  A Practical Adoption Framework
&lt;/h2&gt;

&lt;p&gt;Handing an entire engineering org an AI coding tool on day one usually backfires you get inconsistent usage, review bottlenecks, and skepticism from senior engineers who've been burned by low-quality AI output. A more reliable rollout looks like this:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Pilot with a small, willing team&lt;/strong&gt;: on a real (but non-critical) project for 2–4 weeks.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Define review rules&lt;/strong&gt;: e.g., AI-generated PRs still require the same review bar as human ones, no exceptions.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Track outcomes, not vibes&lt;/strong&gt;: cycle time, bug rate, and PR size are better signals than "it feels faster."&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Standardize the toolchain&lt;/strong&gt;: so context (style guides, architecture docs) is shared across the team instead of living in one engineer's prompts.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Revisit quarterly&lt;/strong&gt;:this space changes fast enough that a tool decision from six months ago may already be outdated.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This is close to how engineering teams evaluate any new dependency: agentic AI coding tools are powerful, but they still need the same rigor as any other addition to a production workflow. Teams that treat AI tooling as an accelerant for experienced engineers not a replacement for code review and architecture decisions tend to get the most durable results.&lt;/p&gt;

&lt;h2&gt;
  
  
  A Quick Example: Agentic Refactor in Practice
&lt;/h2&gt;

&lt;p&gt;Here's a simplified illustration of the kind of task an agentic tool can now handle end-to-end, versus what you'd have done manually a year ago:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Old way: you write the prompt, get a snippet, paste it, fix imports, run tests manually&lt;/span&gt;
&lt;span class="nv"&gt;$ &lt;/span&gt;ai &lt;span class="s2"&gt;"write a function to paginate this list"&lt;/span&gt;

&lt;span class="c"&gt;# Agentic way: the tool plans, edits multiple files, runs tests, and reports back&lt;/span&gt;
&lt;span class="nv"&gt;$ &lt;/span&gt;agent run &lt;span class="s2"&gt;"add cursor-based pagination to /api/users, update the OpenAPI spec, and make the existing tests pass"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Example output the agent might produce and then validate against your test suite
&lt;/span&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;paginate_users&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;users&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cursor&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;limit&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;start&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;cursor&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;start&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;next&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;i&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;u&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;users&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;u&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;id&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;cursor&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
    &lt;span class="n"&gt;page&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;users&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;start&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;limit&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="n"&gt;next_cursor&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;page&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;id&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;if&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;page&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;limit&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;items&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;page&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;next_cursor&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;next_cursor&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The difference isn't the code itself it's that the agent verified the change against your real test suite before handing it back, closing the loop that used to require a human every time.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where This Is Heading
&lt;/h2&gt;

&lt;p&gt;A few trends worth watching as 2026 progresses:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Agentic AI moving from "assistant" to "team member"&lt;/strong&gt;: tools that pick up tickets, open draft PRs, and tag humans only when they're stuck.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;AI-driven workflow automation&lt;/strong&gt;: spreading beyond coding into project management, QA, and DevOps pipelines not just writing code, but operating around it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Low-code/no-code and pro-code converging&lt;/strong&gt;: with AI acting as the translation layer between visual builders and hand-written code for teams that outgrow no-code tools.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Stronger emphasis on governance&lt;/strong&gt;: code provenance, license compliance, and audit trails for AI-generated code, especially in regulated industries like fintech and healthcare.&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;AI coding tools in 2026 aren't a novelty anymore they're infrastructure. The teams getting the most value aren't the ones chasing every new tool, but the ones treating adoption like any other engineering decision: pilot it, measure it, standardize it, and keep your review bar exactly where it was before AI showed up.&lt;/p&gt;

&lt;p&gt;If you're building out this kind of process for your own team, start small, measure real outcomes, and resist the urge to lower your review bar just because the code came from an agent instead of a human.&lt;/p&gt;




</description>
      <category>ai</category>
      <category>productivity</category>
      <category>webdev</category>
      <category>programming</category>
    </item>
    <item>
      <title>Your AI Chatbot Forgets Everything the Moment You Close the Tab. Here's the Fix Nobody's Talking About Yet.</title>
      <dc:creator>Emma Schmidt</dc:creator>
      <pubDate>Wed, 05 Aug 2026 05:18:19 +0000</pubDate>
      <link>https://dev.to/emma_schmidt_/your-ai-chatbot-forgets-everything-the-moment-you-close-the-tab-heres-the-fix-nobodys-talking-1iob</link>
      <guid>https://dev.to/emma_schmidt_/your-ai-chatbot-forgets-everything-the-moment-you-close-the-tab-heres-the-fix-nobodys-talking-1iob</guid>
      <description>&lt;p&gt;Ask a typical RAG-powered &lt;a href="https://zignuts.com/llm-genai-services/ai-chatbot-development/internal-ai-assistant-development?utm_source=seo&amp;amp;utm_medium=backlinks&amp;amp;utm_campaign=seo_referral&amp;amp;utm_id=8" rel="noopener noreferrer"&gt;AI assistant&lt;/a&gt; a follow-up question that depends on something you mentioned three messages ago, and watch it quietly lose the thread. Standard retrieval-augmented generation is excellent at pulling relevant chunks of text based on similarity, and genuinely terrible at understanding how pieces of information actually relate to each other or persisting what it learned about you across a session. This exact gap is what's pushing serious AI application development toward &lt;strong&gt;&lt;a href="https://zignuts.com/blog/graphrag-contextual-memory-smart-app?utm_source=seo&amp;amp;utm_medium=backlinks&amp;amp;utm_campaign=seo_referral&amp;amp;utm_id=8" rel="noopener noreferrer"&gt;GraphRAG&lt;/a&gt;&lt;/strong&gt; and contextual memory, two of the fastest-moving concepts in AI architecture right now.&lt;/p&gt;

&lt;p&gt;Here's what's actually broken with traditional RAG, what GraphRAG and contextual memory do differently, and how to think about building with them.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Standard RAG Hits a Wall
&lt;/h2&gt;

&lt;p&gt;Traditional RAG works by chunking &lt;a href="https://zignuts.com/ai-services/ai-workflow-automation/ai-document-automation-solutions?utm_source=seo&amp;amp;utm_medium=backlinks&amp;amp;utm_campaign=seo_referral&amp;amp;utm_id=8" rel="noopener noreferrer"&gt;documents&lt;/a&gt;, embedding them, and retrieving the chunks most semantically similar to a user's query. It's simple, effective for straightforward lookup questions, and has become the default pattern for grounding AI responses in real data.&lt;/p&gt;

&lt;p&gt;It also has real, well-known limitations that show up quickly in production.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Limitation&lt;/th&gt;
&lt;th&gt;What It Looks Like in Practice&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;No relationship awareness&lt;/td&gt;
&lt;td&gt;Retrieves individual chunks but misses how entities and facts connect across documents&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Weak multi-hop reasoning&lt;/td&gt;
&lt;td&gt;Struggles with questions requiring several linked facts, like "which vendor supplies the part used in the product that failed last quarter"&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;No persistent memory&lt;/td&gt;
&lt;td&gt;Each query is treated in isolation, with no real understanding of what happened earlier in the conversation&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Chunking artifacts&lt;/td&gt;
&lt;td&gt;Splitting documents into fixed-size chunks can sever context that spans a chunk boundary, losing meaning&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Redundant retrieval&lt;/td&gt;
&lt;td&gt;Similar chunks from different documents often surface together, adding noise instead of new information&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;None of this makes standard RAG useless. It makes it a genuinely good starting point that runs out of runway the moment your application needs to reason across relationships or remember anything meaningfully across turns.&lt;/p&gt;

&lt;h2&gt;
  
  
  A Concrete Example of Where This Breaks Down
&lt;/h2&gt;

&lt;p&gt;Picture an internal AI assistant built for a mid-sized company's operations team, trained on years of vendor contracts, compliance documents, and internal policy memos. Someone asks: "Which of our vendors would be affected if the new data residency policy applies to our EU contracts?"&lt;/p&gt;

&lt;p&gt;A standard RAG setup retrieves chunks mentioning "vendors," separately retrieves chunks mentioning "data residency policy," and separately retrieves chunks mentioning "EU contracts." Nothing in that retrieval step actually confirms which vendors are tied to which contracts, or which contracts fall under EU jurisdiction. The model is left to guess at the connections from loosely related text, and in a compliance context, a confident guess dressed up as an answer is genuinely dangerous.&lt;/p&gt;

&lt;p&gt;This is exactly the class of failure that pushed graph-based approaches from a research curiosity into a real production pattern this year, anywhere the cost of a wrong but confident-sounding answer is high.&lt;/p&gt;

&lt;h2&gt;
  
  
  What GraphRAG Actually Changes
&lt;/h2&gt;

&lt;p&gt;GraphRAG restructures the underlying knowledge as a graph, entities as nodes, relationships as edges, instead of a flat collection of embedded text chunks. Instead of retrieving isolated pieces of text based purely on similarity, the system can traverse relationships to answer questions that require connecting multiple facts together.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Entity-relationship structure.&lt;/strong&gt; Facts aren't just stored, they're connected: a product links to its supplier, which links to a region, which links to a regulation&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Multi-hop query support.&lt;/strong&gt; A question requiring three connected facts can be answered by traversing the graph, rather than hoping all three facts happen to land in the same retrieved chunk&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Community-level summarization.&lt;/strong&gt; Graph-based approaches can summarize entire clusters of related entities, giving a system a genuine overview rather than a pile of disconnected snippets&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Better handling of sparse or niche domains.&lt;/strong&gt; Where a document corpus is small or highly specialized, relationship structure often surfaces relevant context that pure similarity search misses entirely&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  How a Knowledge Graph Actually Gets Built
&lt;/h2&gt;

&lt;p&gt;It's worth demystifying this a bit, since "build a knowledge graph" can sound more exotic than the actual process.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Entity extraction.&lt;/strong&gt; An initial pass through the source documents identifies key entities, people, products, organizations, regulations, dates&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Relationship extraction.&lt;/strong&gt; A second pass identifies how those entities connect, which vendor supplies which product, which contract falls under which jurisdiction&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Graph construction.&lt;/strong&gt; Entities become nodes and relationships become edges, forming a structured map of the underlying data instead of a flat pile of text chunks&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Community detection.&lt;/strong&gt; Related clusters of nodes get grouped, which enables the community-level summarization that flat retrieval simply can't produce&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Ongoing maintenance.&lt;/strong&gt; As source documents update, the graph needs re-processing to reflect new entities and relationships, which is the step most teams underestimate when planning a build&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Contextual Memory: The Other Half of the Problem
&lt;/h2&gt;

&lt;p&gt;GraphRAG solves the relationship problem. Contextual memory solves the persistence problem, the part where a system actually remembers relevant information across a conversation or across sessions, instead of starting from zero every single time.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Short-term working memory&lt;/strong&gt; tracks what's been discussed in the current session, so a follow-up question doesn't need to restate context the user already gave&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Long-term memory&lt;/strong&gt; persists meaningful facts about a user or task across sessions, a returning customer's preferences, a project's ongoing status, a prior decision that shouldn't need repeating&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Selective memory, not total recall&lt;/strong&gt; matters just as much as remembering. A well-designed system decides what's actually worth retaining rather than storing every message verbatim, which keeps retrieval fast and relevant instead of bloated&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Different Approaches to Implementing Memory
&lt;/h2&gt;

&lt;p&gt;Not all contextual memory systems work the same way, and picking the right approach matters.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Approach&lt;/th&gt;
&lt;th&gt;How It Works&lt;/th&gt;
&lt;th&gt;Best Suited For&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Sliding window&lt;/td&gt;
&lt;td&gt;Keeps the last N messages in full&lt;/td&gt;
&lt;td&gt;Short interactions where recent context is all that matters&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Summarization-based&lt;/td&gt;
&lt;td&gt;Periodically compresses older turns into a running summary&lt;/td&gt;
&lt;td&gt;Longer conversations where full detail on early turns matters less over time&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Fact extraction&lt;/td&gt;
&lt;td&gt;Pulls out specific durable facts and stores them separately from the raw conversation&lt;/td&gt;
&lt;td&gt;Cross-session persistence, like remembering a user's stated preferences&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Hybrid&lt;/td&gt;
&lt;td&gt;Combines a short-term window with extracted long-term facts&lt;/td&gt;
&lt;td&gt;Most production systems, balancing responsiveness with genuine persistence&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Most serious production systems end up using some version of the hybrid approach, since a sliding window alone can't persist across sessions, and pure summarization alone tends to lose specific, useful details that fact extraction preserves.&lt;/p&gt;

&lt;h2&gt;
  
  
  How These Two Pieces Fit Together
&lt;/h2&gt;

&lt;p&gt;GraphRAG and contextual memory solve different problems, and the strongest AI applications right now are combining both rather than picking one.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;GraphRAG handles reasoning across your knowledge base, connecting facts that live in different documents or records&lt;/li&gt;
&lt;li&gt;Contextual memory handles reasoning across the conversation itself, remembering what the user already told the system&lt;/li&gt;
&lt;li&gt;Together, they let an AI application answer a question like "does this apply to the client I mentioned earlier, given the update we discussed last week" by pulling both the relationship structure from the knowledge graph and the recalled context from memory&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  A Simplified Illustration of the Difference
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Standard RAG on a multi-hop question:&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Which of our suppliers are affected by the new import regulation?"&lt;br&gt;
Retrieves chunks mentioning "suppliers" and chunks mentioning "import regulation" separately, with no guarantee the system connects which supplier is actually affected by which regulation.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;GraphRAG on the same question:&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Traverses supplier nodes connected to region nodes connected to regulation nodes, returning the specific suppliers actually linked to the affected region, because that relationship is explicitly modeled rather than inferred from text similarity.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Add contextual memory:&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;If the user previously said "we're focused on our European suppliers this quarter," the system recalls that context and narrows the answer accordingly, without the user needing to repeat it.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Where Teams Get This Wrong
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Jumping to GraphRAG for every use case&lt;/strong&gt;, when a simple, well-chunked standard RAG setup is genuinely sufficient for straightforward lookup tasks and adds unnecessary complexity for no real benefit&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Building memory that stores everything indiscriminately&lt;/strong&gt;, which bloats retrieval and actually makes responses slower and noisier rather than smarter&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Treating graph construction as a one-time task&lt;/strong&gt;, when knowledge graphs need ongoing maintenance as entities and relationships change over time&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Ignoring evaluation entirely&lt;/strong&gt;, shipping a GraphRAG or memory system without a way to systematically test whether it's actually improving answer quality over the simpler baseline it replaced&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Conflating memory with logging&lt;/strong&gt;, storing raw conversation history and calling it memory, without any real process for deciding what's actually worth retaining long term&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  A Quick Framework for Deciding What You Need
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Does your use case genuinely require connecting facts across multiple documents or records, or are most queries simple, single-fact lookups?&lt;/li&gt;
&lt;li&gt;Does your application need to remember information across turns or sessions, or is each interaction naturally self-contained?&lt;/li&gt;
&lt;li&gt;Do you have the ongoing resources to maintain a knowledge graph as your underlying data evolves?&lt;/li&gt;
&lt;li&gt;How costly is a wrong but confident-sounding answer in your specific use case? The higher that cost, the stronger the case for the added structure GraphRAG provides&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Common Questions Teams Ask When Evaluating This
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Does GraphRAG replace standard RAG entirely?&lt;/strong&gt;&lt;br&gt;
No, most production systems use both together. Simple lookups can still go through standard retrieval, while multi-hop reasoning questions route through the graph.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How much does this increase latency?&lt;/strong&gt;&lt;br&gt;
Graph traversal adds some overhead compared to a single similarity search, though well-indexed graphs with efficient traversal patterns keep this manageable for most interactive use cases. Benchmarking on your actual data is essential rather than assuming.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Is this only worth it for large enterprises?&lt;/strong&gt;&lt;br&gt;
No. Smaller, highly specialized domains often benefit even more, since sparse document corpora are exactly where relationship structure tends to add the most value over pure similarity search.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why This Is Worth Building Properly
&lt;/h2&gt;

&lt;p&gt;Getting graph construction, retrieval traversal, and memory persistence right together is genuinely more involved than standing up a basic RAG pipeline, and it's easy to underestimate the ongoing maintenance a knowledge graph requires as your data changes. This is exactly the kind of &lt;a href="https://zignuts.com/llm-genai-services/rag-development?utm_source=seo&amp;amp;utm_medium=backlinks&amp;amp;utm_campaign=seo_referral&amp;amp;utm_id=8" rel="noopener noreferrer"&gt;RAG development&lt;/a&gt; and AI application architecture work that separates a genuinely smarter AI app from one that just looks smart in a demo, and it's usually worth getting a second opinion on before committing to a full build.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Takeaway
&lt;/h2&gt;

&lt;p&gt;Standard RAG got a lot of AI applications off the ground, and it's still the right choice for plenty of use cases. But the moment an application needs to reason across relationships or remember anything meaningfully across a conversation, that flat, isolated retrieval model runs out of road fast. GraphRAG and contextual memory are exactly the pair of ideas closing that gap this year, and understanding when you actually need them, not just how to build them, is quickly becoming a core skill for anyone building serious AI products.&lt;/p&gt;

&lt;p&gt;Has your team started experimenting with GraphRAG or persistent memory yet, or is standard RAG still handling everything you're throwing at it? Curious how far along everyone actually is with this.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>machinelearning</category>
      <category>llm</category>
      <category>genai</category>
    </item>
    <item>
      <title>Your App Has AI Features. That's Not the Same Thing as Being an AI Company Anymore.</title>
      <dc:creator>Emma Schmidt</dc:creator>
      <pubDate>Fri, 31 Jul 2026 10:48:07 +0000</pubDate>
      <link>https://dev.to/emma_schmidt_/your-app-has-ai-features-thats-not-the-same-thing-as-being-an-ai-company-anymore-5a0n</link>
      <guid>https://dev.to/emma_schmidt_/your-app-has-ai-features-thats-not-the-same-thing-as-being-an-ai-company-anymore-5a0n</guid>
      <description>&lt;p&gt;There's a quiet but important distinction reshaping how serious software gets built in 2026, and most teams haven't caught up to it yet. Bolting a chatbot onto an existing app and designing an application where AI is the actual architecture are two completely different engineering disciplines, and the gap between them is becoming one of the clearest competitive differentiators in software today. This is exactly the shift driving demand for real &lt;strong&gt;&lt;a href="https://zignuts.com/ai-services/custom-ai-development?utm_source=seo&amp;amp;utm_medium=backlinks&amp;amp;utm_campaign=seo_referral&amp;amp;utm_id=7" rel="noopener noreferrer"&gt;custom AI development&lt;/a&gt;&lt;/strong&gt;, not a plugin added after the fact, but AI woven into how a system makes decisions, processes data, and adapts from the very first architectural diagram.&lt;/p&gt;

&lt;p&gt;Here's what actually separates AI-native software from AI-enhanced software, why the distinction matters more than it sounds, and how to think about it if you're planning a build.&lt;/p&gt;

&lt;h2&gt;
  
  
  AI-Enhanced vs AI-Native: The Real Difference
&lt;/h2&gt;

&lt;p&gt;Most existing "AI-powered" products today are AI-enhanced. A traditional application, built the same way it always would have been, with a recommendation widget, a search-with-AI feature, or a support &lt;strong&gt;&lt;a href="https://zignuts.com/chatbot-development-services?utm_source=seo&amp;amp;utm_medium=backlinks&amp;amp;utm_campaign=seo_referral&amp;amp;utm_id=7" rel="noopener noreferrer"&gt;chatbot&lt;/a&gt;&lt;/strong&gt; added on top. The underlying system, its data flow, its decision logic, its architecture, remains essentially unchanged.&lt;/p&gt;

&lt;p&gt;An AI-native application is architected differently from day one. Intelligence isn't a feature sitting on top, it's part of how the system actually functions.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Dimension&lt;/th&gt;
&lt;th&gt;AI-Enhanced&lt;/th&gt;
&lt;th&gt;AI-Native&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Where AI sits&lt;/td&gt;
&lt;td&gt;Bolted on as a feature or module&lt;/td&gt;
&lt;td&gt;Built into the core architecture&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Data flow&lt;/td&gt;
&lt;td&gt;Static, mostly predefined&lt;/td&gt;
&lt;td&gt;Continuous, feeding real-time model decisions&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Adaptability&lt;/td&gt;
&lt;td&gt;Fixed behavior between releases&lt;/td&gt;
&lt;td&gt;Learns and adjusts from ongoing data&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Typical origin&lt;/td&gt;
&lt;td&gt;Retrofit of an existing product&lt;/td&gt;
&lt;td&gt;Designed around AI from the first architecture decision&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Failure mode when done poorly&lt;/td&gt;
&lt;td&gt;AI feature feels bolted on, inconsistent with the rest of the app&lt;/td&gt;
&lt;td&gt;Poor governance and evaluation gaps compound across the whole system&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Neither approach is inherently wrong. A lot of genuinely good products are AI-enhanced and don't need to be anything else. But for products where intelligence is meant to be the actual value proposition, retrofitting an existing architecture tends to be far more expensive and painful than building AI-native from the start.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why This Shift Is Happening Now
&lt;/h2&gt;

&lt;p&gt;A few forces are converging to push serious teams toward AI-native thinking rather than incremental AI feature additions.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Retrofitting is proving genuinely costly.&lt;/strong&gt; Teams that added AI as an afterthought are running into architectural walls, data pipelines that weren't built for continuous model input, decision logic that was never designed to be adaptive, and it's turning into expensive rework rather than a quick feature addition&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Evaluation and observability are now considered table stakes, not extras.&lt;/strong&gt; Serious AI development in 2026 increasingly means having real evaluation pipelines that systematically test outputs against known-good examples, not just shipping a prompt and hoping it behaves&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Security expectations have caught up with adoption.&lt;/strong&gt; Prompt injection, data exfiltration through AI interfaces, and output manipulation are now treated as real attack vectors, which means the AI layer needs the same security discipline as any other system boundary, not a bolted-on afterthought&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Multi-model orchestration is becoming a standard architectural component.&lt;/strong&gt; Rather than routing everything through one model, AI-native systems increasingly route different tasks to different models based on cost, latency, and capability, which only works cleanly if the architecture was designed with that flexibility in mind&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What AI-Native Architecture Actually Requires
&lt;/h2&gt;

&lt;p&gt;Building this way touches more of the stack than a typical feature addition would.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Data pipelines designed for continuous flow&lt;/strong&gt;, not periodic batch updates, since adaptive systems need fresh data to actually adapt&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Evaluation infrastructure built in from the start&lt;/strong&gt;, tracking output quality, catching model regressions, and validating behavior against real, known-good examples&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Clear governance around AI decision-making&lt;/strong&gt;, especially for anything touching regulated data or high-stakes outcomes, where explainability and audit trails matter&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Architecture flexible enough for multi-model routing&lt;/strong&gt;, so the system isn't locked into a single model provider or a single point of failure&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Security treated as a first-class concern for the AI layer specifically&lt;/strong&gt;, not assumed to be covered by the same protections as the rest of the application&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Real-World Scenarios Where This Distinction Actually Matters
&lt;/h2&gt;

&lt;p&gt;To make this concrete, here's where the AI-native versus AI-enhanced choice genuinely changes the outcome.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;A support platform&lt;/strong&gt; adding a chatbot to an existing ticketing system is AI-enhanced. A support platform where routing, prioritization, and resolution suggestions are all driven continuously by live data from the start is AI-native, and it behaves fundamentally differently as ticket volume and complexity grow&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A financial analytics tool&lt;/strong&gt; with an AI summary feature bolted onto existing dashboards is AI-enhanced. One where risk scoring and forecasting are core to how the system processes every transaction is AI-native&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;An internal knowledge tool&lt;/strong&gt; with search-with-AI added to an existing wiki is AI-enhanced. One built around continuously updated embeddings and adaptive retrieval from the ground up is AI-native&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A logistics platform&lt;/strong&gt; with a recommendation widget for routing suggestions is AI-enhanced. One where routing decisions are made continuously by an adaptive model integrated into the core dispatch logic is AI-native&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Where Teams Get This Wrong
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Assuming AI-native means "use more AI features."&lt;/strong&gt; It's an architectural distinction, not a feature count. A product can have fewer visible AI features and still be genuinely AI-native if intelligence is core to how it functions&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Skipping the evaluation and governance layer to move faster.&lt;/strong&gt; This is the corner that gets cut most often, and it's the one that causes the most expensive problems later, once the system is handling real production decisions&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Treating security as something to add after the AI features work.&lt;/strong&gt; By the time an AI-native system is live, retrofitting proper security around prompt handling and data access is far harder than designing it in from the start&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Underestimating the data infrastructure work.&lt;/strong&gt; Teams often plan for the model and the interface, but underestimate how much of the actual effort lives in the data pipelines that feed continuous, adaptive behavior&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  A Quick Framework for Deciding What You Actually Need
&lt;/h2&gt;

&lt;p&gt;Before committing to a full AI-native rebuild, it's worth being honest about which category your product actually falls into.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Is intelligence the core value proposition, or a helpful addition to a product that works fine without it?&lt;/li&gt;
&lt;li&gt;Does your system need to adapt continuously based on new data, or would periodic updates genuinely be sufficient?&lt;/li&gt;
&lt;li&gt;Do you have, or are you willing to build, the evaluation and governance infrastructure this approach requires?&lt;/li&gt;
&lt;li&gt;Is your team prepared for the security implications of treating the AI layer as a first-class system boundary?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If the honest answer to the first two questions is "yes, genuinely," AI-native architecture is worth the upfront investment. If AI is a nice complement to an otherwise solid, deterministic product, a well-built AI-enhanced approach is often the more practical, lower-risk choice.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why This Is Genuinely Hard to Get Right Alone
&lt;/h2&gt;

&lt;p&gt;This isn't a criticism of any team, it's just an honest reflection of how new and fast-moving this discipline still is. The specific technical profile this requires, deep experience across data pipeline design, model evaluation, multi-model orchestration, and AI-specific security, remains genuinely scarce in most hiring markets right now. That's exactly why a lot of serious &lt;strong&gt;&lt;a href="https://zignuts.com/ai-services/custom-ai-development/ai-software-development-services?utm_source=seo&amp;amp;utm_medium=backlinks&amp;amp;utm_campaign=seo_referral&amp;amp;utm_id=7" rel="noopener noreferrer"&gt;AI software development&lt;/a&gt;&lt;/strong&gt; work today involves custom AI development support and &lt;strong&gt;&lt;a href="https://zignuts.com/ai-services/ai-consulting/ai-readiness-assessment-services?utm_source=seo&amp;amp;utm_medium=backlinks&amp;amp;utm_campaign=seo_referral&amp;amp;utm_id=7" rel="noopener noreferrer"&gt;AI readiness assessment&lt;/a&gt;&lt;/strong&gt; brought in from outside, specifically to architect the foundation correctly before a team commits to a direction that's expensive to unwind later. Getting an experienced second opinion on whether a product genuinely needs full AI-native architecture, or whether a well-built AI-enhanced approach would serve it just as well, is often the highest-leverage conversation to have before writing a single line of the core architecture.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Future Outlook
&lt;/h2&gt;

&lt;p&gt;The gap between AI-enhanced and AI-native products is likely to keep widening over the next year or two, not narrow. As evaluation tooling matures and multi-model orchestration becomes more standardized, AI-native architecture is expected to shift from a differentiator into a baseline expectation, particularly for products where intelligence genuinely is the value proposition rather than a nice-to-have layered on top.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Takeaway
&lt;/h2&gt;

&lt;p&gt;Having AI features and being architected as an AI company are not the same thing, and that distinction is only going to matter more as the products competing for the same users diverge further along these two paths. The teams thinking carefully now about whether they genuinely need AI-native architecture, versus a solid, well-built AI-enhanced product, are the ones avoiding the expensive retrofit conversation a year or two from now.&lt;/p&gt;

&lt;p&gt;Is your product built AI-native from the ground up, or is it AI-enhanced with intelligence layered on top? Curious where most teams here actually land on that distinction once they think it through honestly.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>architecture</category>
      <category>machinelearning</category>
      <category>discuss</category>
    </item>
    <item>
      <title>Build Your First MCP Server: A Practical Guide to Connecting AI Agents to Real Tools</title>
      <dc:creator>Emma Schmidt</dc:creator>
      <pubDate>Thu, 30 Jul 2026 06:43:25 +0000</pubDate>
      <link>https://dev.to/emma_schmidt_/build-your-first-mcp-server-a-practical-guide-to-connecting-ai-agents-to-real-tools-2o43</link>
      <guid>https://dev.to/emma_schmidt_/build-your-first-mcp-server-a-practical-guide-to-connecting-ai-agents-to-real-tools-2o43</guid>
      <description>&lt;p&gt;Learn how to build a working MCP server from scratch and connect it to an AI client, step by step.&lt;/p&gt;

&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;If you've ever needed an &lt;strong&gt;&lt;a href="https://zignuts.com/llm-genai-services/ai-agent-development?utm_source=seo&amp;amp;utm_medium=backlinks&amp;amp;utm_campaign=seo_referral&amp;amp;utm_id=7" rel="noopener noreferrer"&gt;AI agent&lt;/a&gt;&lt;/strong&gt; to check a database, call an internal API, or search a knowledge base, you've probably hit the same wall: every tool integration ends up as custom, one-off code that doesn't transfer to your next project. MCP server development and &lt;strong&gt;&lt;a href="https://zignuts.com/llm-genai-services/multi-agent-systems/mcp-integration-services?utm_source=seo&amp;amp;utm_medium=backlinks&amp;amp;utm_campaign=seo_referral&amp;amp;utm_id=7" rel="noopener noreferrer"&gt;MCP integration &lt;/a&gt;&lt;/strong&gt;solve this by giving you one standardized way to expose any tool or data source to any compatible AI client, instead of writing bespoke glue code for every combination.&lt;/p&gt;

&lt;p&gt;This tutorial walks through building an actual working&lt;a href="https://zignuts.com/llm-genai-services/mcp-development/mcp-server-development-services?utm_source=seo&amp;amp;utm_medium=backlinks&amp;amp;utm_campaign=seo_referral&amp;amp;utm_id=7" rel="noopener noreferrer"&gt; &lt;strong&gt;MCP server&lt;/strong&gt;&lt;/a&gt;, connecting it to a client, and testing that it works end to end. By the end, you'll have a functioning server exposing a real tool, and you'll understand exactly what's happening at each layer instead of just copying a snippet.&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;Comfortable reading and writing basic Python&lt;/li&gt;
&lt;li&gt;Python 3.10 or later installed&lt;/li&gt;
&lt;li&gt;A terminal and a code editor&lt;/li&gt;
&lt;li&gt;Roughly 30-45 minutes&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What We're Building
&lt;/h2&gt;

&lt;p&gt;We're building a small MCP server that exposes one practical tool: looking up the weather for a given city. It's simple enough to fully understand in one sitting, but it demonstrates every core piece of setting up MCP tool integration.&lt;/p&gt;

&lt;p&gt;The finished server will be able to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Advertise its available tools to any connecting MCP client&lt;/li&gt;
&lt;li&gt;Accept a tool call with a specific input (a city name)&lt;/li&gt;
&lt;li&gt;Return a structured response back to the calling AI agent&lt;/li&gt;
&lt;li&gt;Run locally so you can test it directly from your terminal&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Step 1: Set Up Your Environment
&lt;/h2&gt;

&lt;p&gt;Create a project folder and install the MCP SDK.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;mkdir &lt;/span&gt;mcp-weather-server
&lt;span class="nb"&gt;cd &lt;/span&gt;mcp-weather-server
python &lt;span class="nt"&gt;-m&lt;/span&gt; venv venv
&lt;span class="nb"&gt;source &lt;/span&gt;venv/bin/activate  &lt;span class="c"&gt;# on Windows use venv\Scripts\activate&lt;/span&gt;
pip &lt;span class="nb"&gt;install &lt;/span&gt;mcp requests
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This gives you the core MCP library plus &lt;code&gt;requests&lt;/code&gt;, which we'll use to call a public weather API inside our tool.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 2: Define the Server and Register Your Tool
&lt;/h2&gt;

&lt;p&gt;Create a file called &lt;code&gt;server.py&lt;/code&gt;. This is illustrative, simplified code meant for learning, not a full production implementation.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# server.py
&lt;/span&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;mcp.server&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Server&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;mcp.types&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Tool&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;TextContent&lt;/span&gt;

&lt;span class="n"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Server&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;weather-server&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nd"&gt;@app.list_tools&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;list_tools&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="nc"&gt;Tool&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;get_weather&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;description&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Get the current weather for a given city&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;inputSchema&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;type&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;object&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;properties&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;city&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;type&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;string&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;description&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Name of the city&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
                &lt;span class="p"&gt;},&lt;/span&gt;
                &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;required&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;city&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This &lt;code&gt;list_tools&lt;/code&gt; function is how a client discovers what your server can do. When an AI agent connects, it asks "what tools do you have," and this is the answer it gets back, in a structured format it can reason about.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 3: Implement What the Tool Actually Does
&lt;/h2&gt;

&lt;p&gt;Now add the logic that runs when the tool is actually called.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# server.py (continued)
&lt;/span&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;

&lt;span class="nd"&gt;@app.call_tool&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;call_tool&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;arguments&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;dict&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;get_weather&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;city&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;arguments&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;city&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="c1"&gt;# Simplified example call, replace with a real weather API and key
&lt;/span&gt;        &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://example-weather-api.test/v1/current?city=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;city&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;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="n"&gt;summary&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;The weather in &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;city&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; is &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;condition&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;unknown&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; at &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;temp&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;?&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;°&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nc"&gt;TextContent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;text&lt;/span&gt;&lt;span class="sh"&gt;"&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;summary&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is the execution layer. The AI model never talks to the weather API directly, it calls your tool through the protocol, and your code decides exactly what happens and what comes back.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 4: Run the Server Locally
&lt;/h2&gt;

&lt;p&gt;Add a simple entry point so the server can actually start.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# server.py (continued)
&lt;/span&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;mcp.server.stdio&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;stdio_server&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;asyncio&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="nf"&gt;stdio_server&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="nf"&gt;as &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;read_stream&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;write_stream&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;read_stream&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;write_stream&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create_initialization_options&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;__name__&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;__main__&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;asyncio&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run it with:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;At this point, the server is running and waiting for a client to connect over standard input and output, which is the simplest transport for local development and testing.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 5: Connect a Client and Test It
&lt;/h2&gt;

&lt;p&gt;To actually test this, you need an MCP-compatible client configured to launch your server. Most MCP client configurations use a simple JSON entry pointing to your script.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"mcpServers"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"weather"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"command"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"python"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"args"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"/full/path/to/server.py"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once your client is configured and connected, ask it something like "what's the weather in Lisbon." If everything is wired correctly, the client will discover your &lt;code&gt;get_weather&lt;/code&gt; tool through the &lt;code&gt;list_tools&lt;/code&gt; call, invoke it with the city argument, and return the result from your &lt;code&gt;call_tool&lt;/code&gt; function back through the model's response.&lt;/p&gt;

&lt;h2&gt;
  
  
  Testing / Verifying It Works
&lt;/h2&gt;

&lt;p&gt;A few checks to confirm your MCP server integration is actually functioning correctly:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Confirm the client's tool list shows &lt;code&gt;get_weather&lt;/code&gt; as an available tool after connecting&lt;/li&gt;
&lt;li&gt;Manually call the tool with a test city and check that the response text looks correct&lt;/li&gt;
&lt;li&gt;Try an invalid or missing argument and confirm your server doesn't crash silently&lt;/li&gt;
&lt;li&gt;Restart the client and reconnect to make sure the server initializes cleanly every time, not just on the first run&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Common Pitfalls and How to Avoid Them
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Forgetting to validate input.&lt;/strong&gt; A missing or malformed &lt;code&gt;city&lt;/code&gt; argument will crash a naive implementation. Add basic validation before making the external call.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Blocking calls inside async functions.&lt;/strong&gt; Using a purely synchronous HTTP library inside an async tool handler can freeze your server under load. Consider an async HTTP client for anything beyond a simple learning project.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Not handling API failures gracefully.&lt;/strong&gt; If the weather API is down, your tool should return a clear error message, not throw an unhandled exception that breaks the whole session.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Overloading one server with too many unrelated tools.&lt;/strong&gt; Keeping a server focused on one coherent set of capabilities makes it easier for both you and the connecting AI agent to reason about.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Best Practices for Production Use
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Add proper authentication and scoped permissions before exposing any server beyond local testing&lt;/li&gt;
&lt;li&gt;Log every tool call, including inputs and outcomes, so failures are debuggable after the fact&lt;/li&gt;
&lt;li&gt;Set reasonable timeouts on any external API calls inside your tools&lt;/li&gt;
&lt;li&gt;Validate all inputs against your declared schema before executing any logic&lt;/li&gt;
&lt;li&gt;Version your tool definitions so you can evolve them without silently breaking existing clients&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  What to Explore Next
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Add a second, related tool to the same server, like a multi-day forecast, and see how tool discovery scales&lt;/li&gt;
&lt;li&gt;Swap the stdio transport for Streamable HTTP to run your server as a proper remote service&lt;/li&gt;
&lt;li&gt;Explore adding authentication middleware so only verified callers can invoke your tools&lt;/li&gt;
&lt;li&gt;Look into structured output schemas so responses can be validated programmatically instead of just returned as plain text&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;Building your first MCP server strips away a lot of the mystery around MCP integration once you've actually wired up discovery, execution, and a real client connection yourself. The pattern you just built scales directly to far more complex tools, databases, internal APIs, search systems, without changing the underlying shape of what you learned here. Once this clicks, adding your next tool is a lot faster than the first one was.&lt;/p&gt;

</description>
      <category>mcp</category>
      <category>ai</category>
      <category>tutorial</category>
      <category>python</category>
    </item>
    <item>
      <title>There's a New Universal Plug for AI, and Most Developers Haven't Wired It In Yet</title>
      <dc:creator>Emma Schmidt</dc:creator>
      <pubDate>Wed, 29 Jul 2026 12:26:39 +0000</pubDate>
      <link>https://dev.to/emma_schmidt_/theres-a-new-universal-plug-for-ai-and-most-developers-havent-wired-it-in-yet-1fc8</link>
      <guid>https://dev.to/emma_schmidt_/theres-a-new-universal-plug-for-ai-and-most-developers-havent-wired-it-in-yet-1fc8</guid>
      <description>&lt;p&gt;Picture this. You've built an AI feature that needs to check a customer's order status, pull data from your CRM, and search internal documentation, three separate systems, three separate custom integrations, each with its own auth, its own data format, its own maintenance burden. Now imagine adding a fourth tool next quarter. And a fifth. This exact integration sprawl is precisely the problem the Model Context Protocol was built to solve, and it's become one of the fastest-adopted standards in recent memory across &lt;a href="https://zignuts.com/llm-genai-services/mcp-development/mcp-server-development-services?utm_source=seo&amp;amp;utm_medium=backlinks&amp;amp;utm_campaign=seo_referral&amp;amp;utm_id=7" rel="noopener noreferrer"&gt;&lt;strong&gt;LLM &amp;amp; GenAI&lt;/strong&gt;&lt;/a&gt; development. Understanding how to actually build with it, not just read about it, is quickly becoming a core skill for anyone shipping AI features that need to touch real data and real tools.&lt;/p&gt;

&lt;p&gt;Here's what MCP actually is, why it's spreading this fast, and how to build your first working MCP server step by step.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why This Protocol Is Spreading Faster Than Almost Anything in AI Tooling
&lt;/h2&gt;

&lt;p&gt;The adoption numbers here are genuinely unusual, even for an industry used to fast-moving trends.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Metric&lt;/th&gt;
&lt;th&gt;Figure&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Monthly SDK downloads (March 2026)&lt;/td&gt;
&lt;td&gt;97 million, up from roughly 100,000 at launch&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Time to reach 100M+ monthly downloads&lt;/td&gt;
&lt;td&gt;About 16 months&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Comparable milestone for React's npm package&lt;/td&gt;
&lt;td&gt;Roughly 3 years&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Public MCP servers in the official registry&lt;/td&gt;
&lt;td&gt;Around 9,600 as of a May 2026 snapshot&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Fortune 500 companies with MCP deployed&lt;/td&gt;
&lt;td&gt;Roughly 28% within 18 months of launch&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Major platforms with shipped MCP support&lt;/td&gt;
&lt;td&gt;OpenAI, Google, Microsoft, and others within about 13 months of launch&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;That last row is the one worth sitting with. A protocol originally released by Anthropic in November 2024 has since been adopted broadly enough across the industry that it now functions as shared infrastructure rather than one company's proprietary approach, which is exactly the kind of cross-platform momentum that turns a promising idea into a genuine standard.&lt;/p&gt;

&lt;h2&gt;
  
  
  What MCP Actually Solves
&lt;/h2&gt;

&lt;p&gt;Before MCP, connecting an AI application to external tools meant building a custom integration for every single combination of model and tool. Ten AI applications and a hundred tools meant a potential one thousand separate integrations, each one bespoke, each one a maintenance burden of its own.&lt;/p&gt;

&lt;p&gt;MCP replaces that with one standardized interface. Think of it the way USB-C replaced a drawer full of proprietary charging cables. Any MCP-compatible client can talk to any MCP-compatible server through the same protocol, regardless of which model or which tool is on either end.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Three Core Pieces You Need to Understand
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;MCP Host.&lt;/strong&gt; The AI application itself, the thing the end user actually interacts with&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;MCP Client.&lt;/strong&gt; Lives inside the host and manages the connection to one or more &lt;a href="https://zignuts.com/llm-genai-services/mcp-development/mcp-server-development-services?utm_source=seo&amp;amp;utm_medium=backlinks&amp;amp;utm_campaign=seo_referral&amp;amp;utm_id=7" rel="noopener noreferrer"&gt;&lt;strong&gt;MCP servers&lt;/strong&gt;&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;MCP Server.&lt;/strong&gt; Exposes specific tools, data sources, or capabilities in the standardized format the protocol expects&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Most developers building on top of MCP will spend their time on the server side, exposing their own systems and tools so any compatible AI application can use them.&lt;/p&gt;

&lt;h2&gt;
  
  
  Building Your First MCP Server, Step by Step
&lt;/h2&gt;

&lt;p&gt;Let's build a simple MCP server that exposes a single tool, checking an order status, using the official &lt;a href="https://zignuts.com/python-development-company?utm_source=seo&amp;amp;utm_medium=backlinks&amp;amp;utm_campaign=seo_referral&amp;amp;utm_id=7" rel="noopener noreferrer"&gt;&lt;strong&gt;Python&lt;/strong&gt;&lt;/a&gt; SDK.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step one: install the SDK&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pip &lt;span class="nb"&gt;install &lt;/span&gt;mcp
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Step two: define the server and register a tool&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;mcp.server&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Server&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;mcp.types&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Tool&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;TextContent&lt;/span&gt;

&lt;span class="n"&gt;server&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Server&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;order-status-server&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nd"&gt;@server.list_tools&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;list_tools&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="nc"&gt;Tool&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;get_order_status&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;description&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Look up the current status of a customer order&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;inputSchema&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;type&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;object&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;properties&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;order_id&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;type&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;string&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
                &lt;span class="p"&gt;},&lt;/span&gt;
                &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;required&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;order_id&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is the discovery step. Any MCP client connecting to this server can now ask what tools are available and get back a structured description it can reason about.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step three: implement what the tool actually does&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="nd"&gt;@server.call_tool&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;call_tool&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;arguments&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;dict&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;get_order_status&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;order_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;arguments&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;order_id&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="n"&gt;status&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;lookup_order_in_database&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;order_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nc"&gt;TextContent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;text&lt;/span&gt;&lt;span class="sh"&gt;"&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="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Order &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;order_id&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; status: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is the actual execution layer. The AI model never touches your database directly, it calls the tool through the standardized protocol, and your server controls exactly what happens and what gets returned.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step four: run the server with the appropriate transport&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;mcp.server.stdio&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;stdio_server&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="nf"&gt;stdio_server&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="nf"&gt;as &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;read_stream&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;write_stream&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;server&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;read_stream&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;write_stream&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;server&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create_initialization_options&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Local development typically uses stdio transport. Production deployments increasingly use Streamable HTTP, which lets the server run as a proper remote service rather than a local process, and it's the transport most enterprise MCP rollouts are standardizing around this year.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step five: secure it before it goes anywhere near production&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;mcp.server.auth&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;RequireAuth&lt;/span&gt;

&lt;span class="nd"&gt;@server.call_tool&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="nd"&gt;@RequireAuth&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;scopes&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;orders:read&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;call_tool&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;arguments&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;dict&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="c1"&gt;# verified caller identity is available in context
&lt;/span&gt;    &lt;span class="bp"&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Every tool call should carry proper identity and scope verification. A recent industry analysis noted that in the MCP era, trust isn't established once at login, it's re-earned with every single tool call and data access an agent makes, which is a meaningfully different security posture than traditional API authentication.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's Changing Right Now, as of This Week
&lt;/h2&gt;

&lt;p&gt;This is genuinely current, not stale reporting. The next major MCP specification, dated 2026-07-28, has its release candidate locked and is shipping as the final spec this week. It introduces a stateless protocol core, an Extensions framework for adding capabilities without breaking existing implementations, a formal deprecation policy, and hardened authorization. If you're starting a new MCP implementation right now, building against this version rather than the November 2025 spec is the right call, since SDK maintainers are expected to support it within a defined validation window.&lt;/p&gt;

&lt;h2&gt;
  
  
  Common Mistakes Teams Are Making With Early MCP Adoption
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Tool overexposure.&lt;/strong&gt; Registering far more tools than a given workflow actually needs, which bloats the context an AI model has to reason over and increases the chance of it calling the wrong tool&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Treating authentication as an afterthought.&lt;/strong&gt; Standing up a functional MCP server quickly and only addressing proper scoped auth after it's already been connected to something sensitive&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Ignoring observability.&lt;/strong&gt; Deploying MCP servers into production workflows without tracking tool call success rates, latency, or error patterns, which makes debugging a failed agent workflow nearly impossible after the fact&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Skipping the governance conversation.&lt;/strong&gt; Rolling out MCP servers across a team or organization without agreeing on security, compliance, and identity controls up front, then retrofitting governance after adoption has already sprawled&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Why This Matters Beyond the Hype Cycle
&lt;/h2&gt;

&lt;p&gt;MCP exhibits genuine network effects. Every new MCP server makes every existing MCP client more capable, and every new client makes building an MCP server more worthwhile. That's a structurally different growth pattern than most developer tools, and it's part of why the ecosystem has grown as fast as it has.&lt;/p&gt;

&lt;p&gt;For teams evaluating whether to invest in this now, the practical answer is usually yes, but scoped carefully. Building custom MCP connectors and servers for your own internal tools and data sources, wired into &lt;strong&gt;&lt;a href="https://zignuts.com/blog/rag-vs-fine-tuning" rel="noopener noreferrer"&gt;RAG&lt;/a&gt;&lt;/strong&gt; development and existing LLM and GenAI workflows, is exactly the kind of foundational integration work that compounds in value as your AI features grow, rather than something that needs rebuilding from scratch every time a new tool gets added to the stack.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Takeaway
&lt;/h2&gt;

&lt;p&gt;The integration sprawl that used to make connecting AI to real business tools a slow, custom, one-off project each time is exactly what MCP was built to eliminate. With cross-vendor support, a maturing specification, and genuine network effects driving adoption, this has moved well past experimental territory into shared infrastructure that's shaping how serious AI applications get built this year.&lt;/p&gt;

&lt;p&gt;Has your team started building or adopting MCP servers yet, or are you still wiring up custom integrations one tool at a time? Curious how far along everyone actually is with this.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Tags:&lt;/strong&gt; #ai #llm #genai #tutorial&lt;/p&gt;

</description>
      <category>ai</category>
      <category>llm</category>
      <category>tutorial</category>
      <category>genai</category>
    </item>
    <item>
      <title>Your AI Feature Isn't Slow. Your Architecture Is Making It Feel Slow.</title>
      <dc:creator>Emma Schmidt</dc:creator>
      <pubDate>Tue, 28 Jul 2026 10:30:54 +0000</pubDate>
      <link>https://dev.to/emma_schmidt_/your-ai-feature-isnt-slow-your-architecture-is-making-it-feel-slow-150p</link>
      <guid>https://dev.to/emma_schmidt_/your-ai-feature-isnt-slow-your-architecture-is-making-it-feel-slow-150p</guid>
      <description>&lt;p&gt;You've seen it a hundred times. A user types a question into an AI feature, hits submit, and then just stares at a blank screen for eight seconds before a wall of text dumps onto the page all at once. That gap between "I asked something" and "something happened" is exactly where users lose patience, and it's rarely the model's fault. It's almost always a streaming problem, not a speed problem. This is one of the core patterns behind modern &lt;a href="https://zignuts.com/ai-services?utm_source=seo&amp;amp;utm_medium=backlinks&amp;amp;utm_campaign=seo_referral&amp;amp;utm_id=7" rel="noopener noreferrer"&gt;&lt;strong&gt;AI services&lt;/strong&gt;&lt;/a&gt; and &lt;a href="https://zignuts.com/ai-services/custom-ai-development/ai-web-application-development-services?utm_source=seo&amp;amp;utm_medium=backlinks&amp;amp;utm_campaign=seo_referral&amp;amp;utm_id=7" rel="noopener noreferrer"&gt;&lt;strong&gt;AI web application development&lt;/strong&gt;&lt;/a&gt;, and getting it right in Next.js is simpler than most developers expect, especially now that the framework's App Router and Server Actions map almost perfectly onto how real-time AI responses actually need to flow.&lt;/p&gt;

&lt;p&gt;Here's how to build a genuinely responsive, streaming AI feature in &lt;strong&gt;&lt;a href="https://zignuts.com/hire-nextjs-developers?utm_source=seo&amp;amp;utm_medium=backlinks&amp;amp;utm_campaign=seo_referral&amp;amp;utm_id=7" rel="noopener noreferrer"&gt;Next.js &lt;/a&gt;&lt;/strong&gt;from the ground up, understanding what's actually happening under the hood instead of just wiring up a library and hoping.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Streaming Changed What "Fast" Means for AI Features
&lt;/h2&gt;

&lt;p&gt;A non-streaming AI feature waits for the entire response to generate before showing anything. For short answers that's tolerable. For anything longer, a paragraph, a summary, a generated document, it means staring at a static loading spinner for several seconds with zero feedback that anything is actually happening.&lt;/p&gt;

&lt;p&gt;Streaming flips this. Tokens appear as the model generates them, the same way ChatGPT-style interfaces work. The perceived speed difference is enormous even when the total generation time is identical, because the user sees progress immediately instead of waiting in silence.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Real-World Difference This Makes
&lt;/h2&gt;

&lt;p&gt;Picture a support tool generating a written summary of a long customer thread. The generation itself takes about six seconds either way.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Without streaming:&lt;/strong&gt; the user submits, sees a static spinner, and waits the full six seconds staring at nothing. To someone who isn't sure the request even registered, six seconds of silence feels much longer than it actually is, and a meaningful number of users will refresh or click again out of doubt, sometimes triggering a duplicate request.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;With streaming:&lt;/strong&gt; the user sees the first words appear within a few hundred milliseconds, and text keeps flowing steadily until the summary is complete. The total time is identical, but it reads as fast because there's constant, visible progress instead of dead air.&lt;/p&gt;

&lt;p&gt;Same backend, same model, same six seconds of actual compute. The only difference is architecture, and it's the difference between a feature that feels broken and one that feels instant.&lt;/p&gt;

&lt;h2&gt;
  
  
  Choosing Your Transport Mechanism
&lt;/h2&gt;

&lt;p&gt;Before writing code, it's worth understanding the three real options for getting streaming data from server to client, since picking the wrong one for your use case creates real problems later.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Server-Sent Events (SSE)&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;One-directional, server to client only&lt;/li&gt;
&lt;li&gt;Works over standard HTTP, no special infrastructure required&lt;/li&gt;
&lt;li&gt;The natural fit for AI text generation, since the client only needs to receive tokens, not send data mid-stream&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;WebSockets&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Bidirectional, full duplex communication&lt;/li&gt;
&lt;li&gt;Better suited for genuinely interactive real-time features like collaborative editing or live multiplayer state&lt;/li&gt;
&lt;li&gt;Overkill for most AI chat features, and adds real infrastructure complexity you don't need for one-way token streaming&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Web Streams API (ReadableStream)&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The lowest-level option, giving direct control over how chunks are read and processed&lt;/li&gt;
&lt;li&gt;What the AI SDK and most Route Handler implementations are actually built on under the hood&lt;/li&gt;
&lt;li&gt;Best when you need fine-grained control over parsing structured data mid-stream, like tool calls or JSON fragments&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For the vast majority of AI chat and generation features, SSE built on top of the Web Streams API is the right choice. Reach for WebSockets only when you genuinely need bidirectional communication during generation, which is rarer than most implementations assume.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step-by-Step: Building a Streaming AI Route Handler
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Step one: set up the project&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx create-next-app@latest ai-streaming-app
&lt;span class="nb"&gt;cd &lt;/span&gt;ai-streaming-app
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Select the App Router when prompted. This pattern depends on Route Handlers, which live specifically in the App Router architecture.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step two: create the streaming Route Handler&lt;/strong&gt;&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="c1"&gt;// app/api/chat/route.ts&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;POST&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;message&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;stream&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;ReadableStream&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nf"&gt;start&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;controller&lt;/span&gt;&lt;span class="p"&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;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;callModelProvider&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

      &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="k"&gt;await &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;chunk&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;controller&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;enqueue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;TextEncoder&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;encode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;chunk&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="nx"&gt;controller&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;close&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;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;stream&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;headers&lt;/span&gt;&lt;span class="p"&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;Content-Type&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;text/event-stream&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="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The key detail here: the API key and the call to the model provider stay entirely server-side. Nothing sensitive ever ships to the client bundle, which matters both for security and for keeping your provider costs from being exposed.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step three: consume the stream on the client&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="c1"&gt;// app/components/ChatInput.tsx&lt;/span&gt;
&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;use client&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useState&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="s1"&gt;react&lt;/span&gt;&lt;span class="dl"&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;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;ChatInput&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setResponse&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;);&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;handleSubmit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;message&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="nf"&gt;setResponse&lt;/span&gt;&lt;span class="p"&gt;(&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;res&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/api/chat&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="na"&gt;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;POST&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;body&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;stringify&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;message&lt;/span&gt; &lt;span class="p"&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;reader&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nf"&gt;getReader&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;decoder&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;TextDecoder&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="k"&gt;while &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="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;done&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;reader&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;read&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;done&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="nf"&gt;setResponse&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;prev&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;prev&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;decoder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;decode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;value&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;return&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is the piece that actually creates the typing effect. Each chunk arrives and appends to state as it comes in, instead of waiting for one giant response.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step four: add proper error and cancellation handling&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;controller&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;AbortController&lt;/span&gt;&lt;span class="p"&gt;();&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;handleSubmit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;message&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;res&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/api/chat&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="na"&gt;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;POST&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;body&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;stringify&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;message&lt;/span&gt; &lt;span class="p"&gt;}),&lt;/span&gt;
      &lt;span class="na"&gt;signal&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;controller&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;signal&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="c1"&gt;// stream reading logic here&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="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;AbortError&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="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Generation cancelled by user&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;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nf"&gt;setError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Something went wrong, please try again&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="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;handleCancel&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;controller&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;abort&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;A stop button that actually cancels an in-flight generation is a small detail users notice immediately when it's missing, and it costs very little to implement properly.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step five: validate structured output when you need more than plain text&lt;/strong&gt;&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="s1"&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;responseSchema&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;summary&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;number&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;validateResponse&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="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="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;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;return&lt;/span&gt; &lt;span class="nx"&gt;responseSchema&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;parsed&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;Instead of hoping a model returns well-formed JSON, defining a schema and validating against it catches malformed output before it ever reaches your UI, which matters a lot once an AI feature is doing more than just displaying conversational text.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step six: add rate limiting before this ever reaches production&lt;/strong&gt;&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="c1"&gt;// app/api/chat/route.ts&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;requestCounts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nb"&gt;Map&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="o"&gt;&amp;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;POST&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Request&lt;/span&gt;&lt;span class="p"&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;userId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;getUserIdFromSession&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&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;currentCount&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;requestCounts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;currentCount&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mi"&gt;20&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="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Rate limit exceeded&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="na"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;429&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nx"&gt;requestCounts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;currentCount&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="c1"&gt;// proceed with streaming logic&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is a simplified example, a real implementation would use a proper store like Redis rather than an in-memory map, but the principle holds regardless of scale. Without rate limiting, a single user or a scripted abuse pattern can run your model provider costs up fast, and this is one of the most commonly skipped steps in early AI feature builds.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step seven: track cost per feature, not just in aggregate&lt;/strong&gt;&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="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;logUsage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;feature&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="nx"&gt;tokenCount&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;model&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;cost&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;tokenCount&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nf"&gt;getCostPerToken&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;model&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;analytics&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;track&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;ai_usage&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="nx"&gt;feature&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;tokenCount&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;cost&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;model&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;Breaking cost down by feature rather than watching one aggregate monthly number lets you catch a specific feature quietly ballooning in usage long before it shows up as a surprise on the bill.&lt;/p&gt;

&lt;h2&gt;
  
  
  Common Mistakes Worth Avoiding
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Forgetting to handle stream errors mid-response, leaving the UI stuck in a permanent loading state if the connection drops partway through&lt;/li&gt;
&lt;li&gt;Skipping the cancellation handling entirely, which leaves users stuck watching a response they no longer want finish generating&lt;/li&gt;
&lt;li&gt;Calling the model provider directly from client-side code, which exposes API keys and lets costs run up uncontrolled&lt;/li&gt;
&lt;li&gt;Not validating structured output, and discovering malformed data only when it breaks something downstream in production&lt;/li&gt;
&lt;li&gt;Shipping without rate limiting and finding out the hard way when a single user or bot script drives up provider costs overnight&lt;/li&gt;
&lt;li&gt;Choosing WebSockets by default out of habit when SSE would be simpler, cheaper to run, and perfectly sufficient for one-way token streaming&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  A Quick Self-Check Before You Ship
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Does your UI show visible progress within the first second, or does it sit on a static spinner while waiting for the full response?&lt;/li&gt;
&lt;li&gt;Can a user actually cancel a generation mid-stream, or does clicking away just leave the request running in the background?&lt;/li&gt;
&lt;li&gt;Is there a rate limit in place, or is the endpoint currently wide open to unlimited requests per user?&lt;/li&gt;
&lt;li&gt;Are you tracking cost per feature, or would a sudden spike in usage only show up once the monthly bill arrives?&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Why This Is Worth Building Properly, Not Just Quickly
&lt;/h2&gt;

&lt;p&gt;Getting a demo chat working in an afternoon is genuinely easy now. Getting it production-ready, proper error handling, rate limiting, cost monitoring, structured output validation, and a UI that gracefully degrades when something goes wrong, is where most teams underestimate the actual scope of the work. Custom AI development and API integration work focused specifically on shipping these features at production scale tends to close that gap far faster than assembling it piece by piece under a deadline, especially for teams integrating multiple providers or building on top of an existing enterprise codebase.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Takeaway
&lt;/h2&gt;

&lt;p&gt;The gap between an AI feature that feels instant and one that feels sluggish usually isn't the model's raw speed, it's whether the response streams token by token or dumps all at once after a long, silent wait. Next.js's architecture, particularly Server Actions and Route Handlers, maps naturally onto this pattern, which is exactly why it's become the default framework for AI-powered web applications this year.&lt;/p&gt;

&lt;p&gt;Has your team already shipped a streaming AI feature in production, or are you still working through the plumbing on this one? Curious what's tripped people up most.&lt;/p&gt;

</description>
      <category>nextjs</category>
      <category>ai</category>
      <category>webdev</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Your ML Model Doesn't Need to Be Bigger. It Needs to Be Smaller and Smarter.</title>
      <dc:creator>Emma Schmidt</dc:creator>
      <pubDate>Mon, 27 Jul 2026 06:37:54 +0000</pubDate>
      <link>https://dev.to/emma_schmidt_/your-ml-model-doesnt-need-to-be-bigger-it-needs-to-be-smaller-and-smarter-3gao</link>
      <guid>https://dev.to/emma_schmidt_/your-ml-model-doesnt-need-to-be-bigger-it-needs-to-be-smaller-and-smarter-3gao</guid>
      <description>&lt;p&gt;For the last few years, the assumption in machine learning was simple: bigger models mean better results, so scale up and worry about the bill later. That assumption is quietly breaking down in 2026. The real shift happening across serious ML teams right now isn't about building bigger models, it's about deployment efficiency, running smaller, specialized models that cost a fraction as much to run while matching or beating general-purpose performance on the specific task they're actually built for. This is exactly where a lot of &lt;strong&gt;&lt;a href="https://zignuts.com/ml-services" rel="noopener noreferrer"&gt;ML services&lt;/a&gt;&lt;/strong&gt; work is heading this year, helping teams figure out which tasks genuinely need a massive general model and which ones a smaller, purpose-tuned one handles just as well for a fraction of the cost.&lt;/p&gt;

&lt;p&gt;This shift has a name, small language models, and understanding how to actually build and deploy one is quickly becoming a core ML skill rather than a niche specialty.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Bigger Stopped Automatically Meaning Better
&lt;/h2&gt;

&lt;p&gt;For a specific, well-defined task, a massive general-purpose model is often carrying enormous amounts of capability you never actually use. Ask a giant model to classify customer support tickets into five categories, and it's spending compute capacity it could use to write poetry or debug &lt;a href="https://zignuts.com/hire-python-developers?utm_source=seo&amp;amp;utm_medium=backlinks&amp;amp;utm_campaign=seo_referral&amp;amp;utm_id=7" rel="noopener noreferrer"&gt;&lt;strong&gt;Python&lt;/strong&gt;&lt;/a&gt;, none of which the task needs.&lt;/p&gt;

&lt;p&gt;A few forces are pushing the industry toward smaller, specialized models instead:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Inference cost adds up fast at real scale.&lt;/strong&gt; A model that's cheap to query once becomes expensive very quickly across millions of daily requests, and a smaller model tuned for the specific task can cut that cost dramatically&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Latency matters more as AI moves into real-time features.&lt;/strong&gt; A smaller model responds faster, which matters enormously for anything user-facing where a slow response actively hurts the experience&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;On-device and edge deployment is only realistic with smaller models.&lt;/strong&gt; A model that needs to run on a phone, a browser, or an embedded device simply can't be enormous&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Specialized accuracy often beats general capability.&lt;/strong&gt; A model trained specifically on your domain's data and terminology frequently outperforms a general model on that exact task, even at a fraction of the parameter count&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The Two Core Techniques Worth Actually Understanding
&lt;/h2&gt;

&lt;p&gt;Two techniques make this shift practical, and both are worth understanding at a working level even if you're not building the tooling yourself.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Quantization&lt;/strong&gt; reduces the precision of a model's internal numbers, typically from 32-bit floating point down to 8-bit or even 4-bit representations. This shrinks the model's memory footprint and speeds up inference, often with only a small, carefully managed loss in accuracy.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Distillation&lt;/strong&gt; trains a smaller "student" model to mimic the behavior of a larger "teacher" model. Instead of learning from raw data alone, the student learns from the teacher's outputs, effectively compressing what the larger model learned into a much smaller package.&lt;/p&gt;

&lt;p&gt;Together, these two techniques are why a well-tuned small model can now handle tasks that would have required a massive general model just a couple of years ago.&lt;/p&gt;

&lt;h2&gt;
  
  
  A Practical Walkthrough: Quantizing a Model for Deployment
&lt;/h2&gt;

&lt;p&gt;Let's walk through a basic quantization workflow using a common open-source library, the kind of step that turns a model too large for practical deployment into one that runs efficiently in production.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step one: load your baseline model&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;transformers&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;AutoModelForSequenceClassification&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;AutoTokenizer&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;your-base-model&lt;/span&gt;&lt;span class="sh"&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;AutoModelForSequenceClassification&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;from_pretrained&lt;/span&gt;&lt;span class="p"&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;tokenizer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;AutoTokenizer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;from_pretrained&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;model_name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Step two: apply post-training quantization&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

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

&lt;span class="n"&gt;quantized_model&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;torch&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;quantization&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;quantize_dynamic&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;torch&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;nn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Linear&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="n"&gt;dtype&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;torch&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;qint8&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This converts the model's linear layers to 8-bit integer precision, typically shrinking the model size significantly and speeding up inference on CPU, often with minimal accuracy loss for well-suited tasks.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step three: benchmark before trusting the result&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

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

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;benchmark&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;input_ids&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;runs&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;start&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;time&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;runs&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="n"&gt;torch&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;no_grad&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
            &lt;span class="nf"&gt;model&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;input_ids&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;return &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;time&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;runs&lt;/span&gt;

&lt;span class="n"&gt;original_latency&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;benchmark&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;sample_input&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;quantized_latency&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;benchmark&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;quantized_model&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;sample_input&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;Original: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;original_latency&lt;/span&gt;&lt;span class="si"&gt;:&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;s, Quantized: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;quantized_latency&lt;/span&gt;&lt;span class="si"&gt;:&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;s&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Never skip this step. The whole point of quantization is a measurable efficiency gain, and you need real numbers on your actual hardware and actual data, not an assumption borrowed from a blog post.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step four: validate accuracy didn't quietly degrade&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;evaluate_accuracy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;test_dataset&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;correct&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;inputs&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;label&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;test_dataset&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="n"&gt;torch&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;no_grad&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
            &lt;span class="n"&gt;prediction&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;model&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;inputs&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;logits&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;argmax&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="n"&gt;correct&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;prediction&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;label&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;correct&lt;/span&gt; &lt;span class="o"&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;test_dataset&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;Original accuracy: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nf"&gt;evaluate_accuracy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;test_set&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;:&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="n"&gt;f&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="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;Quantized accuracy: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nf"&gt;evaluate_accuracy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;quantized_model&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;test_set&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;:&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A quantized model that's faster but meaningfully less accurate isn't actually a win. This comparison step is what turns quantization from a guess into a real, measured engineering decision.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where Small Language Models Are Already Winning
&lt;/h2&gt;

&lt;p&gt;This isn't theoretical. Real deployments are already showing the pattern clearly.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Customer support ticket routing&lt;/strong&gt; using a small, domain-tuned classifier instead of a general-purpose model call for every incoming ticket, cutting both latency and per-request cost significantly&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;On-device features in mobile apps&lt;/strong&gt;, where a compact model handles tasks like text summarization or intent detection locally, without a round trip to a server at all&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Manufacturing and IoT anomaly detection&lt;/strong&gt;, where small, efficient models run directly on edge hardware near the sensors generating the data, since sending everything to the cloud for a giant model to process isn't fast enough for real-time decisions&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;High-volume, narrow classification tasks&lt;/strong&gt; like spam detection or content moderation, where a small specialized model handles the bulk of routine cases and only escalates genuinely ambiguous ones to a larger model&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  A Quick Framework for Deciding When to Go Small
&lt;/h2&gt;

&lt;p&gt;Before defaulting to the largest available model, ask these questions honestly.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Is this task narrow and well-defined, or does it genuinely require broad, general reasoning across many domains?&lt;/li&gt;
&lt;li&gt;Do we have enough quality training or distillation data specific to this task to teach a smaller model well?&lt;/li&gt;
&lt;li&gt;Does latency or on-device deployment actually matter for this specific feature?&lt;/li&gt;
&lt;li&gt;What's the real cost difference at our expected production volume, not just at demo scale?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If a task is narrow, well-defined, and running at real volume, a small, specialized model is very often the better engineering choice, not a compromise.&lt;/p&gt;

&lt;h2&gt;
  
  
  Common Mistakes Worth Avoiding
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Quantizing a model and shipping it without actually benchmarking the accuracy tradeoff on real evaluation data&lt;/li&gt;
&lt;li&gt;Assuming distillation is a one-time step rather than an ongoing process that needs revisiting as the underlying task or data shifts over time&lt;/li&gt;
&lt;li&gt;Defaulting to the largest general model out of convenience for tasks that a much smaller, cheaper model would handle just as well&lt;/li&gt;
&lt;li&gt;Skipping proper monitoring after deployment, since a smaller model can drift or degrade in production just like any other model, and needs the same kind of ongoing evaluation&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Why This Is Worth Doing Properly, Not Just Quickly
&lt;/h2&gt;

&lt;p&gt;Getting the quantization, distillation, and evaluation pipeline right takes real ML engineering discipline, not just running a library function once and hoping for the best. For teams without a dedicated &lt;a href="https://zignuts.com/ml-services/mlops?utm_source=seo&amp;amp;utm_medium=backlinks&amp;amp;utm_campaign=seo_referral&amp;amp;utm_id=7" rel="noopener noreferrer"&gt;&lt;strong&gt;MLOps&lt;/strong&gt;&lt;/a&gt; function already in place, building this properly alongside shipping product features is a genuinely heavy lift. Custom model development, deployment pipeline setup, and ongoing MLOps support built around this exact efficiency-first approach tend to get a team to a well-benchmarked, production-ready small model far faster and more reliably than assembling it piecemeal under deadline pressure.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Takeaway
&lt;/h2&gt;

&lt;p&gt;The biggest available model was never automatically the right choice, it just looked that way while nobody was measuring the actual cost and latency tradeoffs closely. As ML moves deeper into real-time, on-device, and high-volume production use cases, the teams pulling ahead are the ones treating model size as a deliberate engineering decision, matched carefully to the task, rather than a default setting left on maximum.&lt;/p&gt;

&lt;p&gt;Is your team still defaulting to the largest available model for every task, or have you already started matching model size to the actual job? Curious how far along different teams are with this shift.&lt;/p&gt;

</description>
      <category>machinelearning</category>
      <category>ai</category>
      <category>python</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Your Chatbot Answered Perfectly Yesterday. Today It's Confidently Making Things Up. Nobody Noticed.</title>
      <dc:creator>Emma Schmidt</dc:creator>
      <pubDate>Fri, 24 Jul 2026 06:54:44 +0000</pubDate>
      <link>https://dev.to/emma_schmidt_/your-chatbot-answered-perfectly-yesterday-today-its-confidently-making-things-up-nobody-noticed-2o43</link>
      <guid>https://dev.to/emma_schmidt_/your-chatbot-answered-perfectly-yesterday-today-its-confidently-making-things-up-nobody-noticed-2o43</guid>
      <description>&lt;p&gt;Your uptime dashboard is green. Response times look normal. Error rates are near zero. And yet, somewhere in production right now, your AI feature might be giving out subtly wrong answers, hallucinated policy details, a drifted tone, an answer that's technically valid but wrong for your actual use case, and none of your existing monitoring would ever catch it. This is exactly the blind spot pushing &lt;strong&gt;&lt;a href="https://zignuts.com/ai-services?utm_source=seo&amp;amp;utm_medium=backlinks&amp;amp;utm_campaign=seo_referral&amp;amp;utm_id=7" rel="noopener noreferrer"&gt;AI services&lt;/a&gt;&lt;/strong&gt; from a bolted-on feature toward something that needs the same rigor as any other production infrastructure, with dedicated observability, evaluation, and monitoring built in from the start rather than added after something goes wrong.&lt;/p&gt;

&lt;p&gt;This gap has a name now: &lt;strong&gt;&lt;a href="https://zignuts.com/llm-genai-services?utm_source=seo&amp;amp;utm_medium=backlinks&amp;amp;utm_campaign=seo_referral&amp;amp;utm_id=7" rel="noopener noreferrer"&gt;LLM &lt;/a&gt;&lt;/strong&gt;observability, and it's becoming one of the fastest-growing corners of AI infrastructure this year for a very simple reason. Traditional monitoring was built for deterministic software. &lt;strong&gt;&lt;a href="https://zignuts.com/ai-models?utm_source=seo&amp;amp;utm_medium=backlinks&amp;amp;utm_campaign=seo_referral&amp;amp;utm_id=7" rel="noopener noreferrer"&gt;AI models&lt;/a&gt;&lt;/strong&gt; aren't deterministic, and the old playbook doesn't catch the failures that actually matter.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Your Existing Monitoring Can't See This
&lt;/h2&gt;

&lt;p&gt;Traditional application monitoring answers one question well: did the request succeed, and how fast. That's genuinely useful, and it's also completely blind to the specific way AI systems fail.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;A response can be fast, formatted correctly, and still be wrong.&lt;/strong&gt; A hallucinated fact, a policy detail that's outdated, or an answer that sounds confident but references the wrong context all return a perfectly healthy 200 status code&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The same prompt can produce different quality on different days.&lt;/strong&gt; A model that answered a question correctly last week can drift into a subtly wrong pattern this week with no code change on your end at all&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Multi-step AI workflows hide their failures in the middle.&lt;/strong&gt; When a system retrieves documents, reasons over them, and calls tools before producing a final answer, a failure in any middle step can still produce an output that looks fine on the surface&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cost and token usage can balloon silently.&lt;/strong&gt; A workflow that used to cost a few cents per request can quietly triple in cost as prompts grow or retrieval pulls in more context than intended, with nothing in a standard dashboard flagging it&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;None of these show up as an outage. They show up as a slow, invisible erosion of quality that nobody notices until a customer complains, or worse, until nobody notices at all.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Four Things Real AI Observability Actually Tracks
&lt;/h2&gt;

&lt;p&gt;Getting real visibility into an AI system means watching more than the usual infrastructure signals.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;System health.&lt;/strong&gt; The traditional layer, latency, error rates, uptime, still matters and still needs watching&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Model performance and quality.&lt;/strong&gt; Accuracy against known good answers, hallucination rates, and semantic drift over time, not just whether a response was returned&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cost tracking.&lt;/strong&gt; Token usage and per-request cost broken down by feature, so a quiet cost creep gets caught before it shows up as a surprise on the monthly bill&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Behavioral tracing.&lt;/strong&gt; Full visibility into multi-step workflows, what was retrieved, what reasoning path was taken, what tools were called, so a wrong answer can actually be debugged instead of shrugged at&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  A Practical Way to Start Building This
&lt;/h2&gt;

&lt;p&gt;You don't need a massive platform overhaul to start closing this gap. Here's a reasonable starting sequence.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step one: log the full trace, not just the final output&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;log_llm_call&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;prompt&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;retrieved_docs&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;metadata&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;trace&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;timestamp&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;datetime&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;utcnow&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;prompt&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;prompt&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;retrieved_context&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;retrieved_docs&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;response&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;token_count&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;metadata&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;tokens&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;latency_ms&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;metadata&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;latency&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;model_version&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;metadata&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;model&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;trace_store&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;save&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;trace&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Without the full trace, a bad output down the line is nearly impossible to debug. Was it a bad retrieval, a bad prompt, or a bad model response? You can't tell from the final answer alone.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step two: run automated quality scoring on a sample of live traffic&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;score_response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;prompt&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;retrieved_docs&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;faithfulness&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;check_grounded_in_context&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;retrieved_docs&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;relevance&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;check_relevance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;prompt&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;hallucination_risk&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;detect_unsupported_claims&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;retrieved_docs&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;Scoring every single production response can be expensive, but sampling a meaningful percentage catches drift long before it becomes a visible pattern to users.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step three: set alerts on quality signals, not just infrastructure signals&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;quality_scores&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;faithfulness&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mf"&gt;0.7&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="nf"&gt;alert_team&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;Faithfulness score dropped: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;quality_scores&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A latency alert tells you something broke. A faithfulness or drift alert tells you something is quietly getting worse, which is the failure mode that actually damages user trust over time.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step four: track cost per feature, not just cost in aggregate&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;cost_by_feature&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;defaultdict&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;float&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;cost_by_feature&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;feature_name&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;token_count&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;cost_per_token&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A single feature quietly ballooning in token usage is easy to miss in an aggregate monthly bill and very easy to catch when broken down by feature and tracked over time.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step five: close the loop by feeding failures back into evaluation&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Every flagged failure should become part of an ongoing evaluation dataset, not a one-off fire drill. This is what actually improves the system over time instead of just reacting to the same category of failure repeatedly.&lt;/p&gt;

&lt;h2&gt;
  
  
  Real Numbers Worth Knowing
&lt;/h2&gt;

&lt;p&gt;The scale of this gap is bigger than most teams assume. A large share of enterprises now require AI monitoring in production, yet a majority cite a lack of adequate observability tooling as a major barrier to actually having it. That gap between what teams know they need and what they've actually built is exactly where the invisible failures described above tend to live.&lt;/p&gt;

&lt;p&gt;Evaluation overhead itself is a real cost too. Adding a full evaluation pass to a live request can meaningfully increase response latency, which is part of why the emerging best practice for 2026 is combining lightweight in-line scoring on every request with deeper evaluation sampling run asynchronously, rather than trying to fully evaluate every single response in the live path.&lt;/p&gt;

&lt;h2&gt;
  
  
  Common Mistakes Teams Make Getting Started
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Treating LLM observability as identical to traditional APM and only tracking latency and error rates, missing quality entirely&lt;/li&gt;
&lt;li&gt;Scoring 100 percent of production traffic with an expensive evaluation model, which quietly doubles response latency and cost&lt;/li&gt;
&lt;li&gt;Building alerts only for hard failures and missing the slow, gradual drift that's actually the more common failure pattern&lt;/li&gt;
&lt;li&gt;Never closing the loop between a caught failure and an updated evaluation dataset, so the same category of mistake keeps recurring&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Why This Is Worth Building Properly
&lt;/h2&gt;

&lt;p&gt;Getting this right touches more than one layer, evaluation design, tracing infrastructure, alerting thresholds, and cost monitoring all need to work together rather than existing as disconnected tools. For teams without dedicated MLOps or AI infrastructure specialists on staff already, building this from scratch while also shipping product features is a genuinely heavy lift. &lt;strong&gt;&lt;a href="https://zignuts.com/ai-services/ai-integration?utm_source=seo&amp;amp;utm_medium=backlinks&amp;amp;utm_campaign=seo_referral&amp;amp;utm_id=7" rel="noopener noreferrer"&gt;Custom AI integration&lt;/a&gt;&lt;/strong&gt; and observability setup, done by people who've built this exact monitoring layer before, tends to get a team from flying blind to genuinely production-grade visibility far faster than assembling it piecemeal under deadline pressure.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Takeaway
&lt;/h2&gt;

&lt;p&gt;A green dashboard doesn't mean your AI feature is actually working well, it means the parts of it that traditional monitoring knows how to measure are working. The parts that actually matter to users, whether the answer was true, relevant, and useful, live in a layer most teams still aren't watching. That gap is exactly what LLM observability exists to close, and closing it early is a lot cheaper than discovering the failure the way most teams still do, from a customer complaint.&lt;/p&gt;

&lt;p&gt;Is your team actually tracking AI output quality in production, or is your monitoring stack still only watching the infrastructure layer? Curious how many of us have actually closed this gap yet.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>machinelearning</category>
      <category>devops</category>
      <category>discuss</category>
    </item>
    <item>
      <title>Your App Is Fast Enough. It's Also Quietly Burning More Energy Than It Needs To.</title>
      <dc:creator>Emma Schmidt</dc:creator>
      <pubDate>Thu, 23 Jul 2026 12:12:35 +0000</pubDate>
      <link>https://dev.to/emma_schmidt_/your-app-is-fast-enough-its-also-quietly-burning-more-energy-than-it-needs-to-1ehp</link>
      <guid>https://dev.to/emma_schmidt_/your-app-is-fast-enough-its-also-quietly-burning-more-energy-than-it-needs-to-1ehp</guid>
      <description>&lt;p&gt;&lt;strong&gt;Tags:&lt;/strong&gt; #sustainability #cloudcomputing #webdev #discuss&lt;br&gt;
Somewhere in your cloud bill this month, there's a number nobody on your team has ever really looked at: how much energy your application actually consumes to do its job. Not cost, energy. Every unnecessary database query, every bloated Docker image, every inefficient loop running at scale is drawing real power from a real data center, and most engineering teams have never once measured it. This gets even more pressing once &lt;strong&gt;&lt;a href="https://zignuts.com/ai-services?utm_source=seo&amp;amp;utm_medium=backlinks&amp;amp;utm_campaign=seo_referral&amp;amp;utm_id=7" rel="noopener noreferrer"&gt;AI services&lt;/a&gt;&lt;/strong&gt; enter the picture, since AI inference is one of the most energy-hungry workloads a modern application can run, and it's exactly where a lot of this invisible waste tends to hide first.&lt;/p&gt;

&lt;p&gt;That's starting to change fast, and not because of idealism. Green coding, writing and architecting software specifically to minimize energy consumption, has moved from a nice-to-have sustainability talking point to a genuine engineering discipline businesses are being pushed toward from multiple directions at once.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why This Is Suddenly Everyone's Problem
&lt;/h2&gt;

&lt;p&gt;A few forces are converging here, and none of them are going away.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Cloud costs and energy consumption are now directly linked&lt;/strong&gt; in a way they weren't a few years ago, as providers increasingly price compute in ways that reflect actual power draw, not just raw usage time&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Regulatory pressure is rising&lt;/strong&gt; in multiple regions requiring companies to report on and reduce their digital carbon footprint, and software energy use is a growing line item in those reports&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;AI workloads specifically have made this urgent.&lt;/strong&gt; Training and running &lt;strong&gt;&lt;a href="https://zignuts.com/ai-models?utm_source=seo&amp;amp;utm_medium=backlinks&amp;amp;utm_campaign=seo_referral&amp;amp;utm_id=7" rel="noopener noreferrer"&gt;AI models&lt;/a&gt;&lt;/strong&gt; is extraordinarily energy intensive, and companies bolting AI features onto every product are watching their infrastructure energy costs climb in ways that are hard to ignore&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Customers and investors are starting to ask.&lt;/strong&gt; Sustainability reporting increasingly includes technology stack efficiency, not just the usual categories like travel and office energy use&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Data center capacity itself is becoming a real constraint&lt;/strong&gt;, with some regions seeing power grid strain directly tied to the growth of compute-heavy workloads, which puts pressure back on the software layer to use less of it&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;None of this requires anyone to care personally about the planet to take it seriously. It's becoming a real line item, a real compliance risk, and a real cost center.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Inefficient Code Actually Looks Like at Scale
&lt;/h2&gt;

&lt;p&gt;Here's the part that surprises people. None of this requires exotic new practices. It's mostly ordinary engineering habits that were never a priority because energy cost was invisible.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;N+1 queries running millions of times a day&lt;/strong&gt; across a large user base, each one drawing real compute and real power for work that could've been a single efficient join&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Polling instead of event-driven updates&lt;/strong&gt;, where a client checks for new data every few seconds indefinitely, burning compute around the clock for data that changes rarely&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Oversized container images&lt;/strong&gt; that take longer to build, deploy, and run than they need to, multiplied across every deployment and every autoscaling event&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Unoptimized AI inference calls&lt;/strong&gt;, sending far more tokens or running a larger model than the task actually requires, when a smaller, purpose-built model would do the job with a fraction of the energy draw&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Idle infrastructure left running&lt;/strong&gt; in staging and development environments around the clock, consuming power for workloads nobody's actually using outside business hours&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Unbounded background jobs&lt;/strong&gt; that retry endlessly or run on overly aggressive schedules, quietly consuming compute for work that could run a fraction as often&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Individually, each of these looks like a minor inefficiency. At the scale most production systems run at, they add up to a genuinely significant amount of wasted energy and wasted money, quietly, every single day.&lt;/p&gt;

&lt;h2&gt;
  
  
  A Real-World Example of How This Adds Up
&lt;/h2&gt;

&lt;p&gt;Take a mid-sized ecommerce platform serving a few million requests a day. Picture a single product page that fires an N+1 query pattern loading reviews, one that polls every three seconds for inventory updates that actually change a few times an hour, and a recommendation feature calling a large general-purpose AI model when a lightweight, purpose-built model would return the same quality of result.&lt;/p&gt;

&lt;p&gt;None of those three issues, on their own, would ever show up as an incident. No outage, no page, no angry customer email. But multiplied across millions of page loads a day, that's a meaningful chunk of unnecessary compute running continuously, month after month, for work that could've been a fraction of the size with no visible change to the user experience at all. That's the actual shape of this problem in most real production systems: not one dramatic failure, but a thousand small, invisible ones running constantly.&lt;/p&gt;

&lt;h2&gt;
  
  
  A Practical Starting Point
&lt;/h2&gt;

&lt;p&gt;You don't need a sustainability team to start improving this. A few concrete places to look first.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Audit your database query patterns&lt;/strong&gt;&lt;br&gt;
Look specifically for N+1 patterns and queries running far more often than the data actually changes. This is usually the single highest-impact place to start, because database load scales directly with both cost and energy draw.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Replace polling with event-driven architecture where you can&lt;/strong&gt;&lt;br&gt;
A webhook or a push notification that fires only when something actually changes uses a fraction of the compute of a client checking in every few seconds forever.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Right-size your AI model usage&lt;/strong&gt;&lt;br&gt;
Not every task needs the largest, most capable model available. Matching model size to task complexity is one of the fastest-growing cost and energy savings levers teams are finding this year, precisely because so many teams default to the biggest model out of convenience rather than necessity.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Shut down idle environments automatically&lt;/strong&gt;&lt;br&gt;
Staging and dev environments running 24/7 for workloads only used during business hours are pure waste. Automated shutdown schedules are a low-effort, high-impact fix.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Batch and schedule background work intelligently&lt;/strong&gt;&lt;br&gt;
Jobs that run every minute out of habit rather than necessity are an easy, low-risk place to cut unnecessary compute cycles without touching anything user-facing.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Measure before you optimize&lt;/strong&gt;&lt;br&gt;
Most teams have never actually measured their application's energy footprint because the tooling to do it wasn't mainstream until recently. You can't meaningfully improve what you've never measured.&lt;/p&gt;

&lt;h2&gt;
  
  
  A Quick Self-Check
&lt;/h2&gt;

&lt;p&gt;Before deciding this doesn't apply to your team, answer these honestly.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Do you know which endpoints in your application generate the most database load relative to how often that data actually changes?&lt;/li&gt;
&lt;li&gt;Are any of your staging or dev environments running continuously, with nobody checking whether they need to be?&lt;/li&gt;
&lt;li&gt;Is your team defaulting to the largest available AI model for every task, regardless of how simple the task actually is?&lt;/li&gt;
&lt;li&gt;Has anyone ever pulled a report on your cloud provider's energy or carbon metrics, or does that dashboard exist unopened?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If more than one of these gave you pause, there's likely real, low-risk savings sitting in your stack right now, unmeasured and unaddressed.&lt;/p&gt;

&lt;h2&gt;
  
  
  Common Questions Teams Ask When Starting This
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Does this require rewriting our whole application?&lt;/strong&gt;&lt;br&gt;
Almost never. Most of the highest-impact fixes, like resolving N+1 queries or shutting down idle environments, are targeted, low-risk changes rather than architectural rewrites.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Will this slow down feature development?&lt;/strong&gt;&lt;br&gt;
An initial audit takes focused time, but the fixes that come out of it are usually incremental and can be folded into normal sprint work rather than requiring a dedicated multi-month initiative.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Is this only relevant for very large-scale applications?&lt;/strong&gt;&lt;br&gt;
The savings scale with traffic, but the underlying inefficiencies exist at any scale. Catching them early is actually easier and cheaper than untangling them after years of accumulated scale.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why This Matters Beyond the Obvious
&lt;/h2&gt;

&lt;p&gt;There's a business case here independent of any environmental motivation. Energy-efficient code tends to correlate strongly with genuinely well-architected code. The same discipline that reduces unnecessary compute cycles also reduces latency, reduces cloud spend, and reduces the blast radius of scaling problems under real traffic. Teams chasing energy efficiency usually end up with a faster, cheaper, more resilient system as a side effect, not a tradeoff.&lt;/p&gt;

&lt;p&gt;This is also exactly the kind of work that benefits from a proper audit rather than scattered fixes. Untangling inefficient query patterns, right-sizing infrastructure, and rearchitecting around event-driven patterns across an existing production system touches database design, cloud architecture, and AI services integration all at once, which is a lot to take on internally while also shipping new features on the usual roadmap. A dedicated cloud architecture and performance audit, done by people who've mapped this exact kind of waste before, tends to surface savings that are easy to miss when you're deep inside your own codebase every day.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Takeaway
&lt;/h2&gt;

&lt;p&gt;The energy your code consumes was always real, it just wasn't visible on a dashboard anyone was watching. As regulation tightens, AI workloads grow, and cloud providers price compute closer to its real power draw, that invisibility is disappearing fast. The teams getting ahead of this now aren't doing it out of idealism, they're doing it because efficient code was always going to be cheaper, faster, and more resilient too, the environmental benefit just happens to come along for free.&lt;/p&gt;

&lt;p&gt;Has your team ever actually measured your application's energy footprint, or is it still an invisible number buried somewhere in a cloud bill nobody's dug into? Curious how many of us are actually tracking this yet.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>discuss</category>
    </item>
    <item>
      <title>Prompt Engineering Is Dead. Context Engineering Is What Actually Fixes Your AI's Wrong Answers.</title>
      <dc:creator>Emma Schmidt</dc:creator>
      <pubDate>Wed, 22 Jul 2026 10:54:05 +0000</pubDate>
      <link>https://dev.to/emma_schmidt_/prompt-engineering-is-dead-context-engineering-is-what-actually-fixes-your-ais-wrong-answers-2ejg</link>
      <guid>https://dev.to/emma_schmidt_/prompt-engineering-is-dead-context-engineering-is-what-actually-fixes-your-ais-wrong-answers-2ejg</guid>
      <description>&lt;p&gt;You've tuned the prompt a dozen times. Added examples, adjusted the tone, tried three different phrasings of the same instruction. The AI still hallucinates a fact, misses context from earlier in the conversation, or confidently answers a question using the wrong data. If this sounds familiar, the problem was never the prompt. It's what's called context engineering, and it's quietly become one of the most important skills in &lt;strong&gt;&lt;a href="https://zignuts.com/ai-services?utm_source=seo&amp;amp;utm_medium=backlinks&amp;amp;utm_campaign=seo_referral&amp;amp;utm_id=7" rel="noopener noreferrer"&gt;AI development&lt;/a&gt;&lt;/strong&gt; this year. Teams that get this right often lean on structured AI development and integration services specifically because getting the architecture right the first time avoids months of trial-and-error prompt tweaking that never actually fixes the root cause.&lt;/p&gt;

&lt;p&gt;Here's what context engineering actually is, why it matters more than clever prompting, and how to build it into a real application step by step.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Prompt Engineering Alone Stops Working
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://zignuts.com/hire-prompt-engineer?utm_source=seo&amp;amp;utm_medium=backlinks&amp;amp;utm_campaign=seo_referral&amp;amp;utm_id=7" rel="noopener noreferrer"&gt;Prompt engineering&lt;/a&gt;&lt;/strong&gt; treats the model like a black box you talk to more cleverly. Context engineering treats the entire system around the model, what data it sees, in what order, and how it's structured, as the thing you actually design.&lt;/p&gt;

&lt;p&gt;Here's the distinction that matters:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Prompt engineering&lt;/strong&gt; optimizes the instruction you give the model in a single message&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Context engineering&lt;/strong&gt; optimizes everything the model has access to when it generates that response: retrieved documents, conversation history, system instructions, tool outputs, and how all of that is assembled and prioritized&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A perfectly worded prompt pointed at the wrong or poorly organized context still produces a wrong answer. This is why teams that only tune prompts eventually hit a wall, no phrasing fixes a model that's missing the right information entirely.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Core Problem You're Actually Solving
&lt;/h2&gt;

&lt;p&gt;Every AI application built on top of a language model faces the same limitation: a fixed context window and no persistent memory between calls. Context engineering is the discipline of deciding what goes into that limited space and how it's organized so the model can actually use it well.&lt;/p&gt;

&lt;p&gt;Get this wrong and you'll see familiar symptoms:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The model confidently answers using outdated or irrelevant retrieved data&lt;/li&gt;
&lt;li&gt;Earlier parts of a long conversation get silently dropped or ignored&lt;/li&gt;
&lt;li&gt;Retrieved documents get stuffed in with no clear structure, and the model can't tell what's actually relevant&lt;/li&gt;
&lt;li&gt;Adding more context makes answers worse, not better, because signal gets buried in noise&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Building a Real Context Pipeline, Step by Step
&lt;/h2&gt;

&lt;p&gt;Let's walk through building this properly, using a support chatbot pulling from a knowledge base as the example.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step one: separate your context into clear categories&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;context&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;system_instructions&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;You are a support assistant for Acme SaaS...&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;retrieved_docs&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[],&lt;/span&gt;       &lt;span class="c1"&gt;# from your knowledge base
&lt;/span&gt;    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;conversation_history&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[],&lt;/span&gt; &lt;span class="c1"&gt;# prior turns in this session
&lt;/span&gt;    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;user_profile&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{},&lt;/span&gt;         &lt;span class="c1"&gt;# account tier, past tickets, etc
&lt;/span&gt;    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;current_query&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;""&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Treating these as separate, labeled components instead of one giant blob of text is the single biggest shift from prompt engineering to context engineering. It lets you control, debug, and prioritize each piece independently.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step two: retrieve only what's actually relevant&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;retrieve_context&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;top_k&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;query_embedding&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;embed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;results&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;vector_db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;search&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;query_embedding&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;top_k&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;top_k&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;results&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;score&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mf"&gt;0.75&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Notice the relevance threshold. Pulling in five loosely related documents to "give the model more to work with" usually makes answers worse, not better. Fewer, highly relevant documents consistently outperform a large pile of mediocre ones.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step three: manage conversation history deliberately, not by just appending everything&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;build_history&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;max_turns&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;recent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;max_turns&lt;/span&gt;&lt;span class="p"&gt;:]&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;max_turns&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;summary&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;summarize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;[:&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;max_turns&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;role&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;system&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;content&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Earlier context: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;summary&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="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;recent&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;recent&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Long conversations without this kind of management silently push early, important context out of the window entirely. Summarizing older turns instead of dropping them keeps continuity without blowing the token budget.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step four: assemble everything with clear structure, not a wall of text&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;build_prompt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;
System: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;context&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_instructions&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;

Relevant documentation:
&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nf"&gt;format_docs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;retrieved_docs&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;

Conversation so far:
&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nf"&gt;format_history&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;conversation_history&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;

User profile: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;user_profile&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;

Current question: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;current_query&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;
&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Clear section labels matter more than they seem like they should. Models handle structured, clearly delineated context noticeably better than the same information dumped in as one undifferentiated paragraph.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step five: test with adversarial and edge-case queries, not just the happy path&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;test_cases&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;question referencing something from 10 turns ago&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;question where retrieved docs are slightly outdated&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;question with no relevant docs in the knowledge base at all&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is the step most teams skip. A context pipeline that works great on clean, simple test queries often falls apart the moment a real user asks something messy, which is exactly when it matters most.&lt;/p&gt;

&lt;h2&gt;
  
  
  Common Mistakes Worth Knowing Before You Build This
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Context window stuffing.&lt;/strong&gt; Cramming in every possibly-relevant document instead of the few genuinely relevant ones, which drowns out the signal&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No relevance filtering on retrieval.&lt;/strong&gt; Returning the top results regardless of how weak the match actually is&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Flat, unstructured context.&lt;/strong&gt; Pasting everything into one block of text with no labeled sections for the model to anchor on&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Ignoring token budget until it breaks.&lt;/strong&gt; Not tracking how much of the context window is consumed by each component until responses start silently truncating&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No evaluation loop.&lt;/strong&gt; Shipping the pipeline without a way to systematically test whether context changes actually improved or hurt answer quality&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The Takeaway
&lt;/h2&gt;

&lt;p&gt;If your AI feature is giving inconsistent or wrong answers and you've already spent real time tuning the prompt, the prompt was probably never the actual problem. Look at what the model can see when it answers, how it's retrieved, how it's structured, and how much of it is genuinely relevant. That's where the real fix usually lives.&lt;/p&gt;

&lt;p&gt;Have you run into this wall yet, prompt tuning stops helping and the real fix turns out to be the context pipeline underneath it? Curious what broke it open for you.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>machinelearning</category>
      <category>tutorial</category>
      <category>python</category>
    </item>
  </channel>
</rss>
