<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Marc Newstead</title>
    <description>The latest articles on DEV Community by Marc Newstead (@icentric).</description>
    <link>https://dev.to/icentric</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3929651%2Ffa7f595b-8a59-45da-b8be-ee66e3feab4d.png</url>
      <title>DEV Community: Marc Newstead</title>
      <link>https://dev.to/icentric</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/icentric"/>
    <language>en</language>
    <item>
      <title>Why Your RAG Agent Can't Connect the Dots (And How to Fix It)</title>
      <dc:creator>Marc Newstead</dc:creator>
      <pubDate>Mon, 13 Jul 2026 09:13:29 +0000</pubDate>
      <link>https://dev.to/icentric/why-your-rag-agent-cant-connect-the-dots-and-how-to-fix-it-39da</link>
      <guid>https://dev.to/icentric/why-your-rag-agent-cant-connect-the-dots-and-how-to-fix-it-39da</guid>
      <description>&lt;h2&gt;
  
  
  The Problem You've Probably Hit
&lt;/h2&gt;

&lt;p&gt;You've built a RAG agent. It answers questions from your docs brilliantly... until someone asks something that requires connecting information across multiple sources. Then it falls apart.&lt;/p&gt;

&lt;p&gt;"Who worked on projects related to the component that failed in production last week?"&lt;/p&gt;

&lt;p&gt;Your vector-based agent returns documents about the failure, documents about team members, and documents about projects. But it can't &lt;em&gt;connect&lt;/em&gt; them. That's multi-hop reasoning, and it's where vector embeddings hit their ceiling.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Multi-Hop Actually Looks Like in Code
&lt;/h2&gt;

&lt;p&gt;Let's be concrete. Single-hop reasoning is straightforward:&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;# Single hop: "What does the auth service do?"
&lt;/span&gt;&lt;span class="n"&gt;query_embedding&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;embed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;auth service functionality&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;results&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;vector_db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;similarity_search&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;query_embedding&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;# Returns relevant docs about auth service ✓
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Multi-hop reasoning chains multiple steps:&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;# Multi-hop: "Which engineer should fix the auth service bug?"
# Step 1: What is the auth service?
# Step 2: Who maintains it?
# Step 3: Who's currently available?
# Step 4: Who has fixed similar bugs before?
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With vectors alone, you're either:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Hoping all that context lives in one chunk (unlikely)&lt;/li&gt;
&lt;li&gt;Re-querying multiple times and losing the thread&lt;/li&gt;
&lt;li&gt;Jamming everything into the LLM context window and burning tokens&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;None of these scale.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why We Defaulted to Vectors
&lt;/h2&gt;

&lt;p&gt;Vectors were the pragmatic choice in 2023. The tooling was mature, implementation was straightforward, and for 80% of use cases—document retrieval, FAQ matching, semantic search—they worked brilliantly.&lt;/p&gt;

&lt;p&gt;Pinecone, Weaviate, Chroma: all excellent tools. The problem isn't the technology; it's the architectural assumption that &lt;em&gt;every&lt;/em&gt; knowledge retrieval problem is a similarity search problem.&lt;/p&gt;

&lt;p&gt;It isn't.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Graphs Do Differently
&lt;/h2&gt;

&lt;p&gt;Graph databases store knowledge as entities and relationships:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cypher"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Neo4j example&lt;/span&gt;
&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="py"&gt;Alice:&lt;/span&gt;&lt;span class="n"&gt;Engineer&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="ss"&gt;[&lt;/span&gt;&lt;span class="nc"&gt;:MAINTAINS&lt;/span&gt;&lt;span class="ss"&gt;]&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="py"&gt;AuthService:&lt;/span&gt;&lt;span class="n"&gt;Component&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;
&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="n"&gt;AuthService&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="ss"&gt;[&lt;/span&gt;&lt;span class="nc"&gt;:DEPENDS_ON&lt;/span&gt;&lt;span class="ss"&gt;]&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="py"&gt;UserDB:&lt;/span&gt;&lt;span class="n"&gt;Database&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;
&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="n"&gt;UserDB&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="ss"&gt;[&lt;/span&gt;&lt;span class="nc"&gt;:HOSTED_ON&lt;/span&gt;&lt;span class="ss"&gt;]&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="py"&gt;ProdServer:&lt;/span&gt;&lt;span class="n"&gt;Infrastructure&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;
&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="py"&gt;Bob:&lt;/span&gt;&lt;span class="n"&gt;Engineer&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="ss"&gt;[&lt;/span&gt;&lt;span class="nc"&gt;:ON_CALL_FOR&lt;/span&gt;&lt;span class="ss"&gt;]&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ProdServer&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now that multi-hop query becomes traversable:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cypher"&gt;&lt;code&gt;&lt;span class="k"&gt;MATCH&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="py"&gt;bug:&lt;/span&gt;&lt;span class="n"&gt;Issue&lt;/span&gt; &lt;span class="ss"&gt;{&lt;/span&gt;&lt;span class="py"&gt;component:&lt;/span&gt; &lt;span class="s2"&gt;"AuthService"&lt;/span&gt;&lt;span class="ss"&gt;})&lt;/span&gt;
      &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="ss"&gt;[&lt;/span&gt;&lt;span class="nc"&gt;:AFFECTS&lt;/span&gt;&lt;span class="ss"&gt;]&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="py"&gt;service:&lt;/span&gt;&lt;span class="n"&gt;Component&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt;&lt;span class="ss"&gt;[&lt;/span&gt;&lt;span class="nc"&gt;:MAINTAINS&lt;/span&gt;&lt;span class="ss"&gt;]&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="py"&gt;engineer:&lt;/span&gt;&lt;span class="n"&gt;Engineer&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;
      &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="ss"&gt;[&lt;/span&gt;&lt;span class="nc"&gt;:FIXED&lt;/span&gt;&lt;span class="ss"&gt;]&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="py"&gt;similar:&lt;/span&gt;&lt;span class="n"&gt;Issue&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;similar.type&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;bug.type&lt;/span&gt;
