<?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: Hardik Mehta</title>
    <description>The latest articles on DEV Community by Hardik Mehta (@imhardikmehta).</description>
    <link>https://dev.to/imhardikmehta</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%2F3909878%2F2b6a1af6-c9ee-48cd-ab85-b5d12ae323f2.png</url>
      <title>DEV Community: Hardik Mehta</title>
      <link>https://dev.to/imhardikmehta</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/imhardikmehta"/>
    <language>en</language>
    <item>
      <title>Why JSON Schema Isn't Enough for Production AI</title>
      <dc:creator>Hardik Mehta</dc:creator>
      <pubDate>Mon, 06 Jul 2026 10:09:07 +0000</pubDate>
      <link>https://dev.to/aviasoletechnologies/why-json-schema-isnt-enough-for-production-ai-4bfc</link>
      <guid>https://dev.to/aviasoletechnologies/why-json-schema-isnt-enough-for-production-ai-4bfc</guid>
      <description>&lt;h1&gt;
  
  
  Your LLM Can Return Perfect JSON and Still Be Completely Wrong
&lt;/h1&gt;

&lt;p&gt;Most developers (including me) assumed one thing when Structured Outputs became available:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;If my JSON validates against the schema, my extraction is correct.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Unfortunately, that's not true.&lt;/p&gt;

&lt;p&gt;After spending the last few months building &lt;strong&gt;ShapeCraft&lt;/strong&gt;, a structured output library for Node.js that works across OpenAI, Claude, Ollama, and Groq, I realized something important:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;JSON Schema guarantees structure—not truth.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Once you understand that distinction, you'll design much more reliable AI systems.&lt;/p&gt;




&lt;h2&gt;
  
  
  Let's look at an example
&lt;/h2&gt;

&lt;p&gt;Suppose you're extracting data from an invoice.&lt;/p&gt;

&lt;p&gt;The invoice says:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Invoice Total: $900
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Your LLM returns:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"invoiceTotal"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1200&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now let's validate it.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Valid JSON? &lt;strong&gt;Yes&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Matches JSON Schema? &lt;strong&gt;Yes&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Correct data type? &lt;strong&gt;Yes&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Required field present? &lt;strong&gt;Yes&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Correct answer? &lt;strong&gt;No&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The response is &lt;strong&gt;structurally perfect&lt;/strong&gt; but &lt;strong&gt;factually wrong&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;That's the difference between &lt;strong&gt;structural correctness&lt;/strong&gt; and &lt;strong&gt;semantic correctness&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  JSON Schema only solves one problem
&lt;/h2&gt;

&lt;p&gt;JSON Schema is excellent at validating structure.&lt;/p&gt;

&lt;p&gt;It ensures things like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Valid JSON&lt;/li&gt;
&lt;li&gt;Required fields&lt;/li&gt;
&lt;li&gt;Correct data types&lt;/li&gt;
&lt;li&gt;Arrays and objects&lt;/li&gt;
&lt;li&gt;Enum values&lt;/li&gt;
&lt;li&gt;Consistent response shape&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That's incredibly useful.&lt;/p&gt;

&lt;p&gt;But JSON Schema cannot answer questions like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Did the model extract the correct value?&lt;/li&gt;
&lt;li&gt;Is this value actually present in the source document?&lt;/li&gt;
&lt;li&gt;Did the model hallucinate?&lt;/li&gt;
&lt;li&gt;Can I trust this extraction?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Those are &lt;strong&gt;semantic&lt;/strong&gt; questions.&lt;/p&gt;




&lt;h2&gt;
  
  
  Structural Validation vs Semantic Validation
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Structural Validation&lt;/th&gt;
&lt;th&gt;Semantic Validation&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Valid JSON&lt;/td&gt;
&lt;td&gt;Correct value&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Required fields&lt;/td&gt;
&lt;td&gt;Grounded in source&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Correct data types&lt;/td&gt;
&lt;td&gt;No hallucination&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Schema compliance&lt;/td&gt;
&lt;td&gt;Evidence exists&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Safe to deserialize&lt;/td&gt;
&lt;td&gt;Safe to trust&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Most AI SDKs solve the first column.&lt;/p&gt;

&lt;p&gt;Production AI requires both.&lt;/p&gt;




&lt;h2&gt;
  
  
  Not all structured output works the same way
&lt;/h2&gt;

&lt;p&gt;While building ShapeCraft, I discovered something else that surprised me.&lt;/p&gt;

&lt;p&gt;Every provider advertises &lt;strong&gt;structured output&lt;/strong&gt;, but they don't enforce it the same way.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Provider&lt;/th&gt;
&lt;th&gt;Implementation&lt;/th&gt;
&lt;th&gt;Guarantee&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;OpenAI&lt;/td&gt;
&lt;td&gt;Server-side schema enforcement&lt;/td&gt;
&lt;td&gt;Native&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Groq&lt;/td&gt;
&lt;td&gt;Server-side schema enforcement&lt;/td&gt;
&lt;td&gt;Native&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Ollama&lt;/td&gt;
&lt;td&gt;Grammar-constrained decoding (GBNF)&lt;/td&gt;
&lt;td&gt;Constrained&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Anthropic&lt;/td&gt;
&lt;td&gt;Prompt + parse + retry&lt;/td&gt;
&lt;td&gt;Best-effort&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;They all produce structured output.&lt;/p&gt;

&lt;p&gt;But they provide &lt;strong&gt;different guarantees&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;That's an important distinction that's often hidden behind a single API.&lt;/p&gt;




&lt;h2&gt;
  
  
  Structure ≠ Truth
&lt;/h2&gt;

&lt;p&gt;Even with the strongest schema enforcement available today, a model can still return:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"customerName"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"John Smith"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"invoiceTotal"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1200&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"invoiceDate"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2026-07-01"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The JSON is valid.&lt;/p&gt;

&lt;p&gt;The schema passes.&lt;/p&gt;

&lt;p&gt;The data types are correct.&lt;/p&gt;

&lt;p&gt;The answer can still be wrong.&lt;/p&gt;

&lt;p&gt;No JSON Schema validator can detect that.&lt;/p&gt;




&lt;h2&gt;
  
  
  What production AI actually needs
&lt;/h2&gt;

&lt;p&gt;I now think of AI validation as two independent layers.&lt;/p&gt;

&lt;h3&gt;
  
  
  Layer 1 - Structural Validation
&lt;/h3&gt;

&lt;p&gt;Questions like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Is this valid JSON?&lt;/li&gt;
&lt;li&gt;Does it match my schema?&lt;/li&gt;
&lt;li&gt;Can my application deserialize it safely?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is where JSON Schema shines.&lt;/p&gt;

&lt;h3&gt;
  
  
  Layer 2 - Semantic Validation
&lt;/h3&gt;

&lt;p&gt;Questions like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Is the extracted value correct?&lt;/li&gt;
&lt;li&gt;Can this answer be traced back to the original source?&lt;/li&gt;
&lt;li&gt;Does evidence exist?&lt;/li&gt;
&lt;li&gt;Should I trust this response?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This layer is significantly harder.&lt;/p&gt;

&lt;p&gt;And it's where I believe the next generation of AI tooling needs to evolve.&lt;/p&gt;




