Pidoku

Portability and the Model Lifecycle

Expert 50 min Difficulty 4/5 Lesson 03 of 04

Prerequisites Choosing a Model, Evaluation as the Contract

The idea in one minute#

In ordinary software you choose a database and live with it for ten years. In AI the central component — the model — is replaced every few months, whether you want it or not. Providers release new versions several times a year and retire old ones on a published schedule, often with only months of notice. A system built in 2025 has already been through two or three forced model changes.

So the question is not “how do we avoid lock-in?” in the abstract. It is “how cheap is our next model change?” — because there will certainly be one. An organisation that can swap a model in a week treats each new release as an opportunity. One that needs a quarter treats each retirement as a crisis.

Portability comes from a few deliberate seams: a gateway in front of every model, prompts and evaluations that you own, tools exposed through open protocols, and data kept in stores you control. Full independence from every vendor is neither possible nor worth its price. The skill is choosing where to stay flexible and where to commit.

A picture#

flowchart LR
  subgraph OWN["What you own — keep portable"]
    direction TB
    O1[":i-file-text: <b>Prompts</b><br/><small>versioned, per model family</small>"]
    O2[":i-flask-conical: <b>Evaluation sets</b><br/><small>the migration test</small>"]
    O3[":modelcontextprotocol: <b>Tools over MCP</b>"]
    O4[(":i-database: <b>Data and indexes</b><br/><small>re-embeddable</small>")]
    O5[":i-scroll-text: <b>Traces and history</b>"]
  end
  GW[":envoyproxy: <b>Gateway</b><br/><small>logical names: fast, smart</small>"]
  OWN --> GW
  GW --> M1[":i-brain: <b>Model A v5</b><br/><small>current</small>"]
  GW -.->|"evaluated, ready"| M2[":i-brain: <b>Model A v6</b><br/><small>next</small>"]
  GW -.->|"fallback"| M3[":i-brain: <b>Model B</b><br/><small>second provider</small>"]
  CAL[":i-clock: <b>Lifecycle calendar</b><br/><small>release, deprecation, retirement</small>"] -.-> GW
  class O1,O2,O3,O5 compute
  class O4 memory
  class GW queue
  class M1 io
  class M2,M3 neutral
  class CAL warn

How it really works#

The life of a model version#

StageWhat it meansWhat you do
PreviewAvailable to try; may change; often no service commitmentEvaluate; do not put it on a critical path
Generally availableSupported for productionAdopt after it passes your gate
DeprecatedStill works; a retirement date has been announcedStart the migration now
RetiredRequests failYou should have left already

Two further facts shape planning. The same model can have different dates on different platforms — a version retired on its maker’s own API may remain available on a cloud platform, or the reverse. And model aliases that point to “the latest” change behaviour under you without warning; production systems should pin an exact version and move deliberately.

Where lock-in actually lives#

Rank the layers by how hard they are to change, and spend your portability effort from the top.

LayerWhy it sticksHow to keep it loose
Data and its governanceVolume, permissions, pipelines; moving it is a programmeKeep source data in stores you control; treat indexes as rebuildable
Identity and networkDeep in the enterprise landing zoneAccept this commitment — it is the reason you chose the cloud
Agent state and memoryStored in a platform’s proprietary formatPrefer runtimes with exportable state; store long-term memory in your own database
Proprietary platform featuresManaged agents, built-in tools, vendor-specific retrievalUse them where the saving is large; write an ADR naming the exit cost
EmbeddingsVectors from one model cannot be searched with anotherKeep the source text; budget for re-embedding
PromptsTuned to one model’s habitsVersion them per model family; rely on the evaluation set to re-tune
The model APIParameter and feature differencesA gateway and a thin internal interface
Fine-tuned modelsHosted fine-tunes do not transferKeep the training data and the evaluation; retraining is the migration

The model API — the thing most people think of as lock-in — is near the bottom. Data, state and proprietary platform features are where organisations actually get stuck.

Five seams to build in#

  1. A gateway with logical model names. Applications ask for “fast” or “smart”; the mapping to a real model is configuration.
  2. Prompts as versioned assets, outside the code. With the evaluation results they were tested against.
  3. Evaluation sets you own. The single most important portability asset: they turn “will the new model work?” from a debate into a test run.
  4. Tools behind open protocols. An enterprise system exposed over MCP serves any compliant agent, on any platform.
  5. Your own record of what happened. Traces, conversation history and feedback in your stores, in a documented format — not only inside a vendor’s console.

How much portability to buy#

Portability is insurance, and insurance has a premium: lowest-common-denominator features, extra abstraction, two of everything to test. Buy it according to exposure.

SituationSensible posture
Early, low-risk, internal toolSingle provider. A gateway and owned evaluations are enough
Core business processPrimary plus an evaluated fallback on a second provider or region
Regulated or critical serviceFallback exercised regularly; documented exit plan; contractual notice periods
Extreme sensitivity or scaleAn open-weight option you can run yourself, kept warm for the critical path

“Multi-cloud everything” is rarely the right answer. Running one workload identically on three platforms triples the testing and forbids the best features of each. A stronger and cheaper position is one primary platform, clean seams, and a rehearsed exit.

The migration procedure#

