An LLM feature is mostly ordinary software
The interesting part of shipping AI inside an existing product is how little of
the work is about the model. The model call is a function invocation. Everything
around it — the boundary it sits behind, the schema it must conform to, the way
partial output renders, what happens on a timeout, who pays for the tokens — is
ordinary software engineering, and it is where these projects succeed or fail.
That framing is useful because your team already knows how to do ordinary software
engineering well. The failures we get called in to fix are rarely exotic. They are
vendor SDK calls sprinkled across twelve modules, prompts hard-coded beside
business logic, no validation between the model and the database, and no idea
which customer is generating the inference bill.
Provider abstraction is not premature optimisation
It is tempting to call the vendor SDK directly and move on. The reason not to is
empirical: model providers change prices, deprecate versions on their own
timetable, and periodically ship a model that is materially better or cheaper than
what you are using.
If your application talks to your own interface, swapping is a configuration
change plus an evaluation run. If it talks to a vendor SDK in a dozen places, the
same swap is a refactor you did not schedule. The abstraction costs perhaps a day
to build and pays for itself the first time either of those happens — which, at
the current pace, is roughly every few months.
Validate at the boundary, always
Structured output modes have made model responses far more reliable, and they are
still not a guarantee. Assume conformance and you will eventually write malformed
data into a system of record, discover it weeks later as a data-quality incident,
and spend longer tracing the cause than the original feature took to build.
The rule is simple: parse, validate against the schema in your own code, and treat
a failure as a retryable error with a repair prompt. Never regex free text, and
never persist anything that did not pass validation.
Cost has to be attributable before it becomes a problem
A single provider invoice tells you nothing actionable. You need cost per feature
and per tenant, because the two questions you will be asked are “which feature is
expensive” and “which customers are unprofitable” — and neither is answerable
retrospectively without the logging in place.
The same instrumentation makes routing possible. Once you can see that intent
classification is 60% of your call volume, moving it to a small model is an obvious
decision rather than a speculative one.