<?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: Ye Allen</title>
    <description>The latest articles on DEV Community by Ye Allen (@ye_allen_).</description>
    <link>https://dev.to/ye_allen_</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%2F3919611%2F58403f09-105c-4557-bc25-ab555b7b4a22.png</url>
      <title>DEV Community: Ye Allen</title>
      <link>https://dev.to/ye_allen_</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/ye_allen_"/>
    <language>en</language>
    <item>
      <title>Your AI Job Failed. Don’t Lose the Evidence.</title>
      <dc:creator>Ye Allen</dc:creator>
      <pubDate>Fri, 31 Jul 2026 05:18:35 +0000</pubDate>
      <link>https://dev.to/ye_allen_/your-ai-job-failed-dont-lose-the-evidence-496h</link>
      <guid>https://dev.to/ye_allen_/your-ai-job-failed-dont-lose-the-evidence-496h</guid>
      <description>&lt;p&gt;Retries are useful.&lt;/p&gt;

&lt;p&gt;But some AI jobs still fail.&lt;/p&gt;

&lt;p&gt;A document extraction task exhausts its retries. An agent stops after a tool timeout. A RAG indexing job cannot access a source file. A batch workflow hits a context limit.&lt;/p&gt;

&lt;p&gt;What happens next?&lt;/p&gt;

&lt;p&gt;If the answer is “write an error log and move on,” the application is losing more than a request.&lt;/p&gt;

&lt;p&gt;It is losing the evidence needed to understand, repair, and safely replay the work.&lt;/p&gt;

&lt;p&gt;This is where dead letter queues matter.&lt;/p&gt;

&lt;h2&gt;
  
  
  A dead letter queue is a recovery boundary
&lt;/h2&gt;

&lt;p&gt;A dead letter queue, or DLQ, holds jobs that could not be completed safely after their normal retry policy was exhausted.&lt;/p&gt;

&lt;p&gt;It is not a place to hide errors.&lt;/p&gt;

&lt;p&gt;It is a place to preserve failure context.&lt;/p&gt;

&lt;p&gt;For AI workflows, that context can include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the workflow name&lt;/li&gt;
&lt;li&gt;a reference to the input data&lt;/li&gt;
&lt;li&gt;the selected model and route&lt;/li&gt;
&lt;li&gt;prompt or configuration version&lt;/li&gt;
&lt;li&gt;retry count&lt;/li&gt;
&lt;li&gt;fallback history&lt;/li&gt;
&lt;li&gt;error classification&lt;/li&gt;
&lt;li&gt;whether the job is safe to replay&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That is much more useful than a line that says &lt;code&gt;request failed&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  AI failures are rarely just provider failures
&lt;/h2&gt;

&lt;p&gt;A failed model request can be caused by many things:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;a temporary provider outage&lt;/li&gt;
&lt;li&gt;a rate limit&lt;/li&gt;
&lt;li&gt;an oversized context&lt;/li&gt;
&lt;li&gt;invalid structured output&lt;/li&gt;
&lt;li&gt;a missing source document&lt;/li&gt;
&lt;li&gt;broken retrieval&lt;/li&gt;
&lt;li&gt;a tool-call timeout&lt;/li&gt;
&lt;li&gt;an unsupported parameter&lt;/li&gt;
&lt;li&gt;an unapproved model route&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Some of these problems may recover with a retry.&lt;/p&gt;

&lt;p&gt;Others need a prompt change, a schema fix, a route change, or manual review.&lt;/p&gt;

&lt;p&gt;A DLQ stops the system from pretending that every failure has the same solution.&lt;/p&gt;

&lt;h2&gt;
  
  
  What should an AI DLQ record?
&lt;/h2&gt;

&lt;p&gt;A useful record might look like this:&lt;/p&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
json
{
  "job_id": "job_8421",
  "workflow": "document_extraction",
  "payload_reference": "file_2388",
  "model": "model-a",
  "model_config_version": "v12",
  "route": "primary",
  "attempt_count": 3,
  "fallback_used": true,
  "error_class": "structured_output_validation",
  "last_error": "Required field missing",
  "safe_to_replay": true
}
Notice what is missing: a requirement to store every raw prompt forever.
Sensitive inputs may require masking, encryption, access controls, or a reference to the original source instead of a full payload copy.
The important part is keeping enough context to investigate the failure.
A DLQ should not become an invisible retry loop
A common mistake is to automatically replay every dead-lettered job every few hours.
That is just a retry loop with a longer delay.
Before replaying a failed job, ask:
Is the provider healthy again?
Did the model configuration change?
Was the input too large?
Is the original source still available?
Did the job already trigger an external action?
Is replaying it safe?
Should it use the same model route or a reviewed replacement?
A job that failed because of a temporary timeout may be safe to replay.
A job that failed because the JSON schema was wrong needs repair first.
A job that sent an external email may need manual approval.
Separate capture, diagnosis, and replay
A clean workflow has three stages:
Capture the failed job in the DLQ.
Diagnose the actual failure cause.
Replay or repair the job deliberately.
For example:
Primary model returns invalid JSON
→ retry with a constrained prompt
→ fallback route also fails validation
→ send the job to the DLQ
→ inspect source file and output schema
→ update the configuration
→ replay selected failed jobs
This is much safer than repeatedly changing models until a request happens to succeed.
A DLQ is also product feedback
Failed jobs reveal where the product needs work.
A DLQ may show that:
one document type breaks extraction
a prompt fails for long inputs
a model route struggles with multilingual content
a provider limit affects batch traffic
a tool integration frequently times out
a model update changed structured-output behavior
Track metrics such as:
failed jobs by workflow
failure rate by model and route
retry exhaustion rate
time spent in the DLQ
replay success rate
repeated error classes
cost of failed and replayed jobs
The goal is not merely to replay failed work.
It is to reduce the reasons work reaches the queue.
Final thought
Retries help with temporary failures.
Dead letter queues help with failures that are not temporary.
They prevent silent data loss, preserve the context needed for debugging, and make replay an operational decision rather than an automatic gamble.
VectorNode helps teams access, manage, monitor, and optimize global and Chinese frontier models through one multi-model AI infrastructure layer.
https://www.vectronode.com/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

</description>
      <category>ai</category>
      <category>api</category>
      <category>llm</category>
      <category>devops</category>
    </item>
    <item>
      <title>Your AI Dashboard Is Not Your Product Telemetry</title>
      <dc:creator>Ye Allen</dc:creator>
      <pubDate>Thu, 30 Jul 2026 05:24:54 +0000</pubDate>
      <link>https://dev.to/ye_allen_/your-ai-dashboard-is-not-your-product-telemetry-46lc</link>
      <guid>https://dev.to/ye_allen_/your-ai-dashboard-is-not-your-product-telemetry-46lc</guid>
      <description>&lt;p&gt;Most AI teams can tell you which model they used last month.&lt;br&gt;
Far fewer can answer a more useful question:&lt;br&gt;
Which product feature created this AI usage, and did it improve anything for the user?&lt;/p&gt;

&lt;p&gt;That is the gap between an AI dashboard and product telemetry.&lt;br&gt;
An API dashboard can show requests, token usage, and errors. That is necessary. But it does not automatically explain whether a spike came from a successful feature launch, a retry loop, longer conversation history, or a routing change that affected only one workflow.&lt;br&gt;
If you are building multi-model AI features, model-level totals are not enough.&lt;br&gt;
Start with product features, not models&lt;br&gt;
The first mistake is organizing all analysis around model names.&lt;br&gt;
A model is an implementation choice. A product feature is where users receive value.&lt;br&gt;
Instead of beginning with:&lt;br&gt;
Which model used the most tokens?&lt;br&gt;
Which route had the most requests?&lt;br&gt;
Start with:&lt;br&gt;
Did support_reply become more expensive after the latest release?&lt;br&gt;
Is knowledge_search creating more context than expected?&lt;br&gt;
Did document_summary improve after a model change?&lt;br&gt;
Are retries concentrated in one product flow?&lt;br&gt;
A small feature taxonomy is enough to begin:&lt;br&gt;
support_reply&lt;br&gt;
document_summary&lt;br&gt;
knowledge_search&lt;br&gt;
agent_action&lt;br&gt;
image_variant&lt;br&gt;
The naming does not need to be perfect. It needs to be stable.&lt;br&gt;
Add a small application-side trace&lt;br&gt;
Your application already knows why it is calling an AI model. Preserve that context without collecting unnecessary prompt data.&lt;br&gt;
A minimal internal record can look like this:&lt;br&gt;
{&lt;br&gt;
  "request_id": "req_8f1...",&lt;br&gt;
  "feature": "support_reply",&lt;br&gt;
  "release": "2026.07.30",&lt;br&gt;
  "model_id": "your-selected-model",&lt;br&gt;
  "route": "primary"&lt;br&gt;
}&lt;br&gt;
This is not a replacement for API logs. It is the missing product context around them.&lt;br&gt;
The important fields are:&lt;br&gt;
A request identifier&lt;br&gt;
The product feature&lt;br&gt;
The release or configuration version&lt;br&gt;
The selected model and route&lt;br&gt;
A safe link to the application event&lt;br&gt;
Avoid storing raw prompts, private documents, or user data unless there is a clear operational reason and an appropriate data policy.&lt;br&gt;
Use two views of the same request&lt;br&gt;
Platform data and product data answer different questions.&lt;br&gt;
API logs and token statistics help you review what happened at the integration layer. Application telemetry explains what the user was trying to do.&lt;br&gt;
When you connect the two views, you can investigate real changes:&lt;br&gt;
A feature launch increases requests: expected growth or accidental loop?&lt;br&gt;
A model route changes: did output quality improve for that workflow?&lt;br&gt;
Token usage rises: longer inputs, a broken context policy, or a more valuable user task?&lt;br&gt;
Retries increase: one unstable path or a broader application issue?&lt;br&gt;
Without feature context, all of these changes look like “usage went up.”&lt;br&gt;
That is not actionable.&lt;br&gt;
Compare releases, not only totals&lt;br&gt;
A monthly total can hide the reason a system changed.&lt;br&gt;
Suppose token usage rises after a release. That is not automatically bad.&lt;br&gt;
Maybe users are uploading longer documents. Maybe the new feature is working. Maybe a conversation flow now includes too much history. Maybe a fallback route is being used more often than intended.&lt;br&gt;
The useful review sequence is simple:&lt;br&gt;
What changed in the product?&lt;br&gt;
Which feature generated the usage?&lt;br&gt;
Which model and route were configured?&lt;br&gt;
Did the user-facing result improve?&lt;br&gt;
This turns AI observability into a product feedback loop instead of a billing exercise.&lt;br&gt;
Build a weekly review habit&lt;br&gt;
You do not need a large observability project to start.&lt;br&gt;
Once a week:&lt;br&gt;
Review a recent API usage window.&lt;br&gt;
Group application traces by feature.&lt;br&gt;
Compare unusual patterns with releases or configuration changes.&lt;br&gt;
Select one question to investigate.&lt;br&gt;
Create one action: a regression test, a prompt change, a routing rule, or a UI improvement.&lt;br&gt;
The goal is not to create a dashboard nobody revisits.&lt;br&gt;
The goal is to make one better decision every week.&lt;br&gt;
Keep the integration layer and product layer separate&lt;br&gt;
For teams using an AI API gateway, this separation becomes even more important as the model catalog expands.&lt;br&gt;
VectorNode currently provides Logs, token statistics, and data export functions. Use those signals to understand API activity, then combine them with your own feature-level traces to understand product impact.&lt;br&gt;
A model name is useful. A request count is useful.&lt;br&gt;
But the question that matters most is still:&lt;br&gt;
What did this AI request do for the product?&lt;/p&gt;

