<?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: Marc Newstead</title>
    <description>The latest articles on DEV Community by Marc Newstead (@icentric).</description>
    <link>https://dev.to/icentric</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%2F3929651%2Ffa7f595b-8a59-45da-b8be-ee66e3feab4d.png</url>
      <title>DEV Community: Marc Newstead</title>
      <link>https://dev.to/icentric</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/icentric"/>
    <language>en</language>
    <item>
      <title>Why Your E-commerce API Needs an llms.txt File (Before Your Competitors Add One)</title>
      <dc:creator>Marc Newstead</dc:creator>
      <pubDate>Mon, 24 Aug 2026 09:04:55 +0000</pubDate>
      <link>https://dev.to/icentric/why-your-e-commerce-api-needs-an-llmstxt-file-before-your-competitors-add-one-24ee</link>
      <guid>https://dev.to/icentric/why-your-e-commerce-api-needs-an-llmstxt-file-before-your-competitors-add-one-24ee</guid>
      <description>&lt;h2&gt;
  
  
  Why Your E-commerce API Needs an llms.txt File (Before Your Competitors Add One)
&lt;/h2&gt;

&lt;p&gt;Last week, a client asked me why their product pages weren't showing up in ChatGPT's shopping recommendations. My first question: "Do you have an llms.txt file?" Blank stare.&lt;/p&gt;

&lt;p&gt;If you're building or maintaining an e-commerce platform, AI agents are about to become your most important traffic source—and they don't browse like humans do.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Problem: AI Agents Don't Click Around
&lt;/h2&gt;

&lt;p&gt;When a user asks Claude or ChatGPT to "find me the best wireless headphones under £150," the agent doesn't open Chrome and click through your navigation. It queries structured data sources, calls APIs, and follows machine-readable conventions.&lt;/p&gt;

&lt;p&gt;Your beautifully designed product pages? Invisible.&lt;/p&gt;

&lt;p&gt;Your carefully crafted category descriptions? Wasted.&lt;/p&gt;

&lt;p&gt;Unless you expose your catalogue in a way LLMs can actually consume, you're not in the game.&lt;/p&gt;

&lt;h2&gt;
  
  
  Enter llms.txt: The New Robots.txt
&lt;/h2&gt;

&lt;p&gt;Remember when &lt;code&gt;robots.txt&lt;/code&gt; was optional? Then suddenly every site needed one to control crawler behaviour. We're at that inflection point again.&lt;/p&gt;

