<?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>Building Multi-Agent Systems: When Your AI Should Spawn More AIs</title>
      <dc:creator>Marc Newstead</dc:creator>
      <pubDate>Mon, 22 Jun 2026 09:12:00 +0000</pubDate>
      <link>https://dev.to/icentric/building-multi-agent-systems-when-your-ai-should-spawn-more-ais-3hld</link>
      <guid>https://dev.to/icentric/building-multi-agent-systems-when-your-ai-should-spawn-more-ais-3hld</guid>
      <description>&lt;h2&gt;
  
  
  Building Multi-Agent Systems: When Your AI Should Spawn More AIs
&lt;/h2&gt;

&lt;p&gt;You've built a chatbot. It works. Now product wants it to handle legal queries, technical troubleshooting, and customer support—all in one conversation. Your first instinct? Build three specialised agents and hardcode the routing logic. But there's another pattern gaining traction: &lt;strong&gt;supervisor agents that dynamically spawn sub-agents on demand&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Let's talk about when each approach makes sense, because the choice will fundamentally shape your system's cost, reliability, and maintainability.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Hardcoded Hierarchy: Routing Rules You Control
&lt;/h2&gt;

&lt;p&gt;In a static architecture, your orchestration logic is explicit code:&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;route_request&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="k"&gt;if&lt;/span&gt; &lt;span class="nf"&gt;contains_legal_keywords&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="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;legal_agent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;process&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="k"&gt;elif&lt;/span&gt; &lt;span class="nf"&gt;is_technical_issue&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="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;tech_support_agent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;process&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="k"&gt;else&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;general_agent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;process&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;This is &lt;strong&gt;predictable&lt;/strong&gt;. You know exactly which agent handles what, your token costs are bounded, and debugging is straightforward. When something goes wrong, you're reading deterministic code, not trying to decipher why an LLM decided to spawn a "blockchain expert" for a password reset.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The trade-off?&lt;/strong&gt; Brittleness. Every new capability means updating your routing logic. Edge cases pile up. That legal query about API rate limits? Neither your legal agent nor your technical agent was designed for it, and your routing function won't know what to do.&lt;/p&gt;

&lt;h2&gt;
  
  
  Dynamic Orchestration: Let the LLM Decide
&lt;/h2&gt;

&lt;p&gt;Dynamic supervisors flip the script. Instead of hardcoded rules, the supervisor &lt;em&gt;reasons&lt;/em&gt; about which sub-agents to spawn:&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;# Supervisor system prompt (simplified)
&lt;/span&gt;&lt;span class="n"&gt;supervisor_prompt&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 have access to these specialist agents:
- LegalAgent: contract review, compliance, GDPR
- TechAgent: API debugging, infrastructure
- CustomerAgent: billing, account management

Analyse the user&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;s request and spawn appropriate sub-agents.
You may spawn multiple agents if needed.
&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The supervisor becomes a meta-agent that interprets intent and assembles a response pipeline at runtime. For that legal-technical hybrid query? It might spawn both agents, coordinate their outputs, and synthesise a final answer.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;This is powerful.&lt;/strong&gt; New capabilities can be added by updating the agent registry and supervisor prompt—no code changes. The system adapts to novel combinations of requirements you didn't anticipate at design time.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;But it's expensive.&lt;/strong&gt; Every request now includes:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Supervisor reasoning step (100–500 tokens)&lt;/li&gt;
&lt;li&gt;Sub-agent spawning decision (variable)&lt;/li&gt;
&lt;li&gt;Coordination overhead if multiple agents run&lt;/li&gt;
&lt;li&gt;Final synthesis step&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;You've potentially tripled your token spend, and latency scales with the supervisor's decision complexity.&lt;/p&gt;

&lt;h2&gt;
  
  
  When to Choose Which
&lt;/h2&gt;

&lt;p&gt;Here's the decision framework I use:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Choose static hierarchies when:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Your domain is well-defined and stable&lt;/li&gt;
&lt;li&gt;Cost predictability matters more than flexibility&lt;/li&gt;
&lt;li&gt;You need deterministic behaviour for compliance/audit&lt;/li&gt;
&lt;li&gt;Your team is comfortable maintaining explicit orchestration code&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Choose dynamic supervisors when:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Requirements evolve frequently&lt;/li&gt;
&lt;li&gt;You're handling truly unpredictable user input&lt;/li&gt;
&lt;li&gt;Development velocity matters more than marginal cost&lt;/li&gt;
&lt;li&gt;You have robust observability to debug LLM routing decisions&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The Observability Problem
&lt;/h2&gt;

&lt;p&gt;Dynamic systems create a new debugging challenge: &lt;strong&gt;you're troubleshooting decisions made by a model, not by your code&lt;/strong&gt;. When a supervisor routes incorrectly, you need:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Full prompt/response logging for every supervisor decision&lt;/li&gt;
&lt;li&gt;Structured traces showing which sub-agents were spawned and why&lt;/li&gt;
&lt;li&gt;Token usage broken down by orchestration vs. task execution&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Without this, you're flying blind. Budget for engineering time to build proper instrumentation—it's not optional.&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;, investing early in observability patterns for multi-agent systems pays dividends once you're handling production traffic.&lt;/p&gt;

&lt;h2&gt;
  
  
  A Hybrid Approach
&lt;/h2&gt;

&lt;p&gt;In practice, you don't have to pick one or the other. Consider a tiered model:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Static top-level routing&lt;/strong&gt; for broad categories (legal, technical, sales)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Dynamic sub-agent spawning&lt;/strong&gt; within each category for nuanced specialisation&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This gives you cost control at the entry point while preserving flexibility where it matters. Your supervisor still makes intelligent decisions, but within a bounded domain that limits runaway token usage.&lt;/p&gt;

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

&lt;p&gt;When building multi-agent systems, the architecture choice boils down to this: &lt;strong&gt;are you optimising for developer control or system adaptability?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Static hierarchies give you determinism and debuggability. Dynamic supervisors give you flexibility and emergent capabilities. Neither is inherently better—it depends on your constraints.&lt;/p&gt;

&lt;p&gt;If you're still evaluating which pattern fits your use case, the detailed comparison on &lt;a href="https://www.icentricagency.com/insights/supervisor-and-sub-agents-how-one-agent-learns-to-delegate" rel="noopener noreferrer"&gt;how one agent learns to delegate&lt;/a&gt; walks through cost modelling and reliability trade-offs worth considering before you commit.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;One final tip:&lt;/strong&gt; whichever you choose, start simple. A two-level hierarchy (supervisor + three sub-agents) is easier to reason about than a recursive tree of agents spawning agents. Get the observability and cost monitoring right at two levels before you go deeper.&lt;/p&gt;

&lt;p&gt;Your future self—and your AWS bill—will thank you.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>architecture</category>
      <category>softwareengineering</category>
      <category>agents</category>
    </item>
    <item>
      <title>MCP vs A2A: Stop Building Agent Architectures Wrong</title>
      <dc:creator>Marc Newstead</dc:creator>
      <pubDate>Mon, 22 Jun 2026 09:08:45 +0000</pubDate>
      <link>https://dev.to/icentric/mcp-vs-a2a-stop-building-agent-architectures-wrong-fgo</link>
      <guid>https://dev.to/icentric/mcp-vs-a2a-stop-building-agent-architectures-wrong-fgo</guid>
      <description>&lt;h2&gt;
  
  
  MCP vs A2A: Stop Building Agent Architectures Wrong
&lt;/h2&gt;

&lt;p&gt;If you're wiring up AI agents in production right now, you've probably hit the same confusion I did: &lt;em&gt;when do I use MCP, and when do I need A2A?&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Turns out, they're not alternatives. They solve different problems at different layers of your stack. Mixing them up will wreck your architecture before you've shipped v1.&lt;/p&gt;

&lt;p&gt;Let me break down what I wish someone had told me three months ago.&lt;/p&gt;

&lt;h2&gt;
  
  
  MCP: Your Agent Talks to Tools
&lt;/h2&gt;

