All notes

#195 Migrating production AI agents from one frontier model to another

July 19, 2026·5 min read

#195 — Migrating production AI agents from one frontier model to another

Why it matters

If you're moving a production AI agent from one frontier model to another, budget for more than swapping an API key. Every model has quirks baked into how it fills tool arguments, how its cache works, and how it replays reasoning between turns, and your stack has probably specialized around the old model's quirks without anyone noticing.

Fix your test suite first

Before you trust any comparison between two models, check whether your eval suite was built for the old model without you realizing it. In one head-to-head test, a third of the failures had nothing to do with model quality.

  • Tool-call limits sized for one model's habit of calling tools one at a time will flag a new model's correct parallel calls as errors.
  • Test infrastructure that never had to support certain calls (like batched file reads) will penalize a model that leans on them constantly.
  • Watch for silent defaults: one test dataset had an inherited minimum score of 1.0, so a build that scored 0.98 got marked as failed for no real reason.

Look at the actual traces before you trust a pass rate. Otherwise you're just measuring how well the new model copies the old one's behavior.

Check what your tools actually receive

This is the kind of bug that hides in plain sight because everything still reports success. Some models omit optional parameters they don't need. Others fill in every single field, every time, inventing plausible-sounding values for ones they're not using.

The danger: an invented value like offset: 0 looks identical to a real one, and a tool that trusts it can silently return empty or wrong results while still reporting success: true. In one production system, more than half of file reads from the new model came back empty for this exact reason, and nobody knew until they checked.

Telling the model to skip unused fields in your prompts doesn't work this behavior is baked into how the model generates function calls, so you have to design around it rather than instruct it away. The fix: change every optional parameter in your tool schema to required-but-nullable, giving the model an explicit way to say "not using this," then strip the nulls out right before your tool code runs. This one change cut empty file reads to zero and reduced total tool calls by roughly 30%.

Rebuild your caching from scratch

Two providers can both call it "prompt caching" and mean completely different things. Get this wrong and a model can look 50% more expensive than it really is, purely from a config mistake.

Question to askWhy it matters
Is the cache scoped to your whole org or does it need a key per session? ployWrong scope means paying full price on every request
Does it match on partial prefixes or only whole prompts? ployPartial matching gives free hit rate; whole-prompt matching doesn't
Does each cache key have a throughput cap? ployOne global key can overload the cap and start missing anyway
Is there a surcharge on uncached prompts? ploySome providers charge extra whether or not you use caching

Scoping the cache key wrong is expensive either way: one key per conversation gives a near-zero hit rate on new conversations, while one global key overloads its throughput limit and traffic spills to cold, unrelated caches. The fix that worked in practice: layer the cache in tiers a shared static layer for tools and system prompt, a middle layer scoped to the customer, and a session layer for the live conversation so changing one tier doesn't force a full re-bill of everything. Done properly, first-call cache hits went from near zero to over 80%, and the "more expensive" model ended up cheaper once the config was right.

One limitation is structural and won't go away: if a provider's cache identity is tied to a specific key instead of the whole org, you can't share that static prefix across separate tenants or workspaces, so budget one small cold-write cost per idle period, per tenant.

Check how reasoning gets carried between turns

Some model APIs store prior reasoning on their servers and replay it by reference rather than sending the actual content back to you. That's fine until server-side state expires or goes missing mid-conversation, producing errors that look random but aren't. The safer setup for production is requesting reasoning content that's self-contained and encrypted, so you control what gets replayed instead of depending on a pointer to state on someone else's servers. One trap to watch for: with server state involved, your effective prompt can shift even when the text you're sending hasn't changed at all.

The order to do this in

Fix the eval harness first, then the tool schemas, then the caching setup, then reasoning replay last. Each step tends to expose an assumption your system had quietly built around whichever model came first, and that pattern holds no matter which two models you're migrating between.

Frequently asked questions

Should I trust benchmark comparisons between AI models?

Not without checking the eval harness first. In one head-to-head test between Claude Opus 4.8 and GPT-5.6, roughly a third of the raw failures traced back to test infrastructure biased toward the incumbent model, not actual quality gaps . One dataset had a silent default score threshold of 1.0, so a build scoring 0.98 was marked as a failure purely because nobody set the threshold explicitly . Always triage the actual traces, not just the pass rate, before trusting a benchmark.

Why do AI agent tool calls silently return empty results?

Some models fill in every optional tool parameter with invented values instead of omitting unused ones, and a placeholder like offset: 0 is indistinguishable from a real one to your code . In production traces, this caused 52-64% of file reads from GPT-5.6 to come back empty while the tool still reported success: true, meaning the agent never learned it was working with blank data . The fix is a schema-level change, not a prompting fix: making every optional parameter required-but-nullable (anyOf: [T, null]) and stripping nulls before the tool executes .

Why can't I fix bad tool-calling behavior with better prompts?

Because it's often a structural behavior baked into how a model emits function calls, not a comprehension issue. Testing showed that tool-description hints telling the model to 'omit unused parameters,' per-field hints, and even the provider's official strict mode all produced identical behavior the model kept sending every parameter regardless . The only fix that worked was transforming the tool schema itself at the API boundary.

Why does switching AI models suddenly make costs go up instead of down?