When a new version arrives or a retirement is announced, the procedure is the same — and should be boring.

  1. Read the release notes for behaviour and parameter changes, not only the headline.
  2. Run the evaluation set against the candidate with the existing prompts.
  3. Read the differences, case by case. Regressions are usually concentrated in one slice.
  4. Re-tune prompts where needed. Newer models often want less instruction, not more.
  5. Check the system metrics: latency, token counts, cost. A cheaper price per token with longer outputs can cost more.
  6. Shadow, then canary in production; compare quality and cost on live traffic.
  7. Switch, keep the old route available until the new one has run clean, then remove it.
  8. Record the result in the decision log.

With the seams in place this is days of work for one system. Without an evaluation set, step 2 becomes “try it and hope”, which is why migrations without evaluations take months.

A lifecycle process for the organisation#

At platform level, model change becomes a routine.

ElementWhat it is
Model catalogueThe approved models, each with a logical tier, status, and the date it must be left by
Lifecycle calendarRetirement dates for every model in use, with owners
Lead-time ruleFor example: migration starts no later than 90 days before retirement
Subscription to noticesSomeone named reads every provider’s deprecation announcements
Standing budgetTime reserved every quarter for upgrades — it is never zero
Contract termsNotice periods and version availability negotiated where the provider allows

Exit plans#

For any strategic dependency — a platform, a vendor product, a model family — write a one-page exit plan when you adopt it, not when you need it.

EXIT PLAN — Managed agent runtime, vendor X                    reviewed yearly

What we depend on    Hosted agent execution, built-in memory, built-in code sandbox
What we own          Prompts, tool servers (MCP), evaluation sets, traces (exported nightly)
What we would lose   Stored agent memory (proprietary format) — export tested quarterly
Replacement          Self-hosted runtime on our cluster using the same agent framework
Estimated effort     3 engineers × 10 weeks; no change to tools or evaluations
Triggers             Price increase > 30%; loss of in-region processing; two major outages
Notice we need       6 months — contract gives 12

The plan almost never gets executed. Writing it changes the adoption decision, the contract and the architecture, which is its real purpose.

Code#

A lifecycle check a platform team can run every week: for each model in use, how long until retirement, whether a replacement has passed evaluation, and whether the migration is late.

Go
// lifecycle.go — which model migrations are due, late or unprepared.
package main

import (
	"fmt"
	"sort"
	"time"
)

type deployment struct {
	system, model string
	retires       string // provider's announced date, "" if none yet
	replacement   string
	evalPassed    bool
	weeksOfWork   int
}

func main() {
	today := time.Date(2026, 10, 13, 0, 0, 0, 0, time.UTC)
	const leadDays = 90 // migration must have started this long before retirement

	fleet := []deployment{
		{"claims extraction", "mid-v5", "2027-03-01", "mid-v5.5", true, 2},
		{"policy assistant", "mid-v4", "2026-12-15", "mid-v5.5", false, 3},
		{"email triage", "small-v4", "2026-11-10", "small-v5", false, 1},
		{"coding agents", "frontier-v5", "", "", false, 0},
		{"customer assistant", "mid-v4", "2026-12-15", "mid-v5.5", true, 4},
	}

	type row struct {
		d      deployment
		days   int
		status string
	}
	var rows []row
	for _, d := range fleet {
		if d.retires == "" {
			rows = append(rows, row{d, 1 << 30, "no retirement announced — keep watching"})
			continue
		}
		t, _ := time.Parse("2006-01-02", d.retires)
		days := int(t.Sub(today).Hours() / 24)
		slack := days - d.weeksOfWork*7
		var status string
		switch {
		case slack < 0:
			status = "AT RISK: not enough time left for the work"
		case !d.evalPassed && days < leadDays:
			status = "LATE: replacement not yet evaluated"
		case !d.evalPassed:
			status = "evaluate the replacement"
		default:
			status = "ready: schedule the switch"
		}
		rows = append(rows, row{d, days, status})
	}
	sort.Slice(rows, func(i, j int) bool { return rows[i].days < rows[j].days })

	fmt.Printf("%-20s %-12s %10s  %s\n", "system", "model", "days left", "status")
	for _, r := range rows {
		left := "—"
		if r.d.retires != "" {
			left = fmt.Sprint(r.days)
		}
		fmt.Printf("%-20s %-12s %10s  %s\n", r.d.system, r.d.model, left, r.status)
	}
}

The output is the meeting agenda. Sorted by days remaining, it shows at a glance which system is late — not because the work is hard, but because nobody ran the evaluation in time.

Remember this#

  • Model change is certain and frequent. Design for a cheap next migration.
  • Pin exact versions in production. Track retirement dates as operational risk.
  • Lock-in lives mostly in data, state and proprietary platform features — not the model API.
  • Five seams: gateway, versioned prompts, owned evaluations, open tool protocols, your own records.
  • One primary platform with clean seams and a rehearsed exit beats multi-cloud everything.

Try it#

  1. Run lifecycle.go. Which system needs attention first? Change leadDays to 180 and see what a more cautious policy would have flagged.
  2. Look up the published deprecation schedule of one model provider. Which generally available model has the nearest retirement date, and how much notice was given?
  3. Write a one-page exit plan for an AI product or platform you depend on. Which line was hardest to fill in?

Check yourself#

  1. Why is “how cheap is our next model change?” a better question than “how do we avoid lock-in?”
  2. Which layers are hardest to move, and which is usually easiest?
  3. Why is an evaluation set the most important portability asset?
  4. What is the argument against running every workload on three clouds?

↑↓ navigate↵ openesc close

drag to pan · scroll to zoom