&lt;h2&gt;
  
  
  Building ShapeCraft
&lt;/h2&gt;

&lt;p&gt;While exploring these differences, I built &lt;strong&gt;ShapeCraft&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;ShapeCraft is an open-source TypeScript library that provides a unified structured output API across multiple providers while exposing the &lt;strong&gt;actual guarantee level&lt;/strong&gt; instead of pretending every backend behaves the same.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;generate&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;openai&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@aviasole/shapecraft&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;generate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nf"&gt;openai&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;model&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;gpt-4o-mini&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;}),&lt;/span&gt;
  &lt;span class="nx"&gt;schema&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;prompt&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;guaranteeLevel&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// "native"&lt;/span&gt;
&lt;span class="c1"&gt;// "constrained"&lt;/span&gt;
&lt;span class="c1"&gt;// "best-effort"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Current providers:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;OpenAI&lt;/li&gt;
&lt;li&gt;Groq&lt;/li&gt;
&lt;li&gt;Ollama (GBNF constrained decoding)&lt;/li&gt;
&lt;li&gt;Anthropic&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Supported schema types:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Zod&lt;/li&gt;
&lt;li&gt;JSON Schema&lt;/li&gt;
&lt;li&gt;XML&lt;/li&gt;
&lt;li&gt;Regular Expressions&lt;/li&gt;
&lt;li&gt;Custom Validators&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Streaming, retries, and multi-turn structured conversations are also supported through the same API.&lt;/p&gt;

&lt;p&gt;GitHub:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/aviasoletechnologies/shapecraft" rel="noopener noreferrer"&gt;https://github.com/aviasoletechnologies/shapecraft&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;npm:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; @aviasole/shapecraft
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Where I think AI tooling is heading
&lt;/h2&gt;

&lt;p&gt;Structured output solved one of the biggest problems in LLM development.&lt;/p&gt;

&lt;p&gt;Before it, we spent countless hours:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Fixing malformed JSON&lt;/li&gt;
&lt;li&gt;Cleaning invalid responses&lt;/li&gt;
&lt;li&gt;Writing regex parsers&lt;/li&gt;
&lt;li&gt;Handling missing fields&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That problem is largely solved.&lt;/p&gt;

&lt;p&gt;The next challenge isn't better JSON.&lt;/p&gt;

&lt;p&gt;It's &lt;strong&gt;better confidence&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Imagine every response also including:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Evidence for every extracted field&lt;/li&gt;
&lt;li&gt;Field-level confidence scores&lt;/li&gt;
&lt;li&gt;Source attribution&lt;/li&gt;
&lt;li&gt;Semantic verification&lt;/li&gt;
&lt;li&gt;Reliability metrics&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That's where I believe production AI is heading.&lt;/p&gt;




&lt;h2&gt;
  
  
  Final thoughts
&lt;/h2&gt;

&lt;p&gt;Structured output is one of the biggest improvements in modern LLM APIs.&lt;/p&gt;

&lt;p&gt;But it's important to understand what it actually guarantees.&lt;/p&gt;

&lt;p&gt;It guarantees &lt;strong&gt;structure&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;It does &lt;strong&gt;not&lt;/strong&gt; guarantee &lt;strong&gt;correctness&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Once I separated those two ideas, it completely changed how I think about designing reliable AI systems.&lt;/p&gt;

&lt;p&gt;How are you validating AI output in production today?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Schema validation only?&lt;/li&gt;
&lt;li&gt;Human review?&lt;/li&gt;
&lt;li&gt;Semantic verification?&lt;/li&gt;
&lt;li&gt;Something else?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I'd love to hear how others are solving this problem.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>typescript</category>
      <category>node</category>
      <category>llm</category>
    </item>
    <item>
      <title>Stop Guessing: Guaranteed Structured Output from LLMs in Node.js</title>
      <dc:creator>Hardik Mehta</dc:creator>
      <pubDate>Wed, 01 Jul 2026 06:02:31 +0000</pubDate>
      <link>https://dev.to/aviasoletechnologies/stop-guessing-guaranteed-structured-output-from-llms-in-nodejs-4jna</link>
      <guid>https://dev.to/aviasoletechnologies/stop-guessing-guaranteed-structured-output-from-llms-in-nodejs-4jna</guid>
      <description>&lt;h2&gt;
  
  
  Stop Parsing LLM JSON. The Backend Already Knows Better.
&lt;/h2&gt;

&lt;p&gt;If you've built anything with LLMs, you've probably written code like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;raw&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;openai&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;chat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;completions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;parsed&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="nx"&gt;parsed&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;raw&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;choices&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;content&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// retry?&lt;/span&gt;
  &lt;span class="c1"&gt;// strip markdown?&lt;/span&gt;
  &lt;span class="c1"&gt;// log?&lt;/span&gt;
  &lt;span class="c1"&gt;// cry?&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then you added retry logic.&lt;/p&gt;

&lt;p&gt;Then the model started wrapping JSON in Markdown code fences.&lt;/p&gt;

&lt;p&gt;Then it added a trailing comma.&lt;/p&gt;

&lt;p&gt;Then you added another regex.&lt;/p&gt;

&lt;p&gt;Eventually your structured output pipeline became more complicated than the feature you were trying to build.&lt;/p&gt;

&lt;p&gt;The interesting part is:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;This isn't actually an LLM problem.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;It's a &lt;strong&gt;backend capability&lt;/strong&gt; problem.&lt;/p&gt;




&lt;h2&gt;
  
  
  Not all structured output is equal
&lt;/h2&gt;

&lt;p&gt;Most libraries expose a single "structured output" API regardless of which model you're using.&lt;/p&gt;

&lt;p&gt;Under the hood, those providers work very differently.&lt;/p&gt;

&lt;h2&gt;
  
  
  OpenAI
&lt;/h2&gt;

&lt;p&gt;OpenAI performs &lt;strong&gt;server-side schema enforcement&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;If the model doesn't satisfy the schema, the API won't return malformed JSON.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Guarantee:&lt;/strong&gt; Native.&lt;/p&gt;




&lt;h2&gt;
  
  
  Groq
&lt;/h2&gt;

&lt;p&gt;Groq provides a similar native structured output mechanism.&lt;/p&gt;

&lt;p&gt;Again, validation happens before the response reaches your application.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Guarantee:&lt;/strong&gt; Native.&lt;/p&gt;




&lt;h2&gt;
  
  
  Ollama
&lt;/h2&gt;

&lt;p&gt;This is where things get interesting.&lt;/p&gt;

&lt;p&gt;Ollama supports &lt;strong&gt;GBNF grammar constraints&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Instead of validating JSON after generation, the grammar is applied &lt;strong&gt;during token sampling&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;That means the model literally &lt;strong&gt;cannot emit a token that violates your schema&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;There is no malformed JSON to parse.&lt;/p&gt;

&lt;p&gt;There is no retry loop because of formatting mistakes.&lt;/p&gt;

&lt;p&gt;There is no &lt;code&gt;JSON.parse()&lt;/code&gt; risk.&lt;/p&gt;

&lt;p&gt;For local models, this is probably the strongest structured output guarantee currently available.&lt;/p&gt;




