The first model you build on will not be the last. Capability moves every few months, prices move with it, and the provider that suits your work today may raise its rates, retire the version you depend on, or change what it is allowed to do with your data. None of that is a reason to wait. It is a reason to build so that changing providers is a routine job rather than a project nobody wants to start.
The cost of that change is set at build time, usually without anyone deciding it. A team integrates one model, ships, and moves on. A year later the prompts, the data, the glue code and the contract have all grown around a single vendor, and the question “could we switch?” has an answer nobody likes.
Four decisions, made early, set that cost. Before getting to them, it is worth being clear about where the coupling builds up, because the obvious place is the least of it.
Most of the coupling is not in the API call
The API integration is the part teams plan for, and it is rarely the problem. The coupling that costs real time grows around it, in places nobody wrote down:
- Prompts tuned to one model’s habits, with no record of which behaviours were deliberate.
- Output parsing that depends on one model’s formatting quirks.
- Tool definitions, memory, retrieval and workflow logic kept inside the vendor’s hosted features rather than in your code.
- Embeddings stored without the source text they were made from, so a new embedding model means collecting the data again.
- A fine-tune whose training set was never kept in one place.
Each of these is cheap to avoid at the start and expensive to unwind later.
One interface, many providers
Put every model call behind a thin layer your team owns. It takes a request described in your terms, the task, its inputs and the schema the answer must fit, and returns a validated result. The provider and the model name are configuration, not code.
Thin is the point. The layer should not try to hide every difference between vendors, only hold the few things that must stay consistent: how a request is logged, how an output is checked against its schema, how a failure is retried, and which model handled the call. Prompts and tool definitions live in files under version control, next to the application, with the model version they were last tested against.
Use a vendor’s hosted extras, such as built-in memory, managed agents or a drag-and-drop workflow builder, for experiments. Keep anything the business depends on in code you can point at a different provider. Where a provider-specific feature earns its place, wrap it so the dependency is visible, and write down what replacing it would involve.
Your data stays in your systems
A provider should read from your records. It should never become the place the records live. That covers more than the database: retrieval documents, the logs of what the system was asked and what it answered, your team’s corrections, the written rules a process runs on, and the source text behind every embedding all belong in storage you control, in formats another vendor’s tooling can read.
Make export a scheduled job rather than an intention. If a vendor’s product holds conversation history or uploaded files, pull a copy on a cadence and confirm the copy is usable. The day you need it should not be the first time anyone tries.
An evaluation suite makes switching a test run
The asset that does most for portability is an evaluation suite: your own past cases, each paired with the answer a person signed off on. It does not need to be large to start. Take the outputs your team corrected last month, save each one with its input and the right answer, and keep adding every correction from here on. We described the habit in What makes a company AI-native.
With that suite in place, a new model is a candidate rather than a bet. Run the suite, compare accuracy, cost and latency with the current provider, and decide on the numbers. The same run catches regressions when a vendor updates a model underneath you, and it settles prompt debates that would otherwise go by anecdote.
Without it, nobody switches, however much it would save, because nobody can say what would break.
Contract terms that keep the exit open
The commercial side is the least technical part and the most often skipped. Before signing, get these in writing:
- A ceiling on price rises at renewal, or failing that a long notice period.
- No training on your inputs or outputs unless you opt in.
- Export of your data in a documented format, on request, within a stated number of days.
- Advance notice before a model version is retired, long enough to run your suite against its replacement.
- Deletion of your data on exit, confirmed in writing.
- Commitments sized to what you have measured, not to the discount on offer.
If a vendor will not agree to the export clause, treat that as the answer to a different question.
Commitment is still allowed
None of this is an argument for treating every provider as a threat. A thin layer, a kept evaluation suite and a clean contract are cheap. A policy of refusing anything one vendor does well is not: it means slower builds, a weaker product, and engineers maintaining hedges against a switch that may never come.
The useful question is not how to depend on nobody. It is which dependencies you have chosen, what each would take to replace, and whether that answer is written down somewhere other than one engineer’s head. Keep the list of parts that assume a single provider short, and be able to say how long replacing each would take. A dependency you can name and bound is a decision. One you discover at renewal is a problem.
This is how we build: model-agnostic, with the code handed over, the evaluation suite in your repository, and no commission from any provider. If you would like an outside view of which parts of your systems would survive a change of provider, that is a short conversation we are glad to have.