&lt;span class="k"&gt;RETURN&lt;/span&gt; &lt;span class="n"&gt;engineer.name&lt;/span&gt;&lt;span class="ss"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;COUNT&lt;/span&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="n"&gt;similar&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;experience&lt;/span&gt;
&lt;span class="k"&gt;ORDER&lt;/span&gt; &lt;span class="k"&gt;BY&lt;/span&gt; &lt;span class="n"&gt;experience&lt;/span&gt; &lt;span class="k"&gt;DESC&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The graph &lt;em&gt;encodes the connections&lt;/em&gt;. You're not asking an LLM to infer relationships from unstructured text—you're traversing explicit edges.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Practical Hybrid Architecture
&lt;/h2&gt;

&lt;p&gt;Here's what's actually working in production:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Use vectors for:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Initial document retrieval&lt;/li&gt;
&lt;li&gt;Semantic similarity matching&lt;/li&gt;
&lt;li&gt;Unstructured content search&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Use graphs for:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Entity relationships&lt;/li&gt;
&lt;li&gt;Multi-hop queries&lt;/li&gt;
&lt;li&gt;Traversing connected data&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Implementation pattern:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Ingest:&lt;/strong&gt; Extract entities and relationships from your documents (using NER, LLMs, or structured parsers)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Store:&lt;/strong&gt; Documents as vectors, entities and relationships in a graph&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Query:&lt;/strong&gt; Use vectors to find &lt;em&gt;candidate documents&lt;/em&gt;, use graphs to find &lt;em&gt;connected context&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Combine:&lt;/strong&gt; Pass both to your LLM as enriched context&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This isn't theoretical. Teams have measured 40%+ accuracy improvements on multi-hop tasks by adding graph memory to existing vector pipelines. The research on &lt;a href="https://www.icentricagency.com/insights/agent-memory-why-graph-beats-vectors-for-multi-hop-reasoning" rel="noopener noreferrer"&gt;why graph beats vectors&lt;/a&gt; shows the performance gap clearly.&lt;/p&gt;

&lt;h2&gt;
  
  
  Actually Building This
&lt;/h2&gt;

&lt;p&gt;You don't need to rip out your existing stack. Start small:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Identify multi-hop queries&lt;/strong&gt; in your logs (anything requiring "and then" logic)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Extract key entities&lt;/strong&gt; from those query domains&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Add a graph layer&lt;/strong&gt; (Neo4j, Amazon Neptune, or even PostgreSQL with recursive CTEs)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Build a hybrid retriever&lt;/strong&gt; that queries both systems&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If you're working with a team that specialises in &lt;a href="https://www.icentricagency.com" rel="noopener noreferrer"&gt;AI automation and software development&lt;/a&gt;, they'll likely be working through similar architectural decisions right now.&lt;/p&gt;

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

&lt;p&gt;Graphs add complexity. You need:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Entity extraction pipelines&lt;/li&gt;
&lt;li&gt;Relationship modelling&lt;/li&gt;
&lt;li&gt;Graph database expertise&lt;/li&gt;
&lt;li&gt;More complex query logic&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But if your agent needs to reason across connected information—and most interesting agents do—the accuracy gains justify the overhead.&lt;/p&gt;

&lt;p&gt;Vectors are brilliant for similarity. Graphs are brilliant for connectivity. Use both.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>rag</category>
      <category>architecture</category>
      <category>database</category>
    </item>
    <item>
      <title>Stop Measuring AI Agent ROI Like It's a Chatbot: A Developer's Guide</title>
      <dc:creator>Marc Newstead</dc:creator>
      <pubDate>Mon, 13 Jul 2026 09:10:51 +0000</pubDate>
      <link>https://dev.to/icentric/stop-measuring-ai-agent-roi-like-its-a-chatbot-a-developers-guide-4bl1</link>
      <guid>https://dev.to/icentric/stop-measuring-ai-agent-roi-like-its-a-chatbot-a-developers-guide-4bl1</guid>
      <description>&lt;h2&gt;
  
  
  Stop Measuring AI Agent ROI Like It's a Chatbot: A Developer's Guide
&lt;/h2&gt;

&lt;p&gt;If you've recently shipped an AI agent or are being asked to build one, you've probably been handed a spreadsheet that calculates ROI based on "hours saved" or "tickets deflected." These metrics made sense for traditional automation—but they're killing your agentic AI projects before they start.&lt;/p&gt;

&lt;p&gt;Here's why, and what to measure instead.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Problem: Traditional Metrics Miss the Point
&lt;/h2&gt;

&lt;p&gt;Most organisations are still measuring AI agents like they're measuring a search bar upgrade or a new help desk widget. The conversation goes something like this:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"If the agent handles 1,000 queries per month and saves 5 minutes per query, that's 83 hours saved. Times hourly rate, minus infrastructure cost... ROI positive in 18 months!"&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Sounds reasonable. Except agentic AI doesn't just &lt;em&gt;answer questions&lt;/em&gt;—it makes decisions and takes actions. A procurement agent doesn't just look up vendor details; it evaluates quotes, flags compliance risks, and routes approvals. A triage agent doesn't just categorise tickets; it assesses severity, assigns priority, and sometimes resolves the issue outright.&lt;/p&gt;