&lt;h2&gt;
  
  
  Anthropic
&lt;/h2&gt;

&lt;p&gt;Anthropic currently has no equivalent enforcement mechanism.&lt;/p&gt;

&lt;p&gt;The common approach is:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Prompt carefully&lt;/li&gt;
&lt;li&gt;Parse the response&lt;/li&gt;
&lt;li&gt;Validate&lt;/li&gt;
&lt;li&gt;Retry if necessary&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;It works well, but it's still &lt;strong&gt;best effort&lt;/strong&gt;, not guaranteed.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why this matters
&lt;/h2&gt;

&lt;p&gt;Many libraries abstract all providers behind exactly the same API.&lt;/p&gt;

&lt;p&gt;That sounds convenient.&lt;/p&gt;

&lt;p&gt;But it also hides an important architectural difference.&lt;/p&gt;

&lt;p&gt;Treating every provider the same means you're either:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;trusting outputs more than you should, or&lt;/li&gt;
&lt;li&gt;ignoring guarantees your backend already provides.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Knowing the guarantee level lets you design better systems.&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;Fewer retries&lt;/li&gt;
&lt;li&gt;Simpler parsing&lt;/li&gt;
&lt;li&gt;Better observability&lt;/li&gt;
&lt;li&gt;More predictable production behavior&lt;/li&gt;
&lt;li&gt;Cleaner error handling&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  A practical example
&lt;/h2&gt;

&lt;p&gt;Here's a structured output example using Ollama with Zod.&lt;br&gt;
&lt;/p&gt;

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

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;generate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nf"&gt;ollama&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;model&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;llama3.2&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;}),&lt;/span&gt;
  &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;object&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="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;string&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
    &lt;span class="na"&gt;score&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;number&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
  &lt;span class="p"&gt;}),&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Rate this essay.&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The returned object is fully typed, and with Ollama the schema is enforced through GBNF grammar during generation.&lt;/p&gt;




&lt;h2&gt;
  
  
  Different backends, different guarantees
&lt;/h2&gt;

&lt;p&gt;Thinking about structured output in terms of &lt;strong&gt;guarantee levels&lt;/strong&gt; makes provider behavior much easier to reason about.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Backend&lt;/th&gt;
&lt;th&gt;Guarantee&lt;/th&gt;
&lt;th&gt;Enforcement&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;OpenAI&lt;/td&gt;
&lt;td&gt;Native&lt;/td&gt;
&lt;td&gt;Server-side schema validation&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Groq&lt;/td&gt;
&lt;td&gt;Native&lt;/td&gt;
&lt;td&gt;Server-side schema validation&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Ollama&lt;/td&gt;
&lt;td&gt;Constrained&lt;/td&gt;
&lt;td&gt;Token-level GBNF grammar constraints&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Anthropic&lt;/td&gt;
&lt;td&gt;Best effort&lt;/td&gt;
&lt;td&gt;Prompt + validation + retries&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The API surface might look identical.&lt;/p&gt;

&lt;p&gt;The reliability characteristics are not.&lt;/p&gt;




&lt;h2&gt;
  
  
  Building around guarantee levels
&lt;/h2&gt;

&lt;p&gt;I've been experimenting with making these differences explicit rather than hiding them.&lt;/p&gt;

&lt;p&gt;In the library I maintain, every generation returns the guarantee level alongside the parsed result.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;generate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;model&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;schema&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;prompt&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;guaranteeLevel&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="c1"&gt;// "native"&lt;/span&gt;
&lt;span class="c1"&gt;// "constrained"&lt;/span&gt;
&lt;span class="c1"&gt;// "best-effort"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Instead of pretending every backend behaves the same, your application can make informed decisions based on the actual guarantees available.&lt;/p&gt;




&lt;h2&gt;
  
  
  Final thoughts
&lt;/h2&gt;

&lt;p&gt;Structured output isn't just about getting valid JSON.&lt;/p&gt;

&lt;p&gt;It's about understanding &lt;strong&gt;how&lt;/strong&gt; that JSON became valid.&lt;/p&gt;

&lt;p&gt;There's a big difference between:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;"the model happened to follow the prompt,"&lt;/li&gt;
&lt;li&gt;"the server enforced the schema," and&lt;/li&gt;
&lt;li&gt;"the model physically could not generate an invalid token."&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Those differences matter once you're building production systems.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Disclosure:&lt;/strong&gt; I'm one of the maintainers of &lt;strong&gt;ShapeCraft&lt;/strong&gt;, an open-source library that exposes structured output guarantee levels across OpenAI, Groq, Ollama, and Anthropic instead of treating every backend as identical.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;GitHub: &lt;a href="https://github.com/aviasoletechnologies/shapecraft" rel="noopener noreferrer"&gt;https://github.com/aviasoletechnologies/shapecraft&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;npm: &lt;a href="https://www.npmjs.com/package/@aviasole/shapecraft" rel="noopener noreferrer"&gt;https://www.npmjs.com/package/@aviasole/shapecraft&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I'd love to hear how you're handling structured output reliability in production.&lt;/p&gt;

</description>
      <category>node</category>
      <category>typescript</category>
      <category>llm</category>
      <category>ai</category>
    </item>
    <item>
      <title>Why We Read the Legacy System Before Touching It: A Healthcare Modernization Story</title>
      <dc:creator>Hardik Mehta</dc:creator>
      <pubDate>Tue, 23 Jun 2026 07:25:24 +0000</pubDate>
      <link>https://dev.to/aviasoletechnologies/why-we-read-the-legacy-system-before-touching-it-a-healthcare-modernization-story-535j</link>
      <guid>https://dev.to/aviasoletechnologies/why-we-read-the-legacy-system-before-touching-it-a-healthcare-modernization-story-535j</guid>
      <description>&lt;h2&gt;
  
  
  The Call That Started Everything
&lt;/h2&gt;

&lt;p&gt;The client's CTO opened the call with a concrete problem: their prescription processing system was failing on roughly 40% of real-world inputs, routed to a manual review queue that had become load-bearing infrastructure. The developer who had built the original system had left 18 months ago. A mobile app integration was due in 90 days.&lt;/p&gt;

&lt;p&gt;We asked to see the codebase before saying anything else.&lt;/p&gt;

&lt;p&gt;What we found was a system built on a reasonable 2019 commercial OCR library, surrounded by years of conditional logic that had accumulated without any of it being documented. Each addition had made sense at the time - a fix for handwritten abbreviations, a workaround for a specific clinic's prescription format, a retry loop for low-confidence scans. Taken together, they had created something no current team member could reason about in full.&lt;/p&gt;

&lt;p&gt;The 40% failure rate was not a sign the original system was poorly designed. It was a sign the system had drifted far enough from its original design assumptions that it needed to be replaced.&lt;/p&gt;

&lt;p&gt;The business impact was clear: one operations staff member was doing nothing but processing the manual queue. New features were blocked because any change to the conditional logic was too risky without documentation. The system was costing more to maintain than to have originally built it differently.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why Two Prior Attempts Had Failed
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://www.mckinsey.com/capabilities/mckinsey-digital/our-insights/tech-forward/modernizing-legacy-technology" rel="noopener noreferrer"&gt;McKinsey research&lt;/a&gt; consistently finds that companies spend between 60 and 80 percent of their IT budgets maintaining existing systems rather than building new ones. The client had tried to break out of that cycle twice.&lt;/p&gt;

