ANAlpesh Nakrani
SolutionsBlogBooksPraiseAboutWork with me ↗
Back to the blog
Blog/Jun 22, 2026 · 11 min

Build an AI Model Deprecation Strategy Before You Need One

Providers retire models on their own clock, not yours. Here is the abstraction layer and eval gate that turn a forced migration into a config change.

An AI model deprecation strategy is the set of engineering habits that keep a forced provider migration from turning into an outage: an abstraction layer that treats the model ID as configuration instead of a hardcoded string, and an eval suite that gates every swap before it reaches production. Providers do not ask permission before they retire a model, and this month proved it twice.

On June 15, Anthropic retired Claude Opus 4 and Claude Sonnet 4 from the API. Two weeks before that, on June 1, Google shut down Gemini 2.0 Flash. Anthropic gave about two months' notice; Google does not commit to a fixed minimum at all, only that it will tell you before a model's "near future" shutdown arrives. Both models are gone now, and every application still calling either model ID gets an error back, not a slightly worse answer. October brings the biggest one yet: OpenAI has gpt-3.5-turbo, gpt-4, and gpt-4-turbo on the calendar for October 23.

A retired model ID does not return a worse answer. It returns an error, on a date the provider chose, not you.

Key takeaways

  • Notice windows are not standardized. Anthropic commits to at least 60 days; OpenAI commits to at least six months for generally-available models; Google publishes no fixed minimum for the Gemini API.
  • A hardcoded model ID is a single point of failure you don't control. Treat model availability the way you already treat a payment processor that can go down: as an external dependency with its own outage schedule.
  • OpenAI retires gpt-3.5-turbo, gpt-4, and gpt-4-turbo on October 23, 2026. Anthropic already retired Claude Opus 4 and Claude Sonnet 4 on June 15; Google already shut down Gemini 2.0 Flash on June 1.
  • The fix is architectural, not procedural. Route every model call through one boundary, keep the model ID in configuration, and keep prompts versioned separately from application code.
  • An eval suite is the only thing that makes a forced swap safe, and even a passing eval suite will not catch every regression. Production monitoring after cutover is not optional.

What "deprecation" means, on three different clocks