&lt;p&gt;An &lt;code&gt;llms.txt&lt;/code&gt; file (typically served at &lt;code&gt;https://yoursite.com/llms.txt&lt;/code&gt;) tells AI agents:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What your site does&lt;/li&gt;
&lt;li&gt;Where to find structured data&lt;/li&gt;
&lt;li&gt;Which endpoints support agent queries&lt;/li&gt;
&lt;li&gt;Authentication requirements&lt;/li&gt;
&lt;li&gt;Rate limits and usage policies&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here's a minimal example for an e-commerce site:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# llms.txt for MyShop

## Purpose
E-commerce site selling consumer electronics

## Structured Data Endpoints
- Product catalogue: /api/v1/products (JSON-LD)
- Search: /api/v1/search?q={query}
- Product detail: /api/v1/products/{id}

## Authentication
API key required: docs at /api/docs

## Rate Limits
100 requests/minute per key

## Contact
api-support@myshop.com
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Simple, machine-readable, and it takes 15 minutes to implement.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Agents Actually Need From Your API
&lt;/h2&gt;

&lt;p&gt;Beyond the &lt;code&gt;llms.txt&lt;/code&gt; file, make sure your endpoints return:&lt;/p&gt;

&lt;h3&gt;
  
  
  1. &lt;strong&gt;Clean JSON or JSON-LD&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;No HTML scraping. Agents want structured product data:&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;"@context"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://schema.org"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"@type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Product"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Wireless Headphones Pro"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"price"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"129.99"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"priceCurrency"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"GBP"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"availability"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"InStock"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"aggregateRating"&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;"@type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"AggregateRating"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"ratingValue"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"4.5"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"reviewCount"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"287"&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;h3&gt;
  
  
  2. &lt;strong&gt;Real-time Stock and Pricing&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Agents won't recommend out-of-stock items. Your API should return current availability, not cached values from three days ago.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. &lt;strong&gt;Clear Return and Shipping Policies&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Include machine-readable policy data. Agents compare these when making recommendations.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. &lt;strong&gt;Secure, Documented Checkout Flows&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;If you want agents to complete purchases, your checkout API needs OAuth2 support and clear documentation. The agent needs to act on behalf of an authenticated user.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why This Matters Right Now
&lt;/h2&gt;

&lt;p&gt;Early movers in SEO built link equity that competitors couldn't touch for years. &lt;a href="https://www.icentricagency.com/insights/agentic-commerce-preparing-your-website-for-ai-shopping-agents" rel="noopener noreferrer"&gt;Agentic commerce&lt;/a&gt; creates a similar first-mover advantage.&lt;/p&gt;

&lt;p&gt;Once an AI agent successfully transacts with your site, that interaction becomes training data. The agent learns your inventory structure, pricing patterns, and reliability. Competitors entering later face an uphill battle.&lt;/p&gt;

&lt;p&gt;Plus, LLM providers are actively building partnerships with early adopters. OpenAI's plugin marketplace prioritised sites with clean APIs and good documentation. The same dynamic will play out with shopping agents.&lt;/p&gt;

&lt;h2&gt;
  
  
  Getting Started This Week
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Monday:&lt;/strong&gt; Audit your existing APIs. Do you expose product data in structured JSON? Is your search endpoint agent-friendly?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Tuesday:&lt;/strong&gt; Create an &lt;code&gt;llms.txt&lt;/code&gt; file. Use the template above. Deploy it to your root domain.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Wednesday:&lt;/strong&gt; Add JSON-LD markup to your product pages if you haven't already. Use Schema.org's Product type.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Thursday:&lt;/strong&gt; Document your API. OpenAPI specs are ideal. Host the docs at a stable URL and reference them in your &lt;code&gt;llms.txt&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Friday:&lt;/strong&gt; Test it. Ask ChatGPT or Claude to search your catalogue. See what happens.&lt;/p&gt;

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

&lt;p&gt;This isn't just about being "AI-ready." It's about building APIs that are actually useful—to agents, to mobile apps, to your own frontend team. The discipline of making your data machine-readable pays dividends everywhere.&lt;/p&gt;

&lt;p&gt;If you're working on a larger digital transformation around &lt;a href="https://www.icentricagency.com" rel="noopener noreferrer"&gt;AI automation and software development&lt;/a&gt;, treating your e-commerce platform as an API-first system positions you well for whatever interface comes next—whether that's voice assistants, AR shopping, or something we haven't imagined yet.&lt;/p&gt;

&lt;p&gt;The web is shifting from pages to protocols. Your competitors are already noticing. Make sure you're not left behind.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>ecommerce</category>
      <category>webdev</category>
      <category>api</category>
    </item>
    <item>
      <title>Building for Agentic Commerce: What Devs Need to Know Before It's Too Late</title>
      <dc:creator>Marc Newstead</dc:creator>
      <pubDate>Mon, 24 Aug 2026 09:02:18 +0000</pubDate>
      <link>https://dev.to/icentric/building-for-agentic-commerce-what-devs-need-to-know-before-its-too-late-6ej</link>
      <guid>https://dev.to/icentric/building-for-agentic-commerce-what-devs-need-to-know-before-its-too-late-6ej</guid>
      <description>&lt;h2&gt;
  
  
  Building for Agentic Commerce: What Devs Need to Know Before It's Too Late
&lt;/h2&gt;

&lt;p&gt;If you're building ecommerce systems right now, here's something worth thinking about: what happens when your customers aren't humans anymore?&lt;/p&gt;

&lt;p&gt;I don't mean this in a sci-fi dystopia way. I mean practically, architecturally — what changes when an AI agent, not a person clicking through your checkout flow, becomes a first-class user of your system?&lt;/p&gt;

&lt;h2&gt;
  
  
  The Technical Shift That's Coming
&lt;/h2&gt;

&lt;p&gt;Agentic commerce isn't about chatbots that help you find products. It's about delegation at the transaction level. A user says "keep me stocked on coffee beans, optimise for price and delivery" and an agent — with its own credentials, budget, and decision-making logic — handles the rest.&lt;/p&gt;

&lt;p&gt;From a dev perspective, this creates some genuinely new problems:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Authentication that isn't human-centric&lt;/strong&gt;: OAuth flows assume a person clicking buttons. What does auth look like when the client is an autonomous process making purchasing decisions across dozens of merchants?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Rate limiting and bot detection&lt;/strong&gt;: Your current bot protection is designed to &lt;em&gt;block&lt;/em&gt; automated purchasing. Now you need to &lt;em&gt;enable&lt;/em&gt; it, but only for legitimate agents.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Transaction context&lt;/strong&gt;: When a purchase goes wrong, you can't just email the customer. The agent made the call. Who do you notify? What's the rollback protocol?&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Who Sits Between the Agent and Your API?
&lt;/h2&gt;

&lt;p&gt;Here's where it gets commercially interesting, and why I think this matters to you even if you're just shipping features today.&lt;/p&gt;

&lt;p&gt;When humans shop, trust infrastructure is invisible: HTTPS, payment card networks, browser security models. We built all of that over decades.&lt;/p&gt;

&lt;p&gt;With agents, that &lt;a href="https://www.icentricagency.com/insights/agentic-commerce-why-the-trust-layer-is-the-new-battleground" rel="noopener noreferrer"&gt;trust layer&lt;/a&gt; doesn't exist yet — and whoever builds it will control a &lt;em&gt;lot&lt;/em&gt;. Think about:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Agent registries&lt;/strong&gt;: Who certifies that an agent is acting on behalf of a real user with real funds?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Merchant discovery protocols&lt;/strong&gt;: How does an agent even find your API? Is there an agent-readable product feed spec we all converge on?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Dispute resolution&lt;/strong&gt;: When an agent makes a mistake, who mediates? The agent provider? The payment network? A new intermediary?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This isn't theoretical. If you're building &lt;a href="https://www.icentricagency.com" rel="noopener noreferrer"&gt;AI automation and software development&lt;/a&gt; systems, you're already adjacent to this problem space.&lt;/p&gt;

&lt;h2&gt;
  
  
  What You Can Do Right Now
&lt;/h2&gt;

&lt;p&gt;You don't need to rebuild your entire stack, but there are some practical steps worth considering:&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Make your API agent-friendly
&lt;/h3&gt;

&lt;p&gt;If your ecommerce API is designed exclusively for SPAs and mobile apps, it's going to struggle with agents.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Instead of requiring session cookies:&lt;/span&gt;
&lt;span class="nx"&gt;GET&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;products&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt;&lt;span class="nx"&gt;category&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nx"&gt;coffee&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nx"&gt;sort&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nx"&gt;price&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nx"&gt;delivery_speed&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nx"&gt;fast&lt;/span&gt;
&lt;span class="nx"&gt;Authorization&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Bearer&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;agent_token&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;

&lt;span class="c1"&gt;// Return structured, parseable data&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;products&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;_meta&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;agent_hints&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;reorder_eligible&lt;/span&gt;&lt;span class="dl"&gt;"&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;subscription_available&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  2. Instrument for non-human transaction patterns
&lt;/h3&gt;

&lt;p&gt;Your monitoring and analytics probably assume human behaviour: sessions, cart abandonment, browsing patterns.&lt;/p&gt;

&lt;p&gt;Start logging and flagging agent-initiated transactions separately. You'll want to understand:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Purchase frequency and timing patterns&lt;/li&gt;
&lt;li&gt;Decision speed (agents won't browse for 10 minutes)&lt;/li&gt;
&lt;li&gt;Price sensitivity and optimisation behaviour&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  3. Design for delegation, not impersonation
&lt;/h3&gt;

&lt;p&gt;When an agent acts, it's not &lt;em&gt;pretending&lt;/em&gt; to be the user. It's acting &lt;em&gt;on behalf of&lt;/em&gt; the user. That's a meaningful distinction.&lt;/p&gt;

&lt;p&gt;Your data models should capture:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="n"&gt;orders&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="n"&gt;UUID&lt;/span&gt; &lt;span class="k"&gt;PRIMARY&lt;/span&gt; &lt;span class="k"&gt;KEY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;user_id&lt;/span&gt; &lt;span class="n"&gt;UUID&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;placed_by_agent_id&lt;/span&gt; &lt;span class="n"&gt;UUID&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="c1"&gt;-- null if human&lt;/span&gt;
  &lt;span class="n"&gt;agent_authority_token&lt;/span&gt; &lt;span class="nb"&gt;TEXT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="c1"&gt;-- verifiable delegation proof&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;h2&gt;
  
  
  The Bit No One's Solved Yet
&lt;/h2&gt;

&lt;p&gt;Liability and regulation are still wide open. If an agent makes an unauthorised purchase, who's responsible? If it violates terms of service, do you ban the agent? The user? Both?&lt;/p&gt;

&lt;p&gt;There's no case law. There's barely any industry consensus. But these questions will land on &lt;em&gt;your&lt;/em&gt; backlog when your product manager asks you to support agent-driven purchasing.&lt;/p&gt;

&lt;h2&gt;
  
  
  Bottom Line for Devs
&lt;/h2&gt;

&lt;p&gt;Agentic commerce isn't a 2030 problem. If you're in ecommerce, marketplace, or API platform engineering, this is a &lt;strong&gt;2025–2026 problem&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;You don't need to solve it all today, but you &lt;em&gt;do&lt;/em&gt; need to be thinking about:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;How your API will authenticate and rate-limit non-human clients&lt;/li&gt;
&lt;li&gt;What your transaction model looks like when the purchaser isn't clicking buttons&lt;/li&gt;
&lt;li&gt;Who you're architecturally betting on to provide the trust layer&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Because once that trust layer solidifies, migrating will be expensive. Better to have a point of view now.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>ecommerce</category>
      <category>api</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Stop Building AI Agents Like Scripts: A Loop Architecture Primer for Devs</title>
      <dc:creator>Marc Newstead</dc:creator>
      <pubDate>Mon, 17 Aug 2026 09:04:54 +0000</pubDate>
      <link>https://dev.to/icentric/stop-building-ai-agents-like-scripts-a-loop-architecture-primer-for-devs-1cg7</link>
      <guid>https://dev.to/icentric/stop-building-ai-agents-like-scripts-a-loop-architecture-primer-for-devs-1cg7</guid>
      <description>&lt;h2&gt;
  
  
  The Problem With Most AI Agent Code
&lt;/h2&gt;

&lt;p&gt;If you've shipped an AI agent recently, there's a decent chance it's basically a fancy script. You send a prompt, get a response, maybe chain a few calls together, log the output, done. That works fine for demos. But the moment you need that agent to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Decide whether its own output is good enough to proceed&lt;/li&gt;
&lt;li&gt;Spawn sub-agents to handle specific tasks&lt;/li&gt;
&lt;li&gt;Recover from API errors or hallucinated nonsense&lt;/li&gt;
&lt;li&gt;Explain &lt;em&gt;why&lt;/em&gt; it made a decision three steps ago&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;...your script falls apart.&lt;/p&gt;

&lt;p&gt;What you're missing is &lt;strong&gt;loop architecture&lt;/strong&gt; — the control structure that governs how agents reason, act, evaluate, and decide what to do next. Most teams treat this as an afterthought. It shouldn't be.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Loop Architecture Actually Looks Like
&lt;/h2&gt;

&lt;p&gt;Think of a loop architecture as the runtime for your agent. It's not the model, and it's not the prompt. It's the scaffolding that wraps around both and enforces:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;State management&lt;/strong&gt;: What has the agent done? What does it know?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Evaluation logic&lt;/strong&gt;: Did that action succeed? Should we retry, delegate, or stop?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Control flow&lt;/strong&gt;: What happens next? Do we loop again, call a different agent, or return to the user?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here's a toy example in pseudocode:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;AgentLoop&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;task&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;max_iterations&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;task&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;task&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;state&lt;/span&gt; &lt;span class="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;steps&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;status&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;running&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;max_iterations&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;max_iterations&lt;/span&gt;

    &lt;span class="k"&gt;def&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;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;iteration&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;while&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;status&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;running&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;iteration&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;max_iterations&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;action&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;reason&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;execute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;action&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;state&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;evaluate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;iteration&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;state&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;reason&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="c1"&gt;# LLM call: "given state, what should I do next?"
&lt;/span&gt;        &lt;span class="k"&gt;pass&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;execute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;action&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="c1"&gt;# Actually do the thing (API call, DB query, spawn sub-agent)
&lt;/span&gt;        &lt;span class="k"&gt;pass&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;evaluate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="c1"&gt;# LLM or deterministic check: did it work? update state accordingly
&lt;/span&gt;        &lt;span class="k"&gt;pass&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Notice the loop isn't endless. It has a budget. It checks its own output. It maintains state across iterations. That's the foundation.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Failure Modes You'll Hit
&lt;/h2&gt;

&lt;p&gt;Once you start building loops, you'll encounter these failure modes fast:&lt;/p&gt;

&lt;h3&gt;
  
  
  Runaway Spawning
&lt;/h3&gt;

&lt;p&gt;Your orchestrator agent decides every subtask needs its own agent. Suddenly you've got 47 LLM calls in parallel, your API quota is toast, and you have no idea which one caused the failure.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Fix&lt;/strong&gt;: Hard limits on spawn depth and breadth. Track the agent tree explicitly.&lt;/p&gt;

&lt;h3&gt;
  
  
  State Amnesia
&lt;/h3&gt;

&lt;p&gt;The agent forgets what it did two steps ago because you're not persisting state between calls. It repeats work, contradicts itself, or loops forever.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Fix&lt;/strong&gt;: Structured state (JSON, not vibes). Log every state transition. Make it queryable.&lt;/p&gt;

&lt;h3&gt;
  
  
  No Exit Strategy
&lt;/h3&gt;

&lt;p&gt;Your loop has no clear success or failure condition. It just… keeps going until it times out.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Fix&lt;/strong&gt;: Explicit halt conditions. "Task complete", "unrecoverable error", "max budget exceeded". Treat these as first-class citizens in your control flow.&lt;/p&gt;

&lt;h2&gt;
  
  
  Governance Isn't Optional (Especially in the UK)
&lt;/h2&gt;

&lt;p&gt;If you're building agents for finance, healthcare, legal, or public sector, you can't punt on governance. Loop architecture is where you enforce:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Audit trails&lt;/strong&gt;: every decision, every action, every state change&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Human-in-the-loop gates&lt;/strong&gt;: certain actions require approval before execution&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Rollback and replay&lt;/strong&gt;: if something breaks, you can rewind and debug&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This isn't theoretical. If your agent makes a decision that costs money or affects people, you need to be able to explain &lt;em&gt;why&lt;/em&gt; it did that. That explanation lives in your loop architecture, not in a vibe check of your prompt history.&lt;/p&gt;

&lt;p&gt;For a deeper dive into how loop architecture intersects with governance and enterprise constraints, the original piece on &lt;a href="https://www.icentricagency.com/insights/ai-loop-architecture-the-engineering-discipline-most-teams-are-missing" rel="noopener noreferrer"&gt;engineering discipline&lt;/a&gt; is worth reading.&lt;/p&gt;

&lt;h2&gt;
  
  
  Practical Next Steps
&lt;/h2&gt;

&lt;p&gt;If you're refactoring an existing agent or starting fresh:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Make state explicit&lt;/strong&gt;. Use a schema. Version it. Persist it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Define halt conditions upfront&lt;/strong&gt;. Success, failure, budget exhaustion.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Instrument everything&lt;/strong&gt;. Log state transitions, decisions, and evaluations. You'll need this when things break.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Set hard limits&lt;/strong&gt;. Max iterations, max spawn depth, max cost per loop.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Build eval into the loop&lt;/strong&gt;. Don't wait until prod to discover your agent hallucinates half the time.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If you're working with teams who need to scale this across regulated environments, agencies focused on &lt;a href="https://www.icentricagency.com" rel="noopener noreferrer"&gt;AI automation and software development&lt;/a&gt; often have reusable loop patterns and governance templates baked in.&lt;/p&gt;

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

&lt;p&gt;Loop architecture is the difference between a prototype that impresses in a demo and a system you can actually trust in production. Most teams skip this step because it's not as exciting as fine-tuning models or crafting clever prompts. But it's the scaffolding that makes everything else work.&lt;/p&gt;

&lt;p&gt;Treat your agent runtime like you'd treat any other critical system component: with discipline, observability, and respect for failure modes. Your future on-call self will thank you.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>architecture</category>
      <category>agents</category>
      <category>devops</category>
    </item>
    <item>
      <title>Your API Just Got Rolled Back: Building Resilience When AI Models Disappear</title>
      <dc:creator>Marc Newstead</dc:creator>
      <pubDate>Mon, 17 Aug 2026 09:02:14 +0000</pubDate>
      <link>https://dev.to/icentric/your-api-just-got-rolled-back-building-resilience-when-ai-models-disappear-5bag</link>
      <guid>https://dev.to/icentric/your-api-just-got-rolled-back-building-resilience-when-ai-models-disappear-5bag</guid>
      <description>&lt;h2&gt;
  
  
  Your API Just Got Rolled Back: Building Resilience When AI Models Disappear
&lt;/h2&gt;

&lt;p&gt;You wake up to Slack alerts. Your product's AI-powered feature is returning gibberish. You check the vendor's status page: "Model gpt-4-turbo-2024-04-09 deprecated effective immediately. Please migrate to gpt-4-turbo-2024-05-13."&lt;/p&gt;

&lt;p&gt;Sound familiar? If you're integrating third-party AI models into production systems, this isn't a hypothetical anymore. It's Tuesday.&lt;/p&gt;

&lt;p&gt;AI vendors have normalised something that would be unthinkable in traditional software: pulling products with little notice and treating it as routine maintenance. For developers building on these platforms, this changes everything about how we architect integrations.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why This Isn't Like Other Dependencies
&lt;/h2&gt;

&lt;p&gt;When you pin &lt;code&gt;lodash@4.17.21&lt;/code&gt; in your &lt;code&gt;package.json&lt;/code&gt;, you're done. That version behaves identically today, next month, and five years from now. The contract is simple: you control when you upgrade.&lt;/p&gt;

&lt;p&gt;AI model APIs break this contract fundamentally:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Model versions can vanish&lt;/strong&gt; with 30–90 days notice (sometimes less)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Behaviour drifts&lt;/strong&gt; even within the same version identifier&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Rollbacks happen&lt;/strong&gt; when vendors discover post-deployment issues&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Pricing changes&lt;/strong&gt; mid-lifecycle, making your current integration uneconomical&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This isn't a technical problem—it's a business model problem. When OpenAI serves 100 million users across thousands of products, they optimise for their platform economics, not your deployment schedule.&lt;/p&gt;

&lt;p&gt;Agencies working in &lt;a href="https://www.icentricagency.com" rel="noopener noreferrer"&gt;AI automation and software development&lt;/a&gt; have seen this pattern accelerate over the past 18 months. The vendors aren't being malicious; they're treating model deprecation as product hygiene.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Developer's Dilemma
&lt;/h2&gt;

&lt;p&gt;Let's make this concrete. You've built a feature that summarises support tickets using GPT-4. Your product manager loves it. Customers love it. Then the model gets pulled.&lt;/p&gt;

&lt;p&gt;Your options:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Migrate immediately&lt;/strong&gt; to the replacement model (which might behave differently, breaking your prompts)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Disable the feature&lt;/strong&gt; until you can properly test and migrate&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Switch vendors&lt;/strong&gt; entirely (requiring weeks of reintegration work)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;None of these are good. All of them create technical debt, user-facing issues, or both.&lt;/p&gt;

&lt;h2&gt;
  
  
  Defensive Architecture Patterns
&lt;/h2&gt;

&lt;p&gt;Here's what actually works when building on unstable AI foundations:&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Abstract the Model Layer
&lt;/h3&gt;

&lt;p&gt;Don't scatter OpenAI calls throughout your codebase:&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;// Bad: tightly coupled&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;summary&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;openai&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;chat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;completions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;model&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;gpt-4-turbo&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;messages&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="c1"&gt;// Better: abstraction layer&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;summary&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;aiService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;summarise&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;content&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;model&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ModelVersion&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;CURRENT_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 lets you swap implementations, A/B test models, or fall back to alternatives without touching business logic.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Version Your Prompts and Outputs
&lt;/h3&gt;

&lt;p&gt;Track which model version generated which output:&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="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;AISummary&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;content&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="nl"&gt;modelVersion&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="nl"&gt;generatedAt&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;tokensUsed&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="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When behaviour changes, you can identify which historical outputs might be affected.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Build Kill Switches
&lt;/h3&gt;

&lt;p&gt;Feature flags aren't optional—they're critical infrastructure:&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;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;featureFlags&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;isEnabled&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ai-summarisation&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;fallbackSummarisation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;content&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;You need the ability to disable AI features instantly without deploying code.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Monitor Model Behaviour, Not Just Uptime
&lt;/h3&gt;

&lt;p&gt;Traditional API monitoring (latency, error rates) isn't enough. You need to detect &lt;em&gt;behavioural&lt;/em&gt; drift:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Track output length distributions&lt;/li&gt;
&lt;li&gt;Sample outputs for quality checks&lt;/li&gt;
&lt;li&gt;Monitor user feedback signals (edits, deletions, complaints)&lt;/li&gt;
&lt;li&gt;Set up alerts for statistical anomalies&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If the new model suddenly produces 40% longer summaries, you want to know before your UI breaks.&lt;/p&gt;

&lt;h2&gt;
  
  
  What to Demand in SLAs
&lt;/h2&gt;

&lt;p&gt;Developers don't usually negotiate contracts, but you should be feeding requirements to whoever does. Push for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Minimum notice periods&lt;/strong&gt; for deprecations (90+ days)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Explicit version stability guarantees&lt;/strong&gt; (or lack thereof)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Rollback notification requirements&lt;/strong&gt; with severity definitions&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Testing access&lt;/strong&gt; to replacement models before forced migration&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The standard SLA template treats AI like SASS. It isn't. If your procurement team doesn't understand this, point them to resources that explain why &lt;a href="https://www.icentricagency.com/insights/ai-retractions-are-now-routine-is-your-sla-ready" rel="noopener noreferrer"&gt;SLAs need updating&lt;/a&gt; for AI integration.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Uncomfortable Truth
&lt;/h2&gt;

&lt;p&gt;No amount of defensive coding eliminates the fundamental risk: you're building on infrastructure you don't control, with stability guarantees that wouldn't be acceptable for any other dependency.&lt;/p&gt;

&lt;p&gt;That doesn't mean you shouldn't use AI APIs. It means you need to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Architect for failure&lt;/strong&gt; as a first-class concern&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Never make AI critical path&lt;/strong&gt; without a fallback&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Budget time&lt;/strong&gt; for unexpected migrations&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Document assumptions&lt;/strong&gt; about model behaviour&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Treat AI model integrations like you'd treat a startup's beta API: powerful, useful, and potentially unreliable. Build accordingly.&lt;/p&gt;

&lt;p&gt;The vendors have made their position clear through their actions. Now it's on us to build systems that can survive their product decisions.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>architecture</category>
      <category>devops</category>
      <category>api</category>
    </item>
    <item>
      <title>Why Your Multi-Agent AI System Is Probably a Ticking Time Bomb</title>
      <dc:creator>Marc Newstead</dc:creator>
      <pubDate>Mon, 10 Aug 2026 09:04:53 +0000</pubDate>
      <link>https://dev.to/icentric/why-your-multi-agent-ai-system-is-probably-a-ticking-time-bomb-3efc</link>
      <guid>https://dev.to/icentric/why-your-multi-agent-ai-system-is-probably-a-ticking-time-bomb-3efc</guid>
      <description>&lt;h2&gt;
  
  
  Why Your Multi-Agent AI System Is Probably a Ticking Time Bomb
&lt;/h2&gt;

&lt;p&gt;You've built a multi-agent AI system. Maybe it's a research assistant that spawns specialist agents, or a customer service orchestrator that delegates to domain experts. It works brilliantly in demos. Then you put it in production and watch your API costs explode, your logs fill with circular reasoning, and your agents start hallucinating confidently at scale.&lt;/p&gt;

&lt;p&gt;Sound familiar?&lt;/p&gt;

&lt;p&gt;The problem isn't your prompt engineering. It's that you're treating agent orchestration like a script when you should be treating it like distributed systems design.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Loop Is the System
&lt;/h2&gt;

&lt;p&gt;When you chain LLM calls together with the ability to spawn sub-tasks, you're not building a prompt anymore — you're building a control flow system with non-deterministic nodes. Each decision point is a potential branch. Each agent spawn is a potential infinite regress.&lt;/p&gt;

&lt;p&gt;Consider this pseudocode:&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;orchestrator&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;task&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;subtasks&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;llm&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;decompose&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;task&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="p"&gt;[]&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;subtask&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;subtasks&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nf"&gt;is_complex&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;subtask&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
            &lt;span class="n"&gt;results&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;orchestrator&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;subtask&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;  &lt;span class="c1"&gt;# Recursive call
&lt;/span&gt;        &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;results&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;specialist_agent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;subtask&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;llm&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;synthesize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;results&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Looks reasonable, right? Now ask yourself:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What stops infinite recursion if &lt;code&gt;is_complex()&lt;/code&gt; is LLM-based?&lt;/li&gt;
&lt;li&gt;How do you handle when a subtask legitimately requires 47 specialist calls?&lt;/li&gt;
&lt;li&gt;What's your budget ceiling before you cut off mid-execution?&lt;/li&gt;
&lt;li&gt;How do you debug why the orchestrator chose to spawn 12 agents instead of 3?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These aren't prompt problems. They're &lt;strong&gt;architectural&lt;/strong&gt; problems.&lt;/p&gt;

&lt;h2&gt;
  
  
  Three Things You Need to Design Explicitly
&lt;/h2&gt;

&lt;p&gt;If you're serious about production multi-agent systems, you need to treat loop design as a first-class engineering concern. That means explicitly designing:&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Spawning Logic
&lt;/h3&gt;

&lt;p&gt;Your orchestrator needs clear, testable rules for when to delegate. "Let the LLM decide" isn't good enough. You need guard rails:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;SpawnPolicy&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;max_depth&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;
    &lt;span class="n"&gt;max_children_per_node&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;
    &lt;span class="n"&gt;cost_ceiling_per_branch&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;float&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;0.50&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;should_spawn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;TaskContext&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;Decision&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;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;depth&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;max_depth&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;Decision&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;EXECUTE_INLINE&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;current_cost&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;estimated_cost&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;cost_ceiling&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;Decision&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SIMPLIFY&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;Decision&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DELEGATE&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This isn't about limiting capability — it's about &lt;strong&gt;predictable resource consumption&lt;/strong&gt;. Your spawning logic should be as observable and testable as any other system boundary.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. State Management
&lt;/h3&gt;

&lt;p&gt;When agents spawn agents, who owns the context? How do you avoid passing the entire conversation history to every spawned agent? What gets synthesised back up the chain?&lt;/p&gt;

&lt;p&gt;You need explicit state boundaries:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What context each agent receives&lt;/li&gt;
&lt;li&gt;What artifacts persist between calls&lt;/li&gt;
&lt;li&gt;How results get aggregated back to the orchestrator&lt;/li&gt;
&lt;li&gt;When to prune context to stay under token limits&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Treat your agent interactions like microservices. Define clear contracts.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Termination Conditions
&lt;/h3&gt;

&lt;p&gt;Your loop needs to know when to stop. Not just "when the task is done" (the LLM will &lt;em&gt;always&lt;/em&gt; think it can do more), but hard limits:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Maximum depth of delegation&lt;/li&gt;
&lt;li&gt;Token budget exhaustion&lt;/li&gt;
&lt;li&gt;Wall-clock timeout&lt;/li&gt;
&lt;li&gt;Confidence thresholds that trigger escalation to humans&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These should be baked into your architecture, not bolted on as an afterthought.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Production Reality Check
&lt;/h2&gt;

&lt;p&gt;The &lt;a href="https://www.icentricagency.com/insights/agentic-loop-engineering-the-ai-discipline-teams-are-missing" rel="noopener noreferrer"&gt;discipline teams are missing&lt;/a&gt; isn't about better prompts. It's about treating agentic loops with the same rigour you'd apply to any distributed system.&lt;/p&gt;

&lt;p&gt;That means:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Structured logging&lt;/strong&gt; at every spawn decision&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Distributed tracing&lt;/strong&gt; to visualise agent call trees&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Circuit breakers&lt;/strong&gt; to prevent runaway costs&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Regression tests&lt;/strong&gt; that validate spawn behaviour against known scenarios&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cost attribution&lt;/strong&gt; per logical task, not just per API call&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you're building &lt;a href="https://www.icentricagency.com" rel="noopener noreferrer"&gt;AI automation and software development&lt;/a&gt; capabilities into your product, these aren't nice-to-haves. They're survival basics.&lt;/p&gt;

&lt;h2&gt;
  
  
  Start Small, Instrument Everything
&lt;/h2&gt;

&lt;p&gt;You don't need to solve all of this on day one. But you do need to acknowledge that &lt;strong&gt;the loop is your architecture&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Start by making spawning decisions observable. Log every delegation. Visualise your call trees. Set hard cost ceilings. Build dashboards that show you &lt;em&gt;why&lt;/em&gt; an agent spawned five children instead of two.&lt;/p&gt;

&lt;p&gt;Then iterate. Because the alternative — hoping your multi-agent system behaves itself in production — is how you end up with surprise AWS bills and a very awkward Slack message to your CTO.&lt;/p&gt;

&lt;p&gt;Treat your loops like the distributed systems they are, and your future self will thank you.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>architecture</category>
      <category>devops</category>
      <category>bestpractices</category>
    </item>
    <item>
      <title>Your AI Provider Just Yanked Their Best Model. Now What?</title>
      <dc:creator>Marc Newstead</dc:creator>
      <pubDate>Mon, 10 Aug 2026 09:02:15 +0000</pubDate>
      <link>https://dev.to/icentric/your-ai-provider-just-yanked-their-best-model-now-what-2lpf</link>
      <guid>https://dev.to/icentric/your-ai-provider-just-yanked-their-best-model-now-what-2lpf</guid>
      <description>&lt;h2&gt;
  
  
  Your AI Provider Just Yanked Their Best Model. Now What?
&lt;/h2&gt;

&lt;p&gt;Last month, you integrated GPT-4 Turbo into your product. Your users loved it. Then OpenAI quietly rolled it back, swapped the model weights, and your output quality tanked. Sound familiar?&lt;/p&gt;

&lt;p&gt;This isn't hypothetical. Major AI labs are making silent model retractions a regular occurrence, and most dev teams are building on foundations that can shift overnight. If you're calling AI APIs without a plan for this, you're one undocumented rollback away from a very bad sprint.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Problem: API Stability Is a Polite Fiction
&lt;/h2&gt;

&lt;p&gt;We're used to semantic versioning. Breaking changes come with major version bumps. Deprecation warnings give us months to migrate. The social contract of stable APIs is deeply embedded in how we build software.&lt;/p&gt;

&lt;p&gt;AI providers don't play by these rules.&lt;/p&gt;

&lt;p&gt;A model version like &lt;code&gt;gpt-4-turbo&lt;/code&gt; isn't a semantic version—it's a moving target. The weights behind that endpoint can change without warning. Performance characteristics shift. Output formats drift. What worked in your integration tests last Tuesday might fail differently on Friday.&lt;/p&gt;

&lt;p&gt;The incentive structure is clear: labs are in a race for benchmarks, talent, and investment. Shipping fast matters more than stability. If a model has issues post-launch, the path of least resistance is a quiet rollback and a vague status page update.&lt;/p&gt;

&lt;p&gt;For a deeper look at why this pattern is becoming normalised, see &lt;a href="https://www.icentricagency.com/insights/ai-retractions-why-launch-fast-retract-quietly-is-a-business-risk" rel="noopener noreferrer"&gt;launch fast, retract quietly&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Your TOS Actually Says (Spoiler: Not Much)
&lt;/h2&gt;

&lt;p&gt;Most of us click through AI API terms without reading them. When you do read them, the language is blunt:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;No uptime guarantees&lt;/strong&gt; beyond vague "commercially reasonable efforts"&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Unilateral modification rights&lt;/strong&gt; for models, pricing, and availability&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Termination clauses&lt;/strong&gt; that give the provider an exit with minimal notice&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No liability&lt;/strong&gt; for consequential damages (i.e., your product breaking)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You're building critical features on infrastructure that has fewer contractual protections than your email service.&lt;/p&gt;

&lt;p&gt;If you're in a regulated industry or handling enterprise SLAs, this gap isn't just annoying—it's a compliance and commercial risk.&lt;/p&gt;

&lt;h2&gt;
  
  
  Build for Instability: The Abstraction Layer You Actually Need
&lt;/h2&gt;

&lt;p&gt;The correct response isn't to avoid AI. It's to architect for vendor instability from day one.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Abstract the AI boundary
&lt;/h3&gt;

&lt;p&gt;Don't let &lt;code&gt;openai.ChatCompletion.create()&lt;/code&gt; calls sprawl across your codebase. Wrap all AI calls behind an internal interface:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;LLMService&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;generate_response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;prompt&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;context&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="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="c1"&gt;# Your internal contract
&lt;/span&gt;        &lt;span class="k"&gt;pass&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;OpenAIProvider&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;LLMService&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;generate_response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;prompt&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;context&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="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="c1"&gt;# OpenAI-specific implementation
&lt;/span&gt;        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;openai&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ChatCompletion&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(...)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This isn't over-engineering. It's basic dependency inversion. When (not if) you need to swap providers, you're changing one class, not grepping through 47 files.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Version your prompts and expected behaviours
&lt;/h3&gt;

&lt;p&gt;Treat prompts like database migrations. Version them. Test them. Track which version is active in production.&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;PROMPT_V3&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;
You are a customer service assistant.
Always respond in JSON format: {&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;answer&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;: str, &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;confidence&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;: float}
&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;test_prompt_v3_format&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;llm&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;generate_response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;PROMPT_V3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;test_context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="nf"&gt;is_valid_json&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="k"&gt;assert&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;answer&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When model behaviour drifts, you'll spot it in CI, not in production.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Log inputs, outputs, and model versions
&lt;/h3&gt;

&lt;p&gt;You can't debug what you can't see. Log every AI interaction with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Model name and version&lt;/li&gt;
&lt;li&gt;Full prompt (sanitised if needed)&lt;/li&gt;
&lt;li&gt;Raw response&lt;/li&gt;
&lt;li&gt;Timestamp&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When output quality silently degrades, you need data to prove it wasn't your code.&lt;/p&gt;

&lt;h2&gt;
  
  
  Multi-Vendor Isn't Paranoia—It's Risk Management
&lt;/h2&gt;

&lt;p&gt;Running multiple AI providers in parallel sounds expensive and complex. It is. But so is having your product break when your single provider retracts a model or raises prices 3x.&lt;/p&gt;

&lt;p&gt;You don't need full redundancy. You need &lt;strong&gt;viable fallback options&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Keep integration code for 2-3 providers behind your abstraction layer&lt;/li&gt;
&lt;li&gt;Run periodic tests against backup providers to ensure they still work&lt;/li&gt;
&lt;li&gt;Have a decision matrix: which provider for which use case, and what's the fallback?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This isn't about tolerating complexity for its own sake. It's about not having your commercial roadmap held hostage by a vendor's internal politics.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Bottom Line
&lt;/h2&gt;

&lt;p&gt;AI capabilities are transformative. The commercial terms and stability guarantees surrounding them are not.&lt;/p&gt;

&lt;p&gt;If you're building AI features into production systems, architect as if your provider will change the rules mid-game. Because they will.&lt;/p&gt;

&lt;p&gt;Abstraction layers, versioned prompts, structured logging, and multi-vendor optionality aren't gold-plating. They're the minimum due diligence for infrastructure you don't control.&lt;/p&gt;

&lt;p&gt;If your organisation is navigating these tradeoffs at scale, working with specialists in &lt;a href="https://www.icentricagency.com" rel="noopener noreferrer"&gt;AI automation and software development&lt;/a&gt; can help you get the architecture right before the next retraction hits.&lt;/p&gt;

&lt;p&gt;Now go wrap those API calls.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>architecture</category>
      <category>api</category>
      <category>risk</category>
    </item>
    <item>
      <title>We built a GB-first Maps &amp; Places API because the mapping bill stopped making sense</title>
      <dc:creator>Marc Newstead</dc:creator>
      <pubDate>Tue, 04 Aug 2026 09:11:20 +0000</pubDate>
      <link>https://dev.to/icentric/we-built-a-gb-first-maps-places-api-because-the-mapping-bill-stopped-making-sense-39h1</link>
      <guid>https://dev.to/icentric/we-built-a-gb-first-maps-places-api-because-the-mapping-bill-stopped-making-sense-39h1</guid>
      <description>&lt;h2&gt;
  
  
  The bill nobody budgeted for
&lt;/h2&gt;

&lt;p&gt;If you've shipped anything with a map in it lately, you've had a version of this conversation with your finance person.&lt;/p&gt;

&lt;p&gt;The short history: in March 2025 Google Maps Platform retired the flat $200 monthly credit and replaced it with much smaller per-SKU allowances. Subscription tiers followed. The practical effect is that workloads which used to vanish under the credit now bill from a low threshold — and place search sits at the expensive end. Text Search on the Places API (New) runs around $32 per 1,000 calls above a 5,000-call monthly allowance. Request a &lt;code&gt;rating&lt;/code&gt; field and the call moves up an SKU tier. Request reviews and it moves up again.&lt;/p&gt;

&lt;p&gt;None of that is unreasonable for what Google provides. It's an excellent global dataset and you're paying global-dataset prices.&lt;/p&gt;

&lt;p&gt;But plenty of us aren't building for the globe. We're building a UK checkout. A UK store locator. A UK field-service dispatcher. And we're paying for planet-scale coverage, a consumer-search-optimised ranking model, and a session-token billing abstraction we then have to reverse-engineer to forecast next month's spend.&lt;/p&gt;

&lt;p&gt;So we built the thing we wanted instead.&lt;/p&gt;

&lt;h2&gt;
  
  
  Goggle Places
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://www.goggleplaces.com" rel="noopener noreferrer"&gt;Goggle Places&lt;/a&gt;&lt;/strong&gt; is a Maps &amp;amp; Places API for Great Britain: predictive search, unified place search, nearby lookup, hosted vector maps and routing, behind one key, priced per request.&lt;/p&gt;

&lt;p&gt;GB-first is the whole design constraint, and it buys things a global provider can't easily give you:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Postcodes are first-class&lt;/strong&gt;, not a special case bolted onto a generic geocoder. Full and partial input, typo-tolerant, ranked sensibly.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Full national coverage&lt;/strong&gt; — every GB postcode, street, town and landmark, plus amenities, in one index.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Real GB public transport&lt;/strong&gt; — National Rail plus London bus/tube/DLR/ferry, on live timetables.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Sub-50ms typeahead from the edge&lt;/strong&gt;, because autocomplete that lands after the user stops typing isn't autocomplete.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Two search endpoints, and the difference matters
&lt;/h2&gt;

&lt;p&gt;This is the bit worth reading properly, because picking the wrong one is the most likely way to have a bad time.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;GET /predict&lt;/code&gt; is the addresses-only typeahead — postcodes, streets, towns, landmarks. It's what you want behind a checkout address field.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="s2"&gt;"https://api.goggleplaces.com/predict?q=York"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"x-api-key: gk_live_pk_..."&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"hits"&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="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"York"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"town"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"geo_point"&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;"lat"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;53.96&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"lon"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;-1.08&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;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;&lt;code&gt;GET /search&lt;/code&gt; is the single-field façade. It fans out server-side to the gazetteer &lt;em&gt;and&lt;/em&gt; the amenity index, then blends both into one ranked list. So &lt;code&gt;Premier Inn York&lt;/code&gt;, &lt;code&gt;Nando's&lt;/code&gt; and &lt;code&gt;Pizza Express&lt;/code&gt; resolve here — where &lt;code&gt;/predict&lt;/code&gt; returns nothing, because they aren't addresses.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="s2"&gt;"https://api.goggleplaces.com/search?q=premier%20inn%20york&amp;amp;mode=all&amp;amp;key=gk_live_pk_..."&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"q"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"premier inn york"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"mode"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"all"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"total"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"hits"&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="nl"&gt;"display_name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Premier Inn York South West, York"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"kind"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"place"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"lodging"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"locality"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"York"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"geo_point"&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;"lat"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;53.93&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"lon"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;-1.13&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;span class="nl"&gt;"display_name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"York, North Yorkshire"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"kind"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"address"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"town"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"geo_point"&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;"lat"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;53.96&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"lon"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;-1.08&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;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;&lt;code&gt;mode&lt;/code&gt; takes &lt;code&gt;all&lt;/code&gt; (default), &lt;code&gt;addresses&lt;/code&gt; (gazetteer only — identical to &lt;code&gt;/predict&lt;/code&gt;) or &lt;code&gt;places&lt;/code&gt; (amenities only, for a store locator). Pass &lt;code&gt;lat&lt;/code&gt;/&lt;code&gt;lng&lt;/code&gt; as a location bias and the amenity half gets a distance decay, so typing &lt;code&gt;travelodge&lt;/code&gt; with the map over Manchester surfaces Manchester branches first.&lt;/p&gt;

&lt;p&gt;One gotcha, documented but easy to miss: businesses are matched &lt;strong&gt;by name&lt;/strong&gt;. &lt;code&gt;Nando's Manchester&lt;/code&gt; won't match, because amenities aren't named with their city. Bias by coordinates instead.&lt;/p&gt;

&lt;h2&gt;
  
  
  Nearby lookup
&lt;/h2&gt;

&lt;p&gt;Proximity and category rather than typed name — anchored on a point, or on the map viewport so you load exactly what's on screen as the user pans.&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;# around a point (radius in km, default 5, max 25)&lt;/span&gt;
curl &lt;span class="s2"&gt;"https://api.goggleplaces.com/nearby?lat=53.4808&amp;amp;lng=-2.2426&amp;amp;radius=2&amp;amp;categories=restaurant,bar&amp;amp;key=gk_live_pk_..."&lt;/span&gt;

&lt;span class="c"&gt;# within a viewport (bbox = minLng,minLat,maxLng,maxLat)&lt;/span&gt;
curl &lt;span class="s2"&gt;"https://api.goggleplaces.com/nearby?bbox=-2.26,53.46,-2.20,53.50&amp;amp;categories=lodging,charging&amp;amp;key=gk_live_pk_..."&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Categories: &lt;code&gt;restaurant&lt;/code&gt;, &lt;code&gt;bar&lt;/code&gt;, &lt;code&gt;attraction&lt;/code&gt;, &lt;code&gt;transport&lt;/code&gt;, &lt;code&gt;hospital&lt;/code&gt;, &lt;code&gt;parking&lt;/code&gt;, &lt;code&gt;lodging&lt;/code&gt;, &lt;code&gt;charging&lt;/code&gt;. Hits come back nearest-first with &lt;code&gt;distance&lt;/code&gt;, plus &lt;code&gt;opening_hours&lt;/code&gt;, &lt;code&gt;website&lt;/code&gt;, &lt;code&gt;phone&lt;/code&gt;, &lt;code&gt;cuisine&lt;/code&gt; and &lt;code&gt;wheelchair&lt;/code&gt; where we have them. Coverage on those secondary fields varies by area, so don't build a UI that assumes opening hours are always present.&lt;/p&gt;

&lt;h2&gt;
  
  
  Routing
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;POST /directions&lt;/code&gt;, self-hosted over GB data, engine-normalised so the response shape is stable regardless of which engine served it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-X&lt;/span&gt; POST &lt;span class="s2"&gt;"https://api.goggleplaces.com/directions"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"x-api-key: gk_live_sk_..."&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"content-type: application/json"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'{
    "origin": [-2.2426, 53.4808],
    "destination": [-1.8904, 52.4862],
    "mode": "auto",
    "alternatives": true
  }'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Modes are &lt;code&gt;auto&lt;/code&gt;, &lt;code&gt;bicycle&lt;/code&gt;, &lt;code&gt;pedestrian&lt;/code&gt; and &lt;code&gt;transit&lt;/code&gt; (with the obvious aliases). Up to 25 waypoints, &lt;code&gt;optimize&lt;/code&gt; to reorder them as a TSP, GeoJSON &lt;code&gt;LineString&lt;/code&gt; geometry, turn-by-turn legs. Set &lt;code&gt;mode=transit&lt;/code&gt; and each leg carries the service name, board/alight stops and live times.&lt;/p&gt;

&lt;p&gt;Points accept &lt;code&gt;[lon, lat]&lt;/code&gt; arrays or &lt;code&gt;{lat, lon}&lt;/code&gt; / &lt;code&gt;{lat, lng}&lt;/code&gt; objects, so a &lt;code&gt;geo_point&lt;/code&gt; from &lt;code&gt;/search&lt;/code&gt; drops straight in — you can route to a hotel, not just to an address.&lt;/p&gt;

&lt;p&gt;There's a convenience GET for simple two-point routes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="s2"&gt;"https://api.goggleplaces.com/directions?from=53.4808,-2.2426&amp;amp;to=52.4862,-1.8904"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"x-api-key: gk_live_sk_..."&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Maps
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&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;map&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;@goggleplaces/sdk&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;container&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;map&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;gk_live_pk_...&lt;/span&gt;&lt;span class="dl"&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 full UK vector map in your &lt;code&gt;&amp;lt;div&amp;gt;&lt;/code&gt;. Tiles stream from our API — nothing to self-host, no tile server to operate, no per-tile line item on the invoice.&lt;/p&gt;

&lt;h2&gt;
  
  
  Keys
&lt;/h2&gt;

&lt;p&gt;Publishable (&lt;code&gt;gk_live_pk_…&lt;/code&gt;) are safe to ship in a browser but &lt;strong&gt;must&lt;/strong&gt; be origin-locked; anything else is rejected at the edge with a 403. Secret (&lt;code&gt;gk_live_sk_…&lt;/code&gt;) are server-side only. Both are scoped per service, rotatable and metered.&lt;/p&gt;

&lt;h2&gt;
  
  
  Pricing
&lt;/h2&gt;

&lt;p&gt;Free allowance on every service, then a flat per-1,000 rate. Priced per service, no bundles to decode.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Service&lt;/th&gt;
&lt;th&gt;Free / month&lt;/th&gt;
&lt;th&gt;Rate&lt;/th&gt;
&lt;th&gt;Above 5M*&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;/predict&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;30,000&lt;/td&gt;
&lt;td&gt;£1.68 / 1k&lt;/td&gt;
&lt;td&gt;£1.34 / 1k&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;/nearby&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;30,000&lt;/td&gt;
&lt;td&gt;£2.96 / 1k&lt;/td&gt;
&lt;td&gt;£2.37 / 1k&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;/tiles&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;30,000&lt;/td&gt;
&lt;td&gt;£4.15 / 1k&lt;/td&gt;
&lt;td&gt;£3.32 / 1k&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;/directions&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;10,000&lt;/td&gt;
&lt;td&gt;£2.96 / 1k&lt;/td&gt;
&lt;td&gt;£2.37 / 1k&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;*Directions steps down above 1M rather than 5M. Rates as at August 2026 — check &lt;a href="https://www.goggleplaces.com/pricing" rel="noopener noreferrer"&gt;/pricing&lt;/a&gt; for current figures.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;A card is required to activate the account.&lt;/strong&gt; You aren't charged unless you exceed the free allowance.&lt;/p&gt;

&lt;h3&gt;
  
  
  Worked example
&lt;/h3&gt;

&lt;p&gt;The Google comparison depends on your field profile, but a checkout session terminating in a Place Details Pro request is commonly cited around $17 per 1,000 sessions — so ~$1,700 (c £1,260) for 100,000 sessions, against our pricing which would (at an average of 4 debounced calls per session and including the free tier) would work out at £621.60 for the same number of sessions.&lt;/p&gt;

&lt;p&gt;Add a map to that page and Google's dynamic map loads run around $7/1,000 against our £4.15/1,000 with 30,000 free — that gap is wider and more straightforward.&lt;/p&gt;

&lt;h2&gt;
  
  
  When you should &lt;em&gt;not&lt;/em&gt; use this
&lt;/h2&gt;

&lt;p&gt;Worth saying plainly, because you'd find out in week three otherwise:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;You need coverage outside Great Britain.&lt;/strong&gt; We don't have it. Use Google, HERE or Mapbox.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;You depend on ratings and review text.&lt;/strong&gt; We don't return either. If your UI shows star ratings, this isn't a swap you can make.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;You need Street View or equivalent imagery.&lt;/strong&gt; Not something we offer.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Your POI depth requirement is high in long-tail commercial categories.&lt;/strong&gt; Coverage is strongest on transport, infrastructure, hospitality and chains, and thinner on small independents in some areas.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Try it
&lt;/h2&gt;

&lt;p&gt;The search box on &lt;a href="https://www.goggleplaces.com" rel="noopener noreferrer"&gt;goggleplaces.com&lt;/a&gt; hits the live predictive endpoint on every keystroke — same endpoint your app would call, no demo mode. Open the network tab and throw real queries at it before you sign up for anything.&lt;/p&gt;

&lt;p&gt;Docs: &lt;a href="https://www.goggleplaces.com/docs" rel="noopener noreferrer"&gt;goggleplaces.com/docs&lt;/a&gt;. Keys: &lt;a href="https://app.goggleplaces.com" rel="noopener noreferrer"&gt;app.goggleplaces.com&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;If predictive search mis-ranks somewhere you know well, or the router sends you a stupid way round, put it in the comments. GB coverage &lt;em&gt;is&lt;/em&gt; the product, so local knowledge is the most useful bug report we can get.&lt;/p&gt;

</description>
      <category>api</category>
      <category>webdev</category>
      <category>javascript</category>
      <category>showdev</category>
    </item>
    <item>
      <title>Your AI Integration Just Got Deprecated: A Developer's Guide to Vendor Stability</title>
      <dc:creator>Marc Newstead</dc:creator>
      <pubDate>Mon, 03 Aug 2026 09:05:04 +0000</pubDate>
      <link>https://dev.to/icentric/your-ai-integration-just-got-deprecated-a-developers-guide-to-vendor-stability-563j</link>
      <guid>https://dev.to/icentric/your-ai-integration-just-got-deprecated-a-developers-guide-to-vendor-stability-563j</guid>
      <description>&lt;h2&gt;
  
  
  The Problem
&lt;/h2&gt;

&lt;p&gt;You've just spent three sprints integrating a shiny new AI API. Your pull request is merged, monitoring is green, and the product team is already planning the next feature that builds on it. Then you open your inbox:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Important Update: [Feature Name] Deprecated"&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The capability you built around? It's being "refined". Translation: it didn't work as advertised, and now you're rewriting code.&lt;/p&gt;

&lt;p&gt;This isn't a hypothetical. Google, OpenAI, and Anthropic have all shipped features, branded them, and then quietly walked them back. &lt;a href="https://www.icentricagency.com/insights/ai-retractions-why-labs-ship-before-they-know-what-they-ve-built" rel="noopener noreferrer"&gt;Why labs ship&lt;/a&gt; before they fully understand what they've built is a systemic issue, and as developers, we're the ones left holding the technical debt.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why This Hits Developers Harder Than Anyone Else
&lt;/h2&gt;

&lt;p&gt;When marketing changes messaging, they update a deck. When a vendor retracts a feature, &lt;em&gt;you&lt;/em&gt; rewrite the code.&lt;/p&gt;

&lt;p&gt;Here's what actually happens:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Contract breakage disguised as iteration.&lt;/strong&gt; A model that was "multimodal" becomes "optimised for text-primary workflows". Your image processing pipeline now throws errors in production.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Versioning theatre.&lt;/strong&gt; The model version number increments, but the behaviour changes fundamentally. Your integration tests pass, but user-facing accuracy drops 20%.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Documentation drift.&lt;/strong&gt; The API docs still reference capabilities that have been soft-deprecated. You only find out when you hit rate limits or unexpected error codes.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Consumer apps can pivot. Enterprise systems can't. And the codebase you maintain sits somewhere in between, absorbing every breaking change.&lt;/p&gt;

&lt;h2&gt;
  
  
  What to Check Before You Integrate
&lt;/h2&gt;

&lt;p&gt;You can't eliminate risk, but you can avoid the worst landmines. Here's what I look at now:&lt;/p&gt;

&lt;h3&gt;
  
  
  1. &lt;strong&gt;Version Stability Track Record&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Don't trust the roadmap. Check the changelog:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;How often do minor versions introduce breaking changes?&lt;/li&gt;
&lt;li&gt;Are deprecations announced with a migration window, or do they appear retroactively in release notes?&lt;/li&gt;
&lt;li&gt;Is there a public issue tracker where behavioural regressions are discussed?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If a vendor has quietly changed model behaviour three times in six months, assume that's the cadence you'll be dealing with.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. &lt;strong&gt;SLA Reality Check&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Read the actual SLA, not the marketing site:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;❌ "Enterprise-grade reliability"
✅ 99.9% uptime on inference endpoints, 30-day notice on deprecations
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If the SLA doesn't mention API stability or behavioural consistency, you don't have one.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. &lt;strong&gt;Escape Hatch Architecture&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Design for replaceability from day one:&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;# Bad: Tight coupling to vendor SDK
&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;openai&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ChatCompletion&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;gpt-4&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;# Better: Abstraction layer
&lt;/span&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;LLMProvider&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Protocol&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;complete&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;prompt&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="bp"&gt;...&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;OpenAIProvider&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;LLMProvider&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;complete&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;prompt&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;openai&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ChatCompletion&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(...)&lt;/span&gt;

&lt;span class="c1"&gt;# Swap providers without touching business logic
&lt;/span&gt;&lt;span class="n"&gt;provider&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;LLMProvider&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;get_provider&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;  &lt;span class="c1"&gt;# Config-driven
&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;provider&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;complete&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If swapping the vendor would mean rewriting half your application, you've already lost.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. &lt;strong&gt;Feature Flag Everything&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Treat AI features like you'd treat any experimental third-party dependency:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Wrap calls in feature flags so you can disable them instantly&lt;/li&gt;
&lt;li&gt;Log inputs, outputs, and latency separately from your core metrics&lt;/li&gt;
&lt;li&gt;Have a fallback path that doesn't depend on the AI being available or correct&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This isn't paranoia. This is treating external APIs like the network calls they are.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Naming Game
&lt;/h2&gt;

&lt;p&gt;One of the subtler issues: vendors brand capabilities before they've proven them at scale. A feature called "Advanced Reasoning" or "Extended Context" sounds like a contract, but legally and technically, it's marketing.&lt;/p&gt;

&lt;p&gt;As developers, we need to push back:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;If a capability is critical, get the behaviour in writing (SLA, API contract, regression tests)&lt;/li&gt;
&lt;li&gt;If the vendor won't commit to specific accuracy or consistency metrics, treat it as experimental&lt;/li&gt;
&lt;li&gt;If a feature has been in "beta" for a year, it's not becoming stable — that &lt;em&gt;is&lt;/em&gt; the stable state&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What This Means for Your Next Sprint
&lt;/h2&gt;

&lt;p&gt;If you're integrating AI tooling — especially in systems that can't tolerate surprise breakage — apply the same scrutiny you would to any other third-party dependency:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Treat model outputs as untrusted input&lt;/li&gt;
&lt;li&gt;Version your integrations so you can roll back&lt;/li&gt;
&lt;li&gt;Monitor behavioural drift, not just uptime&lt;/li&gt;
&lt;li&gt;Budget time for re-integration work, because it's coming&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The competitive advantages of AI tooling are real, and adoption does create a moat. But only if you build on stable ground. Firms specialising in &lt;a href="https://www.icentricagency.com" rel="noopener noreferrer"&gt;AI automation and software development&lt;/a&gt; often see teams trip over this exact issue: brilliant proof-of-concept, fragile production deployment.&lt;/p&gt;

&lt;h2&gt;
  
  
  Final Thought
&lt;/h2&gt;

&lt;p&gt;AI vendors are shipping fast because the market rewards speed over stability. That's not changing. What &lt;em&gt;can&lt;/em&gt; change is how we integrate: with scepticism, abstraction layers, and an escape plan.&lt;/p&gt;

&lt;p&gt;Because the next retraction email is already being drafted.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>api</category>
      <category>architecture</category>
      <category>devops</category>
    </item>
    <item>
      <title>Stop Writing One-Shot Prompts: Why Your AI Feature Needs a Loop</title>
      <dc:creator>Marc Newstead</dc:creator>
      <pubDate>Mon, 03 Aug 2026 09:02:23 +0000</pubDate>
      <link>https://dev.to/icentric/stop-writing-one-shot-prompts-why-your-ai-feature-needs-a-loop-45ci</link>
      <guid>https://dev.to/icentric/stop-writing-one-shot-prompts-why-your-ai-feature-needs-a-loop-45ci</guid>
      <description>&lt;h2&gt;
  
  
  Stop Writing One-Shot Prompts: Why Your AI Feature Needs a Loop
&lt;/h2&gt;

&lt;p&gt;If you're building AI features the same way you call a REST API — fire a request, get a response, parse the output — you've probably hit the reliability wall. One-shot prompts work brilliantly for demos and narrow tasks, but the moment you need consistency, validation, or multi-step reasoning, they fall apart.&lt;/p&gt;

&lt;p&gt;The answer isn't bigger models or more prompt engineering. It's &lt;strong&gt;agentic loops&lt;/strong&gt;: structured, deterministic systems that let AI reason, validate, and course-correct in a controlled cycle.&lt;/p&gt;

&lt;p&gt;Here's what that actually looks like in practice.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Problem with One-Shot Thinking
&lt;/h2&gt;

&lt;p&gt;Let's say you're building a feature that generates SQL from natural language. A one-shot implementation looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;query&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;llm&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;generate&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;Convert to SQL: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;user_input&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;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;execute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Simple. Clean. And completely brittle.&lt;/p&gt;

&lt;p&gt;What happens when:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The LLM hallucinates a table name?&lt;/li&gt;
&lt;li&gt;The query has a syntax error?&lt;/li&gt;
&lt;li&gt;The user asks for something ambiguous?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You could add validation logic &lt;em&gt;after&lt;/em&gt; the call, but you're still stuck with a single attempt. The model doesn't get to learn from its mistakes, and you can't build guardrails into the reasoning process itself.&lt;/p&gt;

&lt;p&gt;This is where &lt;a href="https://www.icentricagency.com/insights/agentic-loops-the-engineering-discipline-behind-reliable-ai-features" rel="noopener noreferrer"&gt;agentic loops&lt;/a&gt; come in.&lt;/p&gt;

&lt;h2&gt;
  
  
  What an Agentic Loop Actually Is
&lt;/h2&gt;

&lt;p&gt;An agentic loop is a &lt;strong&gt;structured cycle&lt;/strong&gt; where an AI system:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Attempts a task&lt;/li&gt;
&lt;li&gt;Evaluates its own output&lt;/li&gt;
&lt;li&gt;Decides whether to return, retry, or escalate&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Think of it as a &lt;code&gt;while&lt;/code&gt; loop with intelligence:&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;max_iterations&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;
&lt;span class="n"&gt;attempts&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;while&lt;/span&gt; &lt;span class="n"&gt;attempts&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;max_iterations&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;query&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;llm&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;generate&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;Convert to SQL: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;user_input&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;validation&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;validate_sql&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;schema&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;validation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;is_valid&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;query&lt;/span&gt;

    &lt;span class="n"&gt;user_input&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="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;user_input&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="se"&gt;\n\n&lt;/span&gt;&lt;span class="s"&gt;Previous attempt failed: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;validation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;error&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="n"&gt;attempts&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;

&lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nc"&gt;Exception&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Failed to generate valid SQL after 5 attempts&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;Now the model gets &lt;strong&gt;feedback&lt;/strong&gt;. It can see why it failed and adjust. You've turned a fragile one-shot into a self-correcting system.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Three Non-Negotiables
&lt;/h2&gt;

&lt;p&gt;If you're building agentic loops in production, three things need to be explicit and deterministic:&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Exit Conditions
&lt;/h3&gt;

&lt;p&gt;Every loop must have clear success and failure criteria. "The model seems happy" is not an exit condition. "Query passes schema validation" is.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Iteration Limits
&lt;/h3&gt;

&lt;p&gt;Never build an unbounded loop. Set a hard cap (usually 3–7 iterations). If the agent can't succeed by then, escalate or fail gracefully.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. State Management
&lt;/h3&gt;

&lt;p&gt;The agent needs context across iterations. That means passing conversation history, error messages, and intermediate outputs back into the loop. If you're not tracking state, you're not building an agent — you're just retrying.&lt;/p&gt;

&lt;h2&gt;
  
  
  Real-World Patterns
&lt;/h2&gt;

&lt;p&gt;Two architectures have emerged as practical starting points:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Supervisor-worker&lt;/strong&gt;: One agent plans, multiple agents execute. The supervisor breaks a task into subtasks, delegates to specialist workers (e.g. one for SQL generation, one for validation), and synthesises the results.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Chain-of-thought validation&lt;/strong&gt;: The agent generates a solution, then explicitly reasons about whether it meets the requirements. This "thinking step" is logged and used to decide whether to iterate.&lt;/p&gt;

&lt;p&gt;Both patterns share a common trait: &lt;strong&gt;the agent's reasoning is observable and debuggable&lt;/strong&gt;. You're not staring at a black box hoping it works.&lt;/p&gt;

&lt;h2&gt;
  
  
  Observability Is Not Optional
&lt;/h2&gt;

&lt;p&gt;Here's the part that surprises teams: once you ship an agentic loop, you've shipped a &lt;strong&gt;runtime decision-making system&lt;/strong&gt;. That means:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Every iteration should be logged with inputs, outputs, and reasoning&lt;/li&gt;
&lt;li&gt;You need metrics on loop convergence (how many iterations to success?)&lt;/li&gt;
&lt;li&gt;Failed loops need structured error states, not just stack traces&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you're treating this as a dev concern rather than an ops/governance one, you're in for a rough production incident.&lt;/p&gt;

&lt;p&gt;For teams building this infrastructure from scratch, partnering with specialists in &lt;a href="https://www.icentricagency.com" rel="noopener noreferrer"&gt;AI automation and software development&lt;/a&gt; can accelerate time-to-production significantly.&lt;/p&gt;

&lt;h2&gt;
  
  
  Start Small, Build Deliberately
&lt;/h2&gt;

&lt;p&gt;You don't need to rewrite your entire AI stack overnight. Start with one feature where reliability matters:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Wrap a flaky prompt in a validation loop&lt;/li&gt;
&lt;li&gt;Add iteration limits and logging&lt;/li&gt;
&lt;li&gt;Track convergence rates and failure modes&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Once you see the difference in reliability, you'll never go back to one-shot prompts.&lt;/p&gt;

&lt;p&gt;Agentic loops aren't magic. They're structured engineering. And they're the difference between an AI feature that works in demos and one that works in production.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>architecture</category>
      <category>softwaredevelopment</category>
      <category>engineering</category>
    </item>
    <item>
      <title>Your Agentic AI Pilot Is Probably Measuring the Wrong Things</title>
      <dc:creator>Marc Newstead</dc:creator>
      <pubDate>Mon, 27 Jul 2026 09:07:20 +0000</pubDate>
      <link>https://dev.to/icentric/your-agentic-ai-pilot-is-probably-measuring-the-wrong-things-3hi8</link>
      <guid>https://dev.to/icentric/your-agentic-ai-pilot-is-probably-measuring-the-wrong-things-3hi8</guid>
      <description>&lt;h2&gt;
  
  
  Your Agentic AI Pilot Is Probably Measuring the Wrong Things
&lt;/h2&gt;

&lt;p&gt;You've built an agentic AI system. It's working. It's doing real work autonomously—chaining API calls, making decisions, handling edge cases. Now you need to prove it's worth the infrastructure spend.&lt;/p&gt;

&lt;p&gt;So you pull up the metrics dashboard: tokens consumed, average response time, cost per interaction. Clean numbers. Finance-friendly.&lt;/p&gt;

&lt;p&gt;Except these metrics were designed for chatbots, not agents. And that mismatch is quietly killing your business case.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Chatbot Metric Trap
&lt;/h2&gt;

&lt;p&gt;Most teams inherit their AI metrics from RAG systems and support bots. Those systems were evaluated on:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Cost per query&lt;/strong&gt; – How much does one Q&amp;amp;A interaction cost?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Response accuracy&lt;/strong&gt; – Did it retrieve the right answer?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;User satisfaction scores&lt;/strong&gt; – Did the human like the response?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These made sense when you were replacing a glorified search box. But agentic systems don't work like that.&lt;/p&gt;

&lt;p&gt;An agent doesn't answer a question. It &lt;em&gt;executes a workflow&lt;/em&gt;. It might:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Call three different APIs to gather context&lt;/li&gt;
&lt;li&gt;Make a decision based on business rules&lt;/li&gt;
&lt;li&gt;Write data back to your CRM&lt;/li&gt;
&lt;li&gt;Trigger a follow-up task in Slack&lt;/li&gt;
&lt;li&gt;Handle failures and retry with backoff&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you measure that with "cost per query", you're comparing apples to entire fruit salads. The unit of work isn't comparable. Your ROI case falls apart under scrutiny.&lt;/p&gt;

&lt;h2&gt;
  
  
  What You Should Actually Be Measuring
&lt;/h2&gt;

&lt;p&gt;Start with the &lt;em&gt;workflow&lt;/em&gt;, not the AI. Map out what the agent is replacing:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Before (manual process):&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;1. Support agent receives escalation email
2. Looks up customer in CRM (avg 2 mins)
3. Checks order history in legacy system (avg 3 mins)
4. Evaluates refund eligibility (avg 5 mins)
5. Updates CRM and sends response (avg 3 mins)

Total: ~13 minutes per escalation
Cost: £X per hour × time spent
Throughput: Limited by team capacity
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;After (agentic system):&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Pseudocode for agentic refund workflow
&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;handle_refund_escalation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;customer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;crm&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;lookup&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;from_address&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;orders&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;legacy_system&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get_orders&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;customer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;decision&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;agent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;evaluate_refund&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;customer_tier&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;customer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;tier&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;order_history&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;orders&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;request_details&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;body&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;decision&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;approved&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;payments&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;process_refund&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;decision&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;amount&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;crm&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log_interaction&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;customer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;decision&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;email&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send_response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;decision&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;template&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;Measure this:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;End-to-end completion time&lt;/strong&gt; (13 mins → 45 seconds)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Throughput increase&lt;/strong&gt; (8/hour/person → 80/hour)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Error rate&lt;/strong&gt; (manual data entry errors vs. agent failures)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Escalation rate&lt;/strong&gt; (what % still needs human review)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cost per completed workflow&lt;/strong&gt; (not per API call)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now you have numbers that map to business outcomes. You can show that your agent handles 72 more escalations per hour than a human, with 99.2% accuracy and £2.30 per workflow vs. £4.80 for manual processing.&lt;/p&gt;

&lt;p&gt;That's a business case. "We saved 40,000 tokens" is not.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Pilots Hide the Real Wins
&lt;/h2&gt;

&lt;p&gt;Most agentic pilots run &lt;em&gt;in parallel&lt;/em&gt; with existing processes. You're comparing outputs, but not capturing the actual cost savings because the old process is still running.&lt;/p&gt;

&lt;p&gt;This creates three problems:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;No cost reduction shows up&lt;/strong&gt; – You're paying for both systems&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Throughput gains are invisible&lt;/strong&gt; – The agent could handle 10× more volume, but you're not sending it 10× more work&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The comparison is artificial&lt;/strong&gt; – You're cherry-picking tasks instead of measuring real production load&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If you want credible numbers, you need to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Route a &lt;em&gt;percentage&lt;/em&gt; of production traffic to the agent&lt;/li&gt;
&lt;li&gt;Measure actual time/cost saved on those workflows&lt;/li&gt;
&lt;li&gt;Track what happens when you scale up the percentage&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Don't run a science experiment. Run a production rollout with rollback capability.&lt;/p&gt;

&lt;h2&gt;
  
  
  Making Finance Actually Listen
&lt;/h2&gt;

&lt;p&gt;Your CFO doesn't care about your model architecture. They care about:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Unit economics&lt;/strong&gt; – Cost per workflow completed&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Payback period&lt;/strong&gt; – When does cumulative saving exceed build cost?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Risk&lt;/strong&gt; – What happens if it breaks?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Build your metrics around those questions. If you're serious about getting this right, treating &lt;a href="https://www.icentricagency.com/insights/measuring-agentic-ai-why-your-roi-framework-is-broken" rel="noopener noreferrer"&gt;your ROI framework as broken&lt;/a&gt; is the starting point.&lt;/p&gt;

&lt;p&gt;And if you're building agentic systems in a larger digital transformation context, working with teams experienced in &lt;a href="https://www.icentricagency.com" rel="noopener noreferrer"&gt;AI automation and software development&lt;/a&gt; helps you avoid the common structural mistakes that sink pilots before they reach production.&lt;/p&gt;

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

&lt;p&gt;Before you write another line of agentic code, map the workflow it's replacing. Define:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Time saved per workflow&lt;/li&gt;
&lt;li&gt;Error rate comparison&lt;/li&gt;
&lt;li&gt;Throughput ceiling (old vs. new)&lt;/li&gt;
&lt;li&gt;Total cost per completed unit of work&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Then instrument your agent to capture those metrics from day one. Not token counts. Not inference latency. &lt;em&gt;Business outcomes.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Because the best agentic system in the world is worthless if you can't prove it's worth running.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>devops</category>
      <category>architecture</category>
      <category>automation</category>
    </item>
    <item>
      <title>Your RAG system can't answer "why" questions. Here's what you're missing.</title>
      <dc:creator>Marc Newstead</dc:creator>
      <pubDate>Mon, 27 Jul 2026 09:04:44 +0000</pubDate>
      <link>https://dev.to/icentric/your-rag-system-cant-answer-why-questions-heres-what-youre-missing-29f1</link>
      <guid>https://dev.to/icentric/your-rag-system-cant-answer-why-questions-heres-what-youre-missing-29f1</guid>
      <description>&lt;h2&gt;
  
  
  The problem with semantic search
&lt;/h2&gt;

&lt;p&gt;You've built a RAG system. User asks a question, you embed it, run a vector similarity search, retrieve the top 5 chunks, shove them into context, and let the LLM answer. Works brilliantly for simple lookup queries.&lt;/p&gt;

&lt;p&gt;Then someone asks: &lt;em&gt;"Why did the deployment fail after the database migration?"&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Your agent retrieves a chunk about the deployment error. Maybe another about the migration. But it completely misses that the migration changed a column type, which broke a dependency in the service layer, which caused the deployment to fail. That's three hops of reasoning your vector store can't connect.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The gap between 32% and 86% accuracy on multi-hop questions isn't a prompt engineering problem. It's an architecture problem.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What vector search actually gives you
&lt;/h2&gt;

&lt;p&gt;Vector embeddings are phenomenal at semantic similarity. They'll find documents &lt;em&gt;about&lt;/em&gt; the same topic, even if the words differ. But they're terrible at representing &lt;strong&gt;relationships between facts&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;When you embed a sentence like "Service A depends on Service B", that directional relationship gets flattened into a 1536-dimensional float array. The embedding knows these services are related, but it doesn't know &lt;em&gt;how&lt;/em&gt; or &lt;em&gt;which direction&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Ask "what services depend on Service B?" and you might retrieve chunks mentioning both services. Ask "what does Service A depend on?" and you'll get similar chunks. The vector store can't distinguish between these queries because the relationship isn't preserved—just the proximity.&lt;/p&gt;

&lt;h2&gt;
  
  
  The retrieval gap in production
&lt;/h2&gt;

&lt;p&gt;Here's where it breaks in real systems:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Scenario&lt;/strong&gt;: Your AI agent manages a microservices architecture. Documentation lives in Notion, incident reports in Jira, config in GitHub.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Query&lt;/strong&gt;: "What's the blast radius if we take down the auth service?"&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What vector retrieval gets you&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Chunks about the auth service&lt;/li&gt;
&lt;li&gt;Maybe some chunks about services that mention auth&lt;/li&gt;
&lt;li&gt;Possibly incident reports that mention auth failures&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;What you actually need&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Services that directly call auth&lt;/li&gt;
&lt;li&gt;Services that depend on &lt;em&gt;those&lt;/em&gt; services (second hop)&lt;/li&gt;
&lt;li&gt;Downstream effects on user-facing features (third hop)&lt;/li&gt;
&lt;li&gt;Historical incidents showing actual impact patterns&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Vector search retrieves &lt;em&gt;documents&lt;/em&gt;. But reasoning about systems requires traversing a &lt;strong&gt;graph of relationships&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why hybrid retrieval matters
&lt;/h2&gt;

&lt;p&gt;The solution isn't to abandon vector search—it's to stop treating it as your only retrieval mechanism.&lt;/p&gt;

&lt;p&gt;Graph-based memory stores information as &lt;strong&gt;entities and edges&lt;/strong&gt;. When your agent processes documentation, it extracts:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Entities: services, APIs, databases, teams, incidents&lt;/li&gt;
&lt;li&gt;Relationships: depends_on, calls, deploys, owns, caused_by&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now that "blast radius" query becomes a graph traversal:&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;# Pseudocode for hybrid retrieval
&lt;/span&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;answer_query&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="c1"&gt;# Step 1: Use vector search for initial recall
&lt;/span&gt;    &lt;span class="n"&gt;candidate_entities&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;vector_search&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;10&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# Step 2: Expand via graph traversal
&lt;/span&gt;    &lt;span class="n"&gt;related_nodes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;traverse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;start_nodes&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;candidate_entities&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;relationships&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;depends_on&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;calls&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;impacts&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
        &lt;span class="n"&gt;max_depth&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="c1"&gt;# Step 3: Retrieve detailed content for final context
&lt;/span&gt;    &lt;span class="n"&gt;context&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;fetch_content&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;related_nodes&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;llm&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;generate&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;context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You use vectors for semantic recall ("find anything related to auth service"), then use the graph to expand outward along explicit relationships.&lt;/p&gt;

&lt;h2&gt;
  
  
  When you actually need this
&lt;/h2&gt;

&lt;p&gt;Not every agent needs a graph. If you're building a documentation Q&amp;amp;A bot that answers "how do I configure X?", vector search is probably fine.&lt;/p&gt;

&lt;p&gt;You need hybrid retrieval when:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Questions require connecting multiple facts ("why did X happen?")&lt;/li&gt;
&lt;li&gt;You're reasoning about systems with explicit relationships (dependencies, hierarchies, workflows)&lt;/li&gt;
&lt;li&gt;Accuracy on complex queries is more valuable than simplicity&lt;/li&gt;
&lt;li&gt;You're seeing high retrieval scores but wrong final answers&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Quick diagnostic&lt;/strong&gt;: Ask your agent three questions that require connecting information from different documents. If it can retrieve all relevant chunks but still gives incomplete answers, you have a relationship problem, not a retrieval problem.&lt;/p&gt;

&lt;h2&gt;
  
  
  What this looks like in practice
&lt;/h2&gt;

&lt;p&gt;Implementing hybrid retrieval isn't trivial, but it's not exotic either:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Extract entities and relationships&lt;/strong&gt; during document ingestion (use an LLM or NLP pipeline)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Store vectors in your existing vector DB&lt;/strong&gt; (Pinecone, Weaviate, etc.)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Store the graph separately&lt;/strong&gt; (Neo4j, or even a relational DB with recursive CTEs)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Query both&lt;/strong&gt; during retrieval and merge results&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The teams seeing that 86% accuracy boost on multi-hop reasoning aren't using magic—they're just stopped expecting embeddings to preserve information they were never designed to capture. The research on &lt;a href="https://www.icentricagency.com/insights/agent-memory-why-vector-only-retrieval-is-failing-your-ai-stack" rel="noopener noreferrer"&gt;vector-only retrieval&lt;/a&gt; makes this gap clear.&lt;/p&gt;

&lt;p&gt;If you're building production AI systems that need to reason about relationships, not just retrieve similar text, you'll eventually hit this wall. Graph memory isn't a nice-to-have—it's how you bridge the gap between semantic similarity and actual reasoning.&lt;/p&gt;

&lt;p&gt;For more on building robust agent architectures, check out resources on &lt;a href="https://www.icentricagency.com" rel="noopener noreferrer"&gt;AI automation and software development&lt;/a&gt; that cover these hybrid approaches in depth.&lt;/p&gt;

&lt;h2&gt;
  
  
  The bottom line
&lt;/h2&gt;

&lt;p&gt;Vector search is brilliant at finding relevant documents. Terrible at understanding how facts connect. If your agent needs to answer "why" or "what happens if", you need more than cosine similarity. You need a graph.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>rag</category>
      <category>architecture</category>
      <category>machinelearning</category>
    </item>
    <item>
      <title>Stop Measuring Your AI Agent Like It's a Microservice</title>
      <dc:creator>Marc Newstead</dc:creator>
      <pubDate>Mon, 20 Jul 2026 09:10:04 +0000</pubDate>
      <link>https://dev.to/icentric/stop-measuring-your-ai-agent-like-its-a-microservice-4gbi</link>
      <guid>https://dev.to/icentric/stop-measuring-your-ai-agent-like-its-a-microservice-4gbi</guid>
      <description>&lt;h2&gt;
  
  
  Stop Measuring Your AI Agent Like It's a Microservice
&lt;/h2&gt;

&lt;p&gt;You've built an AI agent. It works. It's handling real tasks. Your manager asks: "What's the ROI?"&lt;/p&gt;

&lt;p&gt;You pull up latency metrics, error rates, cost per API call. The same dashboard you'd show for any service. And that's exactly why your pilot is about to die in committee.&lt;/p&gt;

&lt;p&gt;I've watched too many technically successful AI projects get axed because we measured them wrong. Here's what I learned about making agentic AI survive past the pilot phase.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Microservice Trap
&lt;/h2&gt;

&lt;p&gt;When you build a REST API or a background worker, you measure it like infrastructure:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Requests per second&lt;/li&gt;
&lt;li&gt;P99 latency&lt;/li&gt;
&lt;li&gt;Error rate&lt;/li&gt;
&lt;li&gt;Cost per transaction&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These metrics make sense for deterministic systems. You know exactly what each transaction does, and you optimise for doing it cheaper and faster.&lt;/p&gt;

&lt;p&gt;But agentic AI doesn't work like that. Your agent might:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Handle a customer query in 30 seconds that would take a human 15 minutes&lt;/li&gt;
&lt;li&gt;Fail gracefully and route to a human&lt;/li&gt;
&lt;li&gt;Resolve an issue completely, preventing three follow-up tickets&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you're measuring "cost per transaction" at £0.20 per agent interaction versus £0.05 for a traditional form submission, you've already lost the argument. You're comparing apples to entire orchards.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Actually Matters: Task Deflection Rate
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Task deflection rate&lt;/strong&gt; is the percentage of tasks your agent completes without human intervention. Not "handled" or "touched" — actually &lt;strong&gt;completed&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;This is your primary metric. Everything else is secondary.&lt;/p&gt;

&lt;p&gt;Here's why it matters: if your agent deflects 60% of tier-1 support tickets, and you're processing 10,000 tickets monthly, you've just recaptured 6,000 human interactions. Each of those has a fully loaded cost (salary, overhead, management time).&lt;/p&gt;

&lt;p&gt;Let's get concrete:&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;# Traditional metric (wrong)
&lt;/span&gt;&lt;span class="n"&gt;cost_per_agent_call&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;0.20&lt;/span&gt;  &lt;span class="c1"&gt;# £0.20 LLM + infrastructure
&lt;/span&gt;&lt;span class="n"&gt;monthly_agent_calls&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;6000&lt;/span&gt;
&lt;span class="n"&gt;monthly_cost&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;cost_per_agent_call&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;monthly_agent_calls&lt;/span&gt;  &lt;span class="c1"&gt;# £1,200
&lt;/span&gt;
&lt;span class="c1"&gt;# This looks expensive. But watch:
&lt;/span&gt;
&lt;span class="c1"&gt;# Task deflection metric (correct)
&lt;/span&gt;&lt;span class="n"&gt;avg_human_handle_time&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;15&lt;/span&gt;  &lt;span class="c1"&gt;# minutes
&lt;/span&gt;&lt;span class="n"&gt;deflection_rate&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;0.60&lt;/span&gt;
&lt;span class="n"&gt;monthly_tickets&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;10000&lt;/span&gt;

&lt;span class="n"&gt;deflected_tickets&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;monthly_tickets&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;deflection_rate&lt;/span&gt;  &lt;span class="c1"&gt;# 6,000
&lt;/span&gt;&lt;span class="n"&gt;human_hours_recaptured&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;deflected_tickets&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;avg_human_handle_time&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;60&lt;/span&gt;  &lt;span class="c1"&gt;# 1,500 hours
&lt;/span&gt;
&lt;span class="n"&gt;fully_loaded_cost_per_hour&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;35&lt;/span&gt;  &lt;span class="c1"&gt;# £35/hour (salary + overhead)
&lt;/span&gt;&lt;span class="n"&gt;monthly_value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;human_hours_recaptured&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;fully_loaded_cost_per_hour&lt;/span&gt;  &lt;span class="c1"&gt;# £52,500
&lt;/span&gt;
&lt;span class="n"&gt;net_value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;monthly_value&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;monthly_cost&lt;/span&gt;  &lt;span class="c1"&gt;# £51,300/month
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Suddenly your "expensive" agent is generating £51k of monthly value. That's the business case.&lt;/p&gt;

&lt;h2&gt;
  
  
  Measuring Deflection in Practice
&lt;/h2&gt;

&lt;p&gt;You need to instrument this &lt;strong&gt;before&lt;/strong&gt; you finish your pilot. Here's the minimum viable tracking:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;AgentInteraction&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ticketId&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ticketId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;ticketId&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;startTime&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;humanHandoffRequired&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;resolutionConfirmed&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nf"&gt;requiresHandoff&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;humanHandoffRequired&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;logMetric&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;task_deflection&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nf"&gt;confirmResolution&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="o"&gt;!&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;humanHandoffRequired&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;resolutionConfirmed&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;logMetric&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;task_deflection&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;logMetric&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;time_saved_minutes&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;estimatedHumanTime&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;The key is tracking &lt;strong&gt;complete resolution&lt;/strong&gt; versus &lt;strong&gt;partial assistance&lt;/strong&gt;. Your agent might help with 90% of tickets, but only fully resolve 60%. That 60% is your deflection rate.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Human-Hour Recapture Angle
&lt;/h2&gt;

&lt;p&gt;When &lt;a href="https://www.icentricagency.com/insights/measuring-agentic-ai-why-task-deflection-rate-changes-everything" rel="noopener noreferrer"&gt;task deflection rate changes everything&lt;/a&gt;, it's because you're no longer arguing about infrastructure costs. You're talking about capacity.&lt;/p&gt;

&lt;p&gt;Those 1,500 recaptured hours monthly? That's nearly a full FTE. Your business case isn't "we made customer service 3% cheaper" — it's "we created capacity equivalent to one senior engineer without hiring."&lt;/p&gt;

&lt;p&gt;For teams working on &lt;a href="https://www.icentricagency.com" rel="noopener noreferrer"&gt;AI automation and software development&lt;/a&gt;, this reframing is essential. You're not optimising a process. You're multiplying human capability.&lt;/p&gt;

&lt;h2&gt;
  
  
  Before You Ship to Production
&lt;/h2&gt;

&lt;p&gt;Build your measurement framework &lt;strong&gt;during&lt;/strong&gt; the pilot:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Baseline human performance&lt;/strong&gt; — average handle time, escalation rate, resolution rate&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Track deflection explicitly&lt;/strong&gt; — not just "agent engaged" but "human avoided"&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Validate with spot checks&lt;/strong&gt; — random sample of "deflected" tasks to confirm quality&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Calculate fully loaded costs&lt;/strong&gt; — don't use base salary; include overhead&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;When you go to production review, lead with deflection rate and human-hour recapture. Show the capacity you've created. The cost-per-transaction comparison comes last, if at all.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Real Win
&lt;/h2&gt;

&lt;p&gt;The best AI agents don't just save money. They give your team time back to do work that actually requires human judgement. Measure &lt;strong&gt;that&lt;/strong&gt; capability, and you'll get your production budget.&lt;/p&gt;

&lt;p&gt;Your agent isn't a microservice. Stop measuring it like one.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>devops</category>
      <category>productivity</category>
      <category>architecture</category>
    </item>
  </channel>
</rss>