&lt;p&gt;That is the number worth learning to measure.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>api</category>
      <category>llm</category>
      <category>devops</category>
    </item>
    <item>
      <title>Retries Are Not a Reliability Strategy for AI Apps</title>
      <dc:creator>Ye Allen</dc:creator>
      <pubDate>Wed, 29 Jul 2026 05:42:21 +0000</pubDate>
      <link>https://dev.to/ye_allen_/retries-are-not-a-reliability-strategy-for-ai-apps-9ol</link>
      <guid>https://dev.to/ye_allen_/retries-are-not-a-reliability-strategy-for-ai-apps-9ol</guid>
      <description>&lt;p&gt;A failed AI API request does not always need another AI API request.&lt;/p&gt;

&lt;p&gt;Sometimes a retry fixes a temporary network problem.&lt;/p&gt;

&lt;p&gt;Sometimes it doubles your cost, delays the user, repeats an agent action, and hides the incident you actually need to investigate.&lt;/p&gt;

&lt;p&gt;For multi-model AI products, retries are not a small implementation detail.&lt;/p&gt;

&lt;p&gt;They are part of the reliability architecture.&lt;/p&gt;

&lt;h2&gt;
  
  
  A retry, a fallback, and a fix are different actions
&lt;/h2&gt;

&lt;p&gt;When an AI request fails, a system has three possible responses:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Retry the same route because the failure may be temporary.&lt;/li&gt;
&lt;li&gt;Fall back to another route because the primary route is unhealthy or unsuitable.&lt;/li&gt;
&lt;li&gt;Stop and fix the request, workflow, or input.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Treating all three as “retry” creates expensive and confusing behavior.&lt;/p&gt;

&lt;p&gt;For example, a timeout may justify retrying the same provider.&lt;/p&gt;

&lt;p&gt;A context-window error will not.&lt;/p&gt;

&lt;p&gt;Invalid JSON may require a constrained repair prompt.&lt;/p&gt;

&lt;p&gt;A poor RAG answer may require inspecting retrieval rather than changing models.&lt;/p&gt;

&lt;p&gt;A failed tool call may require retrying the tool, not the full model request.&lt;/p&gt;

&lt;h2&gt;
  
  
  Classify failures before writing retry code
&lt;/h2&gt;

&lt;p&gt;A useful policy starts with failure classification.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Failure&lt;/th&gt;
&lt;th&gt;Recommended action&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Temporary network timeout&lt;/td&gt;
&lt;td&gt;Retry with backoff&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Provider 5xx response&lt;/td&gt;
&lt;td&gt;Retry a limited number of times&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Rate limit&lt;/td&gt;
&lt;td&gt;Respect retry timing and reduce pressure&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Stream interrupted before output&lt;/td&gt;
&lt;td&gt;Retry only when safe&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Invalid API key or malformed request&lt;/td&gt;
&lt;td&gt;Fail fast&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Context too large&lt;/td&gt;
&lt;td&gt;Reduce or summarize context&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Invalid JSON output&lt;/td&gt;
&lt;td&gt;Repair or retry with a tighter schema&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Tool execution failure&lt;/td&gt;
&lt;td&gt;Check tool state before retrying&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Bad RAG answer&lt;/td&gt;
&lt;td&gt;Inspect retrieval and context first&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The goal is not to maximize retry count.&lt;/p&gt;

&lt;p&gt;The goal is to recover from temporary failures without repeating predictable ones.&lt;/p&gt;

&lt;h2&gt;
  
  
  Every workflow needs a retry budget
&lt;/h2&gt;

&lt;p&gt;A support chatbot and a batch extraction job should not share the same retry policy.&lt;/p&gt;

&lt;p&gt;A chatbot has a user waiting for a first response.&lt;/p&gt;

&lt;p&gt;A batch job can tolerate longer recovery time.&lt;/p&gt;

&lt;p&gt;An agent may call external tools that should never run twice without checking state.&lt;/p&gt;

&lt;p&gt;A practical policy defines:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;maximum retry count&lt;/li&gt;
&lt;li&gt;maximum total waiting time&lt;/li&gt;
&lt;li&gt;maximum extra cost or token budget&lt;/li&gt;
&lt;li&gt;backoff timing&lt;/li&gt;
&lt;li&gt;fallback conditions&lt;/li&gt;
&lt;li&gt;idempotency requirements&lt;/li&gt;
&lt;li&gt;alert or queue conditions&lt;/li&gt;
&lt;/ul&gt;

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



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
yaml
workflow: support_chat

retry:
  max_attempts: 1
  max_wait_ms: 3000
  retry_on:
    - timeout
    - provider_5xx

fallback:
  enabled: true
  after_primary_failure: true

priority:
  - fast_first_token
  - user_feedback
A batch workflow may allow more attempts, but it should still have a cost boundary.
Without a budget, a temporary failure can turn one intended request into several expensive requests.
Retries can create product failures
A request may eventually return a 200 response while the product experience is already broken.
Imagine a support assistant that waits eight seconds after repeated retries.
Or a coding agent that repeats a tool action after its response times out.
Or a document-extraction workflow that calls an expensive reasoning model twice for every failed file.
These are not only infrastructure problems.
They affect customer experience, unit economics, and trust.
Idempotency matters most for agents
AI agents often call tools that change the world.
They create tickets, send emails, update records, trigger automations, or make purchases.
If a tool response times out, the action may have completed even though the agent did not receive the result.
Retrying the full workflow without checking state can duplicate the action.
Use a request ID and record tool execution status before allowing a retry.
A safe agent workflow should know the difference between:
the tool never started
the tool is still running
the tool completed but the response was lost
the tool failed before making a change
This is where ordinary retry logic becomes operational design.
Retry the route carefully, not immediately
Retries should use exponential backoff with jitter.
A burst of failed requests should not return to the same provider at the same instant.
A simple pattern might be:
Attempt 1: wait about 500 ms
Attempt 2: wait about 1 second
Attempt 3: wait about 2 seconds
The exact limits depend on the workflow and provider guidance.
The important part is avoiding tight retry loops that turn a provider issue into a larger traffic spike.
Log retries and fallbacks separately
A retry is not the same as a fallback.
A retry repeats the same route.
A fallback changes the route.
Your logs should show both:
{
  "request_id": "req_8421",
  "workflow": "rag_answer",
  "primary_model": "model-a",
  "retry_count": 1,
  "retry_reason": "provider_timeout",
  "fallback_used": true,
  "final_model": "model-b",
  "total_latency_ms": 6840,
  "successful_task": true
}
Without this visibility, teams cannot explain why a request became slow, expensive, or inconsistent.
Final thought
Reliable AI systems do not retry everything.
They retry temporary failures, fail fast on predictable errors, protect external actions with idempotency, and limit how much extra latency and cost a request can consume.
VectorNode helps teams access, manage, monitor, and optimize global and Chinese frontier models through one multi-model infrastructure layer.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

</description>
      <category>ai</category>
      <category>api</category>
      <category>llm</category>
      <category>devops</category>
    </item>
    <item>
      <title>Stop Testing New AI Models in Production</title>
      <dc:creator>Ye Allen</dc:creator>
      <pubDate>Tue, 28 Jul 2026 06:00:15 +0000</pubDate>
      <link>https://dev.to/ye_allen_/stop-testing-new-ai-models-in-production-2bfi</link>
      <guid>https://dev.to/ye_allen_/stop-testing-new-ai-models-in-production-2bfi</guid>
      <description>&lt;p&gt;A new AI model appears.&lt;br&gt;
The benchmark looks strong. The context window is larger. The price is attractive.&lt;br&gt;
So someone changes one configuration value in production.&lt;br&gt;
That is how an experiment becomes an incident.&lt;br&gt;
AI teams need to treat model access the same way they treat databases, feature flags, and deployment environments: development, staging, and production should have different rules.&lt;br&gt;
One API key is not an environment strategy&lt;br&gt;
A modern AI product may use different models for:&lt;br&gt;
support chat&lt;br&gt;
RAG answers&lt;br&gt;
coding agents&lt;br&gt;
document extraction&lt;br&gt;
multilingual workflows&lt;br&gt;
batch jobs&lt;br&gt;
image or video analysis&lt;br&gt;
When development, staging, and production all use the same credentials, model allowlist, and routing rules, a small experiment can affect real users.&lt;br&gt;
Common failures look like this:&lt;br&gt;
A developer test consumes the production budget.&lt;br&gt;
An unreviewed model receives customer-like data.&lt;br&gt;
A fallback route is enabled without cost checks.&lt;br&gt;
A model update changes JSON behavior in a live workflow.&lt;br&gt;
A long-context experiment raises latency for everyone.&lt;br&gt;
The problem is not having many models.&lt;br&gt;
The problem is having no boundary between experimenting with models and operating a product.&lt;br&gt;
Development should optimize for learning&lt;br&gt;
Development is the right place to try new models, prompts, context sizes, tool definitions, and routing ideas.&lt;br&gt;
It should be flexible, but controlled.&lt;br&gt;
A development environment can allow:&lt;br&gt;
experimental models&lt;br&gt;
lower-cost models for routine testing&lt;br&gt;
synthetic or anonymized data&lt;br&gt;
strict spend limits&lt;br&gt;
verbose request logs&lt;br&gt;
temporary feature flags&lt;br&gt;
shorter rate-limit windows&lt;br&gt;
The goal is fast feedback.&lt;br&gt;
A developer should be able to compare GPT, Claude, Gemini, DeepSeek, Qwen, Kimi, GLM, MiniMax, and other models without silently changing what customers receive.&lt;br&gt;
Staging should test the real workflow&lt;br&gt;
A playground prompt is not a production test.&lt;br&gt;
A model can look excellent in isolation and still fail when it has to work with retrieved context, tool calls, structured outputs, long histories, or production-like traffic.&lt;br&gt;
Staging is where teams should answer questions such as:&lt;br&gt;
Does the model return valid JSON for our schema?&lt;br&gt;
Does it use retrieved context correctly?&lt;br&gt;
How long does the first token take?&lt;br&gt;
Does the fallback route preserve output quality?&lt;br&gt;
What happens after a tool call retries?&lt;br&gt;
Is the cost still acceptable at realistic prompt sizes?&lt;br&gt;
A useful staging configuration might look like this:&lt;br&gt;
environment: staging&lt;/p&gt;

&lt;p&gt;allowed_models:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;primary_candidate&lt;/li&gt;
&lt;li&gt;fallback_candidate&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;data_policy:&lt;br&gt;
  allow_customer_data: false&lt;br&gt;
  use_anonymized_samples: true&lt;/p&gt;