Every major provider uses roughly the same vocabulary and means something slightly different by it. Anthropic runs a four-stage lifecycle: a model is Active, then Legacy once it stops receiving updates, then Deprecated once a retirement date is assigned, then Retired once requests to it start failing (Anthropic's model deprecations page). The company commits to at least 60 days between the deprecation announcement and the retirement date for publicly released models.

OpenAI collapses that into two moments, announcement and shutdown, but promises a longer runway: at least six months for generally available models, three months for specialized variants, and as little as two weeks for preview models (OpenAI's deprecations documentation). Google's Gemini API deprecation policy defines deprecation as the announcement that a model "will be shut down in the near future," and shutdown as the endpoint being turned off completely, with the shutdown date on its published schedule marked as the earliest possible one rather than a guarantee.

None of those three clocks are synchronized, and none of them are optional for you. A strategy that assumes "we'll get six months" because that is what one provider promises will get a nasty surprise the day the model actually routed through a different vendor's 60-day clock.

ProviderStated minimum notice2026 example
AnthropicAt least 60 daysClaude Opus 4 and Sonnet 4 retired June 15, announced April 14
OpenAIAt least 6 months (GA models)gpt-3.5-turbo, gpt-4, gpt-4-turbo shut down October 23
Google (Gemini API)No fixed minimum publishedGemini 2.0 Flash shut down June 1

The 2026 deprecation calendar you're already living inside

This is not a hypothetical future problem. Claude Opus 4.1 was deprecated on June 5 with a retirement date of August 5, a 61-day window that is already ticking. Claude Opus 4 and Claude Sonnet 4, both retired June 15, took every application still pointed at claude-opus-4-20250514 or claude-sonnet-4-20250514 down with them the moment the clock ran out. Gemini 2.0 Flash and its lite variant are gone as of June 1, replaced by gemini-3.6-flash and gemini-3.1-flash-lite. Gemini 2.5 Flash Image follows on October 2.

The largest single event is still ahead. OpenAI's gpt-3.5-turbo, gpt-4, and gpt-4-turbo lines all shut down October 23, with gpt-5.6-sol and gpt-5.6-terra listed as the substitutes. If your fine-tuning pipeline, a routing config, or a script nobody has touched since last year still calls one of those three model names directly, October 23 is not a maintenance window on someone else's calendar. It is an incident with a date already scheduled.

Notice the direction every one of these migrations points: toward a newer, larger, more capable successor, never toward something smaller. Providers are not being generous when they retire a model. They are reclaiming serving capacity for whatever they now consider frontier, and frontier keeps meaning bigger, which is the whole argument in my book The Bitter Lesson, Revisited: scale keeps beating cleverness, and a provider's deprecation schedule is built around that bet, not around your cost model or your latency budget.

Why a hardcoded model ID is a production risk

Most teams do not think of a model ID as a dependency with its own outage schedule. They think of it as a string they typed once, the way they think of a package version they pinned and forgot. That is the mistake. Model availability is exactly as much a production dependency as a payment API that can return a 503, and it deserves the same architectural respect: a boundary, a fallback, and a plan for the day it goes away, not a string buried three files deep in a prompt template.

The business consequence is not abstract. A retired model ID does not degrade gracefully into a worse answer a customer might not notice. It throws an error, every single call, starting the second the retirement date passes. In a paid product, that error is a support ticket, a failed workflow a customer was relying on, or a refund, not a line item in a changelog nobody reads. I cover the broader selection framework, including where cost and capability trade off against each other before you even get to deprecation, in my guide to how to choose an LLM.

Model availability is a production dependency you do not control. Architect for it the way you already architect for a payment API that can go down.

Design for swap-ability: the model ID is configuration, not code

The fix starts with an audit, not a rewrite. Find every place in the codebase where a model name or a provider-specific call shape appears, and you will usually find more of them than you expected: a routing config, a fine-tuning job definition, a batch script, a notebook someone promoted to production without telling anyone. Centralize all of it behind one boundary, and treat the model ID the way you already treat a database connection string: pulled from configuration at runtime, never typed into a function call.

Prompt templates deserve the same discipline, versioned and stored separately from the application logic that calls them, because a model swap frequently means a prompt adjustment too. A newer model can be more literal about instructions, less tolerant of a sloppy system prompt, or better at a task you were previously prompting around. Keeping prompts as data, not code, means a migration touches a config file and a template, not a pull request across a dozen call sites.

# model ID resolved from config, not hardcoded at the call site
MODEL_ID = config.get("chat_model_id", default="claude-opus-4-8")
PROMPT_VERSION = config.get("chat_prompt_version", default="v14")
def call_model(user_input):
prompt = load_prompt(PROMPT_VERSION)
return client.complete(model=MODEL_ID, prompt=prompt.render(user_input))

The eval suite is what makes a forced migration safe

An abstraction layer answers the question of whether you can swap a model without a rewrite. It says nothing about whether you should, on this date, to this replacement. That question belongs to the eval suite, and it is the one piece of the strategy teams skip most often, usually right when a retirement date is bearing down and skipping it feels fastest.

The discipline is simple to state: freeze a golden eval set built from real production traffic before a migration ever gets scheduled, score your current model against it as the baseline, then score the candidate replacement against the identical set before it touches a real request. A gate that blocks the swap on a real regression, and lets it through on a wash, turns a deprecation deadline from a gamble into a decision with a number attached. I walk through building that harness in full in my guide to eval-driven development.

# illustrative: gate a migration on eval-set regression, not vibes
def gate_migration(candidate_score, baseline_score, floor=0.03):
regression = baseline_score - candidate_score
return "BLOCK" if regression > floor else "SHIP"
# opus-4 -> opus-4-8, full eval set: baseline 0.91, candidate 0.91 -> SHIP
# opus-4 -> opus-4-8, tool-call subset: baseline 0.88, candidate 0.79 -> BLOCK

That second line is the one that matters. Aggregate scores hide subset failures constantly, and a migration that looks clean on the full suite can be quietly broken on the exact slice of traffic, tool calls, a rare intent, a formatting edge case, that your business actually depends on. Score the subsets your eval-driven-development harness already tracks, not just the headline number.

The regression your eval suite won't catch

Here is the honest trade-off nobody puts in the migration runbook. Building and maintaining an abstraction layer and a gating eval suite is real, ongoing engineering cost, not a one-time insurance premium. Someone has to keep the eval set current as the product's real traffic shifts, or it starts measuring last year's task instead of today's. A team calling one model from one place, with low stakes if it breaks, can reasonably decide to eat an occasional forced migration by hand rather than build scaffolding for it. That is a legitimate call, as long as it is a deliberate one and not a default born of never having thought about it.

Even a suite that is current and well-maintained has a hard limit: it can only catch what it samples. A replacement model can clear every aggregate score and every subset you tested, and still regress on a tail behavior the suite never happened to cover, a rare user intent, a tone shift on sensitive topics, a formatting habit that only shows up on inputs longer than your test cases. That is drift by another name, and it is exactly the failure mode I cover in model drift detection: nothing throws an exception when a migrated model quietly gets a little worse on a slice you weren't watching, so the alerting has to be built, not assumed.

The practical answer is to treat the eval gate as the entry condition, not the whole strategy. Sample a slice of real production responses after cutover and score them the same way you scored the pre-migration baseline, watching for the eval score itself to slide over the following weeks. A migration that passed the gate on day one and starts failing the same eval set by week three is not a false alarm. It is the exact signal the gate was built to eventually catch, just later than you'd like.

Frequently asked questions

How much notice do AI providers actually give before deprecating a model? It varies by provider and is not standardized. Anthropic commits to at least 60 days between announcement and retirement. OpenAI commits to at least six months for generally available models, but only around two weeks for preview models. Google's Gemini API publishes shutdown dates as the earliest possible date and does not commit to a fixed minimum notice window at all.

What happens if a request still hits a model ID after its retirement date? The request fails. Retired models do not return a degraded or lower-quality answer, they return an error on every call, which is why a hardcoded model ID buried in a script or a config file is a production incident waiting on a date the provider already picked.

How do you know a replacement model is safe before you're forced to switch? Run it against a frozen eval set built from your own production traffic, comparing its score to your current model's baseline on both the aggregate and the specific subsets that matter to your task, before it ever serves a real request. A migration that clears that bar with room to spare is safe to ship; one that only clears the aggregate while failing a subset is not, no matter how good the average looks.

Is a full model-abstraction layer worth building for a small team? If you call one model from one place and a forced migration would cost you an afternoon, probably not, and a manual swap on the rare deprecation is a fair trade against the ongoing cost of maintaining scaffolding you barely use. Once you are calling models from more than a handful of places, or a failed migration would cost you a customer, the abstraction layer stops being optional and starts being the cheaper option.

If your team is staring at an October 23 deadline, or an Anthropic or Google retirement already came and went without a plan behind it, that gap between "the deprecation is scheduled" and "the eval suite that makes the swap safe actually exists" is exactly the kind of build ViitorCloud's technology consulting team scopes and ships, with the abstraction layer and the evals wired in before the next provider email arrives, not after.

Share
Next

Keep reading

View all blogs

Ask AI about Build an AI Model Deprecation Strategy Before You Need One