← All notes

July 1, 2026

Don't serve a model. Serve a contract.

MLOpsModel servingArchitectureLLMOps

The best architecture decision I made cost 2 days and saved months. It also made my own model swappable in an afternoon.

Early on I had two problems that looked unrelated. The external backend team needed to call my ML features, and every time I refactored internals their integrations broke. And I knew I would eventually need to change the underlying model.

I solved both with the same principle: do not expose your internals, expose a contract.

What I built

A standalone service exposed every ML capability behind a stable JSON and SSE API. The external team integrated against the contract, not my code. After that, every refactor I did was invisible to them, and every new module was just a new endpoint on a consistent schema.

Then I went one layer deeper. I served the model behind an OpenAI-compatible API instead of binding the app to a specific model. The app stopped caring what model was underneath.

The payoff came months later

When I had to benchmark 5 candidate models, the swap interface already existed. I changed one config value, not the application.

Two lessons I keep coming back to:

  1. Build the interface layer before the features. The contract cost 2 days and saved weeks of cross-team integration bugs.
  2. Coupling your app to a specific model name is technical debt that gets very expensive the day the model has to change.

Serve a contract, not a model.

Written by Nadeem Yousaf, senior ML engineer. Have a project like this? Send an inquiry →