<?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: GWEN</title>
    <description>The latest articles on DEV Community by GWEN (@gwenj).</description>
    <link>https://dev.to/gwenj</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%2F3988531%2F36f7e0d8-6aa0-4a21-ba14-62c292320d52.jpg</url>
      <title>DEV Community: GWEN</title>
      <link>https://dev.to/gwenj</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/gwenj"/>
    <language>en</language>
    <item>
      <title>Your AI Fallback Strategy May Be Making Things Worse</title>
      <dc:creator>GWEN</dc:creator>
      <pubDate>Mon, 03 Aug 2026 10:32:47 +0000</pubDate>
      <link>https://dev.to/gwenj/your-ai-fallback-strategy-may-be-making-things-worse-ifi</link>
      <guid>https://dev.to/gwenj/your-ai-fallback-strategy-may-be-making-things-worse-ifi</guid>
      <description>&lt;p&gt;Adding a fallback model sounds easy.&lt;/p&gt;

&lt;p&gt;If the primary model fails, send the request to another one:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;MODELS&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;gpt-5.4-mini&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;claude-sonnet-4.6&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="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;generate_response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;messages&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&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="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;chat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&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="n"&gt;model&lt;/span&gt;&lt;span class="o"&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;messages&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="n"&gt;timeout&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="nb"&gt;TimeoutError&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;RuntimeError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;All models failed&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This works as a basic starting point.&lt;/p&gt;

&lt;p&gt;But a fallback is not just another model name. Different models may produce different formats, response lengths, and behavior. If your application expects reliable output, you need to test the fallback path properly.&lt;/p&gt;

&lt;h2&gt;
  
  
  Use one consistent API layer
&lt;/h2&gt;

&lt;p&gt;Managing several provider SDKs can quickly become messy.&lt;/p&gt;

&lt;p&gt;You may need different clients, API keys, request formats, and error-handling rules. An OpenAI-compatible gateway keeps the integration simpler:&lt;br&gt;
&lt;/p&gt;

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

&lt;span class="n"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;OpenAI&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;base_url&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://api.tokenbay.com/v1&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;api_key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;YOUR_TOKENBAY_API_KEY&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is the TokenBay endpoint I use at work. If you want to try it, there is currently a discount available here:&lt;/p&gt;

&lt;p&gt;[Try TokenBay]&lt;a href="https://www.tokenbay.com/?utm_source=devto&amp;amp;utm_medium=community_content&amp;amp;utm_campaign=week1_free_content" rel="noopener noreferrer"&gt;https://www.tokenbay.com/?utm_source=devto&amp;amp;utm_medium=community_content&amp;amp;utm_campaign=week1_free_content&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can switch models without rewriting the rest of your application:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;chat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&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="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;gpt-5.4-mini&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;messages&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;chat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&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="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;claude-sonnet-4.6&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;messages&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Validate fallback responses
&lt;/h2&gt;

&lt;p&gt;Never assume the fallback response is automatically safe to use.&lt;/p&gt;

&lt;p&gt;If your application expects JSON, validate it:&lt;br&gt;
&lt;/p&gt;

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

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;parse_response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;content&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&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="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;content&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="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;loads&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;content&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;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;JSONDecodeError&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nc"&gt;ValueError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Invalid model output&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A fallback that returns the wrong structure is not a successful fallback. It simply moves the failure to another part of your system.&lt;/p&gt;

&lt;h2&gt;
  
  
  Track when fallbacks happen
&lt;/h2&gt;

&lt;p&gt;Log every fallback event:&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;primary_model&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;gpt-5.4-mini&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;fallback_model&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;claude-sonnet-4.6&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;reason&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;timeout&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;ul&gt;
&lt;li&gt;Fallback frequency&lt;/li&gt;
&lt;li&gt;Failure reason&lt;/li&gt;
&lt;li&gt;Response latency&lt;/li&gt;
&lt;li&gt;Cost per successful request&lt;/li&gt;
&lt;li&gt;Output validation failures&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If fallbacks happen too often, the problem may be your timeout settings, provider reliability, or model configuration.&lt;/p&gt;

&lt;h2&gt;
  
  
  Final thought
&lt;/h2&gt;

&lt;p&gt;A fallback model can improve reliability, but only when it behaves predictably.&lt;/p&gt;

&lt;p&gt;Use a consistent API layer, validate outputs, limit retries, and monitor every fallback event.&lt;/p&gt;

&lt;p&gt;The goal is not to hide failures.&lt;/p&gt;

&lt;p&gt;The goal is to recover from them without making your application harder to maintain.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>python</category>
      <category>llm</category>
      <category>api</category>
    </item>
    <item>
      <title>Your AI App Needs a Timeout Strategy, Not Just a Better Model</title>
      <dc:creator>GWEN</dc:creator>
      <pubDate>Thu, 30 Jul 2026 10:31:58 +0000</pubDate>
      <link>https://dev.to/gwenj/your-ai-app-needs-a-timeout-strategy-not-just-a-better-model-12mh</link>
      <guid>https://dev.to/gwenj/your-ai-app-needs-a-timeout-strategy-not-just-a-better-model-12mh</guid>
      <description>&lt;p&gt;Most AI apps handle successful requests well.&lt;/p&gt;

&lt;p&gt;They send a prompt, wait for the response, and display the result. The problem starts when the model becomes slow or temporarily unavailable.&lt;/p&gt;

&lt;p&gt;A request that normally takes two seconds may suddenly take fifteen. Without a timeout strategy, users are left waiting, and your application appears broken.&lt;/p&gt;

&lt;h2&gt;
  
  
  Set task-specific timeouts
&lt;/h2&gt;

&lt;p&gt;Different tasks need different limits:&lt;br&gt;
This is the TokenBay API endpoint I use at work. If you want to try it, there is currently a discount available:&lt;/p&gt;

&lt;p&gt;[Try TokenBay]&lt;a href="https://www.tokenbay.com/?utm_source=devto&amp;amp;utm_medium=community_content&amp;amp;utm_campaign=week1_free_content" rel="noopener noreferrer"&gt;https://www.tokenbay.com/?utm_source=devto&amp;amp;utm_medium=community_content&amp;amp;utm_campaign=week1_free_content&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;TIMEOUTS&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;chat&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;classification&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;document_summary&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;30&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;Use the timeout when sending the request:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;chat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&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="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;gpt-5.4-mini&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;messages&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;timeout&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;TIMEOUTS&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;chat&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A real-time chat request should fail quickly. A document summary may reasonably need more time.&lt;/p&gt;

&lt;h2&gt;
  
  
  Retry temporary failures
&lt;/h2&gt;

&lt;p&gt;Do not retry every error. Invalid API keys and bad requests will not fix themselves.&lt;/p&gt;

&lt;p&gt;Retry only temporary failures such as timeouts, rate limits, and server errors:&lt;br&gt;
&lt;/p&gt;

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

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;generate_response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;model&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;attempt&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&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="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;chat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&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="n"&gt;model&lt;/span&gt;&lt;span class="o"&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;messages&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="n"&gt;timeout&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="nb"&gt;TimeoutError&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;attempt&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="k"&gt;raise&lt;/span&gt;
            &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Retries should be limited. Otherwise, a slow provider can create more traffic, higher costs, and an even worse outage.&lt;/p&gt;

&lt;h2&gt;
  
  
  Add a fallback model
&lt;/h2&gt;

&lt;p&gt;For important user-facing features, use a fallback:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;MODELS&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;gpt-5.4-mini&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;claude-sonnet-4.6&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="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;generate_with_fallback&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="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&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="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;chat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&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="n"&gt;model&lt;/span&gt;&lt;span class="o"&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;messages&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="n"&gt;timeout&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="nb"&gt;TimeoutError&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;RuntimeError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;All models failed&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;An OpenAI-compatible gateway makes this easier because your application can keep the same client structure while testing different models.&lt;/p&gt;

&lt;p&gt;For 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="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;openai&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;OpenAI&lt;/span&gt;

&lt;span class="n"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;OpenAI&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;base_url&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://api.tokenbay.com/v1&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;api_key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;YOUR_TOKENBAY_API_KEY&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can change the model without adding another SDK or rewriting your request logic.&lt;/p&gt;

&lt;h2&gt;
  
  
  Monitor the right metrics
&lt;/h2&gt;

&lt;p&gt;Track more than average latency:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Timeout rate&lt;/li&gt;
&lt;li&gt;Retry rate&lt;/li&gt;
&lt;li&gt;Fallback rate&lt;/li&gt;
&lt;li&gt;P95 latency&lt;/li&gt;
&lt;li&gt;Cost per successful request&lt;/li&gt;
&lt;li&gt;Failure rate by model&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A model that is fast most of the time but occasionally takes twenty seconds may still create a poor user experience.&lt;/p&gt;

&lt;h2&gt;
  
  
  Final thought
&lt;/h2&gt;

&lt;p&gt;A better model cannot fix an application that waits forever or retries blindly.&lt;/p&gt;

&lt;p&gt;Production AI apps need clear timeouts, limited retries, tested fallbacks, and latency monitoring.&lt;/p&gt;

&lt;p&gt;The goal is simple:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Fail quickly when necessary, recover when possible, and keep the user experience predictable.&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>api</category>
      <category>llm</category>
      <category>python</category>
    </item>
    <item>
      <title>Why Your AI Model Selection Strategy Is Probably Wrong</title>
      <dc:creator>GWEN</dc:creator>
      <pubDate>Tue, 28 Jul 2026 10:22:52 +0000</pubDate>
      <link>https://dev.to/gwenj/why-your-ai-model-selection-strategy-is-probably-wrong-1cef</link>
      <guid>https://dev.to/gwenj/why-your-ai-model-selection-strategy-is-probably-wrong-1cef</guid>
      <description>&lt;p&gt;Most teams choose an AI model once and call it done.&lt;/p&gt;

&lt;p&gt;They pick GPT-4, Claude, or Gemini based on a benchmark score or a recommendation, then deploy it to production. The model works. The feature launches. Nobody thinks about it again until the bill arrives or the model fails.&lt;/p&gt;

&lt;p&gt;This approach has a problem: a model that is optimal for your use case on day one may not be optimal three months later.&lt;/p&gt;

&lt;p&gt;And more importantly, treating model selection as a one-time decision usually means you are not optimizing for what actually matters.&lt;/p&gt;

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

&lt;p&gt;Most teams start by comparing models using public benchmarks.&lt;/p&gt;

&lt;p&gt;GPT-5.4 scores highest on reasoning. Claude-Sonnet excels at long-form writing. Gemini handles context better. DeepSeek is cheaper.&lt;/p&gt;

&lt;p&gt;So you pick the winner and move on.&lt;/p&gt;

&lt;p&gt;But benchmarks measure performance on standardized tests, not on your actual workload.&lt;/p&gt;

&lt;p&gt;Your specific use case—customer support classification, technical documentation summarization, code review, data extraction—may have different performance characteristics than what benchmarks show.&lt;/p&gt;

&lt;p&gt;A model that ranks lower on general reasoning may perform better on your classification task. A model that is slower on average latency may be faster for your exact input size. A model that costs more per token may be cheaper overall because it requires fewer retries.&lt;/p&gt;

&lt;p&gt;Benchmarks are useful as a starting point. They are not a substitute for testing.&lt;/p&gt;

&lt;h2&gt;
  
  
  Production costs reveal what benchmarks hide
&lt;/h2&gt;

&lt;p&gt;In the real world, model choice affects more than just accuracy.&lt;/p&gt;