&lt;p&gt;The first attempt was a rewrite from scratch. A contractor built a new OCR system over four months. It was technically cleaner - but it didn't match the behavior of the legacy system on the inputs the business actually received. Medicine names the legacy system had resolved were missed. Patient identity edge cases that the legacy system had handled silently broke. The contractor had no behavioral baseline to compare against, so they had no way to know what was missing until users reported failures. The rewrite was abandoned.&lt;/p&gt;

&lt;p&gt;The second attempt was a vendor replacement - an off-the-shelf healthcare OCR API. Accuracy on clean inputs was better than the legacy system, but the API returned raw extracted text, not structured data. Integrating its output into the existing database schema would have required rebuilding most of the downstream application. The integration cost exceeded the modernization budget.&lt;/p&gt;

&lt;p&gt;Both attempts shared the same root cause: the team tried to replace the system before they fully understood what it was doing.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.gartner.com/en/documents/3991199" rel="noopener noreferrer"&gt;Gartner estimates&lt;/a&gt; that 70 percent of modernization projects fail for this reason - not because the replacement technology was wrong, but because the team didn't have a reliable map of the system's actual behavior before they started replacing it.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step One: A Behavioral Baseline, Not a Code Analysis
&lt;/h2&gt;

&lt;p&gt;The first thing we did was add logging to the production system.&lt;/p&gt;

&lt;p&gt;Over two weeks, we captured approximately 2,000 real prescription submissions - the input image, every conditional branch triggered, every medicine name resolved or failed, the patient identity outcome, and the final database write or queue assignment. This gave us a behavioral baseline: a record of what the system actually did on real production inputs, across the full range of formats it encountered.&lt;/p&gt;

&lt;p&gt;This golden set became the behavioral contract for the entire migration. Every replacement component we built had to match or improve on the legacy system's outputs on this set before handling production traffic.&lt;/p&gt;

&lt;p&gt;We then used LLM-assisted analysis to read and map the codebase - every conditional branch, every fallback path, every hardcoded value. The output was a plain-language map of what each component did.&lt;/p&gt;

&lt;p&gt;Here is where we want to be precise about what that analysis produced, because this is where projects go wrong when they over-rely on AI tooling:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;AI can describe what code does. It cannot explain why a rule was added.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Consider an example:&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;customer_id&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;1234&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="nf"&gt;skip_verification&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;An LLM analysis correctly identifies this as a verification bypass for a specific customer ID. It cannot tell you whether that customer is a test account, a long-standing enterprise client with a contractual exception, a developer shortcut that never got removed, or a compliance workaround for a specific regulatory situation. That answer lives in someone's memory, a Slack thread, or a contract - not in the code.&lt;/p&gt;

&lt;p&gt;We found several rules like this in the client's system. For each one, we had to go to the remaining team members and, in some cases, dig through email history to understand the original intent. Some rules were still valid. Two had been superseded by changes elsewhere in the system and could be safely removed. One reflected a client-specific exception that needed to be replicated exactly in the replacement.&lt;/p&gt;

&lt;p&gt;The LLM analysis compressed the discovery process from weeks to days. The stakeholder validation work - confirming why each rule existed and whether it was still needed - could not be compressed. That part required humans with institutional knowledge, and no tooling changes that.&lt;/p&gt;

&lt;p&gt;Three findings from the combined analysis shaped the migration plan:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Finding 1: The 40% queue rate was not random.&lt;/strong&gt; It clustered around three input types - handwritten prescriptions, regional brand-name drugs not in the hardcoded medicine list, and poor-lighting photographs. The rest of the system handled its inputs correctly. Most of it did not need to be replaced.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Finding 2: The medicine name lookup was the highest-leverage failure point.&lt;/strong&gt; The static list had been manually maintained and had coverage gaps for regional generics and newer branded molecules. Every failure that reached the manual queue traced to a name the list didn't recognize.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Finding 3: The patient identity resolution logic was correct.&lt;/strong&gt; It handled multi-patient households, ambiguous name matches, and confirmation flows accurately. Replacing it would introduce risk with no corresponding benefit.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Replacement Strategy: What Moved, What Stayed, What Changed
&lt;/h2&gt;

&lt;p&gt;We need to be direct about something that often gets glossed over in modernization case studies: &lt;strong&gt;you don't eliminate complexity, you move it&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The old system handled edge cases through conditional logic in the application code. The new system handles those same edge cases - they have to go somewhere - through Vision LLM prompt design, RAG pipeline threshold tuning, and agent orchestration logic. The complexity still exists. What changed is where it lives and how maintainable it is.&lt;/p&gt;

&lt;p&gt;In the old system, complexity lived in undocumented conditional branches. When something broke, the only way to diagnose it was to read the code and guess which branch had triggered. When a new edge case appeared, a developer added another branch. There was no systematic way to test whether a change had broken anything else.&lt;/p&gt;

&lt;p&gt;In the new system, complexity lives in components that can be independently versioned, tested, and monitored. A prompt change is reviewable. A RAG threshold change can be validated against the golden set before deployment. An agent tool-call failure produces a structured log entry that can be replayed. The diagnostic process changes from reading undocumented code to querying structured logs.&lt;/p&gt;

&lt;p&gt;That's the actual value proposition - not "less complexity" but "complexity in a form you can work with."&lt;/p&gt;

&lt;p&gt;The migration itself had four phases, each independently testable and each with its own rollback path:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Phase 1: Replace the OCR engine with a Vision LLM.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The commercial OCR library output raw character strings with no understanding of document structure. A Vision LLM (we used Google Gemini) extracts structured fields - medicine name, patient name, dosage, frequency, clinic - in a single pass, handling handwritten text, abbreviations, and variable image quality.&lt;/p&gt;

&lt;p&gt;What this moved: the conditional logic that existed to normalize raw OCR output - handling abbreviations, splitting combined entries, cleaning whitespace - became part of the extraction prompt and the validation layer. The branching is still there; it's in the prompt design and the structured output schema instead of the application code.&lt;/p&gt;

&lt;p&gt;Before deploying to production, we ran the Vision LLM against the full 2,000-item golden set and compared outputs against what the legacy OCR had produced. Zero regressions on the inputs the legacy system had processed correctly. Significant improvement on the inputs it had failed.&lt;/p&gt;

&lt;p&gt;Rollback path: the legacy OCR engine ran in parallel for four weeks. Any prescription returning a Vision LLM confidence score below the calibrated threshold was automatically rerouted to the legacy OCR path.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Phase 2: Replace the static medicine list with a four-stage RAG pipeline.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;A static list cannot expand automatically. The new pipeline has four sequential stages: in-memory cache for high-frequency drugs, exact database match, trigram fuzzy search for OCR noise and spelling variants, and vector semantic search for phonetic variants and partial matches. Medicines that pass no stage are queued for automated scraping and added to the database.&lt;/p&gt;

