A Simple Way to Add AI to Your App Without Locking Yourself to One Provider A developer outlines a pattern for adding large language models to applications through a thin, provider-agnostic AI layer, using the open-source Vercel AI SDK in TypeScript to route requests between OpenAI, Anthropic, and local models. The approach centralizes model selection, retries, logging, and observability in one module so that switching or mixing providers does not require touching controllers, routes, or UI code. The writeup also points to LiteLLM for a unified self-hosted gateway and the Model Context Protocol for exposing tools and resources to AI clients. Adding an LLM to an application is easy. The annoying part usually comes six months later. Maybe you started with OpenAI, then another model becomes better for one particular task. Or you want to use a cheaper model for background jobs and a stronger model for user-facing requests. If model-specific code is scattered throughout the application, changing providers becomes unnecessarily painful. A pattern I like is keeping the AI layer very small. For a TypeScript project, an open-source option for this is the AI SDK. Install the core package and whichever providers you need: npm install ai @ai-sdk/openai @ai-sdk/anthropic Instead of calling provider SDKs directly from controllers, routes, or UI code, create one small AI module. js // lib/ai.ts import { generateText } from "ai"; import { openai } from "@ai-sdk/openai"; import { anthropic } from "@ai-sdk/anthropic"; const models = { openai: openai process.env.OPENAI MODEL , anthropic: anthropic process.env.ANTHROPIC MODEL }; export async function askAI prompt: string, provider: keyof typeof models = "openai" { const { text } = await generateText { model: models provider , prompt } ; return text; } Now the rest of the application doesn't really care which company is serving the model. js const summary = await askAI "Summarize this customer support conversation", "anthropic" ; The useful part isn't saving a few lines of code. It's creating a boundary. Once AI starts appearing in multiple parts of a product, it's very easy to end up with something like this: php /api/chat - Provider A /api/summarize - Provider A /jobs/classify - Provider A /api/search - Provider A /admin/generate - Provider A Then configuration, retries, logging and prompts slowly get duplicated everywhere. I'd rather have: Application | v AI Layer | +---- Provider A +---- Provider B +---- Local/Open Model The application talks to your AI layer. The AI layer decides where the request goes. Once this abstraction exists, routing doesn't need to be static either. For example: export async function generateForTask task: "classification" | "reasoning", prompt: string { const provider = task === "classification" ? "openai" : "anthropic"; return askAI prompt, provider ; } In a real application I would probably take this further and route based on things like: This also gives you one place to add observability. js const started = Date.now ; try { const result = await askAI prompt, provider ; console.log { provider, duration: Date.now - started, success: true } ; return result; } catch error { console.error { provider, duration: Date.now - started, success: false } ; throw error; } Nothing complicated, but suddenly debugging AI requests becomes much easier. Another thing I try to avoid is letting the UI know too much about the underlying provider. The frontend should ideally call something like: POST /api/summarize rather than: POST /api/openai/generate Your product feature is summarization . OpenAI, Anthropic, Gemini or a local model is an implementation detail. That distinction becomes useful surprisingly quickly. There are a few interesting projects solving different parts of this problem. Vercel AI SDK provides a common TypeScript interface for working with multiple AI providers. LiteLLM takes a similar idea further on the infrastructure side, providing a unified interface and an optional self-hosted gateway for many different model providers. For applications that need tools and external integrations, Model Context Protocol MCP is also worth looking at. Instead of writing a completely different integration system for every AI client, MCP provides a common protocol for exposing tools and resources. They solve different problems, but they point in roughly the same direction: Keep your application architecture separate from whichever AI model happens to be popular today. I don't think most applications need a huge "AI platform" abstraction from day one. A small module is usually enough. The important part is simply avoiding provider-specific calls everywhere in the codebase. Start with: php App - AI abstraction - Provider Then add routing, fallbacks, logging, caching and more advanced infrastructure only when the application actually needs them. AI models are changing too quickly to make them the foundation of your application architecture. Your product should depend on a capability. Not a model name.