&lt;p&gt;Model Context Protocol (Anthropic's spec) is about &lt;strong&gt;agent-to-tool communication&lt;/strong&gt;. Think of it as the interface layer between your LLM and the stuff it needs to &lt;em&gt;do things&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;When your agent needs to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Query a database&lt;/li&gt;
&lt;li&gt;Call an internal API&lt;/li&gt;
&lt;li&gt;Read from a file system&lt;/li&gt;
&lt;li&gt;Fetch customer records&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;...you're in MCP territory.&lt;/p&gt;

&lt;h3&gt;
  
  
  What MCP Actually Gives You
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// MCP server exposes capabilities&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;mcpServer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;tools&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="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;query_customer_db&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Fetch customer by ID&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;inputSchema&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;customerId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;string&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The protocol standardises how your agent &lt;em&gt;discovers&lt;/em&gt; what tools exist, how to invoke them, and how results flow back. It's RPC with schema negotiation baked in.&lt;/p&gt;

&lt;p&gt;Crucially: &lt;strong&gt;MCP doesn't care about agent autonomy&lt;/strong&gt;. It's a request-response pattern. Your agent asks, the tool answers. Done.&lt;/p&gt;

&lt;h2&gt;
  
  
  A2A: Your Agents Talk to Each Other
&lt;/h2&gt;

&lt;p&gt;Agent-to-Agent protocol (Google's answer to multi-agent coordination) operates at a completely different layer. This is about &lt;strong&gt;autonomous systems negotiating with each other&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;When you need:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A research agent to delegate to a summarisation agent&lt;/li&gt;
&lt;li&gt;A planning agent to coordinate with execution agents&lt;/li&gt;
&lt;li&gt;Agents to negotiate task ownership&lt;/li&gt;
&lt;li&gt;Asynchronous handoffs between agent workflows&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;...you're in A2A territory.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Key Difference
&lt;/h3&gt;

&lt;p&gt;A2A assumes &lt;strong&gt;both sides have agency&lt;/strong&gt;. They're not calling dumb tools — they're collaborating with other intelligent systems that have their own goals, context, and decision-making.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# A2A coordination (conceptual)&lt;/span&gt;
&lt;span class="na"&gt;Agent A -&amp;gt; Agent B&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Can&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;you&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;handle&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;UK&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;tax&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;calculation?"&lt;/span&gt;
&lt;span class="na"&gt;Agent B -&amp;gt; Agent A&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Yes,&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;send&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;me&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;the&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;transaction&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;data"&lt;/span&gt;
&lt;span class="na"&gt;Agent A -&amp;gt; Agent B&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;structured payload&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
&lt;span class="na"&gt;Agent B -&amp;gt; Agent A&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Completed.&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;Result:&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;£2,450&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;VAT&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;due"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Notice the back-and-forth? That's negotiation. MCP doesn't do that.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why This Matters When You're Building
&lt;/h2&gt;

&lt;p&gt;Here's where teams go wrong: they try to use MCP to wire agents together.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Don't do this:&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;# Anti-pattern: Agent-to-agent via MCP
&lt;/span&gt;&lt;span class="n"&gt;mcp_server&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;register_tool&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;call_summarisation_agent&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="c1"&gt;# ❌ This is an agent, not a tool
&lt;/span&gt;    &lt;span class="n"&gt;handler&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;lambda&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;summarisation_agent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&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;Why does this break down?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;MCP is synchronous and blocking — agents need async coordination&lt;/li&gt;
&lt;li&gt;MCP has no concept of agent state or context handoff&lt;/li&gt;
&lt;li&gt;You lose the negotiation layer (what if the agent is busy? unavailable? needs clarification?)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Instead, use MCP to give each agent its own tools, then use A2A (or a message bus, or even HTTP with agent-aware semantics) to let them coordinate.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Better architecture:&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;┌─────────────────┐         ┌─────────────────┐
│   Agent A       │         │   Agent B       │
│                 │         │                 │
│  ┌───────────┐  │  A2A    │  ┌───────────┐  │
│  │ MCP Tools │  │ ◄─────► │  │ MCP Tools │  │
│  └───────────┘  │         │  └───────────┘  │
└─────────────────┘         └─────────────────┘
       │                           │
       │ MCP                       │ MCP
       ▼                           ▼
   [Database]                  [API]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Each agent gets its own MCP interface to tools. Agents talk to each other via A2A.&lt;/p&gt;

&lt;h2&gt;
  
  
  What to Do Tomorrow
&lt;/h2&gt;

&lt;p&gt;If you're designing an agentic system:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Map your tool layer first&lt;/strong&gt; — what external capabilities do agents need? Build MCP servers for those.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Identify agent boundaries&lt;/strong&gt; — where does one agent's responsibility end and another's begin?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Choose your A2A transport&lt;/strong&gt; — could be Google's spec, could be a message queue with agent-aware semantics. Just don't use MCP for it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Keep agents dumb about each other's internals&lt;/strong&gt; — they should coordinate via high-level intent, not RPC.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The &lt;a href="https://www.icentricagency.com/insights/mcp-a2a-the-two-layer-stack-wiring-the-internet-of-agents" rel="noopener noreferrer"&gt;two-layer stack&lt;/a&gt; isn't theoretical — it's the separation of concerns your system needs to scale beyond a proof-of-concept.&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;MCP = agent ↔ tool&lt;/strong&gt; (synchronous, request-response, capability exposure)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A2A = agent ↔ agent&lt;/strong&gt; (asynchronous, stateful, coordination)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Get this wrong and you'll end up refactoring your entire stack when you need to add agent #3. Get it right and your architecture stays clean as you scale.&lt;/p&gt;

&lt;p&gt;If you're building this for real and need architecture help, teams doing serious &lt;a href="https://www.icentricagency.com" rel="noopener noreferrer"&gt;AI automation and software development&lt;/a&gt; are already using this mental model.&lt;/p&gt;

&lt;p&gt;Now go build something that doesn't fall over when you add more agents.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>architecture</category>
      <category>agents</category>
      <category>devops</category>
    </item>
    <item>
      <title>Stop Selling AI Projects on Hours Saved (And What to Track Instead)</title>
      <dc:creator>Marc Newstead</dc:creator>
      <pubDate>Mon, 15 Jun 2026 09:12:42 +0000</pubDate>
      <link>https://dev.to/icentric/stop-selling-ai-projects-on-hours-saved-and-what-to-track-instead-2681</link>
      <guid>https://dev.to/icentric/stop-selling-ai-projects-on-hours-saved-and-what-to-track-instead-2681</guid>
      <description>&lt;h2&gt;
  
  
  Stop Selling AI Projects on Hours Saved (And What to Track Instead)
&lt;/h2&gt;

&lt;p&gt;You've just shipped an AI feature that automates part of your product workflow. Marketing wants ROI numbers. Your PM asks: "How many hours does this save?"&lt;/p&gt;

&lt;p&gt;It's a trap.&lt;/p&gt;

&lt;p&gt;Here's why chasing "hours saved" metrics will sabotage your AI projects—and what you should measure instead.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Problem with Time-Saved Metrics
&lt;/h2&gt;

&lt;p&gt;Let's say you build an AI classifier that auto-tags support tickets. You measure that it saves your support team 30 minutes per day. Ship it, report the win, move on.&lt;/p&gt;

&lt;p&gt;Six months later:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The feature is still running&lt;/li&gt;
&lt;li&gt;No headcount has been reduced&lt;/li&gt;
&lt;li&gt;The support team is just as busy&lt;/li&gt;
&lt;li&gt;Finance asks why costs haven't changed&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;What happened? You optimised for the wrong metric. Time saved doesn't automatically translate to business value—especially when that time gets absorbed by other work, context switching, or simply Parkinson's Law.&lt;/p&gt;

&lt;p&gt;Worse, &lt;strong&gt;hour-based ROI invites the wrong conversations&lt;/strong&gt;. Stakeholders hear "we're automating 10 hours a week" and start asking about redundancies. Your engineering work becomes a political minefield instead of a technical improvement.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Developers Should Measure Instead
&lt;/h2&gt;

&lt;p&gt;Shift your metrics from &lt;em&gt;inputs&lt;/em&gt; (time spent) to &lt;em&gt;outcomes&lt;/em&gt; (results achieved). Ask: what is this process actually supposed to accomplish?&lt;/p&gt;

&lt;p&gt;Let's revisit that support ticket classifier:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Time-saved framing:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;"Saves 30 minutes of manual tagging per day"&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Outcome-based framing:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;"Reduces average ticket resolution time by 18%"&lt;/li&gt;
&lt;li&gt;"Increases first-response accuracy from 73% to 91%"&lt;/li&gt;
&lt;li&gt;"Decreases ticket escalations by 40%"&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;See the difference? The second set of metrics connects directly to what the business cares about: faster support, happier customers, fewer escalations.&lt;/p&gt;

&lt;h3&gt;
  
  
  Practical Examples by Domain
&lt;/h3&gt;

&lt;p&gt;Here's how this translates across common automation scenarios:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Code review automation:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;❌ "Saves 2 hours per week reviewing PRs"&lt;/li&gt;
&lt;li&gt;✅ "Reduces time-to-merge by 35%, catches 60% more style issues pre-review"&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Content moderation ML:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;❌ "Automates 1000 moderation decisions daily"&lt;/li&gt;
&lt;li&gt;✅ "Reduces harmful content visibility by 80%, decreases appeal rate by 25%"&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Inventory forecasting:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;❌ "Saves data team 5 hours weekly on reports"&lt;/li&gt;
&lt;li&gt;✅ "Reduces stockouts by 45%, decreases overstock by 30%"&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Building This Into Your Workflow
&lt;/h2&gt;

&lt;p&gt;The trick is defining success criteria &lt;em&gt;before&lt;/em&gt; you write any code. Here's a lightweight framework:&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Start with the Business Outcome
&lt;/h3&gt;

&lt;p&gt;Before the sprint starts, write down:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What specific outcome are we trying to improve?&lt;/li&gt;
&lt;li&gt;How is it measured today?&lt;/li&gt;
&lt;li&gt;What's the baseline metric?
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Document this in your ADR or project brief
&lt;/span&gt;&lt;span class="n"&gt;BASELINE_METRICS&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;ticket_resolution_time_p50&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;4.2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="c1"&gt;# hours
&lt;/span&gt;    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;first_response_accuracy&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;0.73&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;escalation_rate&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;0.18&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="n"&gt;TARGET_OUTCOMES&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;ticket_resolution_time_p50&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;3.5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="c1"&gt;# 15% improvement
&lt;/span&gt;    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;first_response_accuracy&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;0.85&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;    &lt;span class="c1"&gt;# 12pp improvement
&lt;/span&gt;    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;escalation_rate&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;0.12&lt;/span&gt;             &lt;span class="c1"&gt;# 6pp improvement
&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 Outcomes, Not Activity
&lt;/h3&gt;

&lt;p&gt;Your telemetry should track results, not just usage.&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;// Less useful&lt;/span&gt;
&lt;span class="nx"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;info&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 classifier invoked&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;ticketId&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="c1"&gt;// More useful&lt;/span&gt;
&lt;span class="nx"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;info&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Ticket resolved&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;ticketId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;resolutionTimeMinutes&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;autoTagAccuracy&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;escalated&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;aiAssisted&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  3. Compare Before/After, Control/Treatment
&lt;/h3&gt;

&lt;p&gt;Run A/B tests where possible. Roll out gradually and measure the delta:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;50% of tickets use AI tagging, 50% don't&lt;/li&gt;
&lt;li&gt;Compare resolution times, accuracy, escalations&lt;/li&gt;
&lt;li&gt;Ship to 100% only if outcomes improve&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Why This Matters for Your Career
&lt;/h2&gt;

&lt;p&gt;As a developer, learning to frame your work in business outcomes—not just technical achievements—is a force multiplier. It makes your projects easier to fund, easier to defend, and much harder to cut when budgets tighten.&lt;/p&gt;

&lt;p&gt;The companies getting &lt;a href="https://www.icentricagency.com" rel="noopener noreferrer"&gt;AI automation and software development&lt;/a&gt; right aren't the ones chasing headcount reduction. They're the ones connecting automation directly to revenue, customer satisfaction, or strategic goals.&lt;/p&gt;

&lt;p&gt;If you're presenting AI work to non-technical stakeholders, skip the "hours saved" pitch. Show them &lt;a href="https://www.icentricagency.com/insights/measuring-ai-automation-by-outcomes-not-hours-saved-1" rel="noopener noreferrer"&gt;outcomes, not hours saved&lt;/a&gt;, and watch the conversation shift from "can we afford this?" to "how fast can we scale it?"&lt;/p&gt;

&lt;h2&gt;
  
  
  Quick Takeaways
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Time saved ≠ value delivered.&lt;/strong&gt; Hours are an input; outcomes are what matter.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Define success metrics before you code.&lt;/strong&gt; Baseline, target, measurement strategy.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Instrument for business outcomes, not just feature usage.&lt;/strong&gt; Track resolution time, accuracy, customer impact.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Use A/B testing to prove the delta.&lt;/strong&gt; Control groups make ROI undeniable.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Frame your work in business terms.&lt;/strong&gt; It makes you a more effective engineer and a better communicator.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Your AI feature might save time—but if you can't connect it to a better outcome, you're building on sand.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>devops</category>
      <category>productivity</category>
      <category>career</category>
    </item>
    <item>
      <title>Building Persistent AI Agents: A Dev's Guide to State Management and Long-Running Workflows</title>
      <dc:creator>Marc Newstead</dc:creator>
      <pubDate>Mon, 15 Jun 2026 09:10:05 +0000</pubDate>
      <link>https://dev.to/icentric/building-persistent-ai-agents-a-devs-guide-to-state-management-and-long-running-workflows-42a0</link>
      <guid>https://dev.to/icentric/building-persistent-ai-agents-a-devs-guide-to-state-management-and-long-running-workflows-42a0</guid>
      <description>&lt;h2&gt;
  
  
  The Problem with Stateless Agents
&lt;/h2&gt;

&lt;p&gt;Most AI agents we build today are essentially fancy request-response systems. User asks, agent responds, context dies. Rinse and repeat. But what happens when you need an agent that can start a workflow on Monday, wait for external approval on Wednesday, and resume execution on Friday — all while maintaining perfect context?&lt;/p&gt;

&lt;p&gt;That's the shift from chatbots to &lt;a href="https://www.icentricagency.com/insights/persistent-agents-when-ai-stops-being-a-chatbot-and-starts-being-always-on" rel="noopener noreferrer"&gt;persistent agents&lt;/a&gt;. And it changes everything about how we architect AI systems.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Makes an Agent "Persistent"?
&lt;/h2&gt;

&lt;p&gt;A persistent agent isn't just a chatbot with better memory. It's a system that:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Maintains state across sessions&lt;/strong&gt; — not just conversation history, but workflow position, pending actions, and decision context&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Can pause and resume&lt;/strong&gt; — waiting on external events, human input, or scheduled triggers without losing its place&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Initiates actions autonomously&lt;/strong&gt; — checking conditions, triggering workflows, and making decisions without explicit user prompts&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Recovers gracefully&lt;/strong&gt; — handling failures, retries, and state corruption without manual intervention&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Think less "chat interface" and more "background worker with reasoning capabilities".&lt;/p&gt;

&lt;h2&gt;
  
  
  The Hard Part Isn't the LLM Calls
&lt;/h2&gt;

&lt;p&gt;Here's what surprised me: building the agent logic itself is relatively straightforward. Frameworks like LangGraph, CrewAI, and AutoGen handle the orchestration. Calling GPT-4 or Claude is trivial. Integrating tools and APIs is just... normal backend work.&lt;/p&gt;

&lt;p&gt;The hard part is &lt;strong&gt;state management&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  State Storage: More Than Just JSON
&lt;/h3&gt;

&lt;p&gt;You need to persist:&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="p"&gt;{&lt;/span&gt;
  &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;workflow_id&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;claim_review_001&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;current_step&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;awaiting_manager_approval&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;context&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;claim_amount&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1250&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;supporting_docs&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[...],&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;previous_decisions&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[...]&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;pending_actions&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;type&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;wait_for_approval&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;timeout&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;2024-02-15T17:00:00Z&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;llm_state&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;reasoning_trace&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;tool_call_history&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[...]&lt;/span&gt;
  &lt;span class="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;But here's the thing: this state evolves. The agent needs atomic updates. You need versioning for rollbacks. You need to handle concurrent modifications if multiple agents or humans interact with the same workflow.&lt;/p&gt;

&lt;p&gt;Suddenly you're designing a state machine with persistence, not just prompt engineering.&lt;/p&gt;

&lt;h2&gt;
  
  
  Interruption as a First-Class Concept
&lt;/h2&gt;

&lt;p&gt;In traditional software, interruption is an exception case. In persistent agents, &lt;strong&gt;interruption is the normal case&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Your agent will:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Pause to wait for human approval&lt;/li&gt;
&lt;li&gt;Stop because a rate limit was hit&lt;/li&gt;
&lt;li&gt;Yield while waiting for an external system&lt;/li&gt;
&lt;li&gt;Get interrupted because a higher-priority task arrived&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Each interruption point needs explicit handling:&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;process_claim_step&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="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;requires_human_review&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;PauseState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="n"&gt;resume_trigger&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;approval_received&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;to_dict&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
            &lt;span class="n"&gt;timeout_hours&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;72&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="c1"&gt;# Continue processing...
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You're not building a linear function anymore. You're building a resumable state machine.&lt;/p&gt;

&lt;h2&gt;
  
  
  Human-in-the-Loop Isn't Optional
&lt;/h2&gt;

&lt;p&gt;For any agent doing real work — approving expenses, modifying production data, sending customer communications — human oversight isn't a nice-to-have. It's regulatory, ethical, and practical table stakes.&lt;/p&gt;

&lt;p&gt;But "human-in-the-loop" means different things:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Approval gates&lt;/strong&gt; — agent pauses, human approves/rejects, agent continues&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Suggested actions&lt;/strong&gt; — agent proposes, human edits, agent executes&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Monitoring dashboards&lt;/strong&gt; — humans can intervene at any point&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This isn't a UI concern. It's an architectural decision that affects your state model, your event system, and your error handling.&lt;/p&gt;

&lt;p&gt;If you're building systems that blend &lt;a href="https://www.icentricagency.com" rel="noopener noreferrer"&gt;AI automation and software development&lt;/a&gt;, you need to design for human intervention from day one, not bolt it on later.&lt;/p&gt;

&lt;h2&gt;
  
  
  Observability Gets Weird
&lt;/h2&gt;

&lt;p&gt;How do you debug an agent that's been running for three days and is currently paused?&lt;/p&gt;

&lt;p&gt;Your standard APM tools won't help. You need:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Workflow visualisation&lt;/strong&gt; — where is each agent in its process?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;State inspection&lt;/strong&gt; — what decisions has it made? What's it waiting for?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Reasoning traces&lt;/strong&gt; — why did it take action X instead of Y?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Replay capability&lt;/strong&gt; — can you rerun from a checkpoint with different conditions?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Logging becomes critical. Every LLM call, every tool invocation, every state transition needs to be traceable.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where to Start
&lt;/h2&gt;

&lt;p&gt;If you're building your first persistent agent:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Choose a state backend early&lt;/strong&gt; — Redis, PostgreSQL, or a proper workflow engine like Temporal&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Design your state schema first&lt;/strong&gt; — before you write agent logic&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Build pause/resume into every step&lt;/strong&gt; — don't assume linear execution&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Make state transitions explicit&lt;/strong&gt; — log everything, version your state&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Test interruption scenarios&lt;/strong&gt; — not just happy paths&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  The Shift in Thinking
&lt;/h2&gt;

&lt;p&gt;Persistent agents force us to think differently. We're not building APIs or microservices anymore. We're building &lt;strong&gt;systems that think in the background&lt;/strong&gt; — agents that are always on, always aware, and always ready to pick up where they left off.&lt;/p&gt;

&lt;p&gt;The code isn't harder. The architecture is just... different. And that's the real challenge.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>architecture</category>
      <category>agenticai</category>
      <category>softwareengineering</category>
    </item>
    <item>
      <title>Stop Measuring AI Features By Hours Saved (Measure This Instead)</title>
      <dc:creator>Marc Newstead</dc:creator>
      <pubDate>Mon, 08 Jun 2026 09:12:39 +0000</pubDate>
      <link>https://dev.to/icentric/stop-measuring-ai-features-by-hours-saved-measure-this-instead-n4b</link>
      <guid>https://dev.to/icentric/stop-measuring-ai-features-by-hours-saved-measure-this-instead-n4b</guid>
      <description>&lt;h2&gt;
  
  
  The "Time Saved" Trap We Keep Falling Into
&lt;/h2&gt;

&lt;p&gt;You've just shipped an AI feature. Your manager asks: "How much time does this save users?"&lt;/p&gt;

&lt;p&gt;It sounds reasonable. We're engineers — we optimise for efficiency. But this question often leads us to build the wrong thing and measure what doesn't matter.&lt;/p&gt;

&lt;p&gt;I've watched teams spend months building AI tools that technically saved hours but delivered zero business value. The feature worked. The metrics looked good. Nobody used it after the first week.&lt;/p&gt;

&lt;p&gt;Here's why measuring &lt;a href="https://www.icentricagency.com/insights/measuring-ai-automation-by-outcomes-not-hours-saved" rel="noopener noreferrer"&gt;outcomes not hours&lt;/a&gt; matters more than you think — and how to instrument for it from day one.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why "Hours Saved" Breaks Your Decision-Making
&lt;/h2&gt;

&lt;p&gt;The labour-hour metric made sense when automation meant replacing repetitive tasks. If your script processes 1,000 invoices instead of a human spending 40 hours doing it, the maths is simple.&lt;/p&gt;

&lt;p&gt;But modern AI features don't work like that. They:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Augment decisions&lt;/strong&gt; (suggesting code completions, not writing entire apps)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Enable new workflows&lt;/strong&gt; (analysis that wasn't feasible manually)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Shift quality, not just speed&lt;/strong&gt; (better detection, fewer false positives)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When you measure a code completion tool by "time saved typing", you miss that its real value might be:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Reducing context-switching by keeping developers in flow&lt;/li&gt;
&lt;li&gt;Lowering the barrier for junior devs to write idiomatic code&lt;/li&gt;
&lt;li&gt;Decreasing cognitive load during complex refactors&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;None of those show up in a time-saved metric. Worse, optimising for time-saved might lead you to auto-complete aggressively when developers actually want suggestions that help them &lt;em&gt;think&lt;/em&gt;, not type faster.&lt;/p&gt;

&lt;h2&gt;
  
  
  What to Measure Instead: Outcomes Engineers Can Instrument
&lt;/h2&gt;

&lt;p&gt;Shift your instrumentation to capture &lt;strong&gt;what changed&lt;/strong&gt;, not just &lt;strong&gt;what was faster&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Example: AI-Powered Code Review Assistant
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Don't measure:&lt;/strong&gt; "Saved 15 minutes per PR review"&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Do measure:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Defect escape rate (bugs reaching production)&lt;/li&gt;
&lt;li&gt;Time-to-merge for PRs of similar complexity&lt;/li&gt;
&lt;li&gt;Reviewer confidence scores (post-merge survey)&lt;/li&gt;
&lt;li&gt;Rate of AI suggestions accepted vs. dismissed&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Example: Automated Customer Query Classifier
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Don't measure:&lt;/strong&gt; "Replaced 10 hours/week of manual tagging"&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Do measure:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;First-response accuracy (correct routing)&lt;/li&gt;
&lt;li&gt;Customer satisfaction with resolution&lt;/li&gt;
&lt;li&gt;Escalation rate to human agents&lt;/li&gt;
&lt;li&gt;Query resolution time end-to-end&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  The Pattern
&lt;/h3&gt;

&lt;p&gt;For any AI feature, ask:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;What business outcome does this enable?&lt;/strong&gt; (faster deployments, fewer incidents, better conversion)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;What baseline exists?&lt;/strong&gt; (instrument &lt;em&gt;before&lt;/em&gt; you ship)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;What proxy metrics indicate progress?&lt;/strong&gt; (leading indicators you can measure weekly)&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Instrumenting for Outcomes From Day One
&lt;/h2&gt;

&lt;p&gt;This is where most teams fail: they bolt on measurement after launch. You can't retrofit a baseline.&lt;/p&gt;

&lt;h3&gt;
  
  
  Pre-Launch Checklist
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Pseudocode: What your instrumentation might look like
&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;AIFeatureMetrics&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;feature_name&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;feature&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;feature_name&lt;/span&gt;

    &lt;span class="k"&gt;def&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;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;user_id&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;context&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;
        Log every meaningful interaction:
        - What did the AI suggest?
        - What did the user do with it?
        - What was the context? (task type, user experience level)
        &lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
        &lt;span class="n"&gt;event&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;timestamp&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
            &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;feature&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;feature&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;user&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;user_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;action&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;action&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="c1"&gt;# accepted, rejected, modified
&lt;/span&gt;            &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;context&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;outcome&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;  &lt;span class="c1"&gt;# filled in later
&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;event_store&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="n"&gt;event&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;link_to_outcome&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;interaction_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;outcome_metric&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;
        Connect the AI interaction to business outcome:
        - Did the PR with AI suggestions have fewer bugs?
        - Did the AI-routed ticket resolve faster?
        &lt;/span&gt;&lt;span class="sh"&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;event_store&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;interaction_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;outcome&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;outcome_metric&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;Key principle:&lt;/strong&gt; Capture the interaction &lt;em&gt;and&lt;/em&gt; the eventual outcome. This lets you correlate AI assistance with business results.&lt;/p&gt;

&lt;h2&gt;
  
  
  Making This Work in Practice
&lt;/h2&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;, here's the tactical approach:&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Define Success Before You Code
&lt;/h3&gt;

&lt;p&gt;Write your "definition of done" to include outcome metrics:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gu"&gt;## Feature: AI-Powered Incident Classifier&lt;/span&gt;

&lt;span class="gs"&gt;**Success criteria:**&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; 80% of incidents routed to correct team (up from 65% baseline)
&lt;span class="p"&gt;-&lt;/span&gt; Mean-time-to-engagement decreases by 20%
&lt;span class="p"&gt;-&lt;/span&gt; On-call satisfaction score maintained or improved

&lt;span class="gs"&gt;**NOT success:**&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; "Saves 5 hours/week of manual classification"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  2. Build a Baseline Period
&lt;/h3&gt;

&lt;p&gt;Run your instrumentation for 2-4 weeks &lt;em&gt;before&lt;/em&gt; enabling the AI feature. You need the counterfactual.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Plan Your Feedback Loop
&lt;/h3&gt;

&lt;p&gt;How will you know if outcomes improve?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Weekly cohort analysis (users with AI vs. without)&lt;/li&gt;
&lt;li&gt;Monthly business metric reviews&lt;/li&gt;
&lt;li&gt;Qualitative feedback sessions (what changed in practice?)&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;Hours saved is easy to measure but often meaningless. Outcomes are harder to instrument but tell you whether you built the right thing.&lt;/p&gt;

&lt;p&gt;As engineers, we control the telemetry. Instrument for outcomes from day one, and you'll ship AI features that actually matter.&lt;/p&gt;

&lt;p&gt;What outcome metrics are you tracking for your AI features? Let's discuss in the comments.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>devops</category>
      <category>productivity</category>
      <category>softwareengineering</category>
    </item>
    <item>
      <title>Stop Using One LLM for Everything: A Dev's Guide to Model Routing</title>
      <dc:creator>Marc Newstead</dc:creator>
      <pubDate>Mon, 08 Jun 2026 09:10:08 +0000</pubDate>
      <link>https://dev.to/icentric/stop-using-one-llm-for-everything-a-devs-guide-to-model-routing-4fl1</link>
      <guid>https://dev.to/icentric/stop-using-one-llm-for-everything-a-devs-guide-to-model-routing-4fl1</guid>
      <description>&lt;h2&gt;
  
  
  The Problem With Your Current LLM Stack
&lt;/h2&gt;

&lt;p&gt;If you're sending every prompt through GPT-4 or Claude Opus because "it's the best model", you're probably burning money on overkill. Classifying a support ticket's sentiment doesn't need the same horsepower as generating a product requirements document. Yet most codebases I see treat LLM calls like they're all created equal.&lt;/p&gt;

&lt;p&gt;Model routing solves this. Instead of one model for everything, you dynamically select which model handles each task based on complexity, cost, and latency requirements. Think of it as load balancing, but for intelligence.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Model Routing Actually Looks Like
&lt;/h2&gt;

&lt;p&gt;At its core, a router is middleware between your app and your LLM providers. Here's the mental model:&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;route_llm_request&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;complexity&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;analyse_task&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="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;complexity&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;simple&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;call_model&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;gpt-3.5-turbo&lt;/span&gt;&lt;span class="sh"&gt;"&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="k"&gt;elif&lt;/span&gt; &lt;span class="n"&gt;complexity&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;moderate&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;call_model&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;claude-haiku&lt;/span&gt;&lt;span class="sh"&gt;"&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="k"&gt;else&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;call_model&lt;/span&gt;&lt;span class="p"&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="n"&gt;task&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Obviously production implementations get more sophisticated, but the principle holds: &lt;strong&gt;inspect the task, pick the cheapest model that can handle it reliably&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Mapping Tasks to Models
&lt;/h2&gt;

&lt;p&gt;The hard part isn't the routing logic—it's building a sensible taxonomy of your tasks. Start by auditing what you're actually sending to LLMs:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Classification tasks&lt;/strong&gt;: Intent detection, sentiment analysis, category assignment. These are often binary or multi-class decisions. GPT-3.5-turbo or even GPT-4o-mini handles these beautifully at a fraction of the cost.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Retrieval-augmented generation&lt;/strong&gt;: Answering questions from your docs. Moderate complexity. Models like Claude Haiku or Gemini Flash offer solid performance without flagship pricing.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Content generation&lt;/strong&gt;: Drafting emails, writing code, creating marketing copy. This is where you might actually need GPT-4 or Claude Opus—but only when the stakes justify it.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Structured extraction&lt;/strong&gt;: Pulling entities from text, parsing invoices. If you can define a JSON schema, smaller models work fine, especially with function calling.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The key insight: most applications have a &lt;strong&gt;long tail of simple tasks&lt;/strong&gt; subsidising a small number of complex ones. Route accordingly.&lt;/p&gt;

&lt;h2&gt;
  
  
  Tracking the Wins
&lt;/h2&gt;

&lt;p&gt;You need telemetry. Log every routing decision with:&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="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;taskId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;uuid&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
  &lt;span class="nx"&gt;taskType&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;classification&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;modelSelected&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-3.5-turbo&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;tokens&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;150&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;cost&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;0.0003&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;latency&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;420&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;timestamp&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="nf"&gt;now&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;After a week, aggregate this. You'll likely find:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;70%+ of requests are simple and could use cheaper models&lt;/li&gt;
&lt;li&gt;Your highest costs come from 5-10% of requests&lt;/li&gt;
&lt;li&gt;Latency improves because smaller models are faster&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;One team I worked with cut their monthly LLM bill by 60% just by routing classification and extraction tasks away from GPT-4. The business logic didn't change—just the infrastructure underneath.&lt;/p&gt;

&lt;h2&gt;
  
  
  Fallback Strategies and Provider Diversity
&lt;/h2&gt;

&lt;p&gt;Routing also gives you resilience. If OpenAI's API goes down (and it will), your router can failover to Anthropic or Gemini. This requires:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Normalised interfaces&lt;/strong&gt;: Abstract provider-specific SDKs behind a common interface&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Retry logic&lt;/strong&gt;: Catch rate limits and failures, try the next model in your tier&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Circuit breakers&lt;/strong&gt;: Temporarily skip a provider if it's consistently failing
&lt;/li&gt;
&lt;/ol&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;call_with_fallback&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;models_list&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;model&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;models_list&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;call_model&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;task&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="n"&gt;ProviderError&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;continue&lt;/span&gt;
    &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nc"&gt;AllProvidersFailed&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This multi-provider approach also dodges vendor lock-in. When you're not married to a single API, you can negotiate better pricing and adopt new models faster.&lt;/p&gt;

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

&lt;p&gt;You don't need to build a Netflix-scale routing system on day one. Start simple:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Categorise your prompts&lt;/strong&gt;. Spend an afternoon tagging a sample of requests by complexity.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Benchmark models&lt;/strong&gt; on each category. Test accuracy, cost, and latency.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Implement a basic router&lt;/strong&gt;. Even a hardcoded if/else saves money immediately.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Instrument everything&lt;/strong&gt;. You can't optimise what you don't measure.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Iterate&lt;/strong&gt;. Add more sophisticated routing rules as your usage patterns emerge.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;For a deeper dive into the strategic thinking behind this approach, the team at &lt;a href="https://www.icentricagency.com" rel="noopener noreferrer"&gt;AI automation and software development&lt;/a&gt; have a solid write-up on &lt;a href="https://www.icentricagency.com/insights/model-routing-the-smarter-way-to-deploy-llms-at-scale" rel="noopener noreferrer"&gt;deploying LLMs at scale&lt;/a&gt; that's worth reading.&lt;/p&gt;

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

&lt;p&gt;Using one model for everything is like running every database query against your production master. Sure, it works—but it's wasteful and fragile. Model routing gives you cost control, performance headroom, and architectural flexibility.&lt;/p&gt;

&lt;p&gt;Start small, measure everything, and let the data guide your routing decisions. Your infrastructure budget will thank you.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>architecture</category>
      <category>llm</category>
      <category>devops</category>
    </item>
    <item>
      <title>Why Your RPA Bot Keeps Breaking: A Process Mining Reality Check</title>
      <dc:creator>Marc Newstead</dc:creator>
      <pubDate>Mon, 01 Jun 2026 16:07:47 +0000</pubDate>
      <link>https://dev.to/icentric/why-your-rpa-bot-keeps-breaking-a-process-mining-reality-check-53hg</link>
      <guid>https://dev.to/icentric/why-your-rpa-bot-keeps-breaking-a-process-mining-reality-check-53hg</guid>
      <description>&lt;h2&gt;
  
  
  Why Your RPA Bot Keeps Breaking: A Process Mining Reality Check
&lt;/h2&gt;

&lt;p&gt;You've just shipped an RPA bot that automates invoice processing. It worked perfectly in UAT. Two weeks into production, it's failing 40% of the time. Sound familiar?&lt;/p&gt;

&lt;p&gt;The culprit isn't your code—it's &lt;strong&gt;process variance&lt;/strong&gt; you never knew existed. This is where process mining stops being a cool dashboard and becomes actual engineering work.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Process Mining Actually Shows You
&lt;/h2&gt;

&lt;p&gt;Process mining tools (SAP Signavio, Celonis, etc.) ingest event logs from your ERP, CRM, or whatever system you're working with. They reconstruct what &lt;em&gt;actually&lt;/em&gt; happens versus what the process documentation claims happens.&lt;/p&gt;

&lt;p&gt;Here's a real example from a warehouse management system integration I worked on:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Expected 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;Order Created → Picked → Packed → Shipped → Invoiced
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;What the event logs showed:&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;Order Created → Picked → Packed → Shipped → Invoiced (62% of cases)
Order Created → Picked → Packed → Invoiced → Shipped (23%)
Order Created → Invoiced → Picked → Packed → Shipped (8%)
Order Created → Split → Picked (partial) → ... (7% chaos)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That 38% variance? That's why your automation breaks. The bot was coded for the happy path. The business swore that was the &lt;em&gt;only&lt;/em&gt; path.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Gap Between "Should" and "Does"
&lt;/h2&gt;

&lt;p&gt;This delta is called a &lt;strong&gt;conformance gap&lt;/strong&gt;. As developers, we encounter this constantly:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;API documentation says the field is required, but 15% of records have it null&lt;/li&gt;
&lt;li&gt;The procurement process "always" requires three approvals, except when someone with director-level access shortcuts it&lt;/li&gt;
&lt;li&gt;Purchase orders "must" be created before goods receipt, but half your warehouses do it backwards&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Process mining makes these gaps visible at scale. The problem is that discovering them is the &lt;em&gt;easy&lt;/em&gt; part. &lt;a href="https://www.icentricagency.com/insights/ai-process-mining-the-real-work-begins-after-the-discovery" rel="noopener noreferrer"&gt;The real work begins&lt;/a&gt; when you have to fix them.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why This Matters for Automation Projects
&lt;/h2&gt;

&lt;p&gt;Every process variant you don't account for is a potential failure mode. Consider 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="c1"&gt;# What you wrote
&lt;/span&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;process_invoice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;invoice&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="nf"&gt;validate_po&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;invoice&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;po_number&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;check_three_way_match&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;invoice&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;po&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;goods_receipt&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;post_to_ledger&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;invoice&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# What actually needs to happen
&lt;/span&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;process_invoice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;invoice&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;invoice&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;po_number&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="nf"&gt;validate_po&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;invoice&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;po_number&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;goods_receipt_exists&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;invoice&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;po_number&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
            &lt;span class="nf"&gt;check_three_way_match&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;invoice&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;po&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;goods_receipt&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="c1"&gt;# Handle 12% of cases where GR comes later
&lt;/span&gt;            &lt;span class="nf"&gt;flag_for_manual_review&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;invoice&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="c1"&gt;# Handle 8% of non-PO invoices
&lt;/span&gt;        &lt;span class="nf"&gt;route_to_exception_queue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;invoice&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="nf"&gt;post_to_ledger&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;invoice&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The difference between these two implementations is whether your automation has a 70% success rate or a 95% success rate.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Developer's Role After Discovery
&lt;/h2&gt;

&lt;p&gt;Once you've got process mining data, here's what actually needs doing:&lt;/p&gt;

&lt;h3&gt;
  
  
  1. &lt;strong&gt;Variant Analysis and Prioritisation&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;You can't code for every edge case. Use Pareto principle:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Handle the top 3–5 variants that cover 80%+ of volume&lt;/li&gt;
&lt;li&gt;Build exception queues for the rest&lt;/li&gt;
&lt;li&gt;Don't try to automate the 2% of cases that involve manual overrides from the CFO&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  2. &lt;strong&gt;Root Cause Investigation&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Why does the variant exist?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;System limitation&lt;/strong&gt;: Legacy system doesn't enforce order, need middleware&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Legitimate business reason&lt;/strong&gt;: Expedited orders follow different path&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Workaround&lt;/strong&gt;: Users circumventing a broken approval flow&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Training gap&lt;/strong&gt;: New hires don't know the standard process&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Only the first two belong in your code. The others need process fixes.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. &lt;strong&gt;Design for Observable Variance&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Build your automation to log which variant it's processing:&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;logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;info&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;Processing invoice &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;inv&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; via variant: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;variant_type&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;metrics&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;increment&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;invoice.variant.&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;variant_type&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This gives you telemetry when new variants emerge (and they will).&lt;/p&gt;

&lt;h2&gt;
  
  
  Where Consultancies Come In
&lt;/h2&gt;

&lt;p&gt;SAP and Celonis will sell you the mining tool. They won't:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Interview stakeholders to understand why variants exist&lt;/li&gt;
&lt;li&gt;Redesign broken approval workflows&lt;/li&gt;
&lt;li&gt;Mediate between finance and operations when their processes conflict&lt;/li&gt;
&lt;li&gt;Retrain users or update documentation&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That's consulting work. If you're at an agency focused on &lt;a href="https://www.icentricagency.com" rel="noopener noreferrer"&gt;AI automation and software development&lt;/a&gt;, this is where you add value—bridging the gap between what the data shows and what engineering can actually automate.&lt;/p&gt;

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

&lt;p&gt;Process mining is brilliant for surfacing the mess. But turning those insights into stable, production-grade automation requires:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Engineering rigour to handle variants gracefully&lt;/li&gt;
&lt;li&gt;Business analysis to fix what can be standardised&lt;/li&gt;
&lt;li&gt;Operational discipline to maintain conformance over time&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The ML model that predicts process outcomes is impressive. The unglamorous work of handling the "invoiced before shipped" edge case? That's what keeps your bot running in production.&lt;/p&gt;

&lt;p&gt;Don't confuse deploying a tool with solving the problem.&lt;/p&gt;

</description>
      <category>automation</category>
      <category>processoptimization</category>
      <category>rpa</category>
      <category>enterprisesoftware</category>
    </item>
    <item>
      <title>So Your Company Wants Multi-Agent AI Systems. Who's Actually Going to Build Them?</title>
      <dc:creator>Marc Newstead</dc:creator>
      <pubDate>Mon, 01 Jun 2026 09:11:47 +0000</pubDate>
      <link>https://dev.to/icentric/so-your-company-wants-multi-agent-ai-systems-whos-actually-going-to-build-them-cgo</link>
      <guid>https://dev.to/icentric/so-your-company-wants-multi-agent-ai-systems-whos-actually-going-to-build-them-cgo</guid>
      <description>&lt;h2&gt;
  
  
  So Your Company Wants Multi-Agent AI Systems. Who's Actually Going to Build Them?
&lt;/h2&gt;

&lt;p&gt;I've been watching a strange pattern emerge across enterprise engineering teams: everyone's excited about multi-agent AI systems, but nobody's quite sure who owns them.&lt;/p&gt;

&lt;p&gt;Your backend team says it's an architecture problem. Your ML engineers say they build models, not workflows. Your DevOps team is already drowning. And your product managers are drawing diagrams with arrows between cartoon robots, hoping someone will make it real.&lt;/p&gt;

&lt;p&gt;Welcome to the emerging role of the AI Workflow Architect — and if you've never heard of it, you're not alone.&lt;/p&gt;

&lt;h2&gt;
  
  
  What This Actually Looks Like in Practice
&lt;/h2&gt;

&lt;p&gt;Let me paint a concrete scenario. You're building a customer support system where:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Agent A monitors incoming tickets and classifies urgency&lt;/li&gt;
&lt;li&gt;Agent B pulls relevant documentation and past tickets&lt;/li&gt;
&lt;li&gt;Agent C drafts responses&lt;/li&gt;
&lt;li&gt;Agent D decides whether to auto-send or escalate to humans&lt;/li&gt;
&lt;li&gt;Agent E learns from human edits and feeds back to the others&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now here's the fun part: who designs the handoff protocols? Who decides Agent D's confidence threshold? Who debugs it when Agent C starts hallucinating because Agent B fed it corrupted context? Who ensures Agent A doesn't create a bias feedback loop?&lt;/p&gt;

&lt;p&gt;This isn't just "prompt engineering at scale." It's systems architecture, but the components are non-deterministic and the failure modes are bizarre.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Skills Cocktail Nobody Teaches
&lt;/h2&gt;

&lt;p&gt;The tricky bit is that &lt;a href="https://www.icentricagency.com/insights/the-ai-workflow-architect-the-role-enterprises-can-t-afford-to-ignore" rel="noopener noreferrer"&gt;AI Workflow Architects&lt;/a&gt; need a frankly weird combination of skills:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Systems Design&lt;/strong&gt;: You need to think in state machines, event-driven architectures, and async patterns. If you've designed microservices, you're halfway there — except these services occasionally make things up.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Observability Expertise&lt;/strong&gt;: Traditional logging won't cut it. You need to trace decisions across multiple agents, capture prompt/response pairs, and understand where in a 6-agent chain something went sideways.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Process Mapping&lt;/strong&gt;: Yes, the boring business analyst skill. Because before you automate a workflow, you need to understand what humans actually do (versus what they say they do).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Risk Assessment&lt;/strong&gt;: When Agent D auto-approves a refund, who's liable? What's the blast radius if Agent A misclassifies 1,000 tickets? You're designing systems that take actions, not just make predictions.&lt;/p&gt;

&lt;p&gt;Here's the problem: no bootcamp teaches this. No degree covers it. The people doing this work now are usually:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Senior backend engineers who got curious about LLMs&lt;/li&gt;
&lt;li&gt;Solutions architects who've been burned by bad automation&lt;/li&gt;
&lt;li&gt;That one DevOps person who actually reads the logs&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What This Looks Like in Code Terms
&lt;/h2&gt;

&lt;p&gt;A simplified mental model:&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;WorkflowOrchestrator&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;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;agents&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;load_agents&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_machine&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;define_transitions&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;audit_log&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;AuditLogger&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;circuit_breakers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;CircuitBreakerRegistry&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;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;input_data&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="nc"&gt;WorkflowState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;input_data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;is_terminal&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
            &lt;span class="n"&gt;agent&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;route_to_agent&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;# This is where it gets interesting
&lt;/span&gt;            &lt;span class="k"&gt;with&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;observe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;agent&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="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;trace&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="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;process&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="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&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;validate_output&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="c1"&gt;# What happens here? Retry? Escalate? Log and continue?
&lt;/span&gt;                    &lt;span class="k"&gt;await&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;handle_invalid_output&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;agent&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;trace&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;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;transition&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;audit_log&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;record&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="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;trace&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;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;output&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The devil's in those commented lines. Traditional error handling assumes deterministic failures. Agent failures are... squishy.&lt;/p&gt;

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

&lt;p&gt;We're at an inflection point. Two years ago, "AI in production" meant serving a model behind an API. Now it means coordinating multiple models, traditional services, human-in-the-loop interventions, and decision trees that adapt based on outcomes.&lt;/p&gt;

&lt;p&gt;Most UK organisations are either:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Building this ad-hoc with whoever's available (usually overloaded senior engineers)&lt;/li&gt;
&lt;li&gt;Not building it at all, despite the hype&lt;/li&gt;
&lt;li&gt;Outsourcing to agencies specialising in &lt;a href="https://www.icentricagency.com" rel="noopener noreferrer"&gt;AI automation and software development&lt;/a&gt; to bridge the gap&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What You Can Do About It
&lt;/h2&gt;

&lt;p&gt;If you're a mid-to-senior engineer who enjoys systems thinking, this is a genuinely interesting career direction. Here's how to position yourself:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Build something multi-agent&lt;/strong&gt; (even a toy project) and document what went wrong&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Study observability patterns&lt;/strong&gt; — OpenTelemetry, distributed tracing, that stuff you've been meaning to learn&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Get comfortable with business process mapping&lt;/strong&gt; — yes, really. BPMN isn't sexy but it's useful&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Learn prompt engineering&lt;/strong&gt; — not as the end goal, but as a tool in a larger system&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The companies that figure this out early will have a significant advantage. The engineers who can bridge this gap will be bloody hard to replace.&lt;/p&gt;

&lt;p&gt;And if your company's just added "implement AI agents" to the backlog without assigning a clear owner? Well, that's your opening.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>architecture</category>
      <category>career</category>
      <category>devops</category>
    </item>
    <item>
      <title>The EU AI Act Is Shifting — Here's What It Means for Your Codebase</title>
      <dc:creator>Marc Newstead</dc:creator>
      <pubDate>Mon, 01 Jun 2026 09:09:04 +0000</pubDate>
      <link>https://dev.to/icentric/the-eu-ai-act-is-shifting-heres-what-it-means-for-your-codebase-2540</link>
      <guid>https://dev.to/icentric/the-eu-ai-act-is-shifting-heres-what-it-means-for-your-codebase-2540</guid>
      <description>&lt;h2&gt;
  
  
  The EU AI Act Is Shifting — Here's What It Means for Your Codebase
&lt;/h2&gt;

&lt;p&gt;If you've been tracking the EU AI Act, you probably pencilled in August 2026 as the date when certain systems would need to be compliant. That timeline is now looking less certain. Brussels is floating changes through something called the Digital Omnibus Package, and UK teams are stuck in an especially awkward position — no UK-specific AI law, no clarity on whether to follow EU rules, and compliance work already underway.&lt;/p&gt;

&lt;p&gt;So what should you actually &lt;em&gt;do&lt;/em&gt; about it?&lt;/p&gt;

&lt;h2&gt;
  
  
  The Omnibus Isn't a Repeal — It's a Tweak
&lt;/h2&gt;

&lt;p&gt;First, let's get the framing right. The Digital Omnibus isn't scrapping the AI Act. It's recalibrating parts of it in response to competitiveness concerns, particularly from SMEs who feel the compliance burden is disproportionate.&lt;/p&gt;

&lt;p&gt;What does that mean in practice? Possibly lighter requirements for some model providers,延extended grace periods, or narrower definitions of "high-risk" systems. The core intent — transparency, accountability, risk management — isn't going away.&lt;/p&gt;

&lt;p&gt;For developers, this is important context. If you've been working on compliance tooling, audit logs, model cards, or risk documentation, that work isn't wasted. The &lt;em&gt;deadlines&lt;/em&gt; may shift, but the &lt;em&gt;direction of travel&lt;/em&gt; remains the same.&lt;/p&gt;

&lt;h2&gt;
  
  
  The UK Position: Deliberately Vague
&lt;/h2&gt;

&lt;p&gt;The UK has explicitly avoided EU-style legislation. Instead, it's gone for a "principles-based, sector-led" approach — which in developer terms means: no single rulebook, no clear deadline, and plenty of room for interpretation.&lt;/p&gt;

&lt;p&gt;But here's the catch. If you're building software that:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Serves EU users or customers&lt;/li&gt;
&lt;li&gt;Integrates with EU-based systems&lt;/li&gt;
&lt;li&gt;Uses foundation models trained or hosted in the EU&lt;/li&gt;
&lt;li&gt;Operates in regulated sectors (finance, health, recruitment)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;...then the EU AI Act probably applies to you anyway, regardless of where your servers are.&lt;/p&gt;

&lt;p&gt;So the UK's ambiguity doesn't buy you much. If anything, it means you need to stay across &lt;em&gt;both&lt;/em&gt; jurisdictions.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why "Wait and See" Is the Wrong Move
&lt;/h2&gt;

&lt;p&gt;The temptation right now is to pause compliance work until the dust settles. Understandable, but risky.&lt;/p&gt;

&lt;p&gt;Here's why:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. The fundamentals won't change&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Even if the Omnibus softens certain obligations, the technical requirements around logging, transparency, and testing are baked into good engineering practice anyway. If you're building production AI systems, you should already be doing this stuff.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Procurement and contracts are moving faster than regulation&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Your customers — especially in enterprise or public sector — are already asking compliance questions in RFPs. They're not waiting for final rules. If you can't demonstrate basic governance, you'll lose deals.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Technical debt compounds&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Retrofitting compliance into a system is &lt;em&gt;far&lt;/em&gt; harder than building it in from the start. If you wait until the regulation is finalised, you'll be scrambling to bolt on audit trails, explainability hooks, and data lineage tracking. That's expensive and brittle.&lt;/p&gt;

&lt;p&gt;For a deeper dive on the regulatory landscape, &lt;a href="https://www.icentricagency.com/insights/the-eu-ai-act-deadline-is-shifting-what-should-uk-teams-do-now" rel="noopener noreferrer"&gt;the deadline is shifting&lt;/a&gt; in ways that warrant recalibration, not paralysis.&lt;/p&gt;

&lt;h2&gt;
  
  
  What to Do Instead: Recalibrate, Don't Restart
&lt;/h2&gt;

&lt;p&gt;If you've already started compliance work, don't throw it out. Instead, focus on &lt;strong&gt;no-regret moves&lt;/strong&gt; — things that improve your system regardless of regulatory outcome.&lt;/p&gt;

&lt;h3&gt;
  
  
  Prioritise foundational capabilities:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Structured logging for model decisions&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
If your model makes a decision (e.g. credit scoring, CV filtering), log it with context: input features, model version, timestamp, output, confidence.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Version control for models and datasets&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Treat models like code. Git for weights, DVC for datasets, MLflow or similar for experiment tracking.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Human-in-the-loop hooks&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Build affordances for human review or override, even if they're not always used. It's much easier to expose a UI element than to redesign your inference pipeline later.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Documentation as code&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Model cards, datasheets, risk assessments — write them in Markdown, version them in Git, publish them automatically. Make governance a first-class part of your CI/CD pipeline.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These aren't just compliance theatre. They make your system more maintainable, auditable, and debuggable.&lt;/p&gt;

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

&lt;p&gt;Regulatory uncertainty is uncomfortable, but it's not an excuse to do nothing. The EU AI Act's &lt;em&gt;direction&lt;/em&gt; is clear, even if the &lt;em&gt;details&lt;/em&gt; are in flux. And if you're in the UK, you're not off the hook — you're just operating in a more ambiguous environment.&lt;/p&gt;

&lt;p&gt;The smart play is to treat compliance as an engineering quality concern, not a legal checkbox. Build systems that are transparent, explainable, and auditable &lt;em&gt;because those are good systems&lt;/em&gt;, not just because Brussels says so.&lt;/p&gt;

&lt;p&gt;If you're working on these challenges and need support with &lt;a href="https://www.icentricagency.com" rel="noopener noreferrer"&gt;AI automation and software development&lt;/a&gt;, you're not alone. This is a moving target for everyone.&lt;/p&gt;

&lt;p&gt;But the teams who ship thoughtfully now will be in a much stronger position than those who wait for perfect clarity that may never come.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>compliance</category>
      <category>engineering</category>
      <category>regulation</category>
    </item>
    <item>
      <title>Why Your Image Upload Pipeline Should Check for Physically Impossible Lighting</title>
      <dc:creator>Marc Newstead</dc:creator>
      <pubDate>Mon, 18 May 2026 11:10:19 +0000</pubDate>
      <link>https://dev.to/icentric/why-your-image-upload-pipeline-should-check-for-physically-impossible-lighting-561l</link>
      <guid>https://dev.to/icentric/why-your-image-upload-pipeline-should-check-for-physically-impossible-lighting-561l</guid>
      <description>&lt;h2&gt;
  
  
  Why Your Image Upload Pipeline Should Check for Physically Impossible Lighting
&lt;/h2&gt;

&lt;p&gt;If you're building user-generated content platforms, marketplace verification systems, or anything that ingests images from untrusted sources, you've probably noticed the synthetic media problem getting worse. Gen-AI tools have become good enough that casual users can't spot the fakes anymore.&lt;/p&gt;

&lt;p&gt;But here's the thing: the physics still breaks. And if you know what to look for, you can build surprisingly effective validation layers using simple computer vision techniques.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Shadow Problem: Your First Line of Defence
&lt;/h2&gt;

&lt;p&gt;In any real photograph, shadows share a common light source geometry. This is basic physics—light travels in straight lines. When AI image generators compose scenes from learned patterns rather than simulated physics, they consistently mess this up.&lt;/p&gt;

&lt;p&gt;Here's what you can check programmatically:&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Shadow Direction Consistency
&lt;/h3&gt;

&lt;p&gt;Extract shadow vectors across different objects in the scene. In a genuine photo, these should converge toward a common vanishing point (the light source).&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 shadow vector analysis
&lt;/span&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;analyse_shadow_consistency&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;image&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;objects&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;segment_objects&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;image&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;shadow_vectors&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;obj&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;objects&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;obj&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;has_shadow&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
            &lt;span class="n"&gt;vector&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;calculate_shadow_angle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;shadow&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;shadow_vectors&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="n"&gt;vector&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# Check if vectors converge within tolerance
&lt;/span&gt;    &lt;span class="n"&gt;convergence_score&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;calculate_convergence&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;shadow_vectors&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;convergence_score&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;THRESHOLD&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This won't catch everything, but it'll flag a surprising number of AI-generated images, especially from earlier-generation models or rushed prompts.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Shadow Intensity Relative to Distance
&lt;/h3&gt;

&lt;p&gt;Shadows should soften and lighten with distance from the object casting them. AI generators often produce shadows with uniform intensity throughout, or inconsistent softness between objects at similar distances.&lt;/p&gt;

&lt;p&gt;You can measure this with edge detection and gradient analysis across shadow boundaries.&lt;/p&gt;

&lt;h2&gt;
  
  
  Reflection Geometry: The Silent Tell
&lt;/h2&gt;

&lt;p&gt;Reflections are even harder for generators to get right. Water reflections, glass surfaces, and metallic objects all follow strict geometric rules.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What to check:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Reflections should be vertically symmetrical (for horizontal surfaces)&lt;/li&gt;
&lt;li&gt;Reflection angles must match viewing angles&lt;/li&gt;
&lt;li&gt;Environmental lighting in reflections should match the scene lighting&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A simple geometric validation:&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;validate_reflection&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;surface_region&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;reflected_region&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="c1"&gt;# Extract key points from both regions
&lt;/span&gt;    &lt;span class="n"&gt;surface_features&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;extract_keypoints&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;surface_region&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;reflection_features&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;extract_keypoints&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;reflected_region&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# Check if reflection obeys mirror symmetry
&lt;/span&gt;    &lt;span class="n"&gt;symmetry_score&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;calculate_mirror_symmetry&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;surface_features&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
        &lt;span class="n"&gt;reflection_features&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;symmetry_score&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;MIN_SYMMETRY_THRESHOLD&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Where This Actually Matters in Production
&lt;/h2&gt;

&lt;p&gt;If you're building:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Marketplace verification systems&lt;/strong&gt; — Preventing fake product photos that don't represent real inventory. One e-commerce platform I know ran into this when sellers started using AI to generate "lifestyle" product shots that looked professional but didn't match the actual items.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Content moderation pipelines&lt;/strong&gt; — Flagging synthetic profile pictures in identity verification flows, or detecting manipulated images in insurance claims.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Media asset management&lt;/strong&gt; — Automatically tagging AI-generated images in your DAM system so teams know what they're working with.&lt;/p&gt;

&lt;p&gt;You don't need perfect detection. You need a confidence score that feeds into your review queue prioritisation.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Detection Tool Ecosystem
&lt;/h2&gt;

&lt;p&gt;Before you roll your own, know what exists:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Hive Moderation&lt;/strong&gt; and &lt;strong&gt;Illuminarty&lt;/strong&gt; offer API-based detection with probabilistic scoring&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Google's SynthID&lt;/strong&gt; watermarks AI-generated content at generation time (only useful if the generator cooperates)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Open-source models&lt;/strong&gt; like the ones from Hugging Face give you full control but require more infrastructure&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These tools are useful as part of a layered approach, but they're not silver bullets. False positive rates are still high enough that you'll need human review for edge cases.&lt;/p&gt;

&lt;p&gt;For a deeper look at the specific physical tells and how they manifest across different generators, &lt;a href="https://www.icentricagency.com/insights/the-physics-don-t-lie-spotting-ai-generated-imagery-in-2025" rel="noopener noreferrer"&gt;spotting AI-generated imagery&lt;/a&gt; has become a critical organisational competency.&lt;/p&gt;

&lt;h2&gt;
  
  
  Building a Practical Validation Layer
&lt;/h2&gt;

&lt;p&gt;Here's a sensible architecture:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Fast rejection filters&lt;/strong&gt; — Basic checks for impossible lighting/shadows using CV libraries (OpenCV, scikit-image)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;API-based scoring&lt;/strong&gt; — Send suspicious images to a detection service&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Human review queue&lt;/strong&gt; — Images above a certain suspicion threshold get reviewed&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Feedback loop&lt;/strong&gt; — Feed confirmed cases back into your filters
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;validate_uploaded_image&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;image_file&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="c1"&gt;# Layer 1: Fast physics checks
&lt;/span&gt;    &lt;span class="n"&gt;physics_score&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;check_lighting_consistency&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;image_file&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;physics_score&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mf"&gt;0.3&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;  &lt;span class="c1"&gt;# Clearly fake
&lt;/span&gt;        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;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;rejected&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;reason&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;lighting_anomaly&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;physics_score&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mf"&gt;0.8&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;  &lt;span class="c1"&gt;# Probably real
&lt;/span&gt;        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;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;approved&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;confidence&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;physics_score&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c1"&gt;# Layer 2: API-based detection for ambiguous cases
&lt;/span&gt;    &lt;span class="n"&gt;api_score&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;detection_service&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;analyse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;image_file&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;api_score&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mf"&gt;0.5&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;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;review_queue&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;scores&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;physics&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;physics_score&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;api&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;api_score&lt;/span&gt;&lt;span class="p"&gt;}}&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;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;approved&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;confidence&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;min&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;physics_score&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;api_score&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;p&gt;You can't stop AI-generated images from being uploaded. But you can build systems that flag the physically impossible ones before they cause problems downstream. If you're working on platforms where image authenticity matters—or you're helping clients navigate this space through &lt;a href="https://www.icentricagency.com" rel="noopener noreferrer"&gt;AI automation and software development&lt;/a&gt;—basic physics checks should be in your validation pipeline.&lt;/p&gt;

&lt;p&gt;The generators will get better. But until they're simulating actual light physics rather than pattern-matching, the tells will remain.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>computervision</category>
      <category>security</category>
      <category>python</category>
    </item>
    <item>
      <title>Stop Optimising for One Search Algorithm — You Need Three in 2025</title>
      <dc:creator>Marc Newstead</dc:creator>
      <pubDate>Mon, 18 May 2026 11:04:07 +0000</pubDate>
      <link>https://dev.to/icentric/stop-optimising-for-one-search-algorithm-you-need-three-in-2025-3h81</link>
      <guid>https://dev.to/icentric/stop-optimising-for-one-search-algorithm-you-need-three-in-2025-3h81</guid>
      <description>&lt;h2&gt;
  
  
  The search layer cake nobody warned you about
&lt;/h2&gt;

&lt;p&gt;If you've built anything user-facing in the last 18 months, you've probably noticed something weird: classic Google search still exists, but so do AI Overviews. And ChatGPT. And Perplexity. And whatever Bing is calling their AI feature this week.&lt;/p&gt;

&lt;p&gt;Here's the bit that matters for us as developers: &lt;strong&gt;you're now optimising for three distinct layers of search&lt;/strong&gt;, not one. Classic SEO still matters. Answer Engine Optimisation (AEO) is a thing. And Generative Engine Optimisation (GEO) — making your content LLM-friendly — is rapidly becoming table stakes.&lt;/p&gt;

&lt;p&gt;Ignore any one of these and you're leaving traffic (and revenue) on the table. The good news? A lot of this is automatable. The bad news? Most teams are still pretending it's 2019.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why classic SEO isn't dead (and won't be)
&lt;/h2&gt;

&lt;p&gt;Let's get the obvious out of the way: &lt;strong&gt;traditional SEO fundamentals still matter&lt;/strong&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Core Web Vitals haven't gone anywhere&lt;/li&gt;
&lt;li&gt;Structured data still helps crawlers parse your pages&lt;/li&gt;
&lt;li&gt;Backlink authority is alive and well&lt;/li&gt;
&lt;li&gt;Mobile responsiveness is non-negotiable&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If your Lighthouse scores are in the red or your &lt;code&gt;robots.txt&lt;/code&gt; is blocking half your site, no amount of AI magic will save you. Google's crawlers need to index your content before any algorithm — classic or generative — can surface it.&lt;/p&gt;

&lt;p&gt;The mistake teams make is treating SEO as &lt;em&gt;only&lt;/em&gt; this. It's necessary, but no longer sufficient.&lt;/p&gt;

&lt;h2&gt;
  
  
  AEO: structured answers for featured snippets and voice
&lt;/h2&gt;

&lt;p&gt;Answer Engine Optimisation is about formatting content so it can be &lt;strong&gt;extracted cleanly as a standalone answer&lt;/strong&gt;. Think:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;FAQ schema that actually answers the question in the markup&lt;/li&gt;
&lt;li&gt;Concise &lt;code&gt;&amp;lt;h2&amp;gt;&lt;/code&gt; headings that mirror user queries&lt;/li&gt;
&lt;li&gt;Tables and lists that are trivial to parse&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Example: instead of burying your API rate limits in prose, do this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gu"&gt;## What are the API rate limits?&lt;/span&gt;
&lt;span class="p"&gt;
-&lt;/span&gt; Free tier: 100 requests/hour
&lt;span class="p"&gt;-&lt;/span&gt; Pro tier: 10,000 requests/hour
&lt;span class="p"&gt;-&lt;/span&gt; Enterprise: Custom limits
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This works for featured snippets, voice assistants, and — crucially — gets picked up cleanly by LLM crawlers. Which brings us to layer three.&lt;/p&gt;

&lt;h2&gt;
  
  
  GEO: making your content LLM-legible
&lt;/h2&gt;

&lt;p&gt;Generative Engine Optimisation means &lt;strong&gt;writing and structuring content so LLMs can cite it accurately&lt;/strong&gt;. A few practical tactics:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Use explicit attributions.&lt;/strong&gt; "According to [Your Company], the median API latency is 120ms." LLMs love citations they can quote.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Front-load key facts.&lt;/strong&gt; Don't bury your lede six paragraphs down. Put the answer in the first 100 words.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Avoid jargon overload.&lt;/strong&gt; LLMs are trained on the web; niche terminology without context confuses them.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Link internally with descriptive anchor text.&lt;/strong&gt; "See our authentication guide" beats "click here."&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you want to go deeper on the strategic layer, there's a solid overview of &lt;a href="https://www.icentricagency.com/insights/ai-driven-seo-winning-across-classic-aeo-and-geo-in-2025" rel="noopener noreferrer"&gt;AI-driven SEO&lt;/a&gt; that covers the business case.&lt;/p&gt;

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

&lt;p&gt;Let's say you're documenting a new SDK. Here's the old way:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Our SDK provides a robust interface for interacting with the platform, offering flexibility and performance."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Here's the new way:&lt;/p&gt;

&lt;blockquote&gt;
&lt;h2&gt;
  
  
  How do I install the Python SDK?
&lt;/h2&gt;

&lt;p&gt;Install via pip:&lt;/p&gt;


&lt;pre class="highlight shell"&gt;&lt;code&gt;pip &lt;span class="nb"&gt;install &lt;/span&gt;your-sdk
&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;Supports Python 3.8+. Typical installation takes under 30 seconds.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The second version works for classic SEO (keyword-rich headings), AEO (structured Q&amp;amp;A), and GEO (clear, quotable answer). One piece of content, three optimisation layers satisfied.&lt;/p&gt;

&lt;h2&gt;
  
  
  Tooling that actually helps
&lt;/h2&gt;

&lt;p&gt;You don't need a seven-figure MarTech stack to do this. A few categories worth exploring:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Schema validators&lt;/strong&gt; (Google's Rich Results Test, Schema.org validator)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Content analysis tools&lt;/strong&gt; that flag vague language or poor structure&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;AI-powered SEO platforms&lt;/strong&gt; that surface keyword gaps and suggest schema improvements&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you're working with a team that spans &lt;a href="https://www.icentricagency.com" rel="noopener noreferrer"&gt;AI automation and software development&lt;/a&gt;, ask them to audit your content pipeline. Most of this is scriptable.&lt;/p&gt;