&lt;p&gt;What this moved: the coverage decisions that had been made implicitly by choosing which drugs to add to the static list became explicit in the RAG pipeline - threshold tuning, confidence cutoffs, the definition of "close enough" for fuzzy matching. These decisions are now documented in code and tunable from data rather than locked in a spreadsheet someone last updated nine months ago.&lt;/p&gt;

&lt;p&gt;Threshold tuning required significant calibration against the golden set. Too permissive on fuzzy matching produces false positives - a medicine name matched to the wrong drug. Too strict increases the queue rate. We iterated through several threshold combinations until the new pipeline matched the legacy list's resolution rate on clean inputs while outperforming it on the noisy inputs that had previously gone to the manual queue.&lt;/p&gt;

&lt;p&gt;Rollback path: the legacy medicine list remained as a fallback for any name the new pipeline returned below the confidence threshold.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Phase 3: Wrap the patient identity logic, don't replace it.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The behavioral analysis confirmed this component was correct. We extracted it, wrote a behavioral test suite documenting its outputs for every input class in the golden set, and wrapped it behind a clean API interface. The new system called it identically to how the old system had.&lt;/p&gt;

&lt;p&gt;This was the single highest-leverage decision in the project. Replacing a working component to make it cleaner is one of the most common sources of regression in modernization projects. If the behavior is correct and the blast radius of a change is high, wrap it and move on.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Phase 4: Replace the accumulated conditional logic with a ReAct agent.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The legacy system processed prescriptions through a linear pipeline with hardcoded fallbacks and no structured logging. Debugging a production failure required reading the code and tracing which branch had triggered - which was difficult because the branches interacted in ways that weren't documented anywhere.&lt;/p&gt;

&lt;p&gt;The ReAct agent orchestrates the extraction and matching steps with complete tool-call logging. Every tool call is recorded with its input and output. Any production failure can be replayed exactly from those logs. The complexity of the orchestration is still present - the agent has to make decisions about which tools to call and in what order - but those decisions are visible and testable.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Traffic Migration: Six Weeks of Parallel Operation
&lt;/h2&gt;

&lt;p&gt;We did not cut over to the new system on a date. We migrated traffic incrementally over six weeks, with automatic fallback at every stage.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Weeks 1–2: 5% of traffic.&lt;/strong&gt; The old system handled the rest. Output discrepancies between the two systems were logged and reviewed daily. The most common discrepancy was medicine name formatting - the new system returned canonical names where the legacy system had returned raw OCR output. These weren't errors, but they required downstream validation to confirm they were improvements rather than regressions.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Weeks 3–4: 25% of traffic.&lt;/strong&gt; We calculated per-stage hit rates for the medicine RAG pipeline on live inputs - not just the golden set. The vector search stage was handling 11% of resolutions, within the expected 8–15% range, indicating the pipeline was behaving as designed on real production inputs.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Week 5: 50% of traffic.&lt;/strong&gt; The manual queue rate dropped from 40% to under 8% of total submissions. The operations staff member assigned to the queue was transitioned to other work during this week.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Week 6: 100% of traffic.&lt;/strong&gt; The legacy system was kept warm for two additional weeks before decommissioning.&lt;/p&gt;

&lt;p&gt;The data migration - moving years of patient records, prescription scans, and medicine match histories from the old schema to the new one - ran as a separate workstream after the application layer was stable. We used a read-from-old, write-to-new pattern: new records written to both systems in parallel during a two-week overlap period, with nightly reconciliation checks comparing row counts and spot-checking field values against known records. No cutover happened until reconciliation passed on three consecutive nights.&lt;/p&gt;




&lt;h2&gt;
  
  
  Observability: What We Tracked and Why
&lt;/h2&gt;

&lt;p&gt;AI systems require different monitoring than deterministic systems. You're not just watching for errors - you're watching for distribution shifts that indicate something upstream has changed.&lt;/p&gt;

&lt;p&gt;We tracked four things continuously after go-live:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Per-stage hit rates in the medicine pipeline.&lt;/strong&gt; If the in-memory cache dropped from 35% to 2%, either the cache wasn't warming correctly or the input distribution had shifted. If the vector search stage climbed above 20%, the exact and fuzzy stages were missing inputs they shouldn't be missing. Alerts fired on sustained deviation from established baselines, not on individual anomalies.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Vision LLM extraction confidence scores.&lt;/strong&gt; We tracked the distribution of per-field confidence scores over time, with alerts on a shift in the low-confidence tail. A gradual drift here is a leading indicator that input quality is changing - new prescription formats, different image types - before it shows up as an increased queue rate.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Queue rate as a system health proxy.&lt;/strong&gt; The rate of prescriptions entering the manual confirmation queue was the most reliable single indicator. A baseline of under 8% was established from the golden set. Sustained queue rate above 15% triggered an incident review.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Agent tool-call latency by stage.&lt;/strong&gt; The ReAct agent logs every tool call with timing. When latency spikes, we can see exactly which stage caused it - something that was completely invisible in the legacy system, which had no structured instrumentation at all.&lt;/p&gt;

&lt;p&gt;Every production failure was replayable: the agent's full tool-call trace, the exact Vision LLM output, and the input image were all logged. Diagnosing a production issue typically took minutes rather than the hours required with the original system.&lt;/p&gt;




&lt;h2&gt;
  
  
  Results
&lt;/h2&gt;

&lt;p&gt;By end of week six:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Manual queue dropped from 40% to under 8%.&lt;/strong&gt; The remaining 8% are genuinely ambiguous cases - new prescription formats, heavily degraded images, medicines with no prior occurrence - that legitimately require human judgment. The original 40% was the system failing on inputs it should have handled automatically.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Medicine identification accuracy reached approximately 95 percent.&lt;/strong&gt; The four-stage pipeline resolved brand names, generics, abbreviations, and OCR noise that the static list had been failing on for two years. Coverage improves continuously as the auto-scraper adds new medicines.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Zero OCR data lost during identity confirmation.&lt;/strong&gt; The original system discarded prescription data silently if identity resolution failed. The new system holds unresolved prescriptions in a confirmation queue while returning medicine data immediately - no input is lost.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The mobile app launched within 90 days.&lt;/strong&gt; The modernization produced a documented API as a byproduct. The previous system had no API - every integration had coupled directly to the database. The new API allowed mobile frontend development to run in parallel with the final weeks of traffic migration.&lt;/p&gt;

&lt;p&gt;Full technical architecture is in the &lt;a href="https://aviasole.com/case-studies/ocr-prescription-processing/" rel="noopener noreferrer"&gt;OCR prescription processing case study&lt;/a&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  What We'd Do Differently
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Build the golden set before the scoping conversation.&lt;/strong&gt; We added logging to the legacy system at the start of engagement and waited two weeks before beginning analysis. That was the right sequence, but the two-week wait could have started before we were formally engaged - earlier data means more edge cases in the baseline.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Budget more time for stakeholder rule validation.&lt;/strong&gt; The rules that required human explanation to understand - the exceptions that existed for business or political reasons, not technical ones - took longer to validate than we had initially estimated. In a system with years of accumulated logic, assume several of the rules have non-obvious histories that a developer interview won't immediately surface.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Negotiate a longer parallel operation window for higher-stakes systems.&lt;/strong&gt; Six weeks was sufficient here. For a system with higher transaction volume, stronger regulatory requirements, or more complex failure modes, eight to ten weeks would have been more comfortable.&lt;/p&gt;