&lt;p&gt;It also affects:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Token usage per request&lt;/li&gt;
&lt;li&gt;Failure and retry rates&lt;/li&gt;
&lt;li&gt;Latency and timeout behavior&lt;/li&gt;
&lt;li&gt;Edge case handling&lt;/li&gt;
&lt;li&gt;Consistency across different input types&lt;/li&gt;
&lt;li&gt;Cost per successful result&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A model may have a lower per-token cost but generate longer responses. Another model may be more expensive per token but use fewer tokens overall.&lt;/p&gt;

&lt;p&gt;A model may handle edge cases gracefully while another fails and forces a retry.&lt;/p&gt;

&lt;p&gt;These differences are invisible in benchmarks. They become very visible in your billing.&lt;/p&gt;

&lt;h2&gt;
  
  
  Build a comparison framework
&lt;/h2&gt;

&lt;p&gt;Instead of choosing a model once, build a framework for ongoing comparison:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;MODELS_TO_TEST&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;gpt-5.4-mini&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;claude-sonnet-4.6&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;gemini-2.5-pro&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;deepseek-chat&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="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;generate_response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;task&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;compare&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;False&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;compare&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;results&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;model&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;MODELS_TO_TEST&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="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;chat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&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="n"&gt;model&lt;/span&gt;&lt;span class="o"&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;messages&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                    &lt;span class="n"&gt;timeout&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;30&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="n"&gt;results&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;]&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;content&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&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="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;content&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;tokens&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;usage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;total_tokens&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;latency&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;response_time&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="nb"&gt;Exception&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="n"&gt;results&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;]&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;error&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;error&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;results&lt;/span&gt;

    &lt;span class="n"&gt;model&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;MODELS&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;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;chat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&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="n"&gt;model&lt;/span&gt;&lt;span class="o"&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;messages&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&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="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;content&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run this comparison periodically on your real production data:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;sample_requests&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;get_recent_requests&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;limit&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;100&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;request&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;sample_requests&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;comparison&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;generate_response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;chat&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;compare&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;log_comparison&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;comparison&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Over time, you will collect real data on which models perform better for your specific workload.&lt;/p&gt;

&lt;h2&gt;
  
  
  Track what actually matters
&lt;/h2&gt;

&lt;p&gt;Do not just compare final output quality.&lt;/p&gt;

&lt;p&gt;Track the full cost and reliability picture:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Success rate&lt;/li&gt;
&lt;li&gt;Average latency&lt;/li&gt;
&lt;li&gt;95th percentile latency&lt;/li&gt;
&lt;li&gt;Token usage distribution&lt;/li&gt;
&lt;li&gt;Cost per successful result&lt;/li&gt;
&lt;li&gt;Retry frequency&lt;/li&gt;
&lt;li&gt;Edge case failures&lt;/li&gt;
&lt;li&gt;User satisfaction&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A model that is faster on average but slower at the 95th percentile may cause user frustration during peak traffic. A model that is slightly less accurate but has zero retries may be more cost-efficient than one that requires multiple attempts.&lt;/p&gt;

&lt;h2&gt;
  
  
  Use an OpenAI-compatible gateway for easier testing
&lt;/h2&gt;

&lt;p&gt;Managing multiple provider SDKs makes testing difficult.&lt;/p&gt;

&lt;p&gt;An OpenAI-compatible gateway lets you test different models without changing your application code.&lt;/p&gt;

&lt;p&gt;I work on the TokenBay team. Here is the link：&lt;a href="https://www.tokenbay.com/?utm_source=devto&amp;amp;utm_medium=community_content&amp;amp;utm_campaign=week1_free_content" rel="noopener noreferrer"&gt;https://www.tokenbay.com/?utm_source=devto&amp;amp;utm_medium=community_content&amp;amp;utm_campaign=week1_free_content&lt;/a&gt;&lt;br&gt;
Here is how it simplifies model testing:&lt;br&gt;
&lt;/p&gt;

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

&lt;span class="n"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;OpenAI&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;base_url&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://api.tokenbay.com/v1&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;api_key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;YOUR_TOKENBAY_API_KEY&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can test any supported model by just changing the model name:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;chat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&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="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;gpt-5.4-mini&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;messages&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;chat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&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="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;claude-sonnet-4.6&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;messages&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No SDK changes. No new API keys. No request format adjustments.&lt;/p&gt;

&lt;p&gt;This makes it practical to run regular model comparisons without engineering overhead.&lt;/p&gt;

&lt;h2&gt;
  
  
  Different tasks need different optimization criteria
&lt;/h2&gt;

&lt;p&gt;Not every model should win at the same thing.&lt;/p&gt;

&lt;p&gt;For some tasks, you optimize for cost:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;MODELS&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;classification&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;deepseek-chat&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;background_job&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;gpt-5.4-mini&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For others, you optimize for quality:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;MODELS&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;reasoning&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;claude-sonnet-4.6&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;code_review&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;gpt-5.4&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For real-time user-facing features, you optimize for latency:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;MODELS&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;chat&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;gpt-5.4-mini&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The correct model is not the best model.&lt;/p&gt;

&lt;p&gt;It is the model that meets your specific requirements at an acceptable cost.&lt;/p&gt;

&lt;h2&gt;
  
  
  Revisit your choice quarterly
&lt;/h2&gt;

&lt;p&gt;Model performance changes over time.&lt;/p&gt;

&lt;p&gt;New models are released. Provider prices fluctuate. Your workload evolves. What was optimal three months ago may no longer be optimal today.&lt;/p&gt;

&lt;p&gt;Set a quarterly review:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Run your comparison framework on recent production data&lt;/li&gt;
&lt;li&gt;Compare performance across all tested models&lt;/li&gt;
&lt;li&gt;Check if pricing has changed&lt;/li&gt;
&lt;li&gt;Evaluate new models that have been released&lt;/li&gt;
&lt;li&gt;Update your model assignments&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This does not require a major engineering effort.&lt;/p&gt;

&lt;p&gt;It is a simple script that runs periodically and reports results.&lt;/p&gt;

&lt;p&gt;But it prevents the expensive default: continuing to use a suboptimal model just because nobody bothered to re-evaluate.&lt;/p&gt;

&lt;h2&gt;
  
  
  Final thought
&lt;/h2&gt;

&lt;p&gt;Model selection is not a one-time decision.&lt;/p&gt;

&lt;p&gt;It is an ongoing optimization problem.&lt;/p&gt;

&lt;p&gt;The best model for your use case is the one you actually test against your real data, not the one that wins a benchmark.&lt;/p&gt;

&lt;p&gt;And the best time to test is now, before you spend another three months paying for a model that is slower, more expensive, or less accurate than the alternative sitting right next to it.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>api</category>
      <category>python</category>
      <category>llm</category>
    </item>
    <item>
      <title>How to Reduce AI API Costs Without Making Your App Worse</title>
      <dc:creator>GWEN</dc:creator>
      <pubDate>Mon, 27 Jul 2026 10:14:38 +0000</pubDate>
      <link>https://dev.to/gwenj/how-to-reduce-ai-api-costs-without-making-your-app-worse-53om</link>
      <guid>https://dev.to/gwenj/how-to-reduce-ai-api-costs-without-making-your-app-worse-53om</guid>
      <description>&lt;p&gt;AI apps often become expensive for a simple reason: every request uses the same powerful model.&lt;/p&gt;

&lt;p&gt;That approach is easy to build, but it is rarely efficient.&lt;/p&gt;

&lt;p&gt;A customer asking for a one-line classification does not need the same model used for complex reasoning. A background summary does not always require the fastest available model. Treating every request equally is one of the easiest ways to waste money.&lt;/p&gt;

&lt;h2&gt;
  
  
  The expensive default
&lt;/h2&gt;

&lt;p&gt;A basic implementation may look like this:&lt;br&gt;
&lt;/p&gt;

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

&lt;span class="n"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;OpenAI&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;api_key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;YOUR_API_KEY&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;generate_response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;chat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&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="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;gpt-5.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;messages&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&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="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;content&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This works, but every task goes through the same model:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Simple classification&lt;/li&gt;
&lt;li&gt;FAQ responses&lt;/li&gt;
&lt;li&gt;Long-form writing&lt;/li&gt;
&lt;li&gt;Data extraction&lt;/li&gt;
&lt;li&gt;Complex reasoning&lt;/li&gt;
&lt;li&gt;Background processing&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The result is predictable: higher costs, slower responses, and no clear reason for using an expensive model.&lt;/p&gt;

&lt;h2&gt;
  
  
  Match the model to the task
&lt;/h2&gt;

&lt;p&gt;A better approach is to define models by workload:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;MODELS&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;simple&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;gpt-5.4-mini&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;reasoning&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;claude-sonnet-4.6&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;background&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;deepseek-chat&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then route requests based on the task:&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;generate_response&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;messages&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;model&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;MODELS&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;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;chat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&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="n"&gt;model&lt;/span&gt;&lt;span class="o"&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;messages&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&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="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;content&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A simple request can use a faster, lower-cost 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="n"&gt;answer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;generate_response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="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="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;role&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;user&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;content&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Classify this ticket as billing, technical, or account-related.&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A complex request can use a stronger 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="n"&gt;answer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;generate_response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;reasoning&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;role&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;user&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;content&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Analyze the architectural risks in this system.&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The application logic stays the same. Only the model changes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Use an OpenAI-compatible endpoint
&lt;/h2&gt;

&lt;p&gt;If every provider requires a separate SDK, reducing costs can create more engineering work.&lt;/p&gt;

&lt;p&gt;You may need to manage:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Multiple API keys&lt;/li&gt;
&lt;li&gt;Different request formats&lt;/li&gt;
&lt;li&gt;Different response structures&lt;/li&gt;
&lt;li&gt;Separate usage dashboards&lt;/li&gt;
&lt;li&gt;Provider-specific error handling&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;An OpenAI-compatible gateway simplifies the integration.&lt;/p&gt;

&lt;p&gt;I work on the TokenBay team, so the example below uses TokenBay:&lt;br&gt;
&lt;/p&gt;

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

&lt;span class="n"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;OpenAI&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;base_url&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://api.tokenbay.com/v1&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;api_key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;YOUR_TOKENBAY_API_KEY&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Your code can keep the same request structure while testing different models:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;chat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&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="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;gpt-5.4-mini&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;messages&lt;/span&gt;&lt;span class="o"&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;role&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;user&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;content&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Extract the customer name and order number.&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For another workload:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;chat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&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="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;claude-sonnet-4.6&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;messages&lt;/span&gt;&lt;span class="o"&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;role&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;user&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;content&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Review this technical proposal and identify its major risks.&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You do not need to rewrite the integration every time you test a model.&lt;/p&gt;

&lt;h2&gt;
  
  
  Control the input, not just the model
&lt;/h2&gt;

&lt;p&gt;Model choice is only one part of cost control.&lt;/p&gt;

&lt;p&gt;Large prompts can be expensive even when the output is short. Before sending a request, consider:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Removing irrelevant conversation history&lt;/li&gt;
&lt;li&gt;Limiting retrieved documents&lt;/li&gt;
&lt;li&gt;Summarizing old messages&lt;/li&gt;
&lt;li&gt;Avoiding repeated system instructions&lt;/li&gt;
&lt;li&gt;Setting a reasonable output limit&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For 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="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;chat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&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="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;gpt-5.4-mini&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;messages&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;max_tokens&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;300&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;More context is not automatically better. Unnecessary context can increase cost, latency, and confusion.&lt;/p&gt;

&lt;h2&gt;
  
  
  Cache predictable requests
&lt;/h2&gt;

&lt;p&gt;Some AI requests are repeated frequently.&lt;/p&gt;