&lt;p&gt;release_checks:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;structured_output_pass_rate&lt;/li&gt;
&lt;li&gt;p95_time_to_first_token&lt;/li&gt;
&lt;li&gt;successful_task_rate&lt;/li&gt;
&lt;li&gt;cost_per_successful_task&lt;/li&gt;
&lt;li&gt;fallback_behavior
Staging should be realistic enough to expose risk, but isolated enough that a failed experiment cannot become a customer problem.
Production should use approved model routes
Production needs a smaller, clearer model surface.
Each workflow should have an approved route, a defined fallback, and measurable success criteria.
For example:
Workflow    Production priority
Support chat    Fast first token, reliable streaming
RAG Grounded answers, retrieval quality
Coding agent    Tool-call reliability, task completion
Extraction  Valid structured output
Batch jobs  Throughput and cost control&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This means production configuration should answer:&lt;br&gt;
Which models are approved?&lt;br&gt;
Which route handles each workflow?&lt;br&gt;
When is fallback allowed?&lt;br&gt;
Which teams can change the route?&lt;br&gt;
What metric triggers a rollback?&lt;br&gt;
How are usage and cost monitored?&lt;br&gt;
If those answers are missing, model selection is still an individual preference, not an operational system.&lt;br&gt;
A model switch is a release&lt;br&gt;
Changing a model can change much more than answer quality.&lt;br&gt;
It can affect:&lt;br&gt;
latency&lt;br&gt;
token usage&lt;br&gt;
tool-call behavior&lt;br&gt;
refusal behavior&lt;br&gt;
multilingual performance&lt;br&gt;
context handling&lt;br&gt;
output formatting&lt;br&gt;
cost per successful task&lt;br&gt;
That makes a model switch a release.&lt;br&gt;
The safer path is simple:&lt;br&gt;
Explore in development.&lt;br&gt;
Evaluate the workflow in staging.&lt;br&gt;
Approve the route for production.&lt;br&gt;
Monitor quality, latency, usage, and cost.&lt;br&gt;
Keep a rollback path ready.&lt;br&gt;
Final thought&lt;br&gt;
The teams that adopt new models fastest are not the teams that send every new release directly to production.&lt;br&gt;
They are the teams that can test quickly because their environments, permissions, routes, and monitoring are already separated.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>api</category>
      <category>llm</category>
      <category>devops</category>
    </item>
    <item>
      <title>Your AI App Feels Slow Before the Model Starts Talking</title>
      <dc:creator>Ye Allen</dc:creator>
      <pubDate>Mon, 27 Jul 2026 09:07:53 +0000</pubDate>
      <link>https://dev.to/ye_allen_/your-ai-app-feels-slow-before-the-model-starts-talking-1b5a</link>
      <guid>https://dev.to/ye_allen_/your-ai-app-feels-slow-before-the-model-starts-talking-1b5a</guid>
      <description>&lt;p&gt;Getting an AI request to return successfully is not the same as making an AI product feel responsive.&lt;/p&gt;

&lt;p&gt;In an interactive product, users notice the silence before they notice the final completion time.&lt;/p&gt;

&lt;p&gt;They ask:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Did the request start?&lt;/li&gt;
&lt;li&gt;Is the model thinking?&lt;/li&gt;
&lt;li&gt;Should I retry?&lt;/li&gt;
&lt;li&gt;Did the app freeze?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That is why time to first token, or TTFT, deserves its own metric in multi-model AI applications.&lt;/p&gt;

&lt;h2&gt;
  
  
  A faster completion can still feel slower
&lt;/h2&gt;

&lt;p&gt;Imagine two models used in a support chatbot.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Model A starts streaming in 700 ms and finishes in 8 seconds.&lt;/li&gt;
&lt;li&gt;Model B starts streaming in 4 seconds and finishes in 6 seconds.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Model B has a lower total completion time.&lt;/p&gt;

&lt;p&gt;But it may still feel slower to the user because nothing happens for the first four seconds.&lt;/p&gt;

&lt;p&gt;This distinction matters even more when an app uses multiple models for chat, RAG, coding agents, document analysis, automation, and background work.&lt;/p&gt;

&lt;p&gt;A single average latency number cannot explain the real experience.&lt;/p&gt;

&lt;h2&gt;
  
  
  What TTFT actually measures
&lt;/h2&gt;

&lt;p&gt;Time to first token is the time between sending a request and receiving the first visible streamed response.&lt;/p&gt;

&lt;p&gt;It can include more than model generation:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;authentication and request validation&lt;/li&gt;
&lt;li&gt;queue time&lt;/li&gt;
&lt;li&gt;model routing&lt;/li&gt;
&lt;li&gt;retrieval&lt;/li&gt;
&lt;li&gt;provider connection time&lt;/li&gt;
&lt;li&gt;prompt prefill&lt;/li&gt;
&lt;li&gt;reasoning effort&lt;/li&gt;
&lt;li&gt;tool preparation&lt;/li&gt;
&lt;li&gt;fallback decisions&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A slow TTFT does not always mean the selected model is slow.&lt;/p&gt;

&lt;p&gt;The problem may be a large prompt, a cache miss, a slow retrieval step, a tool call that blocks streaming, or a fallback route.&lt;/p&gt;

&lt;p&gt;That is why teams need request-level visibility.&lt;/p&gt;

&lt;h2&gt;
  
  
  Multi-model systems have multiple latency profiles
&lt;/h2&gt;

&lt;p&gt;Different models can behave very differently in production.&lt;/p&gt;

&lt;p&gt;A model may be excellent for batch reasoning but unsuitable for a live chat experience. Another may stream quickly but take longer to complete. A reasoning model may spend more time before producing a first token. A fallback model may protect availability while quietly worsening the user experience.&lt;/p&gt;

&lt;p&gt;Do not ask:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;What is our AI latency?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Ask:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;What is the p95 time to first token for this workflow, this model, this route, and this prompt size?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That question leads to better decisions.&lt;/p&gt;

&lt;h2&gt;
  
  
  Log the right fields
&lt;/h2&gt;

&lt;p&gt;For every AI request, record more than the HTTP status code.&lt;/p&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
json
{
  "request_id": "req_123",
  "workflow": "support_chat",
  "model": "model-name",
  "route": "primary",
  "streaming": true,
  "input_tokens": 12400,
  "output_tokens": 860,
  "ttft_ms": 920,
  "total_latency_ms": 7400,
  "cache_hit": true,
  "tool_calls": 0,
  "fallback_used": false,
  "success": true
}
This makes it possible to answer useful questions:
Does TTFT rise when prompts become larger?
Which model route has the slowest p95 first token?
Are cache misses creating visible delays?
Does a fallback route improve availability but hurt UX?
Which workflows need streaming most?
Are retries increasing total wait time?
Different workflows need different targets
A customer-support chatbot needs a fast first visible response.
A RAG workflow may need fast retrieval plus clear streaming.
A coding agent may need an early progress event such as "Reading repository" or "Running tests," even if the full task takes longer.
A batch extraction job may not need streaming at all. Its priorities may be throughput, reliability, and cost.
A useful latency policy might look like this:
Workflow    Primary metric
Chatbot Low TTFT
RAG answer  Retrieval time + TTFT
Coding agent    Early progress + successful completion
Background batch job    Throughput + cost per completed task
Automation workflow Retry rate + reliable completion

The goal is not to make every model behave the same way.
The goal is to match the model and route to the user experience the workflow requires.
Measure percentiles, not only averages
Average latency hides bad experiences.
If nine requests return their first token in one second and one request takes 20 seconds, the average may look acceptable. The user waiting 20 seconds will disagree.
Track at least:
p50 TTFT
p95 TTFT
p99 TTFT
p95 total latency
timeout rate
retry rate
fallback rate
successful task completion rate
The p95 metrics usually reveal whether production traffic is becoming unhealthy.
Improve the experience before replacing the model
When first-token latency gets worse, changing models is not always the best first move.
Check whether:
unnecessary history is being sent
context caching is working
retrieval blocks streaming
a tool call happens before any progress is visible
the route has fallen back
reasoning effort is too high for the task
batch traffic competes with interactive traffic
Sometimes a smaller prompt, a better route, or an earlier progress event improves the product more than a model switch.
Final thought
Users do not experience an AI application as an API status code.
They experience waiting.
For multi-model products, time to first token is not only an infrastructure metric. It is a product metric.
Teams that track TTFT alongside total latency, cost, retries, routing, and successful task completion can build AI applications that feel faster and behave more reliably.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

</description>
      <category>ai</category>
      <category>api</category>
      <category>llm</category>
      <category>testing</category>
    </item>
    <item>
      <title>A 1M Context Window Is Not a 1M-Token Budget for Your AI Agent</title>
      <dc:creator>Ye Allen</dc:creator>
      <pubDate>Fri, 24 Jul 2026 14:28:40 +0000</pubDate>
      <link>https://dev.to/ye_allen_/a-1m-context-window-is-not-a-1m-token-budget-for-your-ai-agent-2k2d</link>
      <guid>https://dev.to/ye_allen_/a-1m-context-window-is-not-a-1m-token-budget-for-your-ai-agent-2k2d</guid>
      <description>&lt;p&gt;A 1M-token context window is a capacity limit.&lt;/p&gt;

&lt;p&gt;It is not an operating budget.&lt;/p&gt;

&lt;p&gt;A long-context model makes it tempting to send an agent the whole repository, every retrieved document, and its full tool history on every turn.&lt;/p&gt;

&lt;p&gt;That can still produce a slow, expensive, confused AI system.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Context Window Is Already Spoken For
&lt;/h2&gt;

&lt;p&gt;An agent does not use context only for user instructions.&lt;/p&gt;

&lt;p&gt;It also needs room for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;system instructions&lt;/li&gt;
&lt;li&gt;tool definitions&lt;/li&gt;
&lt;li&gt;retrieved documents&lt;/li&gt;
&lt;li&gt;source files&lt;/li&gt;
&lt;li&gt;tool outputs&lt;/li&gt;
&lt;li&gt;prior messages&lt;/li&gt;
&lt;li&gt;structured output requirements&lt;/li&gt;
&lt;li&gt;the next model response&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Even when all of that fits within the model limit, the result can be poor.&lt;/p&gt;

&lt;p&gt;More context can mean more irrelevant files, weaker retrieval focus, longer prefill time, and higher token cost.&lt;/p&gt;

&lt;p&gt;A model with 1M tokens of context does not mean every task should use 1M tokens.&lt;/p&gt;

&lt;h2&gt;
  
  
  A Recent Example: Kimi K3
&lt;/h2&gt;

&lt;p&gt;Kimi K3 is a useful reminder that context length is also a cost and operations decision.&lt;/p&gt;

&lt;p&gt;Kimi Code documents both a 1M-context K3 option and a 256K-context option. Its documentation notes that the 1M version uses about twice as much quota as the 256K version.&lt;/p&gt;

&lt;p&gt;It also warns that switching model IDs or reasoning effort can invalidate the existing context cache, forcing the context to be prefilled again.&lt;/p&gt;

&lt;p&gt;That means a model switch in the middle of a long agent session is not just a quality decision.&lt;/p&gt;

&lt;p&gt;It can immediately become a latency and cost decision.&lt;/p&gt;

&lt;p&gt;The same principle applies to any multi-model AI application.&lt;/p&gt;

&lt;h2&gt;
  
  
  Define an Operating Budget
&lt;/h2&gt;

&lt;p&gt;Instead of treating the model's maximum context as your usable input budget, reserve capacity for the work that still has to happen.&lt;/p&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
ts
type ContextBudget = {
  maxContext: number;
  reserveForOutput: number;
  reserveForCompaction: number;
  safetyMargin: number;
};

function getSafeInputBudget(budget: ContextBudget) {
  const usable =
    budget.maxContext -
    budget.reserveForOutput -
    budget.reserveForCompaction;

  return Math.floor(usable * (1 - budget.safetyMargin));
}