&lt;h2&gt;
  
  
  What This Pattern Looks Like in Other Contexts
&lt;/h2&gt;

&lt;p&gt;The sequence - behavioral baseline first, component-by-component replacement with rollback paths, incremental traffic migration, continuous observability - applies wherever critical systems have accumulated undocumented complexity.&lt;/p&gt;

&lt;p&gt;In banking, &lt;a href="https://www.ibm.com/thought-leadership/institute-business-value/en-us/report/legacy-modernization" rel="noopener noreferrer"&gt;IBM estimates&lt;/a&gt; 95 billion lines of COBOL are still in active production, processing approximately $3 trillion in daily transactions. The challenge isn't the technology - it's that golden-set creation at scale requires instrumentation before any replacement begins, and the stakeholder validation of extracted business rules is more time-consuming as systems get older and institutional memory degrades.&lt;/p&gt;

&lt;p&gt;In insurance, mainframe policy calculation engines with pricing rules from the 1990s present the same stakeholder challenge in more acute form. Some of those rules exist because of regulatory requirements that have since changed, or client exceptions that were negotiated long before anyone currently at the company started. AI can surface the rules. Humans have to determine which ones are still valid.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.mckinsey.com/capabilities/mckinsey-digital/our-insights" rel="noopener noreferrer"&gt;McKinsey Digital&lt;/a&gt; documents that successful legacy modernizations typically see 20 to 30 percent reductions in IT operating costs. The technical approach matters, but the bigger variable is whether the team invested in a behavioral baseline and stakeholder validation before writing replacement code. The teams that skip those steps are the ones rebuilding for a third time.&lt;/p&gt;




&lt;h2&gt;
  
  
  If Your Organization Is in This Situation
&lt;/h2&gt;

&lt;p&gt;The indicators we look for: a system that's been in production for more than two years, patched by more than one developer, with no behavioral test suite, producing operational cost through manual workarounds or blocking new features because changes feel too risky.&lt;/p&gt;

&lt;p&gt;If that describes something you're carrying, the starting point isn't planning a replacement. It's building the behavioral baseline - logging production inputs and outputs for two to four weeks, so you have a ground-truth record of what the system actually does before you decide what to replace.&lt;/p&gt;

&lt;p&gt;Talk to the &lt;a href="https://aviasole.com/contact/" rel="noopener noreferrer"&gt;Aviasole engineering team&lt;/a&gt; about what that looks like for your system, or review the &lt;a href="https://aviasole.com/case-studies/ocr-prescription-processing/" rel="noopener noreferrer"&gt;OCR prescription processing case study&lt;/a&gt; for the full technical breakdown.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>legacy</category>
      <category>healthcareai</category>
    </item>
    <item>
      <title>AI Automation Gives You Different Answers Than Your Old Software - Here's Why That Matters</title>
      <dc:creator>Hardik Mehta</dc:creator>
      <pubDate>Thu, 18 Jun 2026 05:54:15 +0000</pubDate>
      <link>https://dev.to/aviasoletechnologies/ai-automation-gives-you-different-answers-than-your-old-software-heres-why-that-matters-2i4o</link>
      <guid>https://dev.to/aviasoletechnologies/ai-automation-gives-you-different-answers-than-your-old-software-heres-why-that-matters-2i4o</guid>
      <description>&lt;p&gt;A logistics manager at a mid-size distributor spent three weeks trying to understand why their accounts payable process had become inconsistent. Their ERP - in place for eight years - approved a vendor invoice in under two seconds. Their new AI-powered automation platform flagged the same invoice as a potential duplicate. Both systems had access to the same data. Both vendors claimed high accuracy. The manager couldn't reconcile the two verdicts, so she escalated to her CFO, who spent half a day investigating an invoice that should have taken two seconds.&lt;/p&gt;

&lt;p&gt;The systems weren't malfunctioning. They were working exactly as designed. The problem was that nobody had explained to the manager - or her CFO - what kind of software each one actually was.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Rule-Based Software Actually Does
&lt;/h2&gt;

&lt;p&gt;Legacy software - ERPs, CRMs, compliance checkers, billing systems - is built on explicit rules written by developers. Every decision traces back to a human-authored condition: if this, then that.&lt;/p&gt;

&lt;p&gt;An accounts payable rule might look like: if the vendor is on the approved list AND the invoice amount is under the purchase order cap AND no matching invoice number exists in the last 90 days → approve. If any condition fails → flag for review.&lt;/p&gt;

&lt;p&gt;This is &lt;strong&gt;deterministic&lt;/strong&gt; software. The same input always produces the same output. No exceptions. No variance. Run it a thousand times on a Tuesday and a thousand times on a Friday - you get identical results. The logic is transparent, auditable, and explainable to anyone: a developer, an auditor, a regulator, a judge.&lt;/p&gt;

&lt;p&gt;That predictability is not a limitation. For most business-critical decisions, it is exactly what you want.&lt;/p&gt;

&lt;h2&gt;
  
  
  What AI Automation Actually Does Under the Hood
&lt;/h2&gt;

&lt;p&gt;AI automation works differently at a fundamental level. Instead of rules written by a developer, it uses patterns learned from training data - thousands or millions of past examples - to estimate what the correct answer probably is.&lt;/p&gt;

&lt;p&gt;The output is not a verdict. It is a probability. The model says: based on everything I learned, there is a 91% chance this invoice is legitimate. The system then converts that score into an action - approve if above threshold, flag if below.&lt;/p&gt;

&lt;p&gt;This is &lt;strong&gt;probabilistic&lt;/strong&gt; software. The same input submitted twice may not score identically. The model's confidence depends on how closely the current input resembles patterns it saw during training. Shift the input slightly - different formatting, a vendor name it hasn't seen often, an unusual amount for that category - and the score shifts. Not because the facts changed, but because the model's certainty changed.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where the Outcomes Diverge - and Why It Costs You
&lt;/h2&gt;

&lt;p&gt;The divergence becomes a real business problem in three scenarios.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;When you need auditability.&lt;/strong&gt; A regulator asks why a transaction was approved. With rule-based software, you can print the exact conditions that passed and when. With AI, the honest answer is "the model scored it above threshold." That answer does not satisfy a financial regulator, a HIPAA auditor, or a contract dispute. Some industries - financial services, healthcare, insurance - have explicit requirements for explainable automated decisions. Probabilistic systems, unless purpose-built with explainability layers, do not meet that bar.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;When the cost of a wrong answer is high.&lt;/strong&gt; Rule-based systems fail in predictable ways: if you write a wrong rule, it fails the same way every time, which makes it easy to catch and fix. AI systems fail in unpredictable ways: the model may work correctly 98% of the time and fail on a specific edge case that your testing never surfaced. In loan approvals, drug dosage calculations, or compliance checks, that 2% is not an acceptable error margin.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;When consistency across teams matters.&lt;/strong&gt; Two employees using the same rule-based system get the same answer. Two employees running the same request through an AI system at different times may get different answers - leading to confusion, inconsistency, and the exact kind of operational chaos the logistics manager ran into.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where AI Automation Wins Anyway
&lt;/h2&gt;