&lt;p&gt;Examples include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Product descriptions&lt;/li&gt;
&lt;li&gt;FAQ answers&lt;/li&gt;
&lt;li&gt;Document classifications&lt;/li&gt;
&lt;li&gt;Common translations&lt;/li&gt;
&lt;li&gt;Standard onboarding messages&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If the input and expected output are stable, caching can reduce repeated API calls:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;cache&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;generate_cached&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;prompt&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;prompt&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;cache&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;cache&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;prompt&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

    &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;chat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&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="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;gpt-5.4-mini&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;messages&lt;/span&gt;&lt;span class="o"&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;role&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;user&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;content&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;prompt&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&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="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;content&lt;/span&gt;
    &lt;span class="n"&gt;cache&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;prompt&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In production, use a proper shared cache instead of an in-memory dictionary. The principle remains the same: do not pay for the same answer repeatedly.&lt;/p&gt;

&lt;h2&gt;
  
  
  Measure before making decisions
&lt;/h2&gt;

&lt;p&gt;Do not assume the cheapest model is automatically the best option.&lt;/p&gt;

&lt;p&gt;Track each model’s:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Cost per request&lt;/li&gt;
&lt;li&gt;Average latency&lt;/li&gt;
&lt;li&gt;Error rate&lt;/li&gt;
&lt;li&gt;Output quality&lt;/li&gt;
&lt;li&gt;Token usage&lt;/li&gt;
&lt;li&gt;Retry frequency&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A cheaper model that requires many retries may cost more than a slightly more expensive model that succeeds consistently.&lt;/p&gt;

&lt;p&gt;TokenBay can help centralize model access and provide usage visibility across different model providers. This makes it easier to compare cost and performance instead of relying on guesses.&lt;/p&gt;

&lt;p&gt;Try Tokenbay：&lt;a href="https://www.tokenbay.com/?utm_source=devto&amp;amp;utm_medium=community_content&amp;amp;utm_campaign=week1_free_content" rel="noopener noreferrer"&gt;https://www.tokenbay.com/?utm_source=devto&amp;amp;utm_medium=community_content&amp;amp;utm_campaign=week1_free_content&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Cost control is not quality reduction
&lt;/h2&gt;

&lt;p&gt;The goal is not to use the cheapest model everywhere.&lt;/p&gt;

&lt;p&gt;The goal is to spend more only where better performance creates real value.&lt;/p&gt;

&lt;p&gt;A practical setup might look like this:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Fast model for classification&lt;/li&gt;
&lt;li&gt;Low-cost model for background jobs&lt;/li&gt;
&lt;li&gt;Strong model for complex reasoning&lt;/li&gt;
&lt;li&gt;Fallback model during outages&lt;/li&gt;
&lt;li&gt;Human review for high-impact decisions&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That is more efficient than sending every request to the most powerful model available.&lt;/p&gt;

&lt;h2&gt;
  
  
  Final thought
&lt;/h2&gt;

&lt;p&gt;AI cost problems usually do not come from one unusually expensive request.&lt;/p&gt;

&lt;p&gt;They come from thousands of ordinary requests being routed inefficiently.&lt;/p&gt;

&lt;p&gt;Use the right model for the right task, reduce unnecessary context, cache repeated work, and monitor real usage.&lt;/p&gt;

&lt;p&gt;The best AI cost strategy is not buying cheaper tokens.&lt;/p&gt;

&lt;p&gt;It is avoiding tokens you never needed to spend.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>api</category>
      <category>llm</category>
      <category>python</category>
    </item>
    <item>
      <title>Your AI Agent Is Not Autonomous. It’s Just a Fragile Workflow</title>
      <dc:creator>GWEN</dc:creator>
      <pubDate>Fri, 24 Jul 2026 10:27:33 +0000</pubDate>
      <link>https://dev.to/gwenj/your-ai-agent-is-not-autonomous-its-just-a-fragile-workflow-5bjf</link>
      <guid>https://dev.to/gwenj/your-ai-agent-is-not-autonomous-its-just-a-fragile-workflow-5bjf</guid>
      <description>&lt;p&gt;The AI industry loves calling everything an “agent.”&lt;/p&gt;

&lt;p&gt;Give a language model access to a few tools, connect it to a database, add a loop, and suddenly the system is marketed as autonomous. It can browse the web, send emails, write code, call APIs, and make decisions.&lt;/p&gt;

&lt;p&gt;But most of these systems are not truly autonomous.&lt;/p&gt;

&lt;p&gt;They are fragile workflows with an LLM placed in the middle.&lt;/p&gt;

&lt;p&gt;That distinction matters. A workflow follows predefined steps. An agent operates in an uncertain environment and must decide what to do next. The problem is that many so-called agents still depend on rigid assumptions, unreliable tool calls, incomplete state management, and weak recovery mechanisms.&lt;/p&gt;

&lt;p&gt;They look intelligent during a demo. In production, they often become expensive, unpredictable, and difficult to debug.&lt;/p&gt;

&lt;h2&gt;
  
  
  An LLM Choosing the Next Step Is Not Autonomy
&lt;/h2&gt;

&lt;p&gt;A system is not autonomous just because an LLM decides what to do next.&lt;/p&gt;

&lt;p&gt;Real autonomy requires reliable execution, clear boundaries, observability, and recovery when things go wrong.&lt;/p&gt;

&lt;p&gt;Consider a typical customer-support agent:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Read the user’s request.&lt;/li&gt;
&lt;li&gt;Search the knowledge base.&lt;/li&gt;
&lt;li&gt;Check the customer account.&lt;/li&gt;
&lt;li&gt;Decide whether a refund is allowed.&lt;/li&gt;
&lt;li&gt;Submit the refund request.&lt;/li&gt;
&lt;li&gt;Send a confirmation message.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;On paper, this looks like an autonomous system. In reality, it may fail in several places:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The model may misunderstand the user’s intent.&lt;/li&gt;
&lt;li&gt;The search tool may return irrelevant information.&lt;/li&gt;
&lt;li&gt;The account API may time out.&lt;/li&gt;
&lt;li&gt;The model may call the wrong function.&lt;/li&gt;
&lt;li&gt;The refund request may succeed, but the response may be lost.&lt;/li&gt;
&lt;li&gt;The agent may retry the same action and issue two refunds.&lt;/li&gt;
&lt;li&gt;The final message may claim success even though the operation failed.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The model can choose the next action, but it does not automatically guarantee that the action is correct, safe, or completed.&lt;/p&gt;

&lt;p&gt;That is not autonomy. That is decision-making without sufficient control.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Agent Workflows Break in Production
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Tool Calls Are Not Naturally Reliable
&lt;/h3&gt;

&lt;p&gt;Language models generate text. They do not inherently understand whether an API call is valid, whether a parameter is safe, or whether a side effect has already happened.&lt;/p&gt;

&lt;p&gt;A model may produce a technically valid function call with the wrong business meaning:&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;"user_id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"48291"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"refund_amount"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;499&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 may be perfectly formatted. The amount may still be wrong.&lt;/p&gt;

&lt;p&gt;Schema validation can confirm that the parameter exists, but it cannot always confirm that the action makes sense. Production agents need more than structured output. They need permission checks, business rules, idempotency controls, and post-action verification.&lt;/p&gt;

&lt;p&gt;Without these safeguards, every tool becomes another failure point.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. The Agent Can Lose Its State
&lt;/h3&gt;

&lt;p&gt;Long-running agents often interact with multiple systems. They read documents, call APIs, receive asynchronous responses, and wait for external events.&lt;/p&gt;

&lt;p&gt;If the system does not maintain durable state, the agent may forget:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What it has already done&lt;/li&gt;
&lt;li&gt;Which tools have already been called&lt;/li&gt;
&lt;li&gt;Which action is currently pending&lt;/li&gt;
&lt;li&gt;Whether a previous request succeeded&lt;/li&gt;
&lt;li&gt;Why it made a particular decision&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Once state becomes unclear, the agent may repeat actions, skip steps, or make decisions based on outdated information.&lt;/p&gt;

&lt;p&gt;A conversation history is not the same thing as reliable system state. Chat logs are useful for context, but production systems need explicit state machines, event records, execution IDs, and transaction status.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Loops Are Easy to Create
&lt;/h3&gt;

&lt;p&gt;Agents frequently operate inside loops:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Think&lt;/li&gt;
&lt;li&gt;Call a tool&lt;/li&gt;
&lt;li&gt;Read the result&lt;/li&gt;
&lt;li&gt;Decide what to do next&lt;/li&gt;
&lt;li&gt;Repeat&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This structure is powerful, but dangerous.&lt;/p&gt;

&lt;p&gt;A failed tool call may cause the model to retry indefinitely. A vague goal may lead to unnecessary research. Conflicting information may trigger repeated searches. A poorly designed stop condition can turn a simple task into a costly loop.&lt;/p&gt;

&lt;p&gt;The issue is not just token usage. Every extra iteration increases latency, cost, and the chance of an unwanted action.&lt;/p&gt;

&lt;p&gt;A production agent needs strict limits:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Maximum execution steps&lt;/li&gt;
&lt;li&gt;Timeouts&lt;/li&gt;
&lt;li&gt;Budget limits&lt;/li&gt;
&lt;li&gt;Retry policies&lt;/li&gt;
&lt;li&gt;Circuit breakers&lt;/li&gt;
&lt;li&gt;Human approval for sensitive actions&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If the system cannot stop safely, it is not autonomous. It is uncontrolled.&lt;/p&gt;

&lt;h2&gt;
  
  
  Not Every Problem Needs an Agent
&lt;/h2&gt;

&lt;p&gt;There is a growing tendency to add agents to problems that do not require them.&lt;/p&gt;

&lt;p&gt;If a process is predictable, use a workflow.&lt;/p&gt;

&lt;p&gt;For example, invoice processing may follow a stable sequence:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Receive the invoice.&lt;/li&gt;
&lt;li&gt;Extract the fields.&lt;/li&gt;
&lt;li&gt;Validate the supplier.&lt;/li&gt;
&lt;li&gt;Compare the amount with purchase records.&lt;/li&gt;
&lt;li&gt;Send it for approval.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;An LLM may help extract messy text or classify unusual cases. But the overall process does not need an agent making open-ended decisions.&lt;/p&gt;

&lt;p&gt;Using an agent here can introduce unnecessary uncertainty. A deterministic workflow is easier to test, monitor, and audit.&lt;/p&gt;

&lt;p&gt;Agents are more appropriate when:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The task has no fixed solution path.&lt;/li&gt;
&lt;li&gt;The system must interpret ambiguous information.&lt;/li&gt;
&lt;li&gt;Different tools may be needed depending on the situation.&lt;/li&gt;
&lt;li&gt;The environment changes during execution.&lt;/li&gt;
&lt;li&gt;The system must adapt to unexpected results.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The right question is not, “Can we use an agent?”&lt;/p&gt;

&lt;p&gt;The better question is, “Where does uncertainty actually exist?”&lt;/p&gt;

&lt;p&gt;Use agents for uncertainty. Use workflows for control.&lt;/p&gt;

&lt;h2&gt;
  
  
  What a Production-Grade Agent Actually Needs
&lt;/h2&gt;

&lt;p&gt;A reliable agent is not simply a model connected to tools. It is a controlled execution system with an LLM inside it.&lt;/p&gt;

&lt;h3&gt;
  
  
  Clear Boundaries
&lt;/h3&gt;

&lt;p&gt;The agent should know what it can and cannot do.&lt;/p&gt;

&lt;p&gt;Access should be limited by role, user, environment, and action type. Reading data is not the same as modifying data. Drafting an email is not the same as sending one.&lt;/p&gt;