const safeInputTokens = getSafeInputBudget({
  maxContext: 1_000_000,
  reserveForOutput: 32_000,
  reserveForCompaction: 64_000,
  safetyMargin: 0.1,
});
The exact numbers will vary by workload.
The important part is that the budget is explicit.
Use Different Budgets for Different Workflows
A support chatbot, RAG workflow, coding agent, and research agent should not share one context policy.
A coding agent may need more room for source files and tool results.
A RAG workflow may need tighter retrieval limits and stronger document ranking.
A batch workflow may tolerate compaction, while an interactive user workflow may need predictable latency.
The model choice should follow the workload.
The context budget should too.
Monitor What Happens Before the Limit
Do not wait for a context overflow error to discover a bad policy.
Track:
context utilization before each request
compaction frequency
retry rate after compaction
retrieval relevance
latency by workflow
cost per successful task
model switches within a session
A request can return 200 OK and still fail the user if it loses critical context, produces invalid output, or becomes too slow to use.
The Production Rule
Long context is powerful when it is intentional.
It is not a substitute for retrieval quality, task boundaries, token budgets, or model-routing rules.
The best AI teams do not ask, “Which model has the largest context window?”
They ask, “How much context does this workflow actually need to succeed reliably?”
When teams evaluate global and Chinese frontier models, they need to compare more than context limits. They need to compare task success, latency, cost, output reliability, and how the model behaves inside a real workflow.
VectorNode helps developers access and evaluate multiple AI models from one infrastructure layer: https://www.vectronode.com/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

</description>
      <category>ai</category>
      <category>api</category>
      <category>llm</category>
      <category>testing</category>
    </item>
    <item>
      <title>Your Model Changed. Did Your AI App Regress?</title>
      <dc:creator>Ye Allen</dc:creator>
      <pubDate>Thu, 23 Jul 2026 06:00:02 +0000</pubDate>
      <link>https://dev.to/ye_allen_/your-model-changed-did-your-ai-app-regress-ple</link>
      <guid>https://dev.to/ye_allen_/your-model-changed-did-your-ai-app-regress-ple</guid>
      <description>&lt;p&gt;A model change does not always create an outage.&lt;/p&gt;

&lt;p&gt;Sometimes the API still returns &lt;code&gt;200&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The chatbot still replies.&lt;/p&gt;

&lt;p&gt;The RAG system still produces an answer.&lt;/p&gt;

&lt;p&gt;The agent still calls a tool.&lt;/p&gt;

&lt;p&gt;But the product has already regressed.&lt;/p&gt;

&lt;p&gt;Maybe the RAG answer is no longer grounded in the retrieved context.&lt;/p&gt;

&lt;p&gt;Maybe a tool call is valid JSON but uses the wrong argument.&lt;/p&gt;

&lt;p&gt;Maybe an extraction workflow now omits a required field.&lt;/p&gt;

&lt;p&gt;Maybe Chinese-language quality drops while English test prompts still look fine.&lt;/p&gt;

&lt;p&gt;Maybe the same task now needs more retries, more tokens, or a more expensive fallback.&lt;/p&gt;

&lt;p&gt;This is why every model update should be treated like a software release.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is an AI regression?
&lt;/h2&gt;

&lt;p&gt;An AI regression is a decline in workflow behavior after a change.&lt;/p&gt;

&lt;p&gt;The change may be a:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;new model version&lt;/li&gt;
&lt;li&gt;new provider route&lt;/li&gt;
&lt;li&gt;prompt update&lt;/li&gt;
&lt;li&gt;temperature change&lt;/li&gt;
&lt;li&gt;retrieval change&lt;/li&gt;
&lt;li&gt;tool-schema change&lt;/li&gt;
&lt;li&gt;fallback-policy change&lt;/li&gt;
&lt;li&gt;newly added model in a multi-model route&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The difficult part is that AI regressions are not always binary.&lt;/p&gt;

&lt;p&gt;A traditional test may ask, “Did the function return the expected value?”&lt;/p&gt;

&lt;p&gt;An AI test often needs to ask:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Was the answer grounded in the supplied context?&lt;/li&gt;
&lt;li&gt;Was the JSON valid and complete?&lt;/li&gt;
&lt;li&gt;Did the agent choose the right tool?&lt;/li&gt;
&lt;li&gt;Did the workflow finish successfully?&lt;/li&gt;
&lt;li&gt;Did latency remain acceptable?&lt;/li&gt;
&lt;li&gt;Did cost per successful task increase?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A response existing is not the same as a workflow succeeding.&lt;/p&gt;

&lt;h2&gt;
  
  
  Build tests around product tasks
&lt;/h2&gt;

&lt;p&gt;Do not build a regression suite from generic prompts such as:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Explain artificial intelligence.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Build it from tasks your product actually performs.&lt;/p&gt;

&lt;p&gt;For a RAG application, include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;questions with one clear source&lt;/li&gt;
&lt;li&gt;questions requiring multiple retrieved documents&lt;/li&gt;
&lt;li&gt;ambiguous questions that should trigger clarification&lt;/li&gt;
&lt;li&gt;questions with no supporting context&lt;/li&gt;
&lt;li&gt;long documents&lt;/li&gt;
&lt;li&gt;Chinese and multilingual documents where relevant&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For a tool-using agent, include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;requests that require one tool&lt;/li&gt;
&lt;li&gt;requests that require several tools in sequence&lt;/li&gt;
&lt;li&gt;missing-information cases&lt;/li&gt;
&lt;li&gt;invalid-input cases&lt;/li&gt;
&lt;li&gt;tasks where the agent should stop instead of guessing&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For structured extraction, include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;required-field validation&lt;/li&gt;
&lt;li&gt;optional-field handling&lt;/li&gt;
&lt;li&gt;malformed source documents&lt;/li&gt;
&lt;li&gt;nested JSON output&lt;/li&gt;
&lt;li&gt;multilingual entities and dates&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The evaluation set should reflect where your users and workflows can actually fail.&lt;/p&gt;

&lt;h2&gt;
  
  
  Test properties, not exact wording
&lt;/h2&gt;

&lt;p&gt;Exact string matching is often too strict for AI output.&lt;/p&gt;

&lt;p&gt;A better approach is to define observable properties.&lt;/p&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
ts
const testCase = {
  workflow: "invoice_extraction",
  input: "sample-invoice.pdf",
  assertions: {
    outputMatchesSchema: true,
    requiredFieldsPresent: ["vendor", "total", "currency"],
    totalIsNumeric: true,
    currencyMatchesSource: true,
  },
};
For a RAG answer, properties may include:
const testCase = {
  workflow: "policy_rag",
  input: "What is the cancellation period?",
  assertions: {
    answerUsesRetrievedContext: true,
    answerIncludesCitation: true,
    answerDoesNotInventPolicy: true,
  },
};
For an agent workflow, properties may include:
const testCase = {
  workflow: "support_agent",
  input: "Update my delivery address",
  assertions: {
    selectedTool: "update_address",
    toolArgumentsValid: true,
    taskCompleted: true,
  },
};
This makes the suite useful across model versions without demanding identical wording.
Run the suite for every meaningful change
A model update is not the only reason to run regression tests.
Run the suite whenever you change:
the primary model
the fallback model
a prompt template
a system message
retrieval logic
a structured-output schema
routing rules
model parameters
The workflow can be simple:
Run the approved production configuration as a baseline.
Run the candidate configuration against the same task set.
Compare task success, output validity, latency, retries, and cost.
Investigate meaningful differences.
Promote the candidate only when it meets the workflow contract.
This creates an evidence-based model change process.
Add production signals after deployment
Offline tests are necessary, but they are not enough.
After deployment, continue tracking:
successful task completion
schema-valid output rate
fallback frequency
retry rate
p95 latency
cost per successful task
user corrections and support tickets
A candidate model may pass saved test cases and still struggle with real traffic patterns.
That is why production monitoring belongs in the regression process.
A practical release rule
Before changing a route, be able to answer:
What specific behavior are we protecting, and how will we know if it gets worse?

If the answer is unclear, the release is not ready.
VectorNode gives teams access to global and Chinese frontier models through one AI infrastructure platform. As the model catalog grows, regression testing becomes the discipline that lets teams adopt new options without silently damaging the workflows users depend on.
A model change is easy.
Proving that your product still works is the real engineering work.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

</description>
      <category>ai</category>
      <category>api</category>
      <category>llm</category>
      <category>testing</category>
    </item>
    <item>
      <title>A New Flash Model Is Not a Routing Strategy</title>
      <dc:creator>Ye Allen</dc:creator>
      <pubDate>Wed, 22 Jul 2026 06:52:17 +0000</pubDate>
      <link>https://dev.to/ye_allen_/a-new-flash-model-is-not-a-routing-strategy-4gf5</link>
      <guid>https://dev.to/ye_allen_/a-new-flash-model-is-not-a-routing-strategy-4gf5</guid>
      <description>&lt;p&gt;A new model appears in your catalog.&lt;/p&gt;

&lt;p&gt;Someone on the team asks: “Should we make it the default?”&lt;/p&gt;

&lt;p&gt;That is usually the wrong first question.&lt;/p&gt;

&lt;p&gt;VectorNode recently added &lt;code&gt;gemini-3.6-flash&lt;/code&gt; and &lt;code&gt;gemini-3.5-flash-lite&lt;/code&gt;. New fast and lite options are useful, but a model listing is not a traffic strategy.&lt;/p&gt;

&lt;p&gt;The real question is:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Which workload has earned the right to use this model?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Changing one environment variable can move an entire product onto a new route. It feels efficient. It is also how teams accidentally turn real users into an evaluation dataset.&lt;/p&gt;

&lt;h2&gt;
  
  
  Model names are not workload definitions
&lt;/h2&gt;

&lt;p&gt;A multi-model product may have all of these running at once:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;real-time support replies&lt;/li&gt;
&lt;li&gt;RAG answers&lt;/li&gt;
&lt;li&gt;document classification&lt;/li&gt;
&lt;li&gt;JSON extraction&lt;/li&gt;
&lt;li&gt;coding-agent tool calls&lt;/li&gt;
&lt;li&gt;long-context analysis&lt;/li&gt;
&lt;li&gt;nightly batch jobs&lt;/li&gt;
&lt;li&gt;internal evaluation runs&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These workflows do not need the same thing.&lt;/p&gt;

&lt;p&gt;A support reply may need low latency.&lt;/p&gt;

&lt;p&gt;A batch classification job may need predictable throughput and cost.&lt;/p&gt;

&lt;p&gt;A coding-agent planning step may need stronger reasoning and reliable tool calls.&lt;/p&gt;

&lt;p&gt;A document extraction flow may care more about valid structured output than fluent prose.&lt;/p&gt;

&lt;p&gt;Sending every request to the newest model is not model selection.&lt;/p&gt;

&lt;p&gt;It is avoiding model selection.&lt;/p&gt;

&lt;h2&gt;
  
  
  Give each workflow a route contract
&lt;/h2&gt;

&lt;p&gt;Before testing a new model, write down what success means for the workflow.&lt;/p&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
ts
type Route = {
  model: string;
  goal: string;
  successMetric: string;
  fallback: string;
};

const routes: Record&amp;lt;string, Route&amp;gt; = {
  supportReply: {
    model: "gemini-3.6-flash",
    goal: "Fast, helpful user-facing replies",
    successMetric: "Grounded answer rate and p95 latency",
    fallback: "approved-quality-model",
  },

  nightlyClassification: {
    model: "gemini-3.5-flash-lite",
    goal: "High-volume background classification",
    successMetric: "Valid output rate and cost per completed task",
    fallback: "approved-batch-model",
  },

  agentPlanning: {
    model: "approved-reasoning-model",
    goal: "Reliable multi-step planning",
    successMetric: "Task completion rate and tool-call validity",
    fallback: "human-review-or-secondary-model",
  },
};
The model names in this example are not the important part.
The contract is.
A route should answer four questions:
What job is this model handling?
What does a successful result look like?
Which metric tells us the route is healthy?
What happens when the route fails?
Without those answers, a new model is just another option in a dropdown.
Fast and lite models need different tests
A fast model should not be tested only with a stopwatch.
A lite model should not be tested only with a price comparison.
For a real-time route, measure:
p95 latency
user-visible answer quality
context grounding
retry rate
fallback frequency
For a batch route, measure:
throughput
valid structured output
error recovery
cost per successful task
queue delay
For an agent workflow, measure:
task completion
tool-call validity
loop rate
token usage per completed task
reliability across longer runs
A model can look great in a short demo and still be the wrong choice for a production route.
That does not mean the model is bad.
It means the workload and the model were not a match.
Do not move all traffic on day one
A safer rollout pattern is simple:
Start with offline test cases from a real workflow.
Run the new model in shadow mode or on a small sampled route.
Compare task success, latency, output validity, and cost.
Promote the route only when it meets the workflow contract.
Keep a fallback route available.
This matters even more when a product uses models from multiple providers.
Model behavior can change because of a new version, capacity pressure, an API change, different token pricing, or a small prompt update that interacts badly with a new model.
The route needs to be observable after deployment, not just approved before deployment.
The useful mental model
Do not think:
Which model should we use?