&lt;h2&gt;
  
  
  The metrics trap
&lt;/h2&gt;

&lt;p&gt;One last thing: &lt;strong&gt;rankings are now a lagging indicator&lt;/strong&gt;. A page can rank #1 and still see click-through rates collapse because an AI Overview answered the query above the fold.&lt;/p&gt;

&lt;p&gt;Track:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Impressions vs. clicks (CTR decay is your canary)&lt;/li&gt;
&lt;li&gt;LLM citation frequency (some tools now track this)&lt;/li&gt;
&lt;li&gt;Conversion rates, not just rankings&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If your content is good enough to be cited by ChatGPT but your site never gets the click, you've got a GEO problem — or a business model problem.&lt;/p&gt;

&lt;h2&gt;
  
  
  TL;DR
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Classic SEO fundamentals (Core Web Vitals, schema, backlinks) are still essential&lt;/li&gt;
&lt;li&gt;AEO means structuring content as extractable answers (FAQ schema, lists, tables)&lt;/li&gt;
&lt;li&gt;GEO means writing so LLMs can cite you accurately (front-load facts, use attributions)&lt;/li&gt;
&lt;li&gt;One piece of content can satisfy all three layers if you write it right&lt;/li&gt;
&lt;li&gt;Track CTR and conversions, not just rankings&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The search landscape fragmented. Your optimisation strategy should reflect that — or you'll spend 2025 wondering where your traffic went.&lt;/p&gt;