&lt;p&gt;When you measure these systems purely on cost savings, you're optimising for the wrong thing. You end up building glorified FAQ bots with extra steps.&lt;/p&gt;

&lt;h2&gt;
  
  
  A Better Metric: Decisions Automated Per Hour
&lt;/h2&gt;

&lt;p&gt;Instead of "how much did we save?", ask: &lt;strong&gt;"How many decisions is this system making per hour?"&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This reframes the entire conversation. Suddenly you're thinking about:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Throughput&lt;/strong&gt;: Can this agent handle 10 routing decisions per hour, or 1,000?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Scope&lt;/strong&gt;: What categories of decisions can it own end-to-end?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Latency&lt;/strong&gt;: How quickly does it move from input to action?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Scale&lt;/strong&gt;: What happens when load doubles?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These are questions developers instinctively ask about any production system. Treating your agent as a decision-making service—not a cost-centre—makes architectural choices clearer.&lt;/p&gt;

&lt;h3&gt;
  
  
  Example: Deployment Approval Agent
&lt;/h3&gt;

&lt;p&gt;Let's say you build an agent that reviews deployment requests for a platform team:&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 ROI thinking:
# "Saves 10 minutes per manual review, ~200 reviews/month"
# = 33 hours saved, ~£1,500/month
&lt;/span&gt;
&lt;span class="c1"&gt;# Decisions-per-hour thinking:
# "Handles 50 deployment approvals/hour during peak"
# "Automatically clears 80% with no human in loop"
# "Escalates 20% with full context and risk assessment"
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The second framing makes it obvious this isn't about saving 33 hours—it's about &lt;strong&gt;removing a bottleneck&lt;/strong&gt;. You can now deploy 50 times per hour instead of queuing for manual review. The value isn't the time saved; it's the velocity unlocked.&lt;/p&gt;

&lt;p&gt;This shift in perspective influences everything: how you design the agent, what data it needs, how you monitor it, and how you sell it to stakeholders. The &lt;a href="https://www.icentricagency.com/insights/measuring-agentic-ai-roi-why-decisions-matter-more-than-cost-savings" rel="noopener noreferrer"&gt;decisions matter more&lt;/a&gt; article covers the strategic side of this in detail.&lt;/p&gt;

&lt;h2&gt;
  
  
  What This Changes for You as a Developer
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. &lt;strong&gt;You'll Prioritise Different Features&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Cost-reduction logic says: "Make the agent handle the simplest 80% of queries."&lt;/p&gt;

&lt;p&gt;Decisions-per-hour logic says: "Make the agent handle the highest-volume decision paths end-to-end."&lt;/p&gt;

&lt;p&gt;Very different backlogs.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. &lt;strong&gt;Observability Becomes Central&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;You need to instrument decision quality, not just uptime. Think:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Decision confidence scores&lt;/li&gt;
&lt;li&gt;Escalation rates by decision type&lt;/li&gt;
&lt;li&gt;Feedback loops from humans who review edge cases&lt;/li&gt;
&lt;li&gt;Drift detection on decision patterns&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Your agent is now a service with SLOs. Treat it like one.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. &lt;strong&gt;You'll Design for Throughput, Not Coverage&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;A chatbot optimises for "Can it answer this question?"&lt;/p&gt;

&lt;p&gt;An agent optimises for "Can it close the loop on this workflow?"&lt;/p&gt;

&lt;p&gt;That means thinking about state management, rollback strategies, and idempotency from day one. Your agent isn't read-only.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Quality Trap (and How to Avoid It)
&lt;/h2&gt;

&lt;p&gt;Obviously, "decisions per hour" is meaningless if those decisions are rubbish. The key is to &lt;strong&gt;instrument quality from the start&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Shadow mode first: Run the agent in parallel, compare to human decisions&lt;/li&gt;
&lt;li&gt;Confidence thresholds: Auto-execute high-confidence decisions, escalate the rest&lt;/li&gt;
&lt;li&gt;Continuous evaluation: Sample and audit decisions regularly&lt;/li&gt;
&lt;li&gt;Feedback signals: Did the human override? Did downstream systems reject it?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you're working with teams focused on &lt;a href="https://www.icentricagency.com" rel="noopener noreferrer"&gt;AI automation and software development&lt;/a&gt;, these feedback loops should be baked into your delivery process, not bolted on later.&lt;/p&gt;

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

&lt;p&gt;If your current AI project is being measured purely on "cost per query" or "FTE avoided," push back. Ask what decisions the system could own, how many per hour, and what good looks like.&lt;/p&gt;

&lt;p&gt;You'll build better systems—and you'll have a much easier time explaining why they matter.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>devops</category>
      <category>architecture</category>
      <category>automation</category>
    </item>
    <item>
      <title>MCP and A2A: Two Protocols Every Multi-Agent Dev Should Know</title>
      <dc:creator>Marc Newstead</dc:creator>
      <pubDate>Mon, 06 Jul 2026 09:11:56 +0000</pubDate>
      <link>https://dev.to/icentric/mcp-and-a2a-two-protocols-every-multi-agent-dev-should-know-2hcl</link>
      <guid>https://dev.to/icentric/mcp-and-a2a-two-protocols-every-multi-agent-dev-should-know-2hcl</guid>
      <description>&lt;h2&gt;
  
  
  The Two-Layer Problem Nobody Saw Coming
&lt;/h2&gt;

&lt;p&gt;If you're building anything with AI agents right now, you've probably hit the same wall I did: how do you wire multiple agents together without creating a brittle mess of custom integrations?&lt;/p&gt;