&lt;p&gt;None of this means legacy software is always better. Rule-based systems have a hard ceiling: they require a developer to anticipate every possible condition and write a rule for it. That works when decisions are well-defined and the input is structured. It breaks down quickly in three situations.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Unstructured input.&lt;/strong&gt; Rules need structured data. If your workflow involves processing free-text customer complaints, classifying images, extracting information from scanned documents, or analyzing support tickets - rules cannot handle this. AI can.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Scale beyond human rule-writing capacity.&lt;/strong&gt; Fraud detection across 10 million daily transactions involves patterns no developer could enumerate. Recommendation engines across a 500,000-SKU catalog cannot be rule-driven. When the decision space is too large to hand-code, AI's ability to learn from data is not optional - it's the only viable approach.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Decisions where human judgment was already inconsistent.&lt;/strong&gt; If two senior reviewers in your company would disagree about the right answer 30% of the time anyway, a rule-based system gives you the illusion of consistency without the reality. AI trained on enough labeled data can sometimes outperform the inconsistent baseline.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to Decide Which System Your Business Actually Needs
&lt;/h2&gt;

&lt;p&gt;Before replacing any existing system with AI - or keeping legacy software that's genuinely holding you back - run this four-question audit on each decision point in your workflow:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Can you write down all the conditions needed to make this decision correctly?&lt;/strong&gt;&lt;br&gt;
If yes, a rule-based system is simpler and more reliable. If not - because the decision involves pattern recognition, unstructured data, or too many variables - AI is the right tool.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. What is the cost of a wrong answer?&lt;/strong&gt;&lt;br&gt;
High cost (financial, legal, compliance) → keep deterministic rules, or add hard rules as constraints on top of any AI layer. Low cost at high volume (content tagging, routing, recommendations) → AI is worth the variance.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Does the decision need to be fully explainable to an external party?&lt;/strong&gt;&lt;br&gt;
Regulator, auditor, customer, court → deterministic rules or AI with built-in explainability. Internal optimization → AI is fine.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. Does the input involve unstructured data?&lt;/strong&gt;&lt;br&gt;
Documents, images, free text, audio → AI. Clean structured database records → rules handle this cleanly.&lt;/p&gt;

&lt;p&gt;Most well-designed production systems use both. Deterministic rules enforce hard constraints - you must be on the approved vendor list, the amount must be under the authorized limit. AI handles pattern recognition within those constraints - within the approved vendors, which invoices look statistically unusual compared to historical patterns?&lt;/p&gt;

&lt;h2&gt;
  
  
  Do You Actually Need to Rebuild, or Just Layer?
&lt;/h2&gt;

&lt;p&gt;The most common mistake we see product founders make is treating this as a binary choice. They look at their legacy system, decide it's outdated, and replace it wholesale with an AI automation platform - then spend months dealing with inconsistency, explainability gaps, and edge cases the AI handles differently than the old system.&lt;/p&gt;

&lt;p&gt;The better question is usually: which specific decisions in this workflow genuinely benefit from probabilistic intelligence, and which ones should stay deterministic?&lt;/p&gt;

&lt;p&gt;At Aviasole, we help companies answer that question before a single line of automation code gets written. Our &lt;a href="https://aviasole.com/services/agentic-ai/" rel="noopener noreferrer"&gt;AI development services&lt;/a&gt; include workflow audits that map your decision points, identify where AI creates value versus risk, and design systems that use each approach where it actually belongs - not where it's fashionable.&lt;/p&gt;

&lt;p&gt;Most of the time, the right architecture is not a replacement. It's a layer.&lt;/p&gt;

&lt;h2&gt;
  
  
  Ready to Audit Your Automation Decisions?
&lt;/h2&gt;

&lt;p&gt;If you're evaluating whether to automate a workflow - or trying to understand why an existing AI system is producing inconsistent results - the first step is a decision-point audit, not a technology selection.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://aviasole.com/contact/" rel="noopener noreferrer"&gt;Talk to our team&lt;/a&gt; about mapping your workflow. We'll tell you honestly where AI helps, where it introduces risk, and where your legacy rules are doing exactly what they should.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>programming</category>
      <category>softwaredevelopment</category>
    </item>
    <item>
      <title>MCP 2.0: The Protocol That Finally Gives AI Agents a Universal Power Outlet</title>
      <dc:creator>Hardik Mehta</dc:creator>
      <pubDate>Tue, 16 Jun 2026 13:49:11 +0000</pubDate>
      <link>https://dev.to/aviasoletechnologies/mcp-20-the-protocol-that-finally-gives-ai-agents-a-universal-power-outlet-8p5</link>
      <guid>https://dev.to/aviasoletechnologies/mcp-20-the-protocol-that-finally-gives-ai-agents-a-universal-power-outlet-8p5</guid>
      <description>&lt;p&gt;A team at a mid-size SaaS company spent six weeks building a custom integration layer so their AI agent could talk to Salesforce, Jira, Confluence, and their internal data warehouse. Four tools. Six weeks. The agent still couldn't handle OAuth token refresh without manual intervention every 48 hours.&lt;/p&gt;

&lt;p&gt;Their competitor shipped the same capability in four days.&lt;/p&gt;

&lt;p&gt;That gap - six weeks versus four days - is what Model Context Protocol 2.0 actually closes.&lt;/p&gt;

&lt;h2&gt;
  
  
  What MCP Is (and Why It Took This Long to Need It)
&lt;/h2&gt;

&lt;p&gt;Model Context Protocol is an open standard &lt;a href="https://www.anthropic.com/news/model-context-protocol" rel="noopener noreferrer"&gt;released by Anthropic in November 2024&lt;/a&gt; that defines a universal communication layer between AI applications and external tools, data sources, and services. Think of it as USB-C for AI agents: before USB-C, every device needed a different cable. Before MCP, every AI integration needed custom connector code.&lt;/p&gt;

&lt;p&gt;The original spec established a clean client/server architecture: an AI application (the MCP client) discovers and calls tools exposed by MCP servers, without needing to know each tool's implementation details. Within months, official MCP servers shipped for &lt;a href="https://github.com/modelcontextprotocol/servers/tree/main/src/github" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;, Slack, Notion, PostgreSQL, Google Drive, and dozens more.&lt;/p&gt;

&lt;p&gt;But the first version had real production gaps: no standardized authorization flow, a transport layer that struggled with long-running operations, and no protocol-level way for agents to know whether a tool call was safe to retry. For demos and internal prototypes, these were manageable. For enterprise production deployments - the kind that touch customer data, need compliance audit trails, and run 24/7 - they were blockers.&lt;/p&gt;

&lt;p&gt;The March 2025 spec update - what the community calls MCP 2.0 - fixed all three.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Actually Changed in MCP 2.0
&lt;/h2&gt;

&lt;p&gt;Three changes. Each one fixes a specific production failure mode.&lt;/p&gt;

&lt;h3&gt;
  
  
  OAuth 2.0 Authorization
&lt;/h3&gt;