Think:
Which model tier should handle this workload, under these conditions, with this fallback?

That shift makes a multi-model application easier to operate.
Fast models can serve real-time interaction.
Lite models can handle high-volume background work.
Stronger models can stay reserved for the tasks where quality risk is expensive.
New models can begin in an experimental route until the data says they are ready for more traffic.
A growing model catalog should create more control, not more guesswork.
VectorNode provides access to global and Chinese frontier models through one developer platform. The work that matters next is building clear route contracts around the workloads your product actually serves.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

</description>
      <category>ai</category>
      <category>api</category>
      <category>llm</category>
      <category>devtools</category>
    </item>
    <item>
      <title>A New Flash Model Is Not a Routing Strategy</title>
      <dc:creator>Ye Allen</dc:creator>
      <pubDate>Wed, 22 Jul 2026 06:33:53 +0000</pubDate>
      <link>https://dev.to/ye_allen_/a-new-flash-model-is-not-a-routing-strategy-23hn</link>
      <guid>https://dev.to/ye_allen_/a-new-flash-model-is-not-a-routing-strategy-23hn</guid>
      <description>&lt;p&gt;A new model appears in your catalog.&lt;/p&gt;

&lt;p&gt;Someone on the team asks: “Should we make it the default?”&lt;/p&gt;

&lt;p&gt;That is usually the wrong first question.&lt;/p&gt;

&lt;p&gt;VectorNode recently added &lt;code&gt;gemini-3.6-flash&lt;/code&gt; and &lt;code&gt;gemini-3.5-flash-lite&lt;/code&gt;. New fast and lite options are useful, but a model listing is not a traffic strategy.&lt;/p&gt;

&lt;p&gt;The real question is:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Which workload has earned the right to use this model?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Changing one environment variable can move an entire product onto a new route. It feels efficient. It is also how teams accidentally turn real users into an evaluation dataset.&lt;/p&gt;

&lt;h2&gt;
  
  
  Model names are not workload definitions
&lt;/h2&gt;

&lt;p&gt;A multi-model product may have all of these running at once:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;real-time support replies&lt;/li&gt;
&lt;li&gt;RAG answers&lt;/li&gt;
&lt;li&gt;document classification&lt;/li&gt;
&lt;li&gt;JSON extraction&lt;/li&gt;
&lt;li&gt;coding-agent tool calls&lt;/li&gt;
&lt;li&gt;long-context analysis&lt;/li&gt;
&lt;li&gt;nightly batch jobs&lt;/li&gt;
&lt;li&gt;internal evaluation runs&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These workflows do not need the same thing.&lt;/p&gt;

&lt;p&gt;A support reply may need low latency.&lt;/p&gt;

&lt;p&gt;A batch classification job may need predictable throughput and cost.&lt;/p&gt;

&lt;p&gt;A coding-agent planning step may need stronger reasoning and reliable tool calls.&lt;/p&gt;

&lt;p&gt;A document extraction flow may care more about valid structured output than fluent prose.&lt;/p&gt;

&lt;p&gt;Sending every request to the newest model is not model selection.&lt;/p&gt;

&lt;p&gt;It is avoiding model selection.&lt;/p&gt;

&lt;h2&gt;
  
  
  Give each workflow a route contract
&lt;/h2&gt;

&lt;p&gt;Before testing a new model, define what success means for the workflow.&lt;/p&gt;

&lt;p&gt;Here is a simplified example:&lt;/p&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
ts
type Route = {
  model: string;
  goal: string;
  successMetric: string;
  fallback: string;
};

const routes: Record&amp;lt;string, Route&amp;gt; = {
  supportReply: {
    model: "gemini-3.6-flash",
    goal: "Fast, helpful user-facing replies",
    successMetric: "Grounded answer rate and p95 latency",
    fallback: "approved-quality-model",
  },

  nightlyClassification: {
    model: "gemini-3.5-flash-lite",
    goal: "High-volume background classification",
    successMetric: "Valid output rate and cost per completed task",
    fallback: "approved-batch-model",
  },

  agentPlanning: {
    model: "approved-reasoning-model",
    goal: "Reliable multi-step planning",
    successMetric: "Task completion rate and tool-call validity",
    fallback: "human-review-or-secondary-model",
  },
};
The names in this example are not the important part.
The contract is.
A route should answer four questions:
What job is this model handling?
What does a successful result look like?
Which metric tells us the route is healthy?
What happens when the route fails?
Without those answers, a new model is just another option in a dropdown.
Fast and lite models need different tests
A fast model should not be tested only with a stopwatch.
A lite model should not be tested only with a price comparison.
For a real-time route, measure:
p95 latency
user-visible answer quality
context grounding
retry rate
fallback frequency
For a batch route, measure:
throughput
valid structured output
error recovery
cost per successful task
queue delay
For an agent workflow, measure:
task completion
tool-call validity
loop rate
token usage per completed task
reliability across longer runs
A model can look great in a short demo and still be the wrong choice for a production route.
That does not mean the model is bad.
It means the workload and the model were not a match.
Do not move all traffic on day one
A safer rollout pattern is simple:
Start with offline test cases from a real workflow.
Run the new model in shadow mode or on a small sampled route.
Compare task success, latency, output validity, and cost.
Promote the route only when it meets the workflow contract.
Keep a fallback route available.
This matters even more when a product uses models from multiple providers.
Model behavior can change because of a new version, capacity pressure, an API change, different token pricing, or a small prompt update that interacts badly with a new model.
The route needs to be observable after deployment, not just approved before deployment.
The useful mental model
Do not think:
Which model should we use?

Think:
Which model tier should handle this workload, under these conditions, with this fallback?

That shift makes a multi-model application easier to operate.
Fast models can serve real-time interaction.
Lite models can handle high-volume background work.
Stronger models can stay reserved for the tasks where quality risk is expensive.
New models can begin in an experimental route until the data says they are ready for more traffic.
A growing model catalog should create more control, not more guesswork.
VectorNode provides access to global and Chinese frontier models through one developer platform. The work that matters next is building clear route contracts around the workloads your product actually serves.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

</description>
      <category>ai</category>
      <category>api</category>
      <category>llm</category>
      <category>devtools</category>
    </item>
    <item>
      <title>Rate Limits Are a Product Problem in Multi-Model AI Apps</title>
      <dc:creator>Ye Allen</dc:creator>
      <pubDate>Tue, 21 Jul 2026 09:21:45 +0000</pubDate>
      <link>https://dev.to/ye_allen_/rate-limits-are-a-product-problem-in-multi-model-ai-apps-3bm0</link>
      <guid>https://dev.to/ye_allen_/rate-limits-are-a-product-problem-in-multi-model-ai-apps-3bm0</guid>
      <description>&lt;p&gt;A rate limit is not just an API error.&lt;/p&gt;

&lt;p&gt;It is often the moment an AI product reveals which users and workflows it values most.&lt;/p&gt;

&lt;p&gt;Imagine this:&lt;/p&gt;

&lt;p&gt;A background job starts summarizing thousands of documents.&lt;/p&gt;

&lt;p&gt;At the same time, a customer opens your support chat.&lt;/p&gt;

&lt;p&gt;Both workflows use the same model provider. Both hit the same token pool. The batch job wins simply because it started first.&lt;/p&gt;

&lt;p&gt;The chatbot becomes slow. Retries begin. Queue time rises. A fallback model is selected without checking whether it can return the required JSON or use the same tools.&lt;/p&gt;

&lt;p&gt;Nothing is technically down.&lt;/p&gt;

&lt;p&gt;But the product experience is already broken.&lt;/p&gt;

&lt;p&gt;That is why rate limits are a product problem, not only a provider problem.&lt;/p&gt;

&lt;h2&gt;
  
  
  Retries are not a rate-limit strategy
&lt;/h2&gt;

&lt;p&gt;The default implementation is familiar:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Send a request.&lt;/li&gt;
&lt;li&gt;Receive a &lt;code&gt;429&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Wait.&lt;/li&gt;
&lt;li&gt;Retry.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;That is fine for a script.&lt;/p&gt;

&lt;p&gt;In a production AI application, blind retries can make the problem worse. They add more traffic to an overloaded route, hide the real source of pressure, and delay the requests that matter most.&lt;/p&gt;

&lt;p&gt;A better question is:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Which workflows should get capacity first when demand exceeds a route's limit?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The answer is different for every product.&lt;/p&gt;

&lt;p&gt;A customer-facing chatbot, a RAG answer, an agent run, and a nightly batch job should not compete as equals.&lt;/p&gt;

&lt;h2&gt;
  
  
  Give each workflow a priority
&lt;/h2&gt;