&lt;p&gt;Sensitive operations should require additional verification or human approval.&lt;/p&gt;

&lt;h3&gt;
  
  
  Structured State
&lt;/h3&gt;

&lt;p&gt;The system should store execution state separately from the model’s conversation history.&lt;/p&gt;

&lt;p&gt;This includes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Current task status&lt;/li&gt;
&lt;li&gt;Completed actions&lt;/li&gt;
&lt;li&gt;Pending actions&lt;/li&gt;
&lt;li&gt;Tool responses&lt;/li&gt;
&lt;li&gt;Errors&lt;/li&gt;
&lt;li&gt;Retry counts&lt;/li&gt;
&lt;li&gt;Approval records&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When state is explicit, failures become recoverable instead of mysterious.&lt;/p&gt;

&lt;h3&gt;
  
  
  Validation Before and After Actions
&lt;/h3&gt;

&lt;p&gt;Before calling a tool, validate the request against business rules.&lt;/p&gt;

&lt;p&gt;After the tool responds, verify what actually happened.&lt;/p&gt;

&lt;p&gt;Do not let the agent assume that a successful HTTP response means the business operation succeeded. A payment API can return a response while the transaction remains pending. A database write can succeed while a downstream notification fails.&lt;/p&gt;

&lt;p&gt;The agent must distinguish between “the request was sent,” “the operation succeeded,” and “the user was informed.”&lt;/p&gt;

&lt;h3&gt;
  
  
  Observability
&lt;/h3&gt;

&lt;p&gt;If an agent fails, developers need to know why.&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;Model inputs and outputs&lt;/li&gt;
&lt;li&gt;Tool calls&lt;/li&gt;
&lt;li&gt;Execution timing&lt;/li&gt;
&lt;li&gt;Errors&lt;/li&gt;
&lt;li&gt;Retry behavior&lt;/li&gt;
&lt;li&gt;Token usage&lt;/li&gt;
&lt;li&gt;Routing decisions&lt;/li&gt;
&lt;li&gt;Final outcomes&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Without this data, teams are forced to inspect random conversation logs and guess what went wrong. That does not scale.&lt;/p&gt;

&lt;h3&gt;
  
  
  Recovery Instead of Blind Retries
&lt;/h3&gt;

&lt;p&gt;Retrying every failure is not resilience.&lt;/p&gt;

&lt;p&gt;A temporary network timeout may justify a retry. An invalid parameter should not. A completed payment should never be repeated simply because the confirmation response was delayed.&lt;/p&gt;

&lt;p&gt;The system needs failure classification, idempotency keys, fallback paths, and clear escalation rules.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Infrastructure Behind Reliable Agents
&lt;/h2&gt;

&lt;p&gt;Model quality matters, but it is only one part of the system.&lt;/p&gt;

&lt;p&gt;An agent may need different models for different tasks: a fast model for classification, a stronger model for complex reasoning, and a cheaper model for routine responses. It may also need fallback providers when a model is unavailable or produces unusable output.&lt;/p&gt;

&lt;p&gt;This is where infrastructure becomes important.&lt;/p&gt;

&lt;p&gt;A platform such as Tokenbay can help centralize model access, manage routing, monitor requests, and provide fallback options across providers. More importantly, it can become part of the reliability layer around agent execution.&lt;/p&gt;

&lt;p&gt;Try Tokenbay：&lt;a href="https://www.tokenbay.com/?utm_source=devto&amp;amp;utm_medium=community_content&amp;amp;utm_campaign=week1_free_content" rel="noopener noreferrer"&gt;https://www.tokenbay.com/?utm_source=devto&amp;amp;utm_medium=community_content&amp;amp;utm_campaign=week1_free_content&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The goal is not to hide every failure. The goal is to make failures visible, controllable, and recoverable.&lt;/p&gt;

&lt;p&gt;A production team should be able to answer simple questions quickly:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Which model made this decision?&lt;/li&gt;
&lt;li&gt;What did it cost?&lt;/li&gt;
&lt;li&gt;Which tool call failed?&lt;/li&gt;
&lt;li&gt;Was the response validated?&lt;/li&gt;
&lt;li&gt;Did the system retry?&lt;/li&gt;
&lt;li&gt;Did the fallback model perform better?&lt;/li&gt;
&lt;li&gt;Where did the execution stop?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If these questions cannot be answered, the agent is not ready for serious production use.&lt;/p&gt;

&lt;h2&gt;
  
  
  Stop Calling Fragile Workflows Autonomous
&lt;/h2&gt;

&lt;p&gt;The future of AI agents will not be defined by how many tools a model can call.&lt;/p&gt;

&lt;p&gt;It will be defined by how reliably the entire system behaves when the model is wrong, the API is slow, the data is incomplete, or the environment changes.&lt;/p&gt;

&lt;p&gt;A real agent needs intelligence, but intelligence alone is not enough. It needs boundaries, state, validation, observability, and recovery.&lt;/p&gt;

&lt;p&gt;Otherwise, the “agent” is just a workflow that occasionally improvises—and confidently breaks.&lt;/p&gt;

&lt;p&gt;The winning systems will not be the ones that promise unlimited autonomy.&lt;/p&gt;

&lt;p&gt;They will be the ones that know exactly when to act, when to stop, and when to ask for help.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>api</category>
      <category>llm</category>
      <category>python</category>
    </item>
    <item>
      <title>When Not to Use an LLM</title>
      <dc:creator>GWEN</dc:creator>
      <pubDate>Thu, 23 Jul 2026 09:33:39 +0000</pubDate>
      <link>https://dev.to/gwenj/when-not-to-use-an-llm-23nc</link>
      <guid>https://dev.to/gwenj/when-not-to-use-an-llm-23nc</guid>
      <description>&lt;p&gt;The fastest way to make an AI product worse is to use an LLM where ordinary software would have been better.&lt;/p&gt;

&lt;p&gt;Many products now turn every function into a chatbot. A calculator becomes a conversational assistant. A search box becomes a prompt. A fixed workflow is repackaged as an AI agent.&lt;/p&gt;

&lt;p&gt;The result is predictable: higher costs, slower responses, less consistency, and users who are no longer sure whether the product really understands them.&lt;/p&gt;

&lt;p&gt;LLMs are powerful, but that does not mean they are suitable for every feature.&lt;/p&gt;

&lt;p&gt;The better question is not:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Can an LLM do this?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;It is:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Does this problem actually require language reasoning?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Here are seven AI features that often should have been built with simple software.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Data Extraction from Predictable Documents
&lt;/h2&gt;

&lt;p&gt;Suppose a system needs to extract an invoice number, date, vendor name, and total amount from documents that all follow the same format.&lt;/p&gt;

&lt;p&gt;An LLM can do this, but it may not be the best choice.&lt;/p&gt;

&lt;p&gt;For stable document layouts, OCR, templates, and traditional parsers are often more reliable. They are faster, easier to test, and more predictable.&lt;/p&gt;

&lt;p&gt;An LLM may:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Misread numbers&lt;/li&gt;
&lt;li&gt;Omit fields&lt;/li&gt;
&lt;li&gt;Change formatting&lt;/li&gt;
&lt;li&gt;Return invalid structured output&lt;/li&gt;
&lt;li&gt;Produce different results for the same document&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;LLMs become more useful when documents are highly varied or when the system must interpret ambiguous language.&lt;/p&gt;

&lt;p&gt;The key distinction is simple:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Reading a fixed layout is not the same as understanding meaning.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  2. Classification with Clear Rules
&lt;/h2&gt;

&lt;p&gt;Many so-called AI classification tasks are actually simple conditional logic.&lt;/p&gt;

&lt;p&gt;Examples include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Is an order overdue?&lt;/li&gt;
&lt;li&gt;Is an account inactive?&lt;/li&gt;
&lt;li&gt;Is a file too large?&lt;/li&gt;
&lt;li&gt;Does a user have permission?&lt;/li&gt;
&lt;li&gt;Is a transaction above a limit?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These decisions do not need a language model.&lt;/p&gt;

&lt;p&gt;A rule such as:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;if payment_date &amp;lt; due_date:
    status = "overdue"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;will be faster and more reliable than asking an LLM to interpret the same situation.&lt;/p&gt;

&lt;p&gt;Rules may seem less impressive than AI, but they offer something production systems need: consistency.&lt;/p&gt;

&lt;p&gt;Use an LLM when the input is ambiguous. Do not use one to determine whether one number is greater than another.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Calculations and Financial Operations
&lt;/h2&gt;

&lt;p&gt;LLMs can explain calculations, but they should rarely perform critical calculations themselves.&lt;/p&gt;

&lt;p&gt;This includes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Tax calculations&lt;/li&gt;
&lt;li&gt;Payroll&lt;/li&gt;
&lt;li&gt;Pricing&lt;/li&gt;
&lt;li&gt;Interest&lt;/li&gt;
&lt;li&gt;Invoice totals&lt;/li&gt;
&lt;li&gt;Inventory counts&lt;/li&gt;
&lt;li&gt;Financial reconciliation&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;An LLM generates probable text. It does not guarantee mathematical accuracy.&lt;/p&gt;

&lt;p&gt;A safer architecture is:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Use trusted software to perform the calculation.&lt;/li&gt;
&lt;li&gt;Use an LLM to explain the result when necessary.&lt;/li&gt;
&lt;li&gt;Display the inputs and formulas clearly.&lt;/li&gt;
&lt;li&gt;Keep an audit trail.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;For example, an LLM can explain why an invoice total changed. The actual calculation should come from a calculation engine.&lt;/p&gt;

&lt;p&gt;In financial systems, “usually correct” is not a reliable standard.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Authentication and Authorization
&lt;/h2&gt;

&lt;p&gt;Security decisions should never depend entirely on an LLM’s interpretation.&lt;/p&gt;

&lt;p&gt;Whether a user can access a document, approve a payment, modify a record, or view private data should be decided by explicit permissions and policies.&lt;/p&gt;

&lt;p&gt;A safer process looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;User request → language interpretation → structured action → policy engine → allow or deny
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The model can understand that a user wants to download a report. The authorization system must decide whether the user is allowed to do so.&lt;/p&gt;

&lt;p&gt;This separation matters because security is not a creativity problem. It is a control problem.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. Simple Search and Filtering
&lt;/h2&gt;

&lt;p&gt;Not every search function requires generative AI.&lt;/p&gt;

&lt;p&gt;If users are searching for an exact SKU, order number, employee ID, date range, or file type, traditional search and filtering may provide a better experience.&lt;/p&gt;

&lt;p&gt;Using an LLM for these tasks can lead to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Slower responses&lt;/li&gt;
&lt;li&gt;Higher costs&lt;/li&gt;
&lt;li&gt;Incomplete results&lt;/li&gt;
&lt;li&gt;Difficulty explaining matches&lt;/li&gt;
&lt;li&gt;Failure to retrieve exact records&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Semantic search is valuable when users describe concepts rather than exact terms, or when information is unstructured.&lt;/p&gt;

&lt;p&gt;But searching for order &lt;code&gt;A-1048&lt;/code&gt; does not require semantic reasoning. It requires a good index.&lt;/p&gt;

&lt;p&gt;The best systems often combine both approaches: deterministic search for exact retrieval and AI for semantic discovery.&lt;/p&gt;

&lt;h2&gt;
  
  
  6. Fixed Workflow Automation
&lt;/h2&gt;

&lt;p&gt;Some workflows are repetitive but not intelligent.&lt;/p&gt;

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