</description>
      <category>seo</category>
      <category>ai</category>
      <category>webdev</category>
      <category>devops</category>
    </item>
    <item>
      <title>Your Website's Content Now Has Two Jobs: Feeding Crawlers and Training LLMs</title>
      <dc:creator>Marc Newstead</dc:creator>
      <pubDate>Mon, 18 May 2026 10:47:21 +0000</pubDate>
      <link>https://dev.to/icentric/your-websites-content-now-has-two-jobs-feeding-crawlers-and-training-llms-483d</link>
      <guid>https://dev.to/icentric/your-websites-content-now-has-two-jobs-feeding-crawlers-and-training-llms-483d</guid>
      <description>&lt;h2&gt;
  
  
  Your Website's Content Now Has Two Jobs: Feeding Crawlers and Training LLMs
&lt;/h2&gt;

&lt;p&gt;If you've built a documentation site, marketing platform, or content-heavy application recently, you've probably optimised for Google's crawlers—structured data, semantic HTML, decent page speed, sensible &lt;code&gt;meta&lt;/code&gt; tags. Job done, right?&lt;/p&gt;

&lt;p&gt;Not anymore.&lt;/p&gt;

&lt;p&gt;Google's AI Overviews (and similar LLM-powered search features from Bing, Perplexity, and others) are now extracting, synthesising, and presenting your content &lt;em&gt;without&lt;/em&gt; sending users to your site. Your carefully crafted landing pages might be cited in an AI-generated summary, but the click? Gone.&lt;/p&gt;