&lt;p&gt;Turns out, two protocols are emerging to split this problem cleanly down the middle. &lt;strong&gt;MCP (Model Context Protocol)&lt;/strong&gt; handles the vertical—how a single agent talks to its tools and data sources. &lt;strong&gt;A2A (Agent-to-Agent)&lt;/strong&gt; handles the horizontal—how agents discover and communicate with each other.&lt;/p&gt;

&lt;p&gt;Understanding this split early saves you from architectural regret later. Let me show you why.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Vertical Layer: MCP
&lt;/h2&gt;

&lt;p&gt;Think of MCP as the standardised plumbing between your agent and everything it needs to do actual work. Before MCP, every LLM framework had its own way of wrapping API calls, database queries, or file system access.&lt;/p&gt;

&lt;p&gt;Here's what MCP standardises:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Tool definitions&lt;/strong&gt; — A consistent schema for describing what a function does and what parameters it needs&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Resource access&lt;/strong&gt; — How agents read from databases, file systems, or external APIs&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Prompts and context&lt;/strong&gt; — A protocol-level way to inject context and instructions&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In practice, this means you can write an MCP server once and plug it into Claude, custom LangChain agents, or any other MCP-compatible runtime:&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: MCP server exposing a tool
&lt;/span&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;WeatherMCPServer&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="nd"&gt;@mcp_tool&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_forecast&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;location&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;dict&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;fetch_weather_api&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;location&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Anthropie drives MCP, and adoption is growing fast. If you're building agents that need reliable tool access, MCP is becoming the safe default.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Horizontal Layer: A2A
&lt;/h2&gt;

&lt;p&gt;A2A solves a different problem: &lt;strong&gt;how do agents find each other and coordinate?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Imagine you're building a customer support system with three specialised agents:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;An intake agent that routes requests&lt;/li&gt;
&lt;li&gt;A technical agent that handles product queries&lt;/li&gt;
&lt;li&gt;A billing agent that processes refunds&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Without A2A, you'd hard-code those connections. With A2A, agents register their capabilities in a directory, and other agents discover them dynamically.&lt;/p&gt;

&lt;p&gt;Key A2A concepts:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Agent discovery&lt;/strong&gt; — A registry where agents advertise what they can do&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Message routing&lt;/strong&gt; — Standardised envelopes for inter-agent communication&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Capability negotiation&lt;/strong&gt; — Agents declare their skills; others query and invoke them&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Google's pushing A2A hard, and major cloud vendors are lining up support. The &lt;a href="https://www.icentricagency.com/insights/mcp-a2a-the-two-layer-stack-wiring-the-internet-of-agents-2" rel="noopener noreferrer"&gt;two-layer stack&lt;/a&gt; is quickly becoming the de facto architecture for serious multi-agent systems.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where Devs Get It Wrong
&lt;/h2&gt;

&lt;p&gt;The biggest mistake I see? &lt;strong&gt;Using MCP to solve A2A problems, or vice versa.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;For example:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;❌ Trying to use MCP tool calls to route messages between agents&lt;/li&gt;
&lt;li&gt;❌ Building custom agent discovery when A2A already defines it&lt;/li&gt;
&lt;li&gt;❌ Implementing A2A-style capability negotiation inside MCP servers&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Keep it clean:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;MCP = One agent, many tools&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;A2A = Many agents, one conversation&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;Here's how I'd structure a production system:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;┌─────────────────────────────────────┐
│   A2A Layer (Agent Coordination)    │
│  - Discovery registry               │
│  - Message bus                      │
│  - Routing logic                    │
└─────────────────────────────────────┘
           ↓           ↓           ↓
    Agent A       Agent B       Agent C
       ↓              ↓              ↓
┌──────────────────────────────────────┐
│    MCP Layer (Tool Integration)      │
│  - Database connector                │
│  - API wrappers                      │
│  - File system access                │
└──────────────────────────────────────┘
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Each agent has its own MCP stack. The A2A layer orchestrates the whole system.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Standards Risk
&lt;/h2&gt;

&lt;p&gt;One caveat: &lt;strong&gt;neither protocol is governed by a neutral standards body yet.&lt;/strong&gt; MCP is Anthropic's baby; A2A is Google's. That's not necessarily a dealbreaker, but it does mean the specs could shift based on commercial priorities.&lt;/p&gt;

&lt;p&gt;If you're building something enterprise-grade, keep an eye on governance. The worst-case scenario is ending up locked into one vendor's interpretation of the spec.&lt;/p&gt;

&lt;h2&gt;
  
  
  Should You Care Right Now?
&lt;/h2&gt;

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

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Single-agent systems&lt;/strong&gt; → MCP is immediately useful. Start there.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Multi-agent orchestration&lt;/strong&gt; → You need both layers. Design for A2A from day one.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Enterprise AI at scale&lt;/strong&gt; → The two-layer stack is becoming table stakes. Teams working on &lt;a href="https://www.icentricagency.com" rel="noopener noreferrer"&gt;AI automation and software development&lt;/a&gt; are already adopting this architecture.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The payoff is real: cleaner code, less coupling, easier to extend. And when the next big LLM framework drops, you won't be rewriting everything.&lt;/p&gt;

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

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Experiment with MCP&lt;/strong&gt; — Anthropic's docs are solid. Build a simple tool server.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Read the A2A spec&lt;/strong&gt; — Google published it earlier this year. It's clearer than you'd expect.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Design for the split&lt;/strong&gt; — Even if you're not using both today, structure your code as if you will.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The agent internet is coming. These two protocols are the plumbing.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>architecture</category>
      <category>agents</category>
      <category>protocols</category>
    </item>
    <item>
      <title>Why Your Next AI Agent Should Probably Be a Manager</title>
      <dc:creator>Marc Newstead</dc:creator>
      <pubDate>Mon, 06 Jul 2026 09:09:16 +0000</pubDate>
      <link>https://dev.to/icentric/why-your-next-ai-agent-should-probably-be-a-manager-55fb</link>
      <guid>https://dev.to/icentric/why-your-next-ai-agent-should-probably-be-a-manager-55fb</guid>
      <description>&lt;h2&gt;
  
  
  Why Your Next AI Agent Should Probably Be a Manager
