The lock-in everyone knows — and the one nobody budgets for
Any engineering team worth its salt has an opinion on vendor lock-in. People argue for hours about whether a proprietary AWS database chains them too tightly to a cloud provider. They weigh up whether a SaaS tool traps their data in a format they'll never get back out of. There are architecture principles for it, blog posts, entire consulting careers. Cloud lock-in and SaaS lock-in are priced-in risks.
And then that very same team wires its most important new product to a single provider's model — prompts tuned to that model's quirks, tool calls cast in that model's JSON format, a fine-tune trained on that model's base, evals run exclusively against that one model — and nobody calls it a risk. It appears in no architecture review, in no cost plan, on no risk register.
That is the dependency no one plans for. Model lock-in is vendor lock-in, only without the vigilance vendor lock-in normally earns. And because the model is the layer where the value actually gets created — it writes the answer, makes the classification, extracts the data — the provider ends up holding precisely the lever that decides your margin.
How the lock-in creeps in
Nobody decides on a Monday morning to bind themselves to a provider forever. Lock-in accumulates as the sum of sensible individual decisions, each right on its own, a shackle in aggregate.
Prompts tuned to one model's quirks. You start with a generic prompt and it works so-so. So you file away at it. You notice this model answers better when you wrap the instructions in XML tags. That it needs examples in the system prompt where another model copes with a bare instruction. That one particular phrasing makes it reliable and a marginally different one makes it flaky. Three months later the prompt is a finely tuned instrument — calibrated to the idiosyncrasies of this one model. On any other model the quality drops noticeably, and no one can say any more which of the forty prompt decisions are load-bearing and which are superstition.
Provider-specific features. This is where it becomes technically binding. OpenAI's Structured Outputs with strict JSON schema guarantee valid JSON in a way that is no open standard. The tool-calling format differs between providers in more than cosmetics — the shape of the calls, the schema of the arguments, how parallel tool calls come back. Build your agent logic directly against OpenAI's tools format and you're building against a concrete API, not an abstraction. Moving to Anthropic's tool-use format or Google's function calling is then not a config change but a rewrite.
Fine-tunes on exactly one base model. This is the most expensive trap, because it feels like progress. You gather a clean training set, fine-tune on gpt-3.5-turbo or gpt-4o-mini, and the results are excellent. What you've built is an asset you don't own: the weights belong to the provider, the model runs only on their infrastructure, and it hangs off one specific snapshot. When the provider retires that base model — and it does — the fine-tune isn't portable; it has to be retrained from scratch against a new base. You didn't build a model. You trained a dependency.
Evals against one model only. The quietest mechanism of them all. You build yourself a test suite to measure your AI feature — and run it exclusively against the production model, because that's the one that counts. With that, the eval suite stops being a neutral instrument and becomes implicitly calibrated to the answer patterns of this one model. You can no longer tell in an hour how a competitor's model does on the same task. The question "should we switch?" becomes unanswerable, because the tool to answer it is missing. And a question you can't answer, you eventually stop asking.
The day the bill arrives
As long as the provider behaves benignly, the lock-in costs nothing. That's the trap: the bill only arrives once your interests and theirs diverge — and then it arrives in three forms.
The provider raises prices. Inference prices have mostly fallen over the last few years, which tempts people into assuming they always will. But the price isn't the point — the pricing power is. If you have no exit, you don't negotiate. When the provider introduces a priority tier for your volume, restructures the pricing for large context windows, or simply drops the discount you'd budgeted for, the question isn't whether you find it fair. The question is what your alternative is within two weeks. Without portability, the answer is: none. Your provider then has direct access to your margin, and it knows it.
The provider retires the model. This is no hypothetical worry, it's the base case. OpenAI retired the old gpt-4-0314 and gpt-3.5-turbo-0613 snapshots, buried the entire Completions era along with text-davinci-003, and folded gpt-4-vision-preview into a successor. Google shut down the whole PaLM API together with text-bison and redirected everyone to Gemini. Anthropic put Claude 2 out to pasture. Models have life cycles of months to a few years, not decades. If you've pinned to a specific snapshot — for good reason, because pinning is the only defence against silent behaviour changes — you'll eventually get an email with a shutdown date. And then the clock runs whether it suits you or not.
The provider silently degrades quality. The most insidious case. A model behind the same API name gets an update, and the behaviour shifts — sometimes better, sometimes worse, sometimes just different. Your carefully tuned prompts were calibrated against a moving target. Without an eval suite you can run at the push of a button, you don't notice the shift as a number but as a vaguely rising tide of support tickets three weeks later. And even if you do notice it: what's your move when you're chained to precisely this model?
All three cases share the same core. The problem isn't the provider behaving badly — providers behave sensibly from where they sit. The problem is the asymmetry: they can act, and you can only react.
Portability as engineering work
The good news: portability isn't a matter of hope, it's a matter of how you build. Four measures, in ascending order of effort.
- A thin abstraction or gateway layer. Instead of calling a provider's SDK directly from all over your code, you call a narrow internal interface behind which the provider is swappable. You needn't build this yourself: LiteLLM puts an OpenAI-compatible proxy in front of over a hundred providers, OpenRouter routes the same request to different models, the Vercel AI SDK abstracts provider differences into a common interface, Cloudflare's AI Gateway and Portkey sit in the middle as neutral brokers. The point isn't the specific tool but that the provider's name lives in one place in your code, not forty.
- Provider-agnostic prompts. Write prompts that carry on their meaning, not on a model trick. XML tags where they structure, but not as a cult. Separate the load-bearing instructions from the cosmetic ones and document which are there and why. A prompt you can explain is a prompt you can port.
- An eval suite that runs against any model. This is the highest-leverage measure of the lot. If you have a test suite that can run provider-independently against any model you like, you turn the question "should we switch?" from a holy war into an overnight measurement. You see in black and white what a switch costs or gains you in quality — and that number is the whole difference between a real exit option and merely the feeling that you have one.
- An open-weight fallback. As we set out in an earlier piece on open-weight LLMs versus the API, the gap to the frontier is now small enough for many tasks that a self-hosted model — Llama, Mistral, Qwen — is a realistic fallback. You needn't run it in production. It's enough that the architecture could: then no API provider has the certainty that you have no choice. And a fine-tune on an open-weight model delivers something a hosted fine-tune never does — weights that are yours.
The price of abstraction
Now the honest other side, or a sound observation curdles into an expensive dogma. Portability isn't free, and premature abstraction is a tax in its own right.
An abstraction layer meant to support every provider inevitably converges on the lowest common denominator. The very features that make a single model superior — OpenAI's strict Structured Outputs schema, exactly the right tool-calling behaviour, an especially large context window, a particular provider's prompt caching — are the features that won't fit through the neutral layer. Keep everything portable today and you forgo the best that's available today — as insurance against a switch you may never make.
And that insurance carries a running premium: speed. Every indirection you maintain, every prompt you flatten to the mediocre middle across several models, every eval you keep doubled up for provider neutrality, is time that doesn't go into the product. For many teams — especially early, especially when one model clearly solves the task best — "bet on an excellent model and be fast" beats hedging by a mile. A startup that builds its prototype with the strongest available model in half the time gains more than theoretical portability would ever save it.
The resolution isn't in either extreme. Lock-in is not a switch but a spectrum, and the goal isn't zero coupling — that's unaffordable and usually unnecessary. The goal is a cheap exit. You're allowed to lean hard on a model's best feature, as long as you know where that coupling sits and what unpicking it would cost. The expensive lock-in is never the deliberate one; it's the one nobody had on the list. A fine-tune whose replacement cost you know is a decision. A fine-tune you only discover isn't portable when the retirement email lands is an accident.
Conclusion
Cloud lock-in and SaaS lock-in are on every risk register because teams have learned to fear them. Model lock-in is on none, because the model layer is new and creeps in on the quiet — a tuned prompt here, a provider-specific feature there, a fine-tune that feels like an asset and is in truth a dependency. Right up to the day the price goes up, the model is retired, or the quality quietly slides — and you find you have no move.
The lesson isn't to avoid every coupling. It's to make coupling a deliberate decision rather than an operational accident. Know where you're bound, know the price of getting unbound, and keep that price low enough that "we'll switch" stays a real option and not a pious wish.
That's exactly how we work at NH Labs. We use whichever model solves a given task best — model-specific features included, when they make the difference. But underneath there's always a thin abstraction and a portable eval suite we can run against any model at the push of a button. That keeps a switch a one-night measurement rather than a one-quarter rewrite — and it keeps our clients from becoming hostages to a single price list.