Artificial Intelligence

Building Reliable AI Integrations

Treating an LLM API like any other unreliable third-party dependency — with retries, validation, and fallbacks — is most of the work.

Integrating an LLM API into a production system is, mechanically, similar to integrating any third-party API with variable latency and occasional failures. The mistake we see most often is treating it differently — as though its outputs can be trusted unvalidated because they're produced by a sophisticated model, rather than as an external dependency that needs the same defensive engineering as any other.

Validate structured output, always

If you're asking a model to return structured data — JSON matching a schema, a specific set of fields — validate the response against that schema before using it anywhere downstream. Models occasionally return malformed output, unexpected types, or fields that don't match what you asked for. A validation failure should be treated as a retryable error, the same way you'd treat a malformed response from any other API, not something you try to coerce into shape with brittle string manipulation.

Design explicit timeout and retry behavior

LLM API calls can be slow, and occasionally fail outright. Define sensible timeouts, retry transient failures with backoff, and — critically — decide what your application does if the call ultimately fails after retries. "The feature silently doesn't work" is a worse failure mode than a clear, user-visible degraded state.

Never trust model output for anything security- or business-critical without a check

Prompt injection is a real risk for any system that includes untrusted user input in a prompt alongside instructions. If your system's behavior can be influenced by text a user controls, assume it eventually will be, and design accordingly — don't let a model's output directly trigger a sensitive action (a database write, an email send, a payment) without a validation or authorization step that doesn't depend on the model having behaved correctly.

Keep secrets and provider details server-side

API keys for AI providers should never reach the client. This sounds obvious, but it's a mistake we still see in early-stage products that started as a client-side prototype and never got a proper server-side boundary added before shipping. Every AI call should route through your own server, both for key security and so you have a place to add validation, logging, and rate limiting.

Build a provider abstraction, even if you only use one provider today

Wrapping AI provider calls behind your own interface — rather than calling the vendor SDK directly throughout your codebase — costs little upfront and pays off the first time you need to switch models, add a fallback provider, or handle a provider outage gracefully. It also gives you one place to add cross-cutting concerns like logging, rate limiting, and cost tracking, instead of scattering that logic across every call site.

Log inputs and outputs for anything that matters

When an AI-powered feature behaves unexpectedly in production, you need to be able to see what was actually sent to the model and what came back — not just the final rendered output. This is the same debugging discipline you'd want for any complex system, and skipping it for AI calls specifically because "the model is a black box anyway" makes debugging meaningfully harder than it needs to be.

Treat the model API like any other dependency you don't fully control: validate what it gives you, plan for it to fail sometimes, and never let it be the only thing standing between untrusted input and a consequential action.

LLMsAPIsSecurity

Working through something similar?

Happy to talk through how this applies to your specific situation.