&lt;ol&gt;
&lt;li&gt;Receive a webhook.&lt;/li&gt;
&lt;li&gt;Validate the payload.&lt;/li&gt;
&lt;li&gt;Update a database.&lt;/li&gt;
&lt;li&gt;Send an email.&lt;/li&gt;
&lt;li&gt;Create a task.&lt;/li&gt;
&lt;li&gt;Record the event.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If the steps and decisions are already known, a workflow engine is usually a better choice than an LLM-based agent.&lt;/p&gt;

&lt;p&gt;Traditional automation offers:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;More consistent execution&lt;/li&gt;
&lt;li&gt;Easier debugging&lt;/li&gt;
&lt;li&gt;Better retry behavior&lt;/li&gt;
&lt;li&gt;Lower costs&lt;/li&gt;
&lt;li&gt;Clearer monitoring&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Agents are useful when a system must choose among uncertain paths. They are unnecessary when the path is already fixed.&lt;/p&gt;

&lt;p&gt;A workflow does not become intelligent simply because a model is inserted into it.&lt;/p&gt;

&lt;h2&gt;
  
  
  7. User Interfaces That Need Speed
&lt;/h2&gt;

&lt;p&gt;Users do not want every interaction to become a conversation.&lt;/p&gt;

&lt;p&gt;Opening a menu, sorting a table, changing a setting, loading a dashboard, or confirming a known action should usually happen immediately.&lt;/p&gt;

&lt;p&gt;Adding an LLM to these interactions creates unnecessary latency and uncertainty. If users need several messages to achieve what one button used to do, that is not innovation. It is a worse interface.&lt;/p&gt;

&lt;p&gt;Conversational experiences are valuable for complex exploration and assistance. They should not replace basic product usability.&lt;/p&gt;

&lt;h2&gt;
  
  
  A Practical Test Before Adding an LLM
&lt;/h2&gt;

&lt;p&gt;Before using an LLM, ask four questions:&lt;/p&gt;

&lt;h3&gt;
  
  
  Is the input ambiguous?
&lt;/h3&gt;

&lt;p&gt;If the input has a fixed structure, ordinary software may be enough.&lt;/p&gt;

&lt;h3&gt;
  
  
  Must the output be deterministic?
&lt;/h3&gt;

&lt;p&gt;If identical inputs must always produce identical results, an LLM may be the wrong foundation.&lt;/p&gt;

&lt;h3&gt;
  
  
  Can the result be audited?
&lt;/h3&gt;

&lt;p&gt;If the system cannot explain why it made a decision, the feature may require stronger controls.&lt;/p&gt;

&lt;h3&gt;
  
  
  What happens when the model is wrong?
&lt;/h3&gt;

&lt;p&gt;If an error could cause financial loss, security exposure, legal risk, or permanent data damage, the model should not be the only decision-maker.&lt;/p&gt;

&lt;p&gt;These questions do not mean companies should avoid LLMs. They mean LLMs should be assigned the right responsibilities.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where LLMs Actually Add Value
&lt;/h2&gt;

&lt;p&gt;LLMs are most useful when a product must handle language that is:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Ambiguous&lt;/li&gt;
&lt;li&gt;Unstructured&lt;/li&gt;
&lt;li&gt;Context-dependent&lt;/li&gt;
&lt;li&gt;Difficult to express with fixed rules&lt;/li&gt;
&lt;li&gt;Different for every user&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Common examples include summarization, natural-language search, document interpretation, content generation, and converting user requests into structured actions.&lt;/p&gt;

&lt;p&gt;The strongest architecture usually divides responsibilities:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;LLM for interpretation
Software for execution
Rules for control
Logs for accountability
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is more reliable than asking one model to handle everything.&lt;/p&gt;

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

&lt;p&gt;Once a team stops treating every feature as an LLM problem, a more practical challenge appears.&lt;/p&gt;

&lt;p&gt;Some requests need a model. Others do not. Some require speed, while others need deeper reasoning. Some can tolerate uncertainty, while others require strict validation and fallback behavior.&lt;/p&gt;

&lt;p&gt;This is where Tokenbay becomes useful.&lt;/p&gt;

&lt;p&gt;Tokenbay helps teams manage the parts of a product that genuinely depend on AI, including model routing, output validation, provider switching, monitoring, and fallback strategies.&lt;/p&gt;

&lt;p&gt;Try Tokenbay：&lt;a href="https://www.tokenbay.com/?utm_source=devto&amp;amp;utm_medium=community_content&amp;amp;utm_campaign=week1_free_content" rel="noopener noreferrer"&gt;https://www.tokenbay.com/?utm_source=devto&amp;amp;utm_medium=community_content&amp;amp;utm_campaign=week1_free_content&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The goal is not to maximize model usage.&lt;/p&gt;

&lt;p&gt;The goal is to maximize product reliability.&lt;/p&gt;

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

&lt;p&gt;The future of AI products will not belong to teams that use the most LLMs.&lt;/p&gt;

&lt;p&gt;It will belong to teams that know exactly where LLMs belong—and where they do not.&lt;/p&gt;

&lt;p&gt;A calculator should calculate.&lt;br&gt;&lt;br&gt;
A permission system should enforce permissions.&lt;br&gt;&lt;br&gt;
A search index should retrieve records.&lt;br&gt;&lt;br&gt;
A workflow engine should execute workflows.&lt;/p&gt;

&lt;p&gt;Use an LLM when the problem is genuinely about language and interpretation.&lt;/p&gt;

&lt;p&gt;For everything else, simple software is often the smarter decision.&lt;/p&gt;

</description>
      <category>llm</category>
      <category>ai</category>
      <category>python</category>
      <category>agents</category>
    </item>
    <item>
      <title>Why Structured Output Fails in Production—and How to Fix It</title>
      <dc:creator>GWEN</dc:creator>
      <pubDate>Wed, 22 Jul 2026 09:34:36 +0000</pubDate>
      <link>https://dev.to/gwenj/why-structured-output-fails-in-production-and-how-to-fix-it-1nl5</link>
      <guid>https://dev.to/gwenj/why-structured-output-fails-in-production-and-how-to-fix-it-1nl5</guid>
      <description>&lt;p&gt;Getting an LLM to return JSON in a demo is easy. Getting it to return valid, complete, schema-compliant JSON across thousands of real requests is where things start breaking.&lt;/p&gt;

&lt;p&gt;The usual mistake is treating structured output as a prompt-writing problem:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“Return the result in JSON format.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That may work until users send ambiguous input, prompts get longer, models change behavior, or a provider has a bad day. In production, structured output is not a formatting preference. It is an API contract.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. HTTP 200 is not success
&lt;/h2&gt;

&lt;p&gt;A model request can return successfully while still being unusable:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;JSON is wrapped in Markdown fences&lt;/li&gt;
&lt;li&gt;A required field is missing&lt;/li&gt;
&lt;li&gt;A number arrives as a string&lt;/li&gt;
&lt;li&gt;An enum contains an unsupported value&lt;/li&gt;
&lt;li&gt;Extra commentary appears outside the JSON&lt;/li&gt;
&lt;li&gt;The output is valid JSON but logically incomplete&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If your application accepts all of that because the API returned &lt;code&gt;200 OK&lt;/code&gt;, you are pushing failure downstream—to your database, workflow engine, or end user.&lt;/p&gt;

&lt;p&gt;The correct flow is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Model response → Parse → Validate schema → Validate business rules → Accept or recover
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Parsing checks whether JSON is syntactically valid. Schema validation checks structure. Business validation checks whether the result is actually usable. These are different jobs.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Make the schema do real work
&lt;/h2&gt;

&lt;p&gt;A weak schema only defines field names. A useful schema defines constraints.&lt;/p&gt;

&lt;p&gt;Instead of this:&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;"priority"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"string"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"score"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"number"&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;Use constraints that match your application:&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;"priority"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"low | medium | high"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"score"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"integer from 0 to 100"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"summary"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"non-empty string, maximum 300 characters"&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;For extraction tasks, explicitly define required fields, allowed values, nullable fields, and default behavior when information is unavailable.&lt;/p&gt;

&lt;p&gt;One important rule: do not force the model to invent data just to satisfy a required field. Let it return &lt;code&gt;null&lt;/code&gt;, &lt;code&gt;"unknown"&lt;/code&gt;, or a predefined fallback value when the source does not contain the answer. Fake completeness is worse than an honest gap.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Repair strategy beats blind retry
&lt;/h2&gt;

&lt;p&gt;When validation fails, many systems simply resend the same prompt. That is lazy engineering, and it often produces the same error with more latency and token cost.&lt;/p&gt;

&lt;p&gt;A better recovery policy depends on the failure:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Invalid JSON&lt;/strong&gt;: ask for JSON only, remove Markdown, and include the validation error&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Missing required fields&lt;/strong&gt;: ask the model to regenerate only the incomplete fields&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Wrong enum values&lt;/strong&gt;: provide the allowed values again&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Business-rule failure&lt;/strong&gt;: request a corrected result with the exact failed rule&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Repeated failure&lt;/strong&gt;: switch model, simplify the task, or return a controlled fallback&lt;/li&gt;
&lt;/ul&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Validation failed: "priority" must be one of low, medium, high.
Return only corrected JSON. Do not add explanations.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This gives the model an actionable correction target instead of vaguely saying “try again.”&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Keep the repair loop bounded
&lt;/h2&gt;

&lt;p&gt;A repair loop without limits is a cost leak waiting to happen. Set clear boundaries:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Maximum one or two repair attempts&lt;/li&gt;
&lt;li&gt;Separate token budget for retries&lt;/li&gt;
&lt;li&gt;Timeout budget across the entire request&lt;/li&gt;
&lt;li&gt;A defined degraded response when recovery fails&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That final fallback might be a partial result, a queue-for-review state, or a clear error response. The worst option is silently sending malformed data into the rest of the system.&lt;/p&gt;

&lt;p&gt;Track three metrics in particular:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Initial schema pass rate&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Recovery rate after validation failure&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Average cost per successful structured response&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A high retry success rate is not automatically good news. It may mean your first-pass prompt or model selection is weak.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. Model choice still matters
&lt;/h2&gt;

&lt;p&gt;Different models behave differently under strict output requirements. One may be cheaper and fast for classification but unreliable with nested schemas. Another may be slower but much more stable for complex extraction.&lt;/p&gt;

&lt;p&gt;That is why structured-output workloads benefit from multi-model access. You can route simple jobs to an efficient model, reserve stronger models for complicated schemas, and keep a backup option when validation repeatedly fails.&lt;/p&gt;

&lt;p&gt;The goal is not to find one universally “best” model. It is to build a pipeline where invalid output is detected early, repaired intelligently, and prevented from becoming an application failure.&lt;/p&gt;

&lt;p&gt;Try Tokenbay: &lt;a href="https://www.tokenbay.com/?utm_source=devto&amp;amp;utm_medium=community_content&amp;amp;utm_campaign=week1_free_content" rel="noopener noreferrer"&gt;https://www.tokenbay.com/?utm_source=devto&amp;amp;utm_medium=community_content&amp;amp;utm_campaign=week1_free_content&lt;/a&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>api</category>
      <category>llm</category>
      <category>python</category>
    </item>
    <item>
      <title>Building Reliable AI Applications with Model Fallbacks</title>
      <dc:creator>GWEN</dc:creator>
      <pubDate>Tue, 21 Jul 2026 09:58:39 +0000</pubDate>
      <link>https://dev.to/gwenj/building-reliable-ai-applications-with-model-fallbacks-14a0</link>
      <guid>https://dev.to/gwenj/building-reliable-ai-applications-with-model-fallbacks-14a0</guid>
      <description>&lt;p&gt;Using one AI model is simple. Building a system that remains reliable when the model is slow, unavailable, expensive, or returns invalid output is much harder.&lt;/p&gt;