&lt;p&gt;Multi-model applications need traffic policies beside their routing policies.&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 javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;workflowPolicies&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;support_chat&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;priority&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;high&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;maxConcurrency&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;maxQueueWaitMs&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;3000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;allowFallback&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;rag_answer&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;priority&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;medium&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;maxConcurrency&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;maxQueueWaitMs&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;10000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;allowFallback&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;document_summary_batch&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;priority&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;low&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;maxConcurrency&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;maxQueueWaitMs&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;300000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;allowFallback&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="nx"&gt;The&lt;/span&gt; &lt;span class="nx"&gt;exact&lt;/span&gt; &lt;span class="nx"&gt;numbers&lt;/span&gt; &lt;span class="nx"&gt;are&lt;/span&gt; &lt;span class="nx"&gt;not&lt;/span&gt; &lt;span class="nx"&gt;the&lt;/span&gt; &lt;span class="nx"&gt;point&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
&lt;span class="nx"&gt;The&lt;/span&gt; &lt;span class="nx"&gt;point&lt;/span&gt; &lt;span class="nx"&gt;is&lt;/span&gt; &lt;span class="nx"&gt;deciding&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;deliberately&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;what&lt;/span&gt; &lt;span class="nx"&gt;should&lt;/span&gt; &lt;span class="nx"&gt;wait&lt;/span&gt; &lt;span class="nx"&gt;first&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
&lt;span class="nx"&gt;Without&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt; &lt;span class="nx"&gt;layer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="nx"&gt;low&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="nx"&gt;batch&lt;/span&gt; &lt;span class="nx"&gt;workflow&lt;/span&gt; &lt;span class="nx"&gt;can&lt;/span&gt; &lt;span class="nx"&gt;consume&lt;/span&gt; &lt;span class="nx"&gt;the&lt;/span&gt; &lt;span class="nx"&gt;capacity&lt;/span&gt; &lt;span class="nx"&gt;needed&lt;/span&gt; &lt;span class="nx"&gt;by&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="nx"&gt;paying&lt;/span&gt; &lt;span class="nx"&gt;customer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
&lt;span class="nx"&gt;Requests&lt;/span&gt; &lt;span class="nx"&gt;are&lt;/span&gt; &lt;span class="nx"&gt;not&lt;/span&gt; &lt;span class="nx"&gt;the&lt;/span&gt; &lt;span class="nx"&gt;only&lt;/span&gt; &lt;span class="nx"&gt;thing&lt;/span&gt; &lt;span class="nx"&gt;to&lt;/span&gt; &lt;span class="nx"&gt;limit&lt;/span&gt;
&lt;span class="nx"&gt;Teams&lt;/span&gt; &lt;span class="nx"&gt;often&lt;/span&gt; &lt;span class="nx"&gt;monitor&lt;/span&gt; &lt;span class="nx"&gt;requests&lt;/span&gt; &lt;span class="nx"&gt;per&lt;/span&gt; &lt;span class="nx"&gt;minute&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
&lt;span class="nx"&gt;That&lt;/span&gt; &lt;span class="nx"&gt;is&lt;/span&gt; &lt;span class="nx"&gt;useful&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;but&lt;/span&gt; &lt;span class="nx"&gt;incomplete&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
&lt;span class="nx"&gt;A&lt;/span&gt; &lt;span class="nx"&gt;multi&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;model&lt;/span&gt; &lt;span class="nx"&gt;application&lt;/span&gt; &lt;span class="nx"&gt;should&lt;/span&gt; &lt;span class="nx"&gt;also&lt;/span&gt; &lt;span class="nx"&gt;watch&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="nx"&gt;input&lt;/span&gt; &lt;span class="nx"&gt;and&lt;/span&gt; &lt;span class="nx"&gt;output&lt;/span&gt; &lt;span class="nx"&gt;token&lt;/span&gt; &lt;span class="nx"&gt;volume&lt;/span&gt;
&lt;span class="nx"&gt;concurrent&lt;/span&gt; &lt;span class="nx"&gt;requests&lt;/span&gt;
&lt;span class="nx"&gt;queue&lt;/span&gt; &lt;span class="nx"&gt;wait&lt;/span&gt; &lt;span class="nx"&gt;time&lt;/span&gt;
&lt;span class="nx"&gt;retry&lt;/span&gt; &lt;span class="nx"&gt;count&lt;/span&gt;
&lt;span class="nx"&gt;workflow&lt;/span&gt; &lt;span class="nx"&gt;priority&lt;/span&gt;
&lt;span class="nx"&gt;model&lt;/span&gt; &lt;span class="nx"&gt;and&lt;/span&gt; &lt;span class="nx"&gt;provider&lt;/span&gt;
&lt;span class="nx"&gt;fallback&lt;/span&gt; &lt;span class="nx"&gt;attempts&lt;/span&gt;
&lt;span class="nx"&gt;successful&lt;/span&gt; &lt;span class="nx"&gt;task&lt;/span&gt; &lt;span class="nx"&gt;completion&lt;/span&gt;
&lt;span class="nx"&gt;One&lt;/span&gt; &lt;span class="nx"&gt;large&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;context&lt;/span&gt; &lt;span class="nx"&gt;request&lt;/span&gt; &lt;span class="nx"&gt;can&lt;/span&gt; &lt;span class="nx"&gt;consume&lt;/span&gt; &lt;span class="nx"&gt;more&lt;/span&gt; &lt;span class="nx"&gt;useful&lt;/span&gt; &lt;span class="nx"&gt;capacity&lt;/span&gt; &lt;span class="nx"&gt;than&lt;/span&gt; &lt;span class="nx"&gt;many&lt;/span&gt; &lt;span class="nx"&gt;short&lt;/span&gt; &lt;span class="nx"&gt;chat&lt;/span&gt; &lt;span class="nx"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
&lt;span class="nx"&gt;One&lt;/span&gt; &lt;span class="nx"&gt;agent&lt;/span&gt; &lt;span class="nx"&gt;can&lt;/span&gt; &lt;span class="nx"&gt;create&lt;/span&gt; &lt;span class="nx"&gt;dozens&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;parallel&lt;/span&gt; &lt;span class="nx"&gt;calls&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
&lt;span class="nx"&gt;One&lt;/span&gt; &lt;span class="nx"&gt;RAG&lt;/span&gt; &lt;span class="nx"&gt;workflow&lt;/span&gt; &lt;span class="nx"&gt;can&lt;/span&gt; &lt;span class="nx"&gt;look&lt;/span&gt; &lt;span class="nx"&gt;healthy&lt;/span&gt; &lt;span class="nx"&gt;at&lt;/span&gt; &lt;span class="nx"&gt;the&lt;/span&gt; &lt;span class="nx"&gt;API&lt;/span&gt; &lt;span class="nx"&gt;level&lt;/span&gt; &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="nx"&gt;its&lt;/span&gt; &lt;span class="nx"&gt;queue&lt;/span&gt; &lt;span class="nx"&gt;wait&lt;/span&gt; &lt;span class="nx"&gt;time&lt;/span&gt; &lt;span class="nx"&gt;makes&lt;/span&gt; &lt;span class="nx"&gt;the&lt;/span&gt; &lt;span class="nx"&gt;product&lt;/span&gt; &lt;span class="nx"&gt;feel&lt;/span&gt; &lt;span class="nx"&gt;broken&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
&lt;span class="nx"&gt;This&lt;/span&gt; &lt;span class="nx"&gt;is&lt;/span&gt; &lt;span class="nx"&gt;why&lt;/span&gt; &lt;span class="nx"&gt;rate&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;limit&lt;/span&gt; &lt;span class="nx"&gt;monitoring&lt;/span&gt; &lt;span class="nx"&gt;needs&lt;/span&gt; &lt;span class="nx"&gt;workflow&lt;/span&gt; &lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
&lt;span class="nx"&gt;Use&lt;/span&gt; &lt;span class="nx"&gt;queues&lt;/span&gt; &lt;span class="nx"&gt;before&lt;/span&gt; &lt;span class="nx"&gt;retries&lt;/span&gt;
&lt;span class="nx"&gt;A&lt;/span&gt; &lt;span class="nx"&gt;queue&lt;/span&gt; &lt;span class="nx"&gt;is&lt;/span&gt; &lt;span class="nx"&gt;not&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="nx"&gt;sign&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;failure&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
&lt;span class="nx"&gt;It&lt;/span&gt; &lt;span class="nx"&gt;is&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="nx"&gt;way&lt;/span&gt; &lt;span class="nx"&gt;to&lt;/span&gt; &lt;span class="nx"&gt;control&lt;/span&gt; &lt;span class="nx"&gt;failure&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
&lt;span class="nx"&gt;When&lt;/span&gt; &lt;span class="nx"&gt;traffic&lt;/span&gt; &lt;span class="nx"&gt;rises&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="nx"&gt;queue&lt;/span&gt; &lt;span class="nx"&gt;gives&lt;/span&gt; &lt;span class="nx"&gt;the&lt;/span&gt; &lt;span class="nx"&gt;application&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="nx"&gt;chance&lt;/span&gt; &lt;span class="nx"&gt;to&lt;/span&gt; &lt;span class="nx"&gt;protect&lt;/span&gt; &lt;span class="nx"&gt;high&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;priority&lt;/span&gt; &lt;span class="nx"&gt;workflows&lt;/span&gt; &lt;span class="nx"&gt;and&lt;/span&gt; &lt;span class="nx"&gt;delay&lt;/span&gt; &lt;span class="nx"&gt;work&lt;/span&gt; &lt;span class="nx"&gt;that&lt;/span&gt; &lt;span class="nx"&gt;can&lt;/span&gt; &lt;span class="nx"&gt;safely&lt;/span&gt; &lt;span class="nx"&gt;wait&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
&lt;span class="nx"&gt;For&lt;/span&gt; &lt;span class="nx"&gt;example&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;submitRequest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;workflow&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;policy&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;workflowPolicies&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;workflow&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;queue&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;priority&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;policy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;priority&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;concurrencyKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;workflow&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;timeout&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;policy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;maxQueueWaitMs&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;request&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nx"&gt;This&lt;/span&gt; &lt;span class="nx"&gt;approach&lt;/span&gt; &lt;span class="nx"&gt;makes&lt;/span&gt; &lt;span class="nx"&gt;pressure&lt;/span&gt; &lt;span class="nx"&gt;visible&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
&lt;span class="nx"&gt;It&lt;/span&gt; &lt;span class="nx"&gt;also&lt;/span&gt; &lt;span class="nx"&gt;creates&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="nx"&gt;useful&lt;/span&gt; &lt;span class="nx"&gt;product&lt;/span&gt; &lt;span class="nx"&gt;decision&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="nx"&gt;Should&lt;/span&gt; &lt;span class="nx"&gt;the&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="nx"&gt;wait&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt;
&lt;span class="nx"&gt;Should&lt;/span&gt; &lt;span class="nx"&gt;the&lt;/span&gt; &lt;span class="nx"&gt;request&lt;/span&gt; &lt;span class="nx"&gt;be&lt;/span&gt; &lt;span class="nx"&gt;retried&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt;
&lt;span class="nx"&gt;Should&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="nx"&gt;compatible&lt;/span&gt; &lt;span class="nx"&gt;fallback&lt;/span&gt; &lt;span class="nx"&gt;model&lt;/span&gt; &lt;span class="nx"&gt;be&lt;/span&gt; &lt;span class="nx"&gt;used&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt;
&lt;span class="nx"&gt;Should&lt;/span&gt; &lt;span class="nx"&gt;the&lt;/span&gt; &lt;span class="nx"&gt;workflow&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="nx"&gt;partial&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt;
&lt;span class="nx"&gt;Should&lt;/span&gt; &lt;span class="nx"&gt;the&lt;/span&gt; &lt;span class="nx"&gt;batch&lt;/span&gt; &lt;span class="nx"&gt;task&lt;/span&gt; &lt;span class="nx"&gt;be&lt;/span&gt; &lt;span class="nx"&gt;paused&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt;
&lt;span class="nx"&gt;Those&lt;/span&gt; &lt;span class="nx"&gt;are&lt;/span&gt; &lt;span class="nx"&gt;workflow&lt;/span&gt; &lt;span class="nx"&gt;decisions&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;not&lt;/span&gt; &lt;span class="nx"&gt;generic&lt;/span&gt; &lt;span class="nx"&gt;HTTP&lt;/span&gt; &lt;span class="nx"&gt;decisions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
&lt;span class="nx"&gt;A&lt;/span&gt; &lt;span class="nx"&gt;fallback&lt;/span&gt; &lt;span class="nx"&gt;model&lt;/span&gt; &lt;span class="nx"&gt;must&lt;/span&gt; &lt;span class="nx"&gt;preserve&lt;/span&gt; &lt;span class="nx"&gt;the&lt;/span&gt; &lt;span class="nx"&gt;contract&lt;/span&gt;
&lt;span class="nx"&gt;Fallback&lt;/span&gt; &lt;span class="nx"&gt;is&lt;/span&gt; &lt;span class="nx"&gt;useful&lt;/span&gt; &lt;span class="nx"&gt;only&lt;/span&gt; &lt;span class="nx"&gt;when&lt;/span&gt; &lt;span class="nx"&gt;the&lt;/span&gt; &lt;span class="nx"&gt;backup&lt;/span&gt; &lt;span class="nx"&gt;route&lt;/span&gt; &lt;span class="nx"&gt;can&lt;/span&gt; &lt;span class="nx"&gt;actually&lt;/span&gt; &lt;span class="nx"&gt;complete&lt;/span&gt; &lt;span class="nx"&gt;the&lt;/span&gt; &lt;span class="nx"&gt;job&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
&lt;span class="nx"&gt;Before&lt;/span&gt; &lt;span class="nx"&gt;sending&lt;/span&gt; &lt;span class="nx"&gt;traffic&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="nx"&gt;one&lt;/span&gt; &lt;span class="nx"&gt;model&lt;/span&gt; &lt;span class="nx"&gt;to&lt;/span&gt; &lt;span class="nx"&gt;another&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;check&lt;/span&gt; &lt;span class="nx"&gt;whether&lt;/span&gt; &lt;span class="nx"&gt;the&lt;/span&gt; &lt;span class="nx"&gt;fallback&lt;/span&gt; &lt;span class="nx"&gt;supports&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="nx"&gt;the&lt;/span&gt; &lt;span class="nx"&gt;required&lt;/span&gt; &lt;span class="nx"&gt;language&lt;/span&gt;
&lt;span class="nx"&gt;enough&lt;/span&gt; &lt;span class="nx"&gt;context&lt;/span&gt; &lt;span class="nx"&gt;length&lt;/span&gt;
&lt;span class="nx"&gt;tool&lt;/span&gt; &lt;span class="nx"&gt;calling&lt;/span&gt;
&lt;span class="nx"&gt;structured&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt; &lt;span class="nx"&gt;output&lt;/span&gt;
&lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="nx"&gt;latency&lt;/span&gt; &lt;span class="nx"&gt;requirements&lt;/span&gt;
&lt;span class="nx"&gt;cost&lt;/span&gt; &lt;span class="nx"&gt;limits&lt;/span&gt;
&lt;span class="nx"&gt;expected&lt;/span&gt; &lt;span class="nx"&gt;quality&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="nx"&gt;the&lt;/span&gt; &lt;span class="nx"&gt;workflow&lt;/span&gt;
&lt;span class="nx"&gt;A&lt;/span&gt; &lt;span class="nx"&gt;cheaper&lt;/span&gt; &lt;span class="nx"&gt;or&lt;/span&gt; &lt;span class="nx"&gt;more&lt;/span&gt; &lt;span class="nx"&gt;available&lt;/span&gt; &lt;span class="nx"&gt;model&lt;/span&gt; &lt;span class="nx"&gt;is&lt;/span&gt; &lt;span class="nx"&gt;not&lt;/span&gt; &lt;span class="nx"&gt;automatically&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="nx"&gt;safe&lt;/span&gt; &lt;span class="nx"&gt;fallback&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
&lt;span class="nx"&gt;If&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="nx"&gt;workflow&lt;/span&gt; &lt;span class="nx"&gt;depends&lt;/span&gt; &lt;span class="nx"&gt;on&lt;/span&gt; &lt;span class="nx"&gt;strict&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt; &lt;span class="nx"&gt;validation&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="nx"&gt;fallback&lt;/span&gt; &lt;span class="nx"&gt;that&lt;/span&gt; &lt;span class="nx"&gt;returns&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="nx"&gt;helpful&lt;/span&gt; &lt;span class="nx"&gt;but&lt;/span&gt; &lt;span class="nx"&gt;invalid&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="nx"&gt;is&lt;/span&gt; &lt;span class="nx"&gt;still&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="nx"&gt;failure&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
&lt;span class="nx"&gt;For&lt;/span&gt; &lt;span class="nx"&gt;some&lt;/span&gt; &lt;span class="nx"&gt;workflows&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;waiting&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="nx"&gt;the&lt;/span&gt; &lt;span class="nx"&gt;primary&lt;/span&gt; &lt;span class="nx"&gt;model&lt;/span&gt; &lt;span class="nx"&gt;is&lt;/span&gt; &lt;span class="nx"&gt;better&lt;/span&gt; &lt;span class="nx"&gt;than&lt;/span&gt; &lt;span class="nx"&gt;switching&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
&lt;span class="nx"&gt;For&lt;/span&gt; &lt;span class="nx"&gt;others&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="nx"&gt;fallback&lt;/span&gt; &lt;span class="nx"&gt;route&lt;/span&gt; &lt;span class="nx"&gt;is&lt;/span&gt; &lt;span class="nx"&gt;essential&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
&lt;span class="nx"&gt;Test&lt;/span&gt; &lt;span class="nx"&gt;pressure&lt;/span&gt; &lt;span class="nx"&gt;before&lt;/span&gt; &lt;span class="nx"&gt;users&lt;/span&gt; &lt;span class="nx"&gt;create&lt;/span&gt; &lt;span class="nx"&gt;it&lt;/span&gt;
&lt;span class="nx"&gt;Rate&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;limit&lt;/span&gt; &lt;span class="nx"&gt;behavior&lt;/span&gt; &lt;span class="nx"&gt;should&lt;/span&gt; &lt;span class="nx"&gt;be&lt;/span&gt; &lt;span class="nx"&gt;tested&lt;/span&gt; &lt;span class="nx"&gt;before&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="nx"&gt;major&lt;/span&gt; &lt;span class="nx"&gt;launch&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
&lt;span class="nx"&gt;A&lt;/span&gt; &lt;span class="nx"&gt;useful&lt;/span&gt; &lt;span class="nx"&gt;test&lt;/span&gt; &lt;span class="nx"&gt;asks&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="nx"&gt;What&lt;/span&gt; &lt;span class="nx"&gt;happens&lt;/span&gt; &lt;span class="nx"&gt;when&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="nx"&gt;model&lt;/span&gt; &lt;span class="nx"&gt;route&lt;/span&gt; &lt;span class="nx"&gt;returns&lt;/span&gt; &lt;span class="mi"&gt;429&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt;
&lt;span class="nx"&gt;Which&lt;/span&gt; &lt;span class="nx"&gt;workflow&lt;/span&gt; &lt;span class="nx"&gt;gets&lt;/span&gt; &lt;span class="nx"&gt;queued&lt;/span&gt; &lt;span class="nx"&gt;first&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt;
&lt;span class="nx"&gt;Does&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="nx"&gt;retry&lt;/span&gt; &lt;span class="nx"&gt;amplify&lt;/span&gt; &lt;span class="nx"&gt;traffic&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt;
&lt;span class="nx"&gt;Can&lt;/span&gt; &lt;span class="nx"&gt;the&lt;/span&gt; &lt;span class="nx"&gt;fallback&lt;/span&gt; &lt;span class="nx"&gt;preserve&lt;/span&gt; &lt;span class="nx"&gt;the&lt;/span&gt; &lt;span class="nx"&gt;output&lt;/span&gt; &lt;span class="nx"&gt;schema&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt;
&lt;span class="nx"&gt;Does&lt;/span&gt; &lt;span class="nx"&gt;the&lt;/span&gt; &lt;span class="nx"&gt;customer&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;facing&lt;/span&gt; &lt;span class="nx"&gt;workflow&lt;/span&gt; &lt;span class="nx"&gt;still&lt;/span&gt; &lt;span class="nx"&gt;meet&lt;/span&gt; &lt;span class="nx"&gt;its&lt;/span&gt; &lt;span class="nx"&gt;latency&lt;/span&gt; &lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt;
&lt;span class="nx"&gt;Can&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="nx"&gt;batch&lt;/span&gt; &lt;span class="nx"&gt;job&lt;/span&gt; &lt;span class="nx"&gt;be&lt;/span&gt; &lt;span class="nx"&gt;paused&lt;/span&gt; &lt;span class="nx"&gt;safely&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt;
&lt;span class="nx"&gt;The&lt;/span&gt; &lt;span class="nx"&gt;goal&lt;/span&gt; &lt;span class="nx"&gt;is&lt;/span&gt; &lt;span class="nx"&gt;not&lt;/span&gt; &lt;span class="nx"&gt;to&lt;/span&gt; &lt;span class="nx"&gt;eliminate&lt;/span&gt; &lt;span class="nx"&gt;every&lt;/span&gt; &lt;span class="nx"&gt;rate&lt;/span&gt; &lt;span class="nx"&gt;limit&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
&lt;span class="nx"&gt;The&lt;/span&gt; &lt;span class="nx"&gt;goal&lt;/span&gt; &lt;span class="nx"&gt;is&lt;/span&gt; &lt;span class="nx"&gt;to&lt;/span&gt; &lt;span class="nx"&gt;make&lt;/span&gt; &lt;span class="nx"&gt;the&lt;/span&gt; &lt;span class="nx"&gt;product&lt;/span&gt; &lt;span class="nx"&gt;behave&lt;/span&gt; &lt;span class="nx"&gt;predictably&lt;/span&gt; &lt;span class="nx"&gt;when&lt;/span&gt; &lt;span class="nx"&gt;one&lt;/span&gt; &lt;span class="nx"&gt;occurs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
&lt;span class="nx"&gt;Final&lt;/span&gt; &lt;span class="nx"&gt;thought&lt;/span&gt;
&lt;span class="nx"&gt;As&lt;/span&gt; &lt;span class="nx"&gt;AI&lt;/span&gt; &lt;span class="nx"&gt;products&lt;/span&gt; &lt;span class="nx"&gt;add&lt;/span&gt; &lt;span class="nx"&gt;GPT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Claude&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Gemini&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;DeepSeek&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Qwen&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Kimi&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;GLM&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;MiniMax&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;and&lt;/span&gt; &lt;span class="nx"&gt;other&lt;/span&gt; &lt;span class="nx"&gt;models&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;traffic&lt;/span&gt; &lt;span class="nx"&gt;control&lt;/span&gt; &lt;span class="nx"&gt;becomes&lt;/span&gt; &lt;span class="nx"&gt;part&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;the&lt;/span&gt; &lt;span class="nx"&gt;application&lt;/span&gt; &lt;span class="nx"&gt;architecture&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
&lt;span class="nx"&gt;The&lt;/span&gt; &lt;span class="nx"&gt;best&lt;/span&gt; &lt;span class="nx"&gt;multi&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;model&lt;/span&gt; &lt;span class="nx"&gt;systems&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="nx"&gt;not&lt;/span&gt; &lt;span class="nx"&gt;send&lt;/span&gt; &lt;span class="nx"&gt;every&lt;/span&gt; &lt;span class="nx"&gt;request&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;fast&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;possible&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
&lt;span class="nx"&gt;They&lt;/span&gt; &lt;span class="nx"&gt;know&lt;/span&gt; &lt;span class="nx"&gt;which&lt;/span&gt; &lt;span class="nx"&gt;requests&lt;/span&gt; &lt;span class="nx"&gt;matter&lt;/span&gt; &lt;span class="nx"&gt;most&lt;/span&gt; &lt;span class="nx"&gt;when&lt;/span&gt; &lt;span class="nx"&gt;capacity&lt;/span&gt; &lt;span class="nx"&gt;becomes&lt;/span&gt; &lt;span class="nx"&gt;limited&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
&lt;span class="nx"&gt;VectorNode&lt;/span&gt; &lt;span class="nx"&gt;helps&lt;/span&gt; &lt;span class="nx"&gt;developers&lt;/span&gt; &lt;span class="nx"&gt;access&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;manage&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;monitor&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;and&lt;/span&gt; &lt;span class="nx"&gt;optimize&lt;/span&gt; &lt;span class="nb"&gt;global&lt;/span&gt; &lt;span class="nx"&gt;and&lt;/span&gt; &lt;span class="nx"&gt;Chinese&lt;/span&gt; &lt;span class="nx"&gt;frontier&lt;/span&gt; &lt;span class="nx"&gt;models&lt;/span&gt; &lt;span class="nx"&gt;through&lt;/span&gt; &lt;span class="nx"&gt;one&lt;/span&gt; &lt;span class="nx"&gt;multi&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;model&lt;/span&gt; &lt;span class="nx"&gt;AI&lt;/span&gt; &lt;span class="nx"&gt;infrastructure&lt;/span&gt; &lt;span class="nx"&gt;layer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
&lt;span class="nx"&gt;https&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="c1"&gt;//www.vectronode.com/&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>ai</category>
      <category>api</category>
      <category>llm</category>
      <category>devtools</category>
    </item>
    <item>
      <title>How to Version Prompts and Models in Multi-Model AI Apps</title>
      <dc:creator>Ye Allen</dc:creator>
      <pubDate>Mon, 20 Jul 2026 13:07:30 +0000</pubDate>
      <link>https://dev.to/ye_allen_/how-to-version-prompts-and-models-in-multi-model-ai-apps-5443</link>
      <guid>https://dev.to/ye_allen_/how-to-version-prompts-and-models-in-multi-model-ai-apps-5443</guid>
      <description>&lt;p&gt;A prompt change is a deployment.&lt;/p&gt;