&lt;/h2&gt;

&lt;p&gt;If you've built an AI agent that tries to do everything—answer support tickets, query databases, generate reports, and update CRM records—you've probably noticed it's mediocre at all of them. There's a better pattern, and it's one we've used in software architecture for decades: &lt;strong&gt;delegation&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Instead of building one massive agent with an enormous context window and dozens of tools, build a supervisor agent that spawns specialists on demand. Think of it as a tech lead who routes work to the right engineer, not a full-stack developer trying to do everything themselves.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Problem with Jack-of-All-Trades Agents
&lt;/h2&gt;

&lt;p&gt;A single LLM agent handling a complex workflow hits a wall quickly. You give it:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Access to 15+ API endpoints&lt;/li&gt;
&lt;li&gt;A 3,000-word system prompt&lt;/li&gt;
&lt;li&gt;Instructions for edge cases in six different domains&lt;/li&gt;
&lt;li&gt;Tools for everything from data validation to PDF generation&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;What you get back is an agent that:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Picks the wrong tool 20% of the time&lt;/li&gt;
&lt;li&gt;Hallucinates when context exceeds its sweet spot&lt;/li&gt;
&lt;li&gt;Can't specialise deeply enough to handle domain-specific nuance&lt;/li&gt;
&lt;li&gt;Becomes exponentially harder to debug as complexity grows&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Sound familiar? It's the same reason we stopped building monoliths and started building microservices.&lt;/p&gt;

&lt;h2&gt;
  
  
  Enter the Supervisor Pattern
&lt;/h2&gt;

&lt;p&gt;The &lt;a href="https://www.icentricagency.com/insights/supervisor-and-sub-agents-how-one-agent-learns-to-delegate-2" rel="noopener noreferrer"&gt;supervisor and sub-agents&lt;/a&gt; pattern flips the model. Your supervisor agent doesn't &lt;em&gt;do&lt;/em&gt; the work—it &lt;strong&gt;routes&lt;/strong&gt; it.&lt;/p&gt;

&lt;p&gt;Here's a simplified flow:&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: Supervisor agent receives a task
&lt;/span&gt;&lt;span class="n"&gt;task&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Analyse this customer complaint and update their support ticket&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;