&lt;p&gt;This isn't theoretical. Organic click-through rates are dropping. The &lt;a href="https://www.icentricagency.com/insights/beyond-seo-rankings-why-geo-is-now-the-real-battle-for-uk-search-visibility" rel="noopener noreferrer"&gt;real battle for UK search visibility&lt;/a&gt; isn't just about ranking #1 anymore—it's about being the source LLMs &lt;em&gt;choose to cite&lt;/em&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Changed: From PageRank to Prompt Context
&lt;/h2&gt;

&lt;p&gt;Traditional SEO was a game of signals: backlinks, domain authority, keyword density, Core Web Vitals. You knew the rules. You played by them.&lt;/p&gt;

&lt;p&gt;Generative Engine Optimisation (GEO) is different. LLMs don't "crawl" in the same way. They're trained on massive corpora, then retrieve and synthesise information at inference time. The question isn't &lt;em&gt;"Does this page rank?"&lt;/em&gt; but &lt;em&gt;"Does this content get selected as context for the LLM's response?"&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Think of it 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="c1"&gt;# Traditional SEO
&lt;/span&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_search_results&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;pages&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find&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;# crawled, indexed, ranked
&lt;/span&gt;    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;sorted&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pages&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;lambda&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;pagerank&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# GEO / LLM-powered search
&lt;/span&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_ai_overview&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="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;retrieval_model&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fetch_relevant_docs&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;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&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="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;  &lt;span class="c1"&gt;# user never clicks through
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Your content needs to be selected &lt;em&gt;during retrieval&lt;/em&gt;, not just indexed. That's a different optimisation problem.&lt;/p&gt;

