El Vendor Off-Ramp: Un Patrón para Reducir Costos de IA Sin Reescribir tu Stack
El vendor lock-in en IA no es solo molesto. Es existencial.
He visto equipos construir productos increíbles sobre un solo proveedor de modelos, lanzar rápido, celebrar, y luego abrir la siguiente factura. Ese número reescribe toda tu economía unitaria. Una renovación de contrato, un cambio de precios, un ajuste de rate-limit, y de repente tus márgenes desaparecen.
En Eventbrite, vi una versión de esto de primera mano. Los costos de APIs externas estaban en $15K por día antes de que construyera la capa de caching y deduplicación que los bajó a $40/mes. En la plataforma de Ads, una mejor visibilidad de costos llevó a descontinuar un sistema de ranking ML de terceros que costaba $60K/mes. En ambos casos, la solución no fue cambiar de proveedor - fue convertir la elección de proveedor en una decisión de enrutamiento en lugar de una decisión de arquitectura.
Este post presenta el patrón que uso y recomiendo: el Vendor Off-Ramp.
El problema: Proveedores Hardcodeados por Todas Partes
El patrón que veo más frecuentemente se ve así:
import OpenAI from 'openai';
const client = new OpenAI({
apiKey: process.env.OPENAI_API_KEY,
});
async function classifyTransaction(text: string) {
const response = await client.chat.completions.create({
model: 'gpt-4',
messages: [
{ role: 'user', content: `Classify this transaction: ${text}` },
],
});
return response.choices[0].message.content;
}
El mismo SDK de proveedor importado en cada servicio. GPT-4 para tareas de clasificación que un modelo diez veces más barato podría manejar. GPT-4 para extraer datos estructurados. GPT-4 para generar resúmenes de una oración. Sin capa de cache. Sin proveedor de respaldo. Sin lógica de enrutamiento. Llamadas crudas, sin optimizar, al modelo más caro disponible, en cada code path.
Si le preguntas al equipo "¿Qué pasa si este proveedor cambia sus precios mañana? ¿O tiene una caída de varias horas?" y la respuesta son miradas en blanco, tienes una granada activa debajo de tu P&L.
El Patrón Off-Ramp
Pienso en los vendor off-ramps en tres capas. Cada una aborda una dimensión diferente de dependencia de proveedor, y cada una potencia el valor de las otras.
Capa 1: El Model Gateway
El primer cambio, y el de mayor impacto, es poner un gateway entre tu código de aplicación y tus proveedores de modelos. En lugar de que cada servicio importe un SDK de proveedor directamente, todos hablan con tu gateway. El gateway maneja selección de proveedor, failover, lógica de reintentos y tracking de costos.
Puedes usar una solución open-source como LiteLLM, que te da una API unificada compatible con OpenAI para más de 100 proveedores de modelos. O puedes construir un router personalizado ligero si necesitas lógica de enrutamiento específica para tu dominio.
El principio es simple: tu código de aplicación nunca debe saber qué proveedor está atendiendo una solicitud. En el momento en que tu lógica de negocio contiene el nombre de un proveedor, has creado una dependencia que te costará dinero deshacer.
Capa 2: Portabilidad de Embeddings
Esta es la que los equipos pasan por alto hasta que es demasiado tarde. Si estás construyendo pipelines RAG, tus embeddings son tu activo derivado más valioso. Representan toda la base de conocimiento de tu aplicación, vectorizada e indexada.
El error que veo repetidamente: equipos generan embeddings con un proveedor, almacenan solo los vectores y descartan el texto fuente. Cuando quieren cambiar de proveedor de embeddings - porque un nuevo modelo ofrece mejor calidad de retrieval a la mitad del costo - se dan cuenta de que no pueden re-embedir sin recolectar todos los datos originales.
La solución es directa pero no obvia: siempre almacena el texto crudo junto con los vectores de embedding. Trata los embeddings como un cache que puede ser regenerado, no como la fuente de verdad. Cuando un mejor modelo de embedding aparezca (y aparecerá), ejecutas un job de re-indexación en segundo plano y listo.
Capa 3: Abstracción de Almacenamiento
El mercado de bases de datos vectoriales se mueve rápido. Pinecone, Weaviate, Qdrant, Chroma, pgvector - cada uno tiene diferentes fortalezas, diferentes modelos de precio, diferentes características de escalamiento. Hardcodear tu aplicación a una base de datos vectorial específica es el equivalente en almacenamiento de hardcodear a un proveedor LLM específico.
Un patrón adaptador que te permite intercambiar backends vectoriales sin tocar código de aplicación mantiene la interfaz intencionalmente mínima: store, query, delete. Todo lo demás es detalle de implementación.
Estas tres capas juntas forman el Vendor Off-Ramp: un conjunto de abstracciones que te dan la libertad de moverte entre proveedores basándote en costo, calidad y confiabilidad - no en cuánto código tendrías que reescribir.
La Implementación
Así se ve la arquitectura en código.
El Contrato del Gateway
type TaskTier = 'reasoning' | 'standard' | 'classification';
interface CompletionRequest {
task: TaskTier;
messages: Message[];
maxTokens?: number;
temperature?: number;
}
interface CompletionResponse {
content: string;
provider: string;
model: string;
usage: { inputTokens: number; outputTokens: number };
latencyMs: number;
cost: number;
}
interface ModelGateway {
complete(request: CompletionRequest): Promise<CompletionResponse>;
embed(input: string | string[]): Promise<EmbeddingResult>;
}
Cada servicio en el sistema habla con esta interfaz. No con OpenAI. No con Anthropic. No con Google. Con el gateway.
La Tabla de Enrutamiento
Aquí es donde está el dinero. En lugar de enviar cada solicitud al modelo más caro, enrutas por complejidad de tarea:
interface ModelConfig {
provider: string;
model: string;
priority: number;
costPer1kInput: number;
costPer1kOutput: number;
}
const ROUTING_TABLE: Record<TaskTier, ModelConfig[]> = {
reasoning: [
{
provider: 'anthropic',
model: 'claude-sonnet-4-5',
priority: 1,
costPer1kInput: 0.003,
costPer1kOutput: 0.015,
},
{
provider: 'openai',
model: 'gpt-4o',
priority: 2,
costPer1kInput: 0.01,
costPer1kOutput: 0.03,
},
],
standard: [
{
provider: 'anthropic',
model: 'claude-haiku-4-5',
priority: 1,
costPer1kInput: 0.001,
costPer1kOutput: 0.005,
},
{
provider: 'openai',
model: 'gpt-4o-mini',
priority: 2,
costPer1kInput: 0.00015,
costPer1kOutput: 0.0006,
},
],
classification: [
{
provider: 'google',
model: 'gemini-2.0-flash',
priority: 1,
costPer1kInput: 0.0001,
costPer1kOutput: 0.0004,
},
{
provider: 'anthropic',
model: 'claude-haiku-4-5',
priority: 2,
costPer1kInput: 0.001,
costPer1kOutput: 0.005,
},
],
};
Observa la cadena de failover. Cada nivel de tarea tiene un proveedor primario y uno secundario. Si Anthropic cae, el tráfico se enruta automáticamente a OpenAI. Si Google tiene un mal día, Haiku toma el trabajo de clasificación. Sin intervención humana. El sistema está blindado contra fallas de proveedor único.
El Router
async function route(
request: CompletionRequest
): Promise<CompletionResponse> {
const candidates = ROUTING_TABLE[request.task];
// Check semantic cache first
const cached = await semanticCache.get(request.messages);
if (cached) return cached;
for (const candidate of candidates) {
try {
const start = performance.now();
const response = await providers[candidate.provider].complete({
model: candidate.model,
messages: request.messages,
maxTokens: request.maxTokens,
temperature: request.temperature,
});
const result: CompletionResponse = {
content: response.content,
provider: candidate.provider,
model: candidate.model,
usage: response.usage,
latencyMs: performance.now() - start,
cost: calculateCost(response.usage, candidate),
};
// Cache the result for semantically similar future queries
await semanticCache.set(request.messages, result);
await costTracker.record(result);
return result;
} catch (error) {
logger.warn(
`Failover: ${candidate.provider}/${candidate.model} failed`,
{ error }
);
continue;
}
}
throw new Error('All providers exhausted for task: ' + request.task);
}
Dos detalles importan aquí. Primero, el cache semántico: antes de hacer cualquier llamada a la API, verificamos si una consulta suficientemente similar fue respondida recientemente. Para tareas de clasificación especialmente, esto puede eliminar más del 30% de llamadas redundantes. Segundo, el tracker de costos: cada respuesta registra su costo real, lo que te da la observabilidad para saber exactamente a dónde va el dinero.
La Abstracción de Embeddings
interface EmbeddingStore {
store(
id: string,
text: string,
metadata?: Record<string, unknown>
): Promise<void>;
query(
text: string,
options?: { topK?: number; filter?: Record<string, unknown> }
): Promise<SearchResult[]>;
reindex(provider: EmbeddingProvider): Promise<ReindexReport>;
}
El método reindex es la escotilla de escape. Cuando un mejor modelo de embedding aparece (y en este mercado, eso pasa cada trimestre), llamas reindex con el nuevo proveedor, y el sistema re-embede cada documento almacenado en segundo plano. Sin proyecto de migración. Sin downtime. Simplemente avanzas.
Cuándo NO Abstraer
Sería irresponsable presentar esto como un patrón universal. No lo es. Hay situaciones reales donde construir una capa de abstracción de proveedores es prematuro o contraproducente.
Antes del product-market fit. Si aún estás descubriendo si los clientes quieren tu producto, no pases tres meses construyendo un model gateway. Envía con un solo proveedor. Valida el negocio. La abstracción puede venir después.
Cuando compliance requiere un proveedor específico. Algunas industrias reguladas exigen que el procesamiento de datos ocurra a través de proveedores aprobados. En contextos de salud y defensa, he visto casos donde el vendor lock-in es la funcionalidad - satisface un requisito de auditoría. Abstraer alrededor crea riesgo de compliance.
Cuando el impuesto de abstracción excede el ahorro. Cada capa que agregas introduce latencia, modos de falla y carga cognitiva para tu equipo. Si tu gasto en IA es $2K/mes, un gateway es sobre-ingeniería. El punto de equilibrio, en mi experiencia, está alrededor de $15-20K/mes en gasto de IA. Por debajo de eso, el costo operativo de mantener la abstracción supera los ahorros.
Cuando genuinamente solo usas una capacidad. Si toda tu integración de IA es un solo endpoint de resumen, un gateway completo es un mazo para un clavo. Empieza con una interfaz simple de proveedor y crece desde ahí.
La evaluación siempre es la misma: ¿el costo de la abstracción es menor que el costo de la dependencia? Si no estás seguro, probablemente no lo necesitas aún.
El Principio de Fondo
El vendor off-ramp realmente no se trata de proveedores. Se trata de opcionalidad.
El ecosistema de modelos de IA se mueve más rápido que cualquier mercado tecnológico en el que he trabajado. El mejor modelo para tu caso de uso hoy no será el mejor en seis meses. El proveedor más barato este trimestre no será el más barato el siguiente. Si tu arquitectura no puede absorber ese cambio sin una reescritura, tu economía unitaria está a merced de fuerzas que no controlas.
Aprendí esto en Eventbrite. Los costos de APIs externas eran $15K/día porque no había capa de abstracción, no había caching, no había deduplicación. Construir esa capa no solo ahorró dinero - nos dio la capacidad de redirigir, optimizar y medir sin tocar código de aplicación. El mismo principio aplica a proveedores de LLMs.
Las tres preguntas que hago en cada sistema que reviso:
- ¿Cuál es tu costo por inferencia, desglosado por tarea? Si no conoces este número, no puedes optimizarlo.
- ¿Cuánto tardarías en cambiar de proveedor para tu endpoint de mayor volumen? Si la respuesta es "semanas" o "no sé", tienes una dependencia de proveedor, no una relación.
- ¿Estás almacenando texto crudo junto con tus embeddings? Si no, tu activo de datos más valioso está bloqueado al modelo de embedding que elegiste el día uno.
Construir infraestructura de IA sostenible significa diseñar para el ecosistema que tendrás en dos años, no el de hoy. Los proveedores cambiarán. Los modelos cambiarán. Los precios cambiarán. La única pregunta es si tu arquitectura está preparada para eso.
Si estás revisando tus propios costos de infraestructura de IA y te preguntas si hay un off-ramp, escríbeme. Este es el tipo de pensamiento sistémico que aporto a cada proyecto.