&lt;p&gt;The original MCP spec left auth up to implementers. In practice, that meant agents holding long-lived admin credentials - the path of least resistance, and a compliance nightmare.&lt;/p&gt;

&lt;p&gt;MCP 2.0 makes &lt;a href="https://spec.modelcontextprotocol.io/specification/2025-03-26/basic/authorization/" rel="noopener noreferrer"&gt;OAuth 2.0 a first-class protocol element&lt;/a&gt;. An MCP server declares its authorization requirements; the client satisfies them before tool calls are permitted. A healthcare agent connecting to an EHR system gets scoped, time-limited tokens - not standing admin access. Compliance teams audit agent permissions through existing OAuth infrastructure. Least-privilege access becomes enforceable at the protocol level, not just a policy aspiration that gets ignored under delivery pressure.&lt;/p&gt;

&lt;h3&gt;
  
  
  Streamable HTTP Transport
&lt;/h3&gt;

&lt;p&gt;The original transport was Server-Sent Events: useful for real-time updates, but one-directional and stateless in ways that made long-running operations awkward. If an agent triggered a 20-minute data pipeline and needed live progress updates, SSE was a painful compromise.&lt;/p&gt;

&lt;p&gt;MCP 2.0 replaces SSE with &lt;a href="https://spec.modelcontextprotocol.io/specification/2025-03-26/basic/transports/#streamable-http" rel="noopener noreferrer"&gt;Streamable HTTP&lt;/a&gt;: bidirectional, resumable, built for operations that outlast a single HTTP request. A dev tooling agent monitoring a CI/CD pipeline gets live build events without polling. An agentic workflow processing a 500-document corpus reports progress in real time without timing out.&lt;/p&gt;

&lt;h3&gt;
  
  
  Tool Annotations
&lt;/h3&gt;

&lt;p&gt;Before MCP 2.0, an agent had no protocol-level signal that &lt;code&gt;delete_customer_record&lt;/code&gt; was irreversible, or that &lt;code&gt;get_account_balance&lt;/code&gt; was safe to call ten times without side effects.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://spec.modelcontextprotocol.io/specification/2025-03-26/server/tools/#tool-annotations" rel="noopener noreferrer"&gt;Tool annotations&lt;/a&gt; fix this. Server authors declare whether a tool is &lt;code&gt;readOnly&lt;/code&gt;, &lt;code&gt;destructive&lt;/code&gt;, or &lt;code&gt;idempotent&lt;/code&gt;. An orchestrating agent can run read-only tools in parallel and gate destructive ones behind confirmation steps - without custom guardrail logic per tool. The annotations are hints, not enforced constraints, but they give agents the information they need to behave sensibly by default.&lt;/p&gt;

&lt;h2&gt;
  
  
  4 Use Cases Where MCP 2.0 Changes the Equation
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Enterprise Data Agents
&lt;/h3&gt;

&lt;p&gt;An agent querying Salesforce, pulling from a data warehouse, and cross-referencing a SharePoint knowledge base used to require three separate integrations - different auth patterns, different response schemas, different error handling for each.&lt;/p&gt;

&lt;p&gt;With MCP, the agent talks to three MCP servers using one protocol. Add a fourth data source? Stand up another MCP server - no changes to the agent. The integration surface stays flat as the tool count grows. For clients running AI agents across 5–15 internal systems, this is the difference between a maintainable architecture and a brittle custom integration that breaks every quarter.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Healthcare Agents with Auth-Gated Records
&lt;/h3&gt;

&lt;p&gt;Healthcare is where MCP 2.0's OAuth layer matters most. An AI agent pulling patient records, lab results, and prescription history from different systems can't hold a single admin key - HIPAA requires scoped access with audit trails.&lt;/p&gt;

&lt;p&gt;MCP 2.0's OAuth 2.0 framework delivers exactly that: per-system tokens with scoped permissions, revocable at any time, auditable through standard OAuth infrastructure. The agent gets access to what it needs. Nothing else. And every access is logged in a format compliance teams already know how to read.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Multi-Agent Orchestration
&lt;/h3&gt;

&lt;p&gt;As AI systems move from single agents to networks of specialized agents, the communication layer between them matters as much as the agents themselves.&lt;/p&gt;

&lt;p&gt;MCP is increasingly the protocol layer in multi-agent architectures: an orchestrating agent dispatches tasks to specialized sub-agents via MCP tool calls, collects results, and synthesizes them. The orchestrator doesn't need to know how the research agent retrieves information or how the code agent runs tests - it calls their MCP-exposed tools. This is the pattern behind the multi-agent frameworks that are actually working in production environments, not just in research papers.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Developer Tooling Agents
&lt;/h3&gt;

&lt;p&gt;A dev agent connecting GitHub, a CI/CD system, and application monitoring used to face a painful choice: poll for updates (slow, expensive) or build custom webhooks into each tool (complex, brittle).&lt;/p&gt;

&lt;p&gt;Streamable HTTP transport in MCP 2.0 eliminates both options. The agent subscribes to live events from each tool via its MCP server. A failed build triggers the CI/CD server to push an event; the agent receives it, queries the GitHub MCP server for the relevant diff, checks the monitoring MCP server for correlated errors, and surfaces a diagnosis - all from one real-time signal. No polling infrastructure. No custom webhook code.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where Aviasole Fits
&lt;/h2&gt;

&lt;p&gt;We build AI agents for production - not demos, not proof-of-concepts that stall at month two. MCP 2.0 is a core part of how we architect integrations for our &lt;a href="https://aviasole.com/services/agentic-ai/" rel="noopener noreferrer"&gt;agentic AI engagements&lt;/a&gt; because it solves the problems that actually kill agent projects in enterprise environments: auth that satisfies compliance teams, integrations that don't fragment when you add a new tool, and enough protocol-level safety information for agents to behave sensibly without custom guardrails per connector.&lt;/p&gt;

&lt;p&gt;For clients working on &lt;a href="https://aviasole.com/services/generative-ai/" rel="noopener noreferrer"&gt;LLM application development&lt;/a&gt;, MCP also changes how we think about context retrieval - moving away from bespoke retrieval connectors toward protocol-native tool servers that any agent in the stack can reuse without duplication.&lt;/p&gt;

&lt;p&gt;The practical signal for when MCP is worth the adoption cost: if your agent calls more than two or three external systems, you're already paying the price of custom integration complexity. MCP 2.0 is now mature enough - with OAuth, streaming, and a growing ecosystem of official servers - to be the right answer for most enterprise-grade agent architectures.&lt;/p&gt;

&lt;h2&gt;
  
  
  Ready to Build MCP-Native Agents?
&lt;/h2&gt;

&lt;p&gt;If you're evaluating MCP 2.0 for your agent architecture - or you've already started and hit friction with auth, transport, or integration sprawl - &lt;a href="https://aviasole.com/contact/" rel="noopener noreferrer"&gt;talk to our team&lt;/a&gt;. We'll work through the specifics of your stack and tell you honestly whether MCP solves your actual problem or whether a simpler approach fits better.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>mcp</category>
      <category>agenticai</category>
      <category>llmtool</category>
    </item>
  </channel>
</rss>