&lt;h2&gt;
  
  
  What LLMs Actually Reward
&lt;/h2&gt;

&lt;p&gt;Based on research into how generative engines select sources, here's what seems to matter:&lt;/p&gt;

&lt;h3&gt;
  
  
  1. &lt;strong&gt;Authoritative, Structured Answers&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;LLMs favour content that directly answers questions in a clear, hierarchical format. Think:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Concise definitions at the top&lt;/li&gt;
&lt;li&gt;Bullet lists for steps or options&lt;/li&gt;
&lt;li&gt;Tables for comparisons&lt;/li&gt;
&lt;li&gt;Headings that map to user intent ("How to...", "What is...", "Best practices for...")&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  2. &lt;strong&gt;Semantic Richness&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Keyword stuffing is dead. LLMs look for &lt;em&gt;semantic coverage&lt;/em&gt;—related concepts, synonyms, contextual depth. If you're documenting an API, don't just list endpoints. Explain use cases, common errors, and edge cases.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. &lt;strong&gt;Freshness and Specificity&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Generic evergreen content is losing ground to timely, specific answers. If you're writing a guide, reference current versions, real-world examples, and actual data.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. &lt;strong&gt;Citation-Friendly Formatting&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;LLMs are more likely to cite content that's easy to extract and attribute. This means:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Clear authorship and publication dates&lt;/li&gt;
&lt;li&gt;Structured data (JSON-LD, Open Graph)&lt;/li&gt;
&lt;li&gt;Blockquotes, code snippets, and other semantically marked-up elements&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Practical Steps: Optimise for Both
&lt;/h2&gt;