&lt;span class="c1"&gt;# Supervisor decomposes and delegates
&lt;/span&gt;&lt;span class="n"&gt;supervisor&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;task&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;# Output: [
#   {"agent": "sentiment_analyser", "input": complaint_text},
#   {"agent": "crm_updater", "input": ticket_id, "sentiment": result}
# ]
&lt;/span&gt;
&lt;span class="c1"&gt;# Each specialist does one thing well
&lt;/span&gt;&lt;span class="n"&gt;sentiment&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;sentiment_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;complaint_text&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;crm_agent&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;ticket_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;sentiment&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The supervisor's job is &lt;strong&gt;orchestration, not execution&lt;/strong&gt;. It:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Breaks down the user's request into subtasks&lt;/li&gt;
&lt;li&gt;Determines which specialist agent handles each subtask&lt;/li&gt;
&lt;li&gt;Passes context between agents&lt;/li&gt;
&lt;li&gt;Aggregates results and responds&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Each sub-agent has:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A narrow, well-defined role&lt;/li&gt;
&lt;li&gt;A smaller, focused system prompt&lt;/li&gt;
&lt;li&gt;Only the tools it actually needs&lt;/li&gt;
&lt;li&gt;Higher accuracy within its domain&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Why This Works (and Why It's Familiar)
&lt;/h2&gt;

&lt;p&gt;If you've built distributed systems, this should feel natural. It's the same principles:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Single Responsibility Principle&lt;/strong&gt;: Each agent does one thing well&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Loose Coupling&lt;/strong&gt;: Agents don't need to know about each other&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Bounded Context&lt;/strong&gt;: Clear domain boundaries reduce complexity&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Graceful Degradation&lt;/strong&gt;: One agent failing doesn't tank the whole system&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You wouldn't build a microservice that handles payments, inventory, and email notifications. Don't build agents that way either.&lt;/p&gt;

&lt;h2&gt;
  
  
  Dynamic Spawning: The Next Level
&lt;/h2&gt;

&lt;p&gt;Static sub-agent pools work, but the real power comes when your supervisor can &lt;strong&gt;spawn agents dynamically&lt;/strong&gt;. Frameworks like LangGraph, AutoGen, and CrewAI support this.&lt;/p&gt;

&lt;p&gt;Imagine your supervisor encounters a task it's never seen:&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;# Task: "Translate this legal document to French and summarise it"
&lt;/span&gt;
&lt;span class="c1"&gt;# Supervisor spawns specialists on-the-fly:
&lt;/span&gt;&lt;span class="n"&gt;supervisor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;spawn_agent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;role&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;legal_translator&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;tools&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;translation_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;context&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;French legal terminology, formal tone&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;supervisor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;spawn_agent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;role&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;document_summariser&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;tools&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;text_analysis&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="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Legal summary, bullet points, max 200 words&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;No need to pre-define every possible agent. The supervisor adapts to the task.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Gotchas (Because There Always Are)
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Routing errors are your biggest risk.&lt;/strong&gt; If the supervisor sends a task to the wrong specialist, you're worse off than with a generalist. Mitigation strategies:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Use structured outputs (JSON, Pydantic models) for routing decisions&lt;/li&gt;
&lt;li&gt;Log every delegation decision for debugging&lt;/li&gt;
&lt;li&gt;Implement confidence scores—if the supervisor isn't sure, escalate to a human&lt;/li&gt;
&lt;li&gt;Test routing logic obsessively&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Token costs add up.&lt;/strong&gt; Multiple agents mean multiple LLM calls. Profile your usage and optimise:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Use smaller models for specialist tasks&lt;/li&gt;
&lt;li&gt;Cache common decompositions&lt;/li&gt;
&lt;li&gt;Consider local models for low-stakes subtasks&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Observability is critical.&lt;/strong&gt; Distributed agent systems are harder to debug than single agents. Invest in:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Tracing (OpenTelemetry, LangSmith)&lt;/li&gt;
&lt;li&gt;Structured logging with request IDs&lt;/li&gt;
&lt;li&gt;Dashboards showing agent performance and routing patterns&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Should You Build This?
&lt;/h2&gt;

&lt;p&gt;If your agent workflow has:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Multiple distinct domains (e.g., data retrieval + analysis + reporting)&lt;/li&gt;
&lt;li&gt;More than 8–10 tools&lt;/li&gt;
&lt;li&gt;Frequent routing mistakes&lt;/li&gt;
&lt;li&gt;Growing system prompts that feel unwieldy&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;...then yes, try the supervisor pattern.&lt;/p&gt;

&lt;p&gt;If you're building a simple chatbot or single-purpose assistant, stick with one agent. Don't over-engineer.&lt;/p&gt;

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

&lt;p&gt;Pick one complex agent workflow you've already built. Identify two or three distinct subtasks. Refactor into a supervisor + two specialists. Measure accuracy and token usage before and after.&lt;/p&gt;

&lt;p&gt;You'll know quickly if it's the right pattern for your use case.&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; at scale, this pattern is increasingly becoming the default. It's not about replacing single agents—it's about knowing when orchestration beats execution.&lt;/p&gt;

&lt;p&gt;Now go build something modular.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>architecture</category>
      <category>automation</category>
      <category>agents</category>
    </item>
    <item>
      <title>MCP + A2A: You're Building Two Integration Layers Whether You Realise It or Not</title>
      <dc:creator>Marc Newstead</dc:creator>
      <pubDate>Mon, 29 Jun 2026 09:05:26 +0000</pubDate>
      <link>https://dev.to/icentric/mcp-a2a-youre-building-two-integration-layers-whether-you-realise-it-or-not-1578</link>
      <guid>https://dev.to/icentric/mcp-a2a-youre-building-two-integration-layers-whether-you-realise-it-or-not-1578</guid>
      <description>&lt;h2&gt;
  
  
  The Problem You Probably Have Already
&lt;/h2&gt;

&lt;p&gt;If you're building agentic systems in 2025, chances are you've already got two integration layers in your stack:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;MCP&lt;/strong&gt; (Model Context Protocol) — wiring your AI models to databases, APIs, filesystems, internal tools&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A2A&lt;/strong&gt; (Agent-to-Agent) protocols — letting your agents discover, negotiate with, and invoke &lt;em&gt;each other&lt;/em&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;They're not competing. They're complementary. But without a clear interoperability story, you're setting yourself up for the kind of integration spaghetti that kept enterprise architects busy (and miserable) in the ESB era.&lt;/p&gt;

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

&lt;p&gt;MCP is Anthropic's answer to a simple problem: how do you give an LLM structured, reliable access to external resources without writing bespoke glue code for every data source?&lt;/p&gt;

&lt;p&gt;Instead of hardcoding database queries or API calls into your prompts, you expose them as &lt;strong&gt;MCP servers&lt;/strong&gt;. Your AI client connects via a standard protocol, discovers available tools, and invokes them with typed parameters.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Example use case:&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;# MCP server exposes a tool
&lt;/span&gt;&lt;span class="nd"&gt;@mcp_tool&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;query_customer_orders&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;customer_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;list&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Order&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;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;execute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;SELECT * FROM orders WHERE customer_id = ?&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;customer_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Your LLM can now call &lt;code&gt;query_customer_orders&lt;/code&gt; as a function — no prompt engineering, no brittle scraping, no hoping the model "figures it out".&lt;/p&gt;

&lt;p&gt;MCP is &lt;strong&gt;vertical integration&lt;/strong&gt;: connecting one agent to the resources it needs to do its job.&lt;/p&gt;

&lt;h2&gt;
  
  
  What A2A Actually Does
&lt;/h2&gt;

&lt;p&gt;A2A is horizontal. It's about agents talking to &lt;em&gt;other agents&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Imagine you've got:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A customer service agent that handles support tickets&lt;/li&gt;
&lt;li&gt;A logistics agent that tracks shipments&lt;/li&gt;
&lt;li&gt;A billing agent that processes refunds&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When a customer asks "Where's my refund?", the support agent needs to talk to billing. That's A2A.&lt;/p&gt;

&lt;p&gt;A2A protocols define:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Discovery&lt;/strong&gt;: how does Agent A find Agent B?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Capability negotiation&lt;/strong&gt;: what can Agent B actually do?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Invocation&lt;/strong&gt;: how does Agent A call Agent B and handle the response?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Unlike MCP, A2A is still fragmented. There's no single standard. You might be using:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;HTTP APIs with custom service meshes&lt;/li&gt;
&lt;li&gt;Pub/sub queues (Kafka, RabbitMQ)&lt;/li&gt;
&lt;li&gt;gRPC with Protobuf schemas&lt;/li&gt;
&lt;li&gt;Proprietary frameworks from LangChain, AutoGen, CrewAI&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Each works. None interoperate cleanly.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why This Feels Familiar (and Not in a Good Way)
&lt;/h2&gt;

&lt;p&gt;If you worked in enterprise integration in the 2000s, this smells like &lt;strong&gt;ESB déjà vu&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The Enterprise Service Bus promised to solve the n-squared integration problem: instead of every system talking directly to every other system, route everything through a central bus.&lt;/p&gt;

&lt;p&gt;It worked — until it didn't. ESBs became:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Single points of failure&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Performance bottlenecks&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Proprietary lock-in traps&lt;/strong&gt; (looking at you, TIBCO and WebSphere)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The &lt;a href="https://www.icentricagency.com/insights/mcp-a2a-the-two-layer-stack-wiring-the-internet-of-agents-1" rel="noopener noreferrer"&gt;two-layer stack&lt;/a&gt; emerging now — MCP below, A2A above — risks the same fate if we're not careful.&lt;/p&gt;

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

&lt;h3&gt;
  
  
  1. Treat MCP as infrastructure, not application logic
&lt;/h3&gt;

&lt;p&gt;MCP is brilliant for standardising resource access. Don't abuse it by cramming business logic into MCP tools. Keep them thin, composable, and stateless.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Pick &lt;em&gt;one&lt;/em&gt; A2A pattern per bounded context
&lt;/h3&gt;

&lt;p&gt;Don't mix pub/sub and RPC in the same workflow unless you have a damn good reason. Consistency beats flexibility when debugging multi-agent failures at 2am.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Design for replaceability
&lt;/h3&gt;

&lt;p&gt;Whatever A2A framework you choose today will probably be legacy in 18 months. Wrap it. Abstract it. Make it swappable.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Example:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;AgentInvoker&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Protocol&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;invoke&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;agent_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;task&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;dict&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;dict&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="bp"&gt;...&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;KafkaAgentInvoker&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;AgentInvoker&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="c1"&gt;# Implementation today
&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;GrpcAgentInvoker&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;AgentInvoker&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="c1"&gt;# Swap in tomorrow
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  4. Monitor both layers separately
&lt;/h3&gt;

&lt;p&gt;MCP failures look different to A2A failures:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;MCP: "Tool not found", "Database timeout", "API key expired"&lt;/li&gt;
&lt;li&gt;A2A: "Agent unavailable", "Circular dependency", "Message bus backlog"&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Your observability stack needs to distinguish them.&lt;/p&gt;

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

&lt;p&gt;There's no silver bullet yet. MCP is maturing fast, but A2A is still the Wild West. If you're building production agentic systems — especially in regulated industries or at scale — treat this as an &lt;strong&gt;architecture risk&lt;/strong&gt;, not just a tooling choice.&lt;/p&gt;

&lt;p&gt;You don't need to freeze development. But you &lt;em&gt;do&lt;/em&gt; need to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Isolate the integration layer&lt;/li&gt;
&lt;li&gt;Version your agent contracts&lt;/li&gt;
&lt;li&gt;Plan for migration&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The teams that get this right won't be the ones with the cleverest agents. They'll be the ones who can rewire them without a full rewrite.&lt;/p&gt;




&lt;p&gt;If you're evaluating MCP, A2A, or any other part of the agentic stack and want a second opinion, teams specialising in &lt;a href="https://www.icentricagency.com" rel="noopener noreferrer"&gt;AI automation and software development&lt;/a&gt; can help you de-risk the architecture before you're too deep to reverse course.&lt;/p&gt;

&lt;p&gt;But honestly? Just don't build another ESB. We've been there. It wasn't fun.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>architecture</category>
      <category>agents</category>
      <category>integration</category>
    </item>
    <item>
      <title>Stop Hardcoding Your Agent Workflows (or Don't): A Dev's Guide to Supervisor Delegation</title>
      <dc:creator>Marc Newstead</dc:creator>
      <pubDate>Mon, 29 Jun 2026 09:02:40 +0000</pubDate>
      <link>https://dev.to/icentric/stop-hardcoding-your-agent-workflows-or-dont-a-devs-guide-to-supervisor-delegation-36gi</link>
      <guid>https://dev.to/icentric/stop-hardcoding-your-agent-workflows-or-dont-a-devs-guide-to-supervisor-delegation-36gi</guid>
      <description>&lt;h2&gt;
  
  
  Stop Hardcoding Your Agent Workflows (or Don't): A Dev's Guide to Supervisor Delegation
&lt;/h2&gt;

&lt;p&gt;If you're building anything with LLM agents right now, you've probably hit this fork in the road: do you hardcode which agent handles what, or do you let a "supervisor" agent decide at runtime?&lt;/p&gt;

&lt;p&gt;It's tempting to reach for the clever solution—dynamic delegation feels &lt;em&gt;proper&lt;/em&gt;, like good OOP. But after shipping a few of these systems, I've learned the hard way that the right answer is annoyingly context-dependent.&lt;/p&gt;

&lt;p&gt;Let me walk you through the trade-offs, so you can make the call before you burn through your token budget.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Two Approaches (in 60 Seconds)
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Hardcoded routing&lt;/strong&gt; is exactly what it sounds like:&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_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="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;refund&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;task&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;lower&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;refund_agent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;handle&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="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;track order&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;task&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;lower&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;tracking_agent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;handle&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="n"&gt;general_support_agent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;handle&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;Simple. Deterministic. Zero tokens spent on routing logic.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Supervisor delegation&lt;/strong&gt; puts an LLM in charge of routing:&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_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="n"&gt;supervisor_prompt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;
    Given this task: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;task&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;

    Available agents:
    - refund_agent: handles refund requests
    - tracking_agent: handles order tracking
    - support_agent: general queries

    Which agent should handle this? Return JSON.
    &lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;

    &lt;span class="n"&gt;decision&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;call&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;supervisor_prompt&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;get_agent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;decision&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;agent&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]).&lt;/span&gt;&lt;span class="nf"&gt;handle&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;Flexible. Handles edge cases you didn't anticipate. Also: costs tokens on every single request.&lt;/p&gt;

&lt;h2&gt;
  
  
  When the Supervisor Actually Earns Its Keep
&lt;/h2&gt;

&lt;p&gt;Dynamic delegation makes sense when your input space is genuinely unpredictable. I'm talking:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Research workflows&lt;/strong&gt; where you don't know upfront whether a query needs web search, database lookup, or code execution&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Multi-domain customer support&lt;/strong&gt; where a single ticket might touch billing, technical support, and account management&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Data pipelines&lt;/strong&gt; where the shape of incoming data determines which transformation agents fire&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The key signal: &lt;strong&gt;you can't write the if/else tree because you genuinely don't know the patterns yet&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;If you're in this camp, &lt;a href="https://www.icentricagency.com/insights/supervisor-and-sub-agents-how-one-agent-learns-to-delegate-1" rel="noopener noreferrer"&gt;supervisor and sub-agents&lt;/a&gt; can save you from an unmaintainable mess of routing logic.&lt;/p&gt;

&lt;h2&gt;
  
  
  When You Should Just Write the Damn If Statement
&lt;/h2&gt;

&lt;p&gt;Here's the uncomfortable truth: most enterprise use cases are &lt;em&gt;way&lt;/em&gt; more constrained than we pretend.&lt;/p&gt;

&lt;p&gt;Customer service triage? You've got maybe 6–10 intent categories. Document classification? Probably fewer than 20 types. Internal tooling automation? You know exactly what your users are going to ask for because you control the interface.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;If you can enumerate the cases in a planning doc, you can hardcode the routing.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Hardcoded routing gives you:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Predictable costs&lt;/strong&gt;: no surprise token spikes&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Faster execution&lt;/strong&gt;: skip the LLM call entirely&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Easier debugging&lt;/strong&gt;: stack traces beat "the supervisor made a weird choice"&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Simpler observability&lt;/strong&gt;: you know exactly which code path ran&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Start here. Add the supervisor later if you actually need it.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Hidden Costs Nobody Talks About
&lt;/h2&gt;

&lt;p&gt;Even if dynamic delegation &lt;em&gt;works&lt;/em&gt;, it compounds costs in ways that'll bite you:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Supervisor reasoning&lt;/strong&gt;: tokens on every request&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Sub-agent context&lt;/strong&gt;: each agent needs enough context to work, often duplicating the supervisor's input&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Inter-agent communication&lt;/strong&gt;: if agents collaborate, they're burning tokens talking to each other&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Retry logic&lt;/strong&gt;: when delegation fails, you pay again&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;I've seen teams blow their monthly OpenAI budget in a week because their supervisor was re-analysing the same 500-word input on every routing decision.&lt;/p&gt;

&lt;h3&gt;
  
  
  Observability Is Your Real Problem
&lt;/h3&gt;

&lt;p&gt;Debugging "why did the supervisor send this to the wrong agent?" is &lt;em&gt;miserable&lt;/em&gt;. You're spelunking through LLM logs, trying to reconstruct reasoning that wasn't deterministic to begin with.&lt;/p&gt;

&lt;p&gt;Hardcoded routing? &lt;code&gt;grep&lt;/code&gt; works. Supervisor delegation? You need structured logging, trace IDs, and probably a vector database just to understand what happened.&lt;/p&gt;

&lt;p&gt;If you're not already doing observability well, adding a supervisor will hurt.&lt;/p&gt;

&lt;h2&gt;
  
  
  My Default Recommendation
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Start with hardcoded routing.&lt;/strong&gt; Write the simplest if/elif/else chain that handles your known cases. Add a catch-all that logs unknown inputs.&lt;/p&gt;

&lt;p&gt;Then instrument &lt;em&gt;heavily&lt;/em&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;match&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;extract_intent&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;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;Routing &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;task_id&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; to &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;match&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;agent&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;intent&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;match&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;intent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;confidence&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;match&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;score&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;route_to&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;match&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;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="n"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;warning&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;No route for &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;task_id&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;task&lt;/span&gt;&lt;span class="o"&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;return&lt;/span&gt; &lt;span class="n"&gt;fallback_agent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;handle&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;Once you've got a month of prod data showing you &lt;em&gt;can't&lt;/em&gt; write better rules, &lt;strong&gt;then&lt;/strong&gt; evaluate a supervisor.&lt;/p&gt;

&lt;p&gt;And if you're working with a team that specialises in &lt;a href="https://www.icentricagency.com" rel="noopener noreferrer"&gt;AI automation and software development&lt;/a&gt;, they'll probably tell you the same thing: solve the problem you have, not the one that sounds clever.&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;Supervisor delegation ≠ always better&lt;/li&gt;
&lt;li&gt;Hardcode first if your domain is constrained&lt;/li&gt;
&lt;li&gt;Dynamic routing pays for itself when inputs are genuinely unpredictable&lt;/li&gt;
&lt;li&gt;Observability and cost control are harder than you think&lt;/li&gt;
&lt;li&gt;Start simple, instrument everything, upgrade if data proves you need it&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Your future self (and your token budget) will thank you.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>architecture</category>
      <category>devops</category>
      <category>llm</category>
    </item>
    <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>
  </channel>
</rss>