&lt;p&gt;That is why fallback design matters in production AI applications.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. A fallback is more than a backup model
&lt;/h2&gt;

&lt;p&gt;Many developers use a basic pattern:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Call Model A
If it fails, call Model B
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This works as a starting point, but it is too simple for real systems. Not every failure should trigger the same response.&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;A timeout may require a faster model.&lt;/li&gt;
&lt;li&gt;Invalid JSON may require a stricter prompt.&lt;/li&gt;
&lt;li&gt;High cost may require a smaller model.&lt;/li&gt;
&lt;li&gt;A complex reasoning task may require a more capable model.&lt;/li&gt;
&lt;li&gt;A temporary provider error may justify switching providers.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The fallback strategy should be based on the &lt;strong&gt;failure type&lt;/strong&gt;, not just whether the request failed.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Validate the output before accepting it
&lt;/h2&gt;

&lt;p&gt;An API returning HTTP 200 does not mean the task succeeded. The response may still contain:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Missing fields&lt;/li&gt;
&lt;li&gt;Invalid JSON&lt;/li&gt;
&lt;li&gt;Incorrect data types&lt;/li&gt;
&lt;li&gt;Unsupported values&lt;/li&gt;
&lt;li&gt;Incomplete instructions&lt;/li&gt;
&lt;li&gt;Unclear or unverifiable content&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For structured tasks, validate the response against a schema before returning it to the user. For text generation, use simpler checks such as required sections, minimum content, or prohibited patterns.&lt;/p&gt;

&lt;p&gt;This creates a clear decision flow:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Request → Model response → Output validation → Accept or fallback
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Without output validation, your system may treat a failed answer as a successful one.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Set different retry rules for different failures
&lt;/h2&gt;

&lt;p&gt;Retrying every error is usually a bad idea. It increases latency and cost while repeating the same mistake.&lt;/p&gt;

&lt;p&gt;A better approach is to define limits by failure category:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Timeout&lt;/strong&gt;: retry once with a faster model&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Format error&lt;/strong&gt;: retry with a corrected prompt or stricter schema&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Provider error&lt;/strong&gt;: switch to another provider&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Task failure&lt;/strong&gt;: use a stronger model&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Budget exceeded&lt;/strong&gt;: stop retrying and return a simplified result&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You should also record whether the fallback actually improved the result. The key metric is not how often fallback runs, but its &lt;strong&gt;recovery rate&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Keep routing rules simple at first
&lt;/h2&gt;

&lt;p&gt;You do not need a complex machine-learning router on day one. Start with predictable rules based on:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Task type&lt;/li&gt;
&lt;li&gt;Input length&lt;/li&gt;
&lt;li&gt;Required output format&lt;/li&gt;
&lt;li&gt;Latency requirements&lt;/li&gt;
&lt;li&gt;Maximum token budget&lt;/li&gt;
&lt;li&gt;Historical model performance&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For example, a lightweight model may handle classification and simple extraction, while a more capable model handles code generation, long documents, or complex reasoning.&lt;/p&gt;

&lt;p&gt;As production data accumulates, you can refine these rules using actual success rates and cost data instead of assumptions.&lt;/p&gt;

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

&lt;p&gt;Reliable AI systems are not built by choosing one “best” model. They are built by combining model selection, output validation, failure classification, and controlled fallback.&lt;/p&gt;

&lt;p&gt;A unified API can make it easier to access and compare multiple models without maintaining a separate integration for every provider.&lt;/p&gt;

&lt;p&gt;Try Tokenbay:  &lt;a href="https://www.tokenbay.com/?utm_source=devto&amp;amp;utm_medium=community_content&amp;amp;utm_campaign=week1_free_content" rel="noopener noreferrer"&gt;https://www.tokenbay.com/?utm_source=devto&amp;amp;utm_medium=community_content&amp;amp;utm_campaign=week1_free_content&lt;/a&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>llm</category>
      <category>python</category>
      <category>api</category>
    </item>
    <item>
      <title>Designing a Robust Multi-Model Router: Evaluation, Fallback, and Cost Control</title>
      <dc:creator>GWEN</dc:creator>
      <pubDate>Mon, 20 Jul 2026 10:13:09 +0000</pubDate>
      <link>https://dev.to/gwenj/designing-a-robust-multi-model-router-evaluation-fallback-and-cost-control-443h</link>
      <guid>https://dev.to/gwenj/designing-a-robust-multi-model-router-evaluation-fallback-and-cost-control-443h</guid>
      <description>&lt;p&gt;Most teams can “connect” multi-models. Fewer can “run them reliably.” Once you plug in GPT/Claude/Gemini/GLM, the real work becomes: &lt;strong&gt;routing strategy, failure backstops, cost control, and credible evaluation&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;This post is about an engineering approach: build a measurable router (rules + data), then use &lt;strong&gt;fallback&lt;/strong&gt; so production doesn’t face single-model surprises.&lt;/p&gt;

&lt;h2&gt;
  
  
  1) Start with failure modes, not model hype
&lt;/h2&gt;

&lt;p&gt;A router’s job isn’t to make models “stronger.” It’s to keep the system in an acceptable state under failure. Define your failure modes up front:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Format failures&lt;/strong&gt;: schema/JSON doesn’t match
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Refusal / safety blocks&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Factual errors&lt;/strong&gt;: answers sound right but don’t verify
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Task not completed&lt;/strong&gt;: missing steps, incomplete output
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Latency limits&lt;/strong&gt;: timeouts, bad P95/P99
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cost runaway&lt;/strong&gt;: retries expand token usage
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Context inconsistency&lt;/strong&gt;: constraints break across turns
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;No quantified failure modes = a router that’s basically a “vibes switch.”&lt;/p&gt;

&lt;h2&gt;
  
  
  2) Use two stages: Plan → Execute
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Plan (routing decision)&lt;/strong&gt; outputs: &lt;code&gt;primary_model&lt;/code&gt;, &lt;code&gt;backup_models&lt;/code&gt;, and &lt;code&gt;strategy&lt;/code&gt; (strict JSON? allow long reasoning? enable retrieval?).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Execute (real calls + checks)&lt;/strong&gt; does three things:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Validate output&lt;/strong&gt; (schema/fields/constraints)
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Evaluate result&lt;/strong&gt; (task success + what you can verify)
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Trigger fallback&lt;/strong&gt; with precise conditions
&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  3) Evaluation set: make it match production risk
&lt;/h2&gt;

&lt;p&gt;Maintain three types of data:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Real request samples&lt;/strong&gt; (from logs, keep real distributions)
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Boundary cases&lt;/strong&gt; (long inputs, missing fields, near-schema inputs, mixed language)
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Negative bank&lt;/strong&gt; (historical failures tagged by failure type)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Track metrics beyond “accuracy”:&lt;br&gt;
&lt;strong&gt;task success&lt;/strong&gt;, &lt;strong&gt;format pass rate&lt;/strong&gt;, &lt;strong&gt;fact error rate&lt;/strong&gt; (when verifiable), &lt;strong&gt;P95/P99 latency&lt;/strong&gt;, &lt;strong&gt;token/cost overhead&lt;/strong&gt;, and &lt;strong&gt;recovery rate&lt;/strong&gt; after fallback.&lt;/p&gt;

&lt;h2&gt;
  
  
  4) Fallback: switch strategies, not just models
&lt;/h2&gt;

&lt;p&gt;Common mistake: primary fails → retry backup with the same behavior. That ignores the root cause—often it’s prompt instability or missing validation.&lt;/p&gt;

&lt;p&gt;Better fallback dimensions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Switch only the model&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Switch only the strategy&lt;/strong&gt; (tighten JSON prompt, add schema examples, reduce creativity)
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Strategy repair first&lt;/strong&gt;, model swap second
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Retry limits by failure type&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Input transformation&lt;/strong&gt; (truncate context, compress history)
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Goal: survival under stress, not “always force the strongest answer.”&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion: Route like a system
&lt;/h2&gt;

&lt;p&gt;Unified APIs reduce integration pain, but &lt;strong&gt;routing quality still depends on failure-mode definitions, real evaluation sets, and executable fallback rules&lt;/strong&gt;. If you treat it like an engineering system, you get stability, cost control, and defensible improvements.&lt;/p&gt;

&lt;p&gt;Try Tokenbay: &lt;a href="https://www.tokenbay.com/?utm_source=devto&amp;amp;utm_medium=community_content&amp;amp;utm_campaign=week1_free_content" rel="noopener noreferrer"&gt;https://www.tokenbay.com/?utm_source=devto&amp;amp;utm_medium=community_content&amp;amp;utm_campaign=week1_free_content&lt;/a&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>llm</category>
      <category>api</category>
      <category>python</category>
    </item>
    <item>
      <title>How to Choose the Right AI Model for Your Application</title>
      <dc:creator>GWEN</dc:creator>
      <pubDate>Fri, 17 Jul 2026 09:42:29 +0000</pubDate>
      <link>https://dev.to/gwenj/how-to-choose-the-right-ai-model-for-your-application-5a41</link>
      <guid>https://dev.to/gwenj/how-to-choose-the-right-ai-model-for-your-application-5a41</guid>
      <description>&lt;p&gt;Integrating multiple AI models is not difficult. The real challenge is determining &lt;strong&gt;which model is best suited for each task&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Many developers choose models based only on benchmarks, brand recognition, or a few test results. In real applications, however, model performance depends on the task, input length, output format, response speed, and cost. A model that performs well at code generation may not be suitable for large-scale classification. A model with strong reasoning capabilities may not be ideal for low-latency scenarios.&lt;/p&gt;

&lt;h2&gt;
  
  
  There Is No “Best Model” for Every Scenario
&lt;/h2&gt;

&lt;p&gt;Choosing an AI model is essentially a multi-objective trade-off.&lt;/p&gt;

&lt;p&gt;You usually need to consider:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Output quality&lt;/li&gt;
&lt;li&gt;Response latency&lt;/li&gt;
&lt;li&gt;Token cost&lt;/li&gt;
&lt;li&gt;Context length&lt;/li&gt;
&lt;li&gt;Structured output stability&lt;/li&gt;
&lt;li&gt;Concurrency and rate limits&lt;/li&gt;
&lt;li&gt;Fallback capabilities when tasks fail&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you focus only on quality, costs may become difficult to control. If you focus only on price, rework and manual review costs may increase. If you focus only on latency, accuracy on complex tasks may suffer.&lt;/p&gt;

&lt;p&gt;Instead of asking, “Which model is the best?” ask:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;For this task, which model combination provides the lowest overall cost and the most stable results?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Classify Tasks Before Choosing Models
&lt;/h2&gt;

&lt;p&gt;Model selection should start with business tasks, not brand names.&lt;/p&gt;

&lt;p&gt;A typical AI application may include the following tasks:&lt;/p&gt;

&lt;h3&gt;
  
  
  Text Classification
&lt;/h3&gt;

&lt;p&gt;Text classification usually requires a model that is stable, fast, and cost-efficient. For intent detection, label classification, and initial content filtering, advanced reasoning capabilities may be unnecessary.&lt;/p&gt;

&lt;h3&gt;
  
  
  Long-Document Analysis
&lt;/h3&gt;

&lt;p&gt;Tasks such as summarizing long documents, analyzing contracts, and extracting information from technical materials depend more on context handling. You should focus on whether the model can process long inputs without missing important details.&lt;/p&gt;

&lt;h3&gt;
  
  
  Code Generation
&lt;/h3&gt;