&lt;p&gt;The good news? You don't have to choose. Most GEO best practices &lt;em&gt;also&lt;/em&gt; improve traditional SEO. Here's a starter playbook:&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Audit Your Content for "Extract-ability"&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Can someone (or an LLM) quickly pull a useful answer from your page? If your intro is 300 words of marketing fluff before the actual information, you're in trouble.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Use Structured Data Everywhere&lt;/strong&gt;
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"application/ld+json"&lt;/span&gt;&lt;span class="nt"&gt;&amp;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;@context&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://schema.org&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@type&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;TechArticle&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;headline&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Building Resilient APIs&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;author&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;@type&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Person&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;name&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Jane Dev&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;datePublished&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;2024-01-15&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This helps both crawlers and LLMs understand your content's context.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Write for Humans, Optimise for Machines&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Your content should read naturally, but also be scannable. Use:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Bold text&lt;/strong&gt; for key terms&lt;/li&gt;
&lt;li&gt;Short paragraphs (2-3 sentences max)&lt;/li&gt;
&lt;li&gt;Code blocks for examples (not screenshots)&lt;/li&gt;
&lt;li&gt;Tables and lists for structured info&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Track Non-Click Visibility&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;If your content is cited in an AI Overview but doesn't generate clicks, that's still brand exposure. Tools are emerging to track "impression share" in AI-generated results, but even anecdotal monitoring (searching your own key topics and noting citations) is useful.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Workflow Shift
&lt;/h2&gt;