&lt;p&gt;So is a model change.&lt;/p&gt;

&lt;p&gt;So is a new JSON schema, a new fallback rule, a new tool definition, or a different retry limit.&lt;/p&gt;

&lt;p&gt;AI teams often record the model name and forget the rest.&lt;/p&gt;

&lt;p&gt;That works until a workflow changes behavior in production and nobody can explain why.&lt;/p&gt;

&lt;h2&gt;
  
  
  A model ID is not the full configuration
&lt;/h2&gt;

&lt;p&gt;An AI workflow is usually shaped by more than one setting:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;model ID&lt;/li&gt;
&lt;li&gt;provider or endpoint&lt;/li&gt;
&lt;li&gt;system prompt&lt;/li&gt;
&lt;li&gt;prompt template&lt;/li&gt;
&lt;li&gt;output schema&lt;/li&gt;
&lt;li&gt;tool definitions&lt;/li&gt;
&lt;li&gt;retrieval settings&lt;/li&gt;
&lt;li&gt;token limits&lt;/li&gt;
&lt;li&gt;retry behavior&lt;/li&gt;
&lt;li&gt;fallback model&lt;/li&gt;
&lt;li&gt;latency and cost limits&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If any of these changes, the product can behave differently.&lt;/p&gt;

&lt;p&gt;A support workflow may still use the same model but become less accurate after a prompt update.&lt;/p&gt;