&lt;p&gt;For code-related tasks, it is not enough to check whether the output “looks like code.” More important factors include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Whether the model understands the existing project structure;&lt;/li&gt;
&lt;li&gt;Whether it follows the specified language and framework;&lt;/li&gt;
&lt;li&gt;Whether the output format remains consistent;&lt;/li&gt;
&lt;li&gt;Whether the generated code can run;&lt;/li&gt;
&lt;li&gt;Whether edge cases are handled correctly.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Real-Time Conversations
&lt;/h3&gt;

&lt;p&gt;Real-time customer service, online assistants, and interactive tools typically prioritize latency. A model with slightly better response quality but much slower performance may not be suitable for high-frequency conversations.&lt;/p&gt;

&lt;h3&gt;
  
  
  Structured Data Extraction
&lt;/h3&gt;

&lt;p&gt;When a model needs to return JSON, field lists, or fixed enum values, structured output stability is more important than general language fluency.&lt;/p&gt;

&lt;p&gt;Using different models for different tasks does not necessarily make a system more complex. In fact, clearly defining task boundaries can make model routing easier to maintain.&lt;/p&gt;

&lt;h2&gt;
  
  
  Replace Subjective Judgment with Evaluation Data
&lt;/h2&gt;

&lt;p&gt;Many teams select models by testing a few simple Prompts and then making a decision based on intuition. The problem is obvious: the sample size is too small to reflect real-world usage.&lt;/p&gt;

&lt;p&gt;A more reliable approach is to build a small evaluation set containing at least:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Normal requests;&lt;/li&gt;
&lt;li&gt;Ambiguous requests;&lt;/li&gt;
&lt;li&gt;Overly long inputs;&lt;/li&gt;
&lt;li&gt;Multilingual inputs;&lt;/li&gt;
&lt;li&gt;Historical failure cases;&lt;/li&gt;
&lt;li&gt;Requests prone to formatting errors;&lt;/li&gt;
&lt;li&gt;Requests requiring refusal or cautious responses.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Each task should have clearly defined evaluation criteria.&lt;/p&gt;

&lt;p&gt;For example, when testing a product information extraction task, you can validate the result as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;evaluate_product_result&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="nf"&gt;isinstance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="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="bp"&gt;False&lt;/span&gt;

    &lt;span class="n"&gt;required_fields&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;name&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;category&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;price&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;field&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;required_fields&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;field&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;False&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="nf"&gt;isinstance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;price&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="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;float&lt;/span&gt;&lt;span class="p"&gt;)):&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;False&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is more reliable than simply checking whether the response “reads well.” Production systems ultimately need usable results, not just fluent text.&lt;/p&gt;

&lt;h2&gt;
  
  
  Do Not Look Only at the Average Score
&lt;/h2&gt;

&lt;p&gt;Average scores in model evaluations can easily hide important problems.&lt;/p&gt;

&lt;p&gt;Suppose a model performs well on 100 test samples but fails on all five critical business scenarios. Is it suitable for production? Clearly not.&lt;/p&gt;

&lt;p&gt;Your evaluation should separately track:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Overall success rate;&lt;/li&gt;
&lt;li&gt;Success rate by task;&lt;/li&gt;
&lt;li&gt;Structured output error rate;&lt;/li&gt;
&lt;li&gt;Factual error rate;&lt;/li&gt;
&lt;li&gt;Average response time;&lt;/li&gt;
&lt;li&gt;P95 or P99 latency;&lt;/li&gt;
&lt;li&gt;Average token usage;&lt;/li&gt;
&lt;li&gt;Recovery rate after failures.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;P95 and P99 latency are especially important. A normal average response time does not necessarily mean that the user experience remains acceptable during peak traffic.&lt;/p&gt;

&lt;h2&gt;
  
  
  Model Costs Include More Than Token Prices
&lt;/h2&gt;

&lt;p&gt;The cost of a model is usually more than the API bill.&lt;/p&gt;

&lt;p&gt;You should also consider:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Additional requests caused by retries;&lt;/li&gt;
&lt;li&gt;Manual review caused by invalid output;&lt;/li&gt;
&lt;li&gt;Post-processing required to fix formatting errors;&lt;/li&gt;
&lt;li&gt;User churn caused by low-quality results;&lt;/li&gt;
&lt;li&gt;Reprocessing after business failures;&lt;/li&gt;
&lt;li&gt;Engineering time spent maintaining multiple provider integrations.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Sometimes a more expensive model is actually cheaper overall because it reduces retries and manual fixes.&lt;/p&gt;

&lt;p&gt;A simple cost estimation function might look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;estimate_total_cost&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;api_cost&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;retry_cost&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;review_cost&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;failure_cost&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;api_cost&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;retry_cost&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;review_cost&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;failure_cost&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The goal is not to calculate every cost with perfect precision. It is to avoid focusing only on the price per million tokens.&lt;/p&gt;

&lt;h2&gt;
  
  
  Design Primary and Fallback Models
&lt;/h2&gt;

&lt;p&gt;Production systems should not depend on a single model.&lt;/p&gt;

&lt;p&gt;A basic routing policy might look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;MODEL_POLICY&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;classification&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;primary&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;fast-model&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;fallback&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;stable-model&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;document_analysis&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;primary&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;reasoning-model&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;fallback&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;general-model&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;code_generation&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;primary&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;code-model&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;fallback&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;general-model&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;However, a fallback model is not simply “another model to call after the first one fails.”&lt;/p&gt;

&lt;p&gt;Before switching, define:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Which errors should trigger fallback;&lt;/li&gt;
&lt;li&gt;Whether the original Prompt should be preserved;&lt;/li&gt;
&lt;li&gt;Whether the input needs to be shortened;&lt;/li&gt;
&lt;li&gt;Whether the output format needs to be adjusted;&lt;/li&gt;
&lt;li&gt;How many retries are allowed;&lt;/li&gt;
&lt;li&gt;Whether fallback results should be marked for later manual review.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Without these rules, automatic fallback may simply move the problem from one model to another.&lt;/p&gt;

&lt;h2&gt;
  
  
  A Unified Interface Solves Integration Problems
&lt;/h2&gt;

&lt;p&gt;Different models often vary in authentication methods, request parameters, error formats, and supported capabilities. If an application integrates multiple providers directly, the code can quickly become filled with repetitive adapter logic.&lt;/p&gt;

&lt;p&gt;A unified API can reduce these low-level differences and make model integration, switching, and comparison more convenient.&lt;/p&gt;

&lt;p&gt;TokenBay provides access to models such as GPT, Claude, Gemini, and GLM through a unified API and an OpenAI-compatible interface. It can be used for multi-model integration, model comparison during development, and adjusting model configurations based on specific tasks.&lt;/p&gt;

&lt;p&gt;Try Tokenbay：&lt;a href="https://www.tokenbay.com/?utm_source=devto&amp;amp;utm_medium=community_content&amp;amp;utm_campaign=week1_free_content" rel="noopener noreferrer"&gt;https://www.tokenbay.com/?utm_source=devto&amp;amp;utm_medium=community_content&amp;amp;utm_campaign=week1_free_content&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;However, a unified interface does not automatically guarantee consistent model behavior. Developers still need to evaluate models against real tasks and configure appropriate Prompts, parameters, and output validation rules for each model.&lt;/p&gt;

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

&lt;p&gt;Choosing an AI model is not a one-time procurement decision. It is an ongoing engineering problem.&lt;/p&gt;

&lt;p&gt;A practical process is to:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Break down the business tasks;&lt;/li&gt;
&lt;li&gt;Define acceptance criteria for each task;&lt;/li&gt;
&lt;li&gt;Build an evaluation set using real requests;&lt;/li&gt;
&lt;li&gt;Compare quality, latency, cost, and failure patterns;&lt;/li&gt;
&lt;li&gt;Configure primary and fallback models;&lt;/li&gt;
&lt;li&gt;Continuously collect production data and adjust routing.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;A mature multi-model system is not one that integrates every available model. It is one that knows where each model should be used—and when it should no longer be used.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>api</category>
      <category>llm</category>
      <category>python</category>
    </item>
    <item>
      <title>Practical Multi-Model API Integration: Designing a Switchable, Observable, and Rollback-Friendly LLM Layer</title>
      <dc:creator>GWEN</dc:creator>
      <pubDate>Wed, 15 Jul 2026 10:17:05 +0000</pubDate>
      <link>https://dev.to/gwenj/practical-multi-model-api-integration-designing-a-switchable-observable-and-rollback-friendly-562j</link>
      <guid>https://dev.to/gwenj/practical-multi-model-api-integration-designing-a-switchable-observable-and-rollback-friendly-562j</guid>
      <description>&lt;p&gt;When teams integrate large language models, the first step is usually connecting to a model’s API. Once the code runs and returns responses, integration is often considered complete.&lt;/p&gt;

&lt;p&gt;In production, however, the real problems begin:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The same Prompt produces inconsistent output after switching models.&lt;/li&gt;
&lt;li&gt;A temporary rate limit on one model causes business requests to fail.&lt;/li&gt;
&lt;li&gt;Different models have different token prices and context limits.&lt;/li&gt;
&lt;li&gt;One model returns valid output while another produces unparsable JSON.&lt;/li&gt;
&lt;li&gt;Model names are hardcoded throughout the business logic, making future migration expensive.&lt;/li&gt;
&lt;li&gt;When quality issues occur, it is difficult to determine whether the cause is the model, the Prompt, or the input data.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Therefore, the core challenge of multi-model integration is not “how to send a request once,” but how to build a reliable model-calling infrastructure layer.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Separate Model Calls from Business Logic
&lt;/h2&gt;

&lt;p&gt;A common anti-pattern is to hardcode model calls directly into business logic:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;chat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&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="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;some-model&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;messages&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;temperature&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mf"&gt;0.2&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This may look simple in the short term, but it tightly couples the model provider, model name, parameter settings, and business logic.&lt;/p&gt;

&lt;p&gt;A better approach is to abstract a unified calling interface:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;LLMClient&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;generate&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;request&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nb"&gt;NotImplementedError&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The business layer only needs to handle the request and task requirements. It should not depend directly on a specific 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="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;llm&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;generate&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;task&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;extract_product_info&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;messages&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;response_format&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;json&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;The underlying layer can then select a model based on configuration:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;MODEL_CONFIG&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;default&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;model-a&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;fallback&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;model-b&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;high_quality&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;model-c&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;The value of this design is not just cleaner code. It also allows you to handle the following independently:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Model switching&lt;/li&gt;
&lt;li&gt;Retry logic&lt;/li&gt;
&lt;li&gt;Fallback strategies&lt;/li&gt;
&lt;li&gt;Unified logging&lt;/li&gt;
&lt;li&gt;Token tracking&lt;/li&gt;
&lt;li&gt;Output validation&lt;/li&gt;
&lt;li&gt;Quality evaluation&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If these concerns are scattered throughout the business code, maintenance costs will quickly become unmanageable as the number of models increases.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. A Unified API Does Not Mean Unified Behavior
&lt;/h2&gt;

&lt;p&gt;Even if different models support similar OpenAI-compatible API formats, you cannot assume that they behave identically.&lt;/p&gt;