&lt;p&gt;If you're building content pipelines or CMS tooling, consider:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;AI-assisted content audits&lt;/strong&gt;: Use LLMs to identify gaps in semantic coverage or question-answer alignment&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Automated structured data generation&lt;/strong&gt;: Parse your markdown/HTML and inject schema.org markup programmatically&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Prompt testing&lt;/strong&gt;: Literally query LLMs (ChatGPT, Claude, Perplexity) with your target keywords and see if your content surfaces&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Agencies focused on &lt;a href="https://www.icentricagency.com" rel="noopener noreferrer"&gt;AI automation and software development&lt;/a&gt; are building these workflows into content ops—treating GEO as a CI/CD problem, not just an editorial one.&lt;/p&gt;

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

&lt;p&gt;If you're maintaining documentation, a developer blog, or any content-heavy platform, your success metrics are shifting. Rankings matter less than &lt;em&gt;retrieval&lt;/em&gt;. Clicks matter less than &lt;em&gt;citation&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Optimise for both crawlers and LLMs. Structure your content like an API response: clear, hierarchical, and easy to parse. And remember—your content isn't just being read anymore. It's being &lt;em&gt;used as training data&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Make sure it's worth learning from.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>seo</category>
      <category>webdev</category>
      <category>content</category>
    </item>
  </channel>
</rss>