&lt;p&gt;A document extraction workflow may start failing after a schema adds one required field.&lt;/p&gt;

&lt;p&gt;A fallback may prevent visible errors while quietly increasing cost or changing output quality.&lt;/p&gt;

&lt;p&gt;The model name alone cannot explain these outcomes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Treat configuration as a release artifact
&lt;/h2&gt;

&lt;p&gt;A useful pattern is to store the whole workflow configuration as a versioned object.&lt;/p&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
json
{
  "workflow": "support-classification",
  "config_version": "2026-07-20",
  "primary_model": "model-a",
  "fallback_model": "model-b",
  "prompt_version": "support-v4",
  "schema_version": "ticket-v2",
  "retry_limit": 1,
  "fallback_enabled": true,
  "max_output_tokens": 500
}
This does not need to be complicated.
The important part is that the configuration is explicit, reviewable, and reproducible.
When a request fails, the team should be able to answer:
Which model handled the request?
Which prompt version was active?
Which schema was expected?
Was a retry used?
Did the workflow fall back to another model?
Without that context, production debugging becomes guesswork.
Version prompts separately
Prompts deserve their own version numbers.
For example:
support-v3
support-v4
support-v4-chinese
support-v5-structured-output
Why?
Because prompt changes can alter:
response quality
output consistency
refusal behavior
JSON validity
tool-call accuracy
latency
token usage
A prompt that works well with one model may be too long, too vague, or too restrictive for another.
That matters in products that compare or route across GPT, Claude, Gemini, DeepSeek, Qwen, Kimi, GLM, MiniMax, Doubao, and other models.
Version schemas and tools too
Structured output contracts are part of the application.
A schema update can introduce a new required field.
An enum value can change.
A downstream service can stop accepting a previous field name.
The same is true for tool definitions.
An agent may use the same model and prompt, but a changed tool parameter can create a completely new failure mode.
Treat these changes like API changes.
Give them versions.
Test them before rollout.
Log them with every request.
Compare configurations, not models in isolation
A model evaluation should test the full workflow.
Not just this:
Model A vs. Model B
But this:
Model A + prompt v4 + schema v2 + retry rule 1
vs.
Model B + prompt v5 + schema v2 + fallback rule 2
The full configuration is what users experience.
A test set should include real inputs:
normal user requests
incomplete requests
long documents
Chinese and English mixed content
ambiguous tasks
malformed source data
prompt injection attempts
high-risk cases
Then measure:
task completion rate
schema validation rate
semantic accuracy
retry rate
fallback rate
p95 latency
cost per successful task
This shows whether a new configuration is actually better.
Roll out changes gradually
Do not send a new configuration to all traffic immediately.
A safer rollout looks like this:
Run offline tests against a fixed evaluation set.
Send a small percentage of production traffic to the new version.
Compare results with the current version.
Review failures, latency, cost, and user corrections.
Expand only when the workflow remains stable.
This applies to model changes, prompt changes, schema changes, and routing changes.
It also makes rollback simple.
If configuration 2026-07-20 performs worse than 2026-07-12, the team knows exactly what to restore.
Log configuration metadata
Every request log should include enough metadata to reproduce the behavior.
For example:
workflow=support-classification
config_version=2026-07-20
primary_model=model-a
prompt_version=support-v4
schema_version=ticket-v2
retry_count=0
fallback_used=false
This makes operational reviews much more useful.
Instead of asking, “Why did this model fail?”, teams can ask:
“Did failures begin after the prompt update?”
“Did the fallback rate rise after the schema change?”
“Which configuration gives the lowest cost per successful task?”
That is the level where multi-model operations become manageable.
Final thought
AI configuration is production code.
It needs versions, tests, release notes, observability, and rollback paths.
Teams that version only model IDs will eventually face failures they cannot reproduce.
Teams that version the full workflow can change models with confidence.
VectorNode helps developers access, test, monitor, and manage global and Chinese frontier models through one multi-model AI infrastructure layer.
Learn more at https://www.vectronode.com/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

</description>
      <category>ai</category>
      <category>api</category>
      <category>llm</category>
      <category>devtools</category>
    </item>
    <item>
      <title>How to Test Structured Outputs Across Multiple AI Models</title>
      <dc:creator>Ye Allen</dc:creator>
      <pubDate>Sat, 18 Jul 2026 09:10:05 +0000</pubDate>
      <link>https://dev.to/ye_allen_/how-to-test-structured-outputs-across-multiple-ai-models-d7g</link>
      <guid>https://dev.to/ye_allen_/how-to-test-structured-outputs-across-multiple-ai-models-d7g</guid>
      <description>&lt;p&gt;Getting a model to return JSON is easy.&lt;/p&gt;

&lt;p&gt;Getting reliable JSON across multiple models is a production problem.&lt;/p&gt;

&lt;p&gt;A response can parse successfully and still break the workflow:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;a required field is missing&lt;/li&gt;
&lt;li&gt;an enum value is unsupported&lt;/li&gt;
&lt;li&gt;a number is returned as text&lt;/li&gt;
&lt;li&gt;the model adds explanation before the JSON&lt;/li&gt;
&lt;li&gt;the extracted value is wrong but syntactically valid&lt;/li&gt;
&lt;li&gt;a fallback model changes the meaning of the response&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This matters when an AI product uses GPT, Claude, Gemini, DeepSeek, Qwen, Kimi, GLM, MiniMax, Doubao, or other models for different workflows.&lt;/p&gt;

&lt;p&gt;The API shape may look similar.&lt;/p&gt;

&lt;p&gt;The output behavior is not.&lt;/p&gt;

&lt;h2&gt;
  
  
  JSON is not the contract
&lt;/h2&gt;

&lt;p&gt;Consider a support-ticket classifier:&lt;/p&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
json
{
  "category": "billing",
  "priority": "high",
  "needs_human_review": false,
  "summary": "Customer was charged twice."
}
A production contract should define:
which fields are required
which values are allowed
which fields can be null
maximum string lengths
whether extra fields are permitted
what happens when validation fails
Without a contract, every model response becomes an unverified suggestion.
Test syntax, schema, and meaning separately
Structured output reliability has three layers.
1. Syntax validity
Can the response be parsed as JSON?
import json

def parse_json(response_text):
    try:
        return json.loads(response_text), None
    except json.JSONDecodeError as error:
        return None, str(error)
This catches markdown fences, extra explanation, truncated responses, and malformed JSON.
2. Schema validity
Does the object match the fields and types the application expects?
from jsonschema import validate, ValidationError

ticket_schema = {
    "type": "object",
    "required": ["category", "priority", "needs_human_review", "summary"],
    "properties": {
        "category": {
            "type": "string",
            "enum": ["billing", "technical", "account", "other"]
        },
        "priority": {
            "type": "string",
            "enum": ["low", "medium", "high"]
        },
        "needs_human_review": {"type": "boolean"},
        "summary": {
            "type": "string",
            "maxLength": 300
        }
    },
    "additionalProperties": False
}

def validate_ticket(data):
    try:
        validate(instance=data, schema=ticket_schema)
        return True, None
    except ValidationError as error:
        return False, error.message
A valid JSON object is not necessarily a valid application payload.
3. Semantic validity
Did the model make the correct decision?
A model may return:
{
  "category": "technical",
  "priority": "low",
  "needs_human_review": false,
  "summary": "Customer was charged twice."
}
The schema passes.
The classification does not.
This is why test cases need expected outcomes, not only JSON schemas.
Build a workflow test set
Do not test only clean prompts.
A useful test set includes:
complete customer requests
incomplete requests
multilingual inputs
Chinese and English mixed content
long documents
ambiguous instructions
malformed source data
prompt injection attempts
missing values
high-risk cases that require human review
For each test case, record:
expected schema result
expected business outcome
maximum acceptable latency
whether retry is allowed
whether fallback is allowed
maximum cost for a successful task
This creates a repeatable model evaluation harness.
Measure the failure modes that matter
A single output pass rate hides important differences.
Track these metrics by model and workflow:
JSON parse success rate
schema validation rate
semantic accuracy rate
retry recovery rate
fallback success rate
refusal rate
empty-output rate
p95 workflow latency
cost per successful task
For example, one model may be excellent at simple ticket classification but unreliable at extracting fields from long Chinese documents.
Another may produce stronger reasoning but cost too much for background automation.
The right model depends on the job.
Test the real production path
Do not compare responses only in a playground.
Run the same path used by the application:
system prompt
model request
output-format settings
JSON parsing
schema validation
retry logic
fallback routing
database or tool call
request logging
The model may succeed while the workflow still fails.
A valid payload may exceed a database limit. A tool call may contain an invalid identifier. A fallback response may be correct but arrive too late for the product experience.
End-to-end completion is the metric that matters.
Turn test results into routing rules
Structured-output tests should improve production behavior.
For example:
route simple classification to a lower-cost model
route ambiguous inputs to a stronger reasoning model
retry once after a syntax failure
switch models after repeated schema failures
require human review for high-risk categories
log every validation failure for future evaluation
This makes model routing evidence-based instead of manual.
Final thought
A multi-model AI product needs more than model access.
It needs confidence that model output is safe for the next system step.
Valid JSON is only the beginning.
Reliable structured output means the response is parseable, schema-compliant, semantically useful, observable, and recoverable when it fails.
VectorNode helps teams access, test, monitor, and manage global and Chinese frontier models through one multi-model AI infrastructure layer.
Learn more at https://www.vectronode.com/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

</description>
      <category>ai</category>
      <category>api</category>
      <category>llm</category>
      <category>devtools</category>
    </item>
  </channel>
</rss>