&lt;p&gt;The same Prompt may produce different results across models because of differences in:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;How system instructions are prioritized;&lt;/li&gt;
&lt;li&gt;Long-context processing capabilities;&lt;/li&gt;
&lt;li&gt;Compliance with JSON, function calling, and enum constraints;&lt;/li&gt;
&lt;li&gt;How ambiguous requirements are completed;&lt;/li&gt;
&lt;li&gt;The practical effects of parameters such as temperature and maximum tokens.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;A unified interface can standardize the &lt;strong&gt;request method&lt;/strong&gt;, but it cannot automatically standardize &lt;strong&gt;output quality&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The application layer still needs explicit output constraints. Instead of simply asking a model to “return JSON,” define the required fields and types clearly:&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;"title"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"string"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"category"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"string"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"confidence"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"number"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"reason"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"string"&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 response should then be parsed and validated:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;validate_result&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;required_fields&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;title&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;category&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;confidence&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="nf"&gt;isinstance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;dict&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;False&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nf"&gt;any&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;field&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;field&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;required_fields&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;False&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="nf"&gt;isinstance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;confidence&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;float&lt;/span&gt;&lt;span class="p"&gt;)):&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;False&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;confidence&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Model output is not a database record. You should not write it directly into a production system simply because it “looks like JSON.”&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Do Not Treat Retries as a Universal Solution
&lt;/h2&gt;

&lt;p&gt;When an API call fails, many systems immediately retry. However, failures must be classified first.&lt;/p&gt;

&lt;h3&gt;
  
  
  Situations Suitable for Retrying
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Network connection failures;&lt;/li&gt;
&lt;li&gt;Request timeouts;&lt;/li&gt;
&lt;li&gt;Temporary service unavailability;&lt;/li&gt;
&lt;li&gt;Explicit rate-limit errors;&lt;/li&gt;
&lt;li&gt;5xx responses from the upstream service.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Situations Unsuitable for Blind Retries
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;The Prompt itself is incomplete;&lt;/li&gt;
&lt;li&gt;The input exceeds the context limit;&lt;/li&gt;
&lt;li&gt;The output format repeatedly fails validation;&lt;/li&gt;
&lt;li&gt;Invalid parameters;&lt;/li&gt;
&lt;li&gt;The request triggers a model safety policy;&lt;/li&gt;
&lt;li&gt;The underlying business data is incorrect.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If every error triggers multiple retries, the usual result is increased latency and cost, followed by the same failure.&lt;/p&gt;

&lt;p&gt;A more practical strategy is:&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;call_with_policy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;call_model&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&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;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;is_success&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;is_retryable&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;retry_with_backoff&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&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;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;is_format_error&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;repair_or_fallback&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&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;handle_business_failure&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Retry counts, backoff intervals, and fallback models should be configurable rather than hardcoded.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Route Models by Task, Not Personal Preference
&lt;/h2&gt;

&lt;p&gt;The question “Which model is the best?” is usually not very meaningful in practice.&lt;/p&gt;

&lt;p&gt;Different tasks prioritize different capabilities:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Classification may prioritize stability and cost;&lt;/li&gt;
&lt;li&gt;Complex analysis may prioritize reasoning quality;&lt;/li&gt;
&lt;li&gt;Code generation may prioritize format compliance and executability;&lt;/li&gt;
&lt;li&gt;Real-time interaction may prioritize latency;&lt;/li&gt;
&lt;li&gt;Long-document processing may prioritize context capacity.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A more practical design is to configure model routing by task:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;ROUTING_POLICY&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;classification&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;primary&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;model-a&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;fallback&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;model-b&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;long_document_analysis&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;primary&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;model-c&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;fallback&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;model-a&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;code_generation&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;primary&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;model-b&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;fallback&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;model-c&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;More dimensions can be added later, including:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Current model availability;&lt;/li&gt;
&lt;li&gt;Per-request cost;&lt;/li&gt;
&lt;li&gt;Historical success rate;&lt;/li&gt;
&lt;li&gt;Average response time;&lt;/li&gt;
&lt;li&gt;Output format error rate;&lt;/li&gt;
&lt;li&gt;Task-level accuracy.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is far more practical than sending every request to whichever model is currently the most popular.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. Build a Minimum Viable Model Evaluation Set
&lt;/h2&gt;

&lt;p&gt;Before switching models, prepare at least a set of real request samples. Do not rely solely on a few manually written demos, because demos are often unrealistically ideal.&lt;/p&gt;

&lt;p&gt;Your evaluation set can include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Anonymized real user inputs;&lt;/li&gt;
&lt;li&gt;Historical failure cases;&lt;/li&gt;
&lt;li&gt;Edge cases;&lt;/li&gt;
&lt;li&gt;Overly long inputs;&lt;/li&gt;
&lt;li&gt;Multilingual content;&lt;/li&gt;
&lt;li&gt;Tasks with complex formatting requirements;&lt;/li&gt;
&lt;li&gt;Questions that are prone to hallucinations.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Each request should include an expected result or acceptance criteria:&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;"input"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Original user request"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"expected"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"category"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Technical issue"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"must_include"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"cause"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"solution"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"must_not_include"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"unverified facts"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;During evaluation, do not look only at whether the response is fluent. At minimum, compare:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Factual accuracy;&lt;/li&gt;
&lt;li&gt;Instruction compliance;&lt;/li&gt;
&lt;li&gt;Output format validity;&lt;/li&gt;
&lt;li&gt;Response latency;&lt;/li&gt;
&lt;li&gt;Token usage;&lt;/li&gt;
&lt;li&gt;Failure types;&lt;/li&gt;
&lt;li&gt;Business task completion rate.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Failure patterns are particularly important. A model may achieve a good average score while consistently failing on a critical category of requests. Average scores should not conceal this problem.&lt;/p&gt;

&lt;h2&gt;
  
  
  6. Build Observability In from the Start
&lt;/h2&gt;

&lt;p&gt;At a minimum, each model call should record information such as:&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;"request_id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"req_123"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"model"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"model-a"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"task"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"extract_product_info"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"input_tokens"&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;"output_tokens"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;380&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"latency_ms"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1450&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"status"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"success"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"validation"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"passed"&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;However, do not automatically log complete user inputs and model outputs. When privacy, business confidentiality, or personal data is involved, use masking, truncation, or hashing.&lt;/p&gt;

&lt;p&gt;Observability is not only for tracking costs. More importantly, it helps answer key production questions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Which model fails most often on which tasks?&lt;/li&gt;
&lt;li&gt;Are output-format errors concentrated in a particular type of Prompt?&lt;/li&gt;
&lt;li&gt;Is rising latency caused by the model or by longer inputs?&lt;/li&gt;
&lt;li&gt;Does fallback actually improve the business success rate?&lt;/li&gt;
&lt;li&gt;Has lower cost come at the expense of too much quality?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Without this data, “model optimization” often becomes nothing more than switching models based on intuition.&lt;/p&gt;

&lt;h2&gt;
  
  
  7. Use a Unified API to Reduce Integration Costs, but Do Not Skip Compatibility Testing
&lt;/h2&gt;

&lt;p&gt;If every new model requires separately maintaining authentication methods, request formats, error handling, and logging logic, multi-model development can quickly turn into a provider-adaptation project.&lt;/p&gt;

&lt;p&gt;Using a unified API and an OpenAI-compatible interface can reduce low-level integration differences and make it easier to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Integrate multiple models;&lt;/li&gt;
&lt;li&gt;Switch between models;&lt;/li&gt;
&lt;li&gt;Centralize configuration;&lt;/li&gt;
&lt;li&gt;Compare models during development;&lt;/li&gt;
&lt;li&gt;Add backup models.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;However, this only reduces integration costs. It does not replace compatibility testing. Before production deployment, you still need to verify parameter support, context limits, output structures, and error behavior for each model.&lt;/p&gt;

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

&lt;p&gt;The difficulty of building a multi-model system has never been simply sending requests. The real challenge is keeping the system controllable when models change, APIs fluctuate, and outputs become unstable.&lt;/p&gt;

&lt;p&gt;A practical approach is to build a unified calling layer, establish task-level routing, validate outputs, classify errors, and continuously evaluate model performance using real requests.&lt;/p&gt;

&lt;p&gt;TokenBay provides access to models such as GPT, Claude, Gemini, and GLM through a unified API and an OpenAI-compatible interface. It can help reduce the development costs of integrating and switching between multiple models, while also making model comparisons easier during development.&lt;/p&gt;

&lt;p&gt;Try Tokenbay：&lt;a href="https://www.tokenbay.com/?utm_source=devto&amp;amp;utm_medium=community_content&amp;amp;utm_campaign=week1_free_content" rel="noopener noreferrer"&gt;https://www.tokenbay.com/?utm_source=devto&amp;amp;utm_medium=community_content&amp;amp;utm_campaign=week1_free_content&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Ultimately, system reliability is not determined by how many models you integrate. It is determined by whether you have genuinely verified how they perform.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>llm</category>
      <category>python</category>
      <category>api</category>
    </item>
    <item>
      <title>Why Does the Same Prompt Behave Differently Across AI Models?</title>
      <dc:creator>GWEN</dc:creator>
      <pubDate>Tue, 14 Jul 2026 09:40:42 +0000</pubDate>
      <link>https://dev.to/gwenj/why-does-the-same-prompt-behave-differently-across-ai-models-4nnk</link>
      <guid>https://dev.to/gwenj/why-does-the-same-prompt-behave-differently-across-ai-models-4nnk</guid>
      <description>&lt;p&gt;A prompt can work well with one model and produce poor results with another. This is not necessarily a bug in your application.&lt;/p&gt;

&lt;p&gt;Different models may interpret instructions differently, prioritize context differently, or have different strengths in reasoning, coding, and structured output. Even when they support the same API format, their behavior is not identical.&lt;/p&gt;

&lt;h3&gt;
  
  
  Common Sources of Inconsistency
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Instruction following&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Some models follow output constraints strictly, while others may ignore part of the requested format when the prompt becomes complex.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Context handling&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;A model may perform well with short context but struggle when the prompt contains long documents, multiple examples, or conflicting instructions.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Reasoning style&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Models can reach different conclusions from the same information because their training, reasoning behavior, and response strategies are different.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Output formatting&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;JSON, tool calls, and structured responses may require different prompt designs and validation rules across models.&lt;/p&gt;

&lt;h3&gt;
  
  
  How Should Developers Handle This?
&lt;/h3&gt;

&lt;p&gt;Treat model changes as compatibility testing, not just configuration changes.&lt;/p&gt;

&lt;p&gt;A practical approach is to create a small evaluation set containing real user requests. Test each model against the same cases and compare:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Factual accuracy&lt;/li&gt;
&lt;li&gt;Instruction compliance&lt;/li&gt;
&lt;li&gt;Output format validity&lt;/li&gt;
&lt;li&gt;Latency&lt;/li&gt;
&lt;li&gt;Token usage&lt;/li&gt;
&lt;li&gt;Failure patterns&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Also avoid relying on one “perfect prompt.” A prompt that works for one model may need different instructions, examples, or validation logic elsewhere.&lt;/p&gt;

&lt;p&gt;Using multiple models can improve flexibility, but only if your application is designed to handle behavioral differences. A unified API can simplify access to different models, while the application still needs model-specific testing and safeguards.&lt;/p&gt;

&lt;p&gt;TokenBay provides access to models such as GPT, Claude, Gemini, and GLM through a unified API, which can make this kind of model comparison easier during development.&lt;/p&gt;

&lt;p&gt;Try Tokenbay：&lt;a href="https://www.tokenbay.com/?utm_source=devto&amp;amp;utm_medium=community_content&amp;amp;utm_campaign=week1_free_content" rel="noopener noreferrer"&gt;https://www.tokenbay.com/?utm_source=devto&amp;amp;utm_medium=community_content&amp;amp;utm_campaign=week1_free_content&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The difficult part of multi-model development is not sending the request. It is knowing whether the response is reliable enough to use.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>python</category>
      <category>discuss</category>
      <category>api</category>
    </item>
  </channel>
</rss>