Usually because of prompt caching, not the model's actual pricing. In one real migration, a new model looked 50% more expensive than the old one purely due to cache misconfiguration once the caching setup was corrected, the same model ended up cheaper than the incumbent . If you're cost-comparing two models and one has a cold or misconfigured cache, you're comparing your setup, not the models.

How does OpenAI's prompt caching differ from Anthropic's?

Anthropic's caching can be org-wide and shared across any conversation or workspace with a single entry, reaching 92-96% hit rates with minimal setup . OpenAI's newer models dropped partial-prefix matching entirely, requiring explicit cache breakpoints plus a mandatory cache key, with each key limited to roughly 15 requests per minute before traffic spills to a separate, cold cache node . This means OpenAI-style caching requires deliberate key-scoping design that Anthropic's architecture doesn't.

What's the right way to scope a prompt cache key for a multi-tenant SaaS product?

Scope it per-workspace or per-customer, not per-conversation or globally. A per-conversation key produced a 0% first-call cache hit rate in testing, while a single global key overloaded the throughput cap and spilled traffic to unrelated cold caches . Workspace-scoped keys, combined with layered cache breakpoints (shared static layer, workspace layer, session layer), pushed first-call hit rates from near 0% to 83.7% .

Can I share a cached prompt prefix across different customers or tenants?

It depends on the provider's cache architecture, and for some models it's structurally impossible. Because certain caching systems tie cache identity to a specific key rather than the whole organization, cross-tenant sharing of a static prompt prefix isn't achievable teams instead budget for one small cold-write cost (around $0.18) per idle window, per tenant, as a bounded but unavoidable expense .

Why is my AI agent throwing 'item not found' errors mid-conversation?

This typically happens when a model API replays prior-turn reasoning as a server-side reference rather than sending the full content back to you, and that server-side state can expire or go missing during a live conversation . The fix is requesting self-contained, encrypted reasoning content instead of relying on server-side pointers, which eliminates dependency on state you don't control .

Why did my AI agent's behavior change even though I didn't edit the prompt?

If your setup relies on server-side reasoning or state replay, the effective prompt reaching the model can shift upstream of you even when the text you're sending is byte-for-byte identical and append-only . This is a known trap that looks like model nondeterminism but is actually a side effect of server-managed state switching to self-contained reasoning replay removes this variable.

In what order should I approach migrating a production AI agent to a new model?

Fix the eval harness first, then audit tool-call schemas, then rebuild the caching architecture, then check reasoning or state replay behavior last . This sequence matters because each earlier step tends to mask or distort the problems in the steps after it for example, a biased eval harness can hide real cost differences caused by cache misconfiguration.

Does a newer AI model always produce better design or code output than an older one?

Not automatically model upgrades often trade one weakness for another. In one comparison, the newer model wrote dramatically leaner code (a 2,508-character stylesheet with 45 variables versus the older model's 17,957 characters and 174 mostly-unused variables) but showed a tendency to default to clean, generic layouts unless actively steered toward a specific brand's design system . Faster and cheaper doesn't guarantee stylistically superior output without additional steering work.

How much can switching AI models actually save on cost and speed?

In one production comparison across 10-11 matched builds, the newer model averaged $2.22 per completed build versus $3.06 for the incumbent, a 27% cost reduction, while cutting wall-clock time from 8 minutes to 3 minutes 42 seconds, more than 2x faster . Output token usage nearly halved too, dropping from 33.0K to 17.1K tokens per build, which is often the bigger lever since output tokens typically cost more than input tokens .

Does using a universal LLM SDK like Vercel's AI SDK make model migration painless?

It standardizes the API surface but doesn't eliminate provider-specific behavior underneath it. Even using a universal SDK, one team still had to discover through failed evals that tool-argument filling, prompt caching, and reasoning replay were all provider-specific behaviors their stack had quietly specialized around . A unified SDK reduces boilerplate, not the underlying architectural differences between model providers.

How do you write good visual/design evals for an AI coding or website-building agent?

Effective visual evals use binary, specific checks rather than vague scoring for example, ten yes/no questions like 'the hero is a full-bleed photographic scene' or 'primary CTAs are rounded rectangles, not pills' scored against a reference design, combined with content checks, tool-trajectory checks, and file assertions . Every failed case should be triaged against its full execution trace, not just the numeric score, since silent defaults (like an inherited minimum score threshold) can produce false failures .

What's a realistic sample size for comparing two AI models before switching in production?

One real-world comparison used 10-11 completed builds per model as an initial signal before rolling out a default model change, which is small enough to be directional rather than statistically definitive . Teams treating small-sample results as a green light should pair them with production monitoring after rollout, since the true failure modes (like tool schema handling or cache misconfiguration) often only surface at higher volume .

What does 'server-side reasoning' mean in AI model APIs, and why does it matter?

It refers to models storing their internal reasoning from a previous turn on the provider's servers and passing back only a reference ID for future turns, instead of returning the full reasoning content to your application . This creates a dependency on infrastructure you don't control if that stored reference expires or isn't found, your agent throws mid-conversation errors, which is why requesting self-contained encrypted reasoning blobs is the more resilient production pattern .

more than just words|

We're here to help you grow better at every stage of the climb.

let's go to market

Whether you're finding problem-market fit, refining your positioning, shipping product, or scaling go-to-market we're built for every stage of the journey.