Back

Cómo reducir tus costos de API LLM en un 90%: Caching, Routing y Optimización de Prompts que funcionan de verdad

Tu factura de API LLM acaba de llegar a 2,400estemes.Elmespasadofueron2,400 este mes. El mes pasado fueron 800. El anterior, $300. Tu producto crece, a los usuarios les encantan las funciones de IA, y el equipo de finanzas empieza a hacer preguntas incómodas.

¿Te suena? No sos el único. En 2026, el producto SaaS promedio con IA gasta entre el 30 y 50% de su presupuesto de infraestructura en llamadas a APIs de LLM. Y la mayor parte de ese gasto es completamente innecesario.

La verdad incómoda: la mayoría de las aplicaciones envían consultas redundantes, usan modelos caros para tareas triviales y transmiten muchos más tokens de los necesarios. La solución no es usar menos IA — es usarla de forma más inteligente.

En esta guía cubrimos cinco estrategias probadas en producción para reducir tus costos de API LLM entre 70-90% sin sacrificar calidad. No son trucos teóricos. Cada técnica incluye código listo para producción, cálculos de costos reales y análisis franco de trade-offs.

Primero lo primero: Entender la estructura de costos

Antes de optimizar nada, necesitás entender cómo te están cobrando realmente. La mayoría de los devs tienen una idea vaga de que "los tokens cuestan plata" pero no entienden el panorama completo.

La economía de tokens

Todos los proveedores principales cobran por token, pero la matemática no es lineal:

Snapshot de precios 2026 (por 1M de tokens):

┌─────────────────────────┬──────────┬───────────┐
│ Modelo                  │  Input   │  Output   │
├─────────────────────────┼──────────┼───────────┤
│ GPT-4.1                 │  $1.00   │   $4.00   │
│ GPT-4.1 mini            │  $0.20   │   $0.80   │
│ GPT-4.1 nano            │  $0.05   │   $0.20   │
│ Claude Opus 4.6         │  $5.00   │  $25.00   │
│ Claude Sonnet 4.6       │  $3.00   │  $15.00   │
│ Claude Haiku 4.5        │  $1.00   │   $5.00   │
│ Gemini 2.5 Pro          │  $1.25   │  $10.00   │
│ Gemini 2.5 Flash        │  $0.30   │   $2.50   │
│ DeepSeek V4             │  $0.30   │   $0.50   │
└─────────────────────────┴──────────┴───────────┘

Dos cosas saltan a la vista:

  1. Los tokens de salida cuestan 3-5x más que los de entrada. Un prompt de 200 tokens que genera una respuesta de 2,000 tokens cuesta mucho más de lo que esperarías mirando solo la entrada.
  2. La diferencia entre tiers es enorme. Claude Opus 4.6 cuesta 125x más por token de salida que GPT-4.1 nano. Y para muchas tareas, el modelo barato funciona igual de bien.

Dónde se va la plata realmente

En una aplicación con IA típica, los costos se distribuyen así:

Distribución típica de costos LLM:

  Consultas repetidas/similares:         35-45%  ← Cacheable
  Tareas simples en modelos premium:     20-30%  ← Redirigible a modelos baratos
  Prompts inflados:                      15-20%  ← Comprimible
  Consultas únicas complejas inevitables: 10-20%  ← Optimizar largo de salida

Eso significa que entre 60-80% de tu gasto en LLM es reducible sin tocar la calidad del producto. Vamos estrategia por estrategia.

Estrategia 1: Semantic Caching

Es la optimización con mayor retorno. Si tu aplicación maneja patrones repetitivos — soporte al cliente, generación de contenido, asistencia de código, búsqueda — probablemente estás haciendo llamadas idénticas o casi idénticas miles de veces.

El problema del caching tradicional

El caching tradicional usa matching exacto de strings. Pero las consultas a LLMs casi nunca son idénticas. Mirá estas tres entradas de usuario:

"¿Cómo reseteo mi contraseña?"
"¿Cómo cambio mi contraseña?"
"Olvidé mi contraseña, ¿cómo la recupero?"

Semánticamente son idénticas — deberían devolver la misma respuesta. Pero un cache de matching exacto las trata como tres llamadas facturables separadas.

Cómo funciona el Semantic Caching

Convierte las consultas en vectores de embedding y usa similitud coseno para encontrar respuestas cacheadas "suficientemente similares" en significado:

import { OpenAI } from 'openai'; import { createClient } from 'redis'; import { Index } from '@upstash/vector'; const openai = new OpenAI(); const redis = createClient(); const vectorIndex = new Index({ url: process.env.UPSTASH_VECTOR_URL!, token: process.env.UPSTASH_VECTOR_TOKEN!, }); interface CachedResponse { response: string; model: string; timestamp: number; hitCount: number; } const SIMILARITY_THRESHOLD = 0.92; // Afiná esto con cuidado const CACHE_TTL = 86400; // 24 horas async function queryWithSemanticCache( prompt: string, systemPrompt: string, model: string = 'gpt-4.1-mini' ): Promise<{ response: string; cached: boolean; savings: number }> { // 1. Generar embedding de la consulta entrante const embedding = await openai.embeddings.create({ model: 'text-embedding-3-small', input: `${systemPrompt}\n${prompt}`, }); const vector = embedding.data[0].embedding; // 2. Buscar consultas cacheadas semánticamente similares const results = await vectorIndex.query({ vector, topK: 1, includeMetadata: true, }); // 3. Verificar si hay un match suficientemente cercano if (results.length > 0 && results[0].score >= SIMILARITY_THRESHOLD) { const cacheKey = results[0].id; const cached = await redis.get(`llm:${cacheKey}`); if (cached) { const parsed: CachedResponse = JSON.parse(cached); parsed.hitCount++; await redis.set(`llm:${cacheKey}`, JSON.stringify(parsed), { EX: CACHE_TTL, }); return { response: parsed.response, cached: true, savings: estimateCost(prompt, parsed.response, model), }; } } // 4. Cache miss — hacer la llamada real const completion = await openai.chat.completions.create({ model, messages: [ { role: 'system', content: systemPrompt }, { role: 'user', content: prompt }, ], }); const response = completion.choices[0].message.content!; // 5. Guardar en vector index y Redis const cacheId = crypto.randomUUID(); await vectorIndex.upsert({ id: cacheId, vector, metadata: { prompt: prompt.slice(0, 200) }, }); await redis.set( `llm:${cacheId}`, JSON.stringify({ response, model, timestamp: Date.now(), hitCount: 0, } satisfies CachedResponse), { EX: CACHE_TTL } ); return { response, cached: false, savings: 0 }; }

El threshold de similitud lo es todo

El SIMILARITY_THRESHOLD es el parámetro de ajuste más crítico. Si lo configurás mal:

  • Demasiado alto (>0.97): Casi nada matchea. Hit rate cercana a cero. Construiste un no-op caro.
  • Demasiado bajo (<0.85): Consultas sin relación devuelven respuestas cacheadas. Los usuarios reciben respuestas incorrectas.

El punto óptimo depende de tu caso de uso:

Caso de UsoThreshold RecomendadoPor qué
FAQ / Soporte0.90 - 0.93Las preguntas se agrupan por tema
Generación de código0.95 - 0.97Diferencias mínimas producen código distinto
Resumen de contenido0.88 - 0.92Mismo doc → mismo resumen sin importar la redacción
Escritura creativaNo cachearCada respuesta debe ser única

Impacto real en costos

La matemática para un chatbot de soporte procesando 100,000 consultas/mes:

Sin caching:
  100,000 consultas × ~500 tokens input × ~800 tokens output
  = 50M input + 80M output tokens
  GPT-4.1 mini: (50 × $0.20) + (80 × $0.80) = $74/mes

Con semantic caching (65% hit rate):
  35,000 llamadas API reales + 65,000 cache hits
  Embeddings: $0.04
  API: (17.5M × $0.20 + 28M × $0.80) / 1M = $25.90/mes
  Vector DB: ~$10 / Redis: ~$5
  Total: ~$41/mes → 45% de ahorro

Y eso con un hit rate conservador del 65%. Aplicaciones con patrones repetitivos suelen superar el 80%, con ahorros superiores al 70%.

Estrategia 2: Routing Inteligente de Modelos

Esta es la optimización que la mayoría de los equipos saltean porque parece complejidad innecesaria. Pero la matemática es convincente: probablemente estás usando un modelo de 15/Mtokensparatareasqueunmodelode15/M tokens para tareas que un modelo de 0.05/M resuelve igual de bien.

La arquitectura de routing

La idea es simple: antes de enviar una request a un modelo caro, clasificala y redirigila al modelo más barato que pueda resolverla.

type ComplexityLevel = 'trivial' | 'simple' | 'moderate' | 'complex'; interface RouteConfig { model: string; maxTokens: number; temperature: number; costPer1MInput: number; costPer1MOutput: number; } const MODEL_ROUTES: Record<ComplexityLevel, RouteConfig> = { trivial: { model: 'gpt-4.1-nano', maxTokens: 256, temperature: 0.1, costPer1MInput: 0.05, costPer1MOutput: 0.20, }, simple: { model: 'gpt-4.1-mini', maxTokens: 1024, temperature: 0.3, costPer1MInput: 0.20, costPer1MOutput: 0.80, }, moderate: { model: 'claude-haiku-4.5', maxTokens: 2048, temperature: 0.5, costPer1MInput: 1.00, costPer1MOutput: 5.00, }, complex: { model: 'claude-sonnet-4.6', maxTokens: 4096, temperature: 0.7, costPer1MInput: 3.00, costPer1MOutput: 15.00, }, }; async function classifyComplexity(prompt: string): Promise<ComplexityLevel> { // ¡Usar el modelo más barato para clasificar — meta-optimización! const classification = await openai.chat.completions.create({ model: 'gpt-4.1-nano', max_tokens: 10, temperature: 0, messages: [ { role: 'system', content: `Classify the user query complexity. Respond with ONLY one word: - "trivial": greeting, yes/no question, simple lookup - "simple": single-step task, basic Q&A, formatting - "moderate": multi-step reasoning, comparison, analysis - "complex": creative writing, code generation, deep research Respond with the single classification word only.`, }, { role: 'user', content: prompt }, ], }); const level = classification.choices[0].message.content! .trim().toLowerCase() as ComplexityLevel; return MODEL_ROUTES[level] ? level : 'simple'; } async function routedQuery( prompt: string, systemPrompt: string ): Promise<{ response: string; model: string; cost: number }> { const complexity = await classifyComplexity(prompt); const route = MODEL_ROUTES[complexity]; const response = await callModel(route.model, systemPrompt, prompt, { maxTokens: route.maxTokens, temperature: route.temperature, }); const inputTokens = estimateTokens(systemPrompt + prompt); const outputTokens = estimateTokens(response); const cost = (inputTokens / 1_000_000) * route.costPer1MInput + (outputTokens / 1_000_000) * route.costPer1MOutput; return { response, model: route.model, cost }; }

La paradoja del costo de clasificación

"Momento — estás haciendo una llamada API extra solo para clasificar. ¿Eso no cuesta más?"

Hagamos los números. La clasificación usa GPT-4.1 nano con ~100 tokens input y ~5 output:

Costo de clasificación por consulta:
  (100 / 1M) × $0.05 + (5 / 1M) × $0.20 = $0.000006

Sin routing (todo a Claude Sonnet 4.6):
  (500 / 1M) × $3.00 + (800 / 1M) × $15.00 = $0.0135

Con routing (40% Sonnet, 30% Haiku, 20% Mini, 10% Nano):
  = (0.4 × $0.0135) + (0.3 × $0.0045) + (0.2 × $0.00074) + (0.1 × $0.000185) + $0.000006
  = $0.0069 por consulta

Ahorro: 49% por consulta

El clasificador se paga solo 1000 veces. Y eso es conservador.

Avanzado: Routing con validación de calidad y fallback

La versión más inteligente no solo rutea — valida que el modelo barato haya dado un resultado aceptable:

async function routedQueryWithFallback( prompt: string, systemPrompt: string, qualityThreshold: number = 0.7 ): Promise<{ response: string; model: string; attempts: number }> { const complexity = await classifyComplexity(prompt); const route = MODEL_ROUTES[complexity]; const response = await callModel(route.model, systemPrompt, prompt, { maxTokens: route.maxTokens, }); // Para rutas no complejas, verificar calidad con un chequeo barato if (complexity !== 'complex') { const qualityScore = await quickQualityCheck(prompt, response); if (qualityScore < qualityThreshold) { // Escalar al siguiente tier const nextTier = getNextTier(complexity); const betterResponse = await callModel( MODEL_ROUTES[nextTier].model, systemPrompt, prompt, { maxTokens: MODEL_ROUTES[nextTier].maxTokens } ); return { response: betterResponse, model: MODEL_ROUTES[nextTier].model, attempts: 2 }; } } return { response, model: route.model, attempts: 1 }; }

Estrategia 3: Compresión de Prompts

La mayoría de los prompts están inflados. Los system prompts especialmente tienden a crecer con el tiempo. Un system prompt que empezó en 200 tokens se infla a 2,000 — y ese costo se multiplica con cada request.

Auditá tus system prompts

Antes (847 tokens):

You are a helpful customer support assistant for our e-commerce platform.
You should always be polite and professional in your responses.
When a customer asks about their order, you should look up the order
details and provide them with relevant information about the status
of their order, including the tracking number if available...
(continúa 400 tokens más)

Después (189 tokens):

E-commerce support agent. Rules:
- Lookup order details, provide status + tracking if available
- If no access to order data, direct to support team
- Match customer's language
- Never reveal internal systems/pricing/employee info
- For frustrated customers: acknowledge → empathize → solve
- Tone: professional, warm, concise

Mismo comportamiento, 78% menos tokens. A 100,000 consultas/mes con GPT-4.1 mini:

Ahorro de tokens: 658 tokens × 100,000 = 65.8M tokens/mes
Ahorro de costos: (65.8 / 1M) × $0.20 = $13.16/mes solo en input

13/messuenapoco,peroseacumula.Con10featuresdeIAypromptsinflados,son13/mes suena poco, pero se acumula. Con 10 features de IA y prompts inflados, son 130/mes — $1,560/año — solo por podar system prompts.

Compresión programática de prompts

Para prompts dinámicos que incluyen contexto (RAG, historial de conversación), comprimí antes de enviar:

function compressConversationHistory( messages: Array<{ role: string; content: string }>, maxTokens: number = 2000 ): Array<{ role: string; content: string }> { const estimated = messages.reduce( (sum, m) => sum + estimateTokens(m.content), 0 ); if (estimated <= maxTokens) return messages; // Estrategia: conservar primer mensaje (contexto) y últimos N // Resumir los del medio const first = messages[0]; const last3 = messages.slice(-3); const middle = messages.slice(1, -3); if (middle.length === 0) return messages; const middleSummary = middle .map(m => `${m.role}: ${m.content.slice(0, 50)}...`) .join('\n'); return [ first, { role: 'system', content: `[Resumen de la conversación: ${middleSummary}]`, }, ...last3, ]; }

La trampa del token de salida

Recordá: los tokens de salida cuestan 3-5x más que los de entrada. Configurar max_tokens es la forma más fácil de controlar costos:

// ❌ Mal: Dejar que el modelo se extienda const response = await openai.chat.completions.create({ model: 'gpt-4.1-mini', messages: [{ role: 'user', content: 'Resumí este artículo' }], // Sin max_tokens = el modelo decide el largo }); // ✅ Bien: Restringir largo de salida const response = await openai.chat.completions.create({ model: 'gpt-4.1-mini', messages: [{ role: 'user', content: 'Resumí este artículo en 3 oraciones.' }], max_tokens: 200, // Límite duro como red de seguridad });

Para salidas estructuradas, usá modo JSON con schemas — produce respuestas consistentemente más cortas y predecibles:

const response = await openai.chat.completions.create({ model: 'gpt-4.1-mini', response_format: { type: 'json_schema', json_schema: { name: 'sentiment_analysis', schema: { type: 'object', properties: { sentiment: { type: 'string', enum: ['positive', 'negative', 'neutral'] }, confidence: { type: 'number' }, keywords: { type: 'array', items: { type: 'string' }, maxItems: 5 }, }, required: ['sentiment', 'confidence', 'keywords'], }, }, }, messages: [{ role: 'user', content: `Analizá: "${text}"` }], max_tokens: 100, });

Estrategia 4: Procesamiento Batch

Si tu workload no es time-sensitive, las batch APIs ofrecen descuentos fuertes. La Batch API de OpenAI cobra 50% menos que las llamadas real-time. Para procesamiento en segundo plano — generación nocturna de contenido, clasificación masiva, enriquecimiento de datos — es plata gratis.

Cuándo usar batch

Requiere tiempo real:
  ✗ Chat cara al usuario
  ✗ Autocompletado de código en vivo
  ✗ Búsqueda interactiva

Apto para batch:
  ✓ Resúmenes nocturnos de contenido
  ✓ Clasificación masiva de emails
  ✓ Generación de reportes semanales
  ✓ Etiquetado y enriquecimiento de datos
  ✓ Backlog de moderación de contenido
  ✓ Tandas de traducción

Implementación

import { OpenAI } from 'openai'; import * as fs from 'fs'; const openai = new OpenAI(); interface BatchItem { custom_id: string; method: 'POST'; url: '/v1/chat/completions'; body: { model: string; messages: Array<{ role: string; content: string }>; max_tokens: number; }; } async function submitBatchJob( items: Array<{ id: string; prompt: string }>, systemPrompt: string, model: string = 'gpt-4.1-mini' ): Promise<string> { // 1. Crear archivo JSONL const batchLines: string[] = items.map(item => { const batchItem: BatchItem = { custom_id: item.id, method: 'POST', url: '/v1/chat/completions', body: { model, messages: [ { role: 'system', content: systemPrompt }, { role: 'user', content: item.prompt }, ], max_tokens: 1024, }, }; return JSON.stringify(batchItem); }); const filePath = `/tmp/batch-${Date.now()}.jsonl`; fs.writeFileSync(filePath, batchLines.join('\n')); // 2. Subir archivo const file = await openai.files.create({ file: fs.createReadStream(filePath), purpose: 'batch', }); // 3. Crear batch const batch = await openai.batches.create({ input_file_id: file.id, endpoint: '/v1/chat/completions', completion_window: '24h', }); return batch.id; } async function checkBatchStatus(batchId: string) { const batch = await openai.batches.retrieve(batchId); if (batch.status === 'completed') { const file = await openai.files.content(batch.output_file_id!); const text = await file.text(); const results = text .split('\n') .filter(Boolean) .map(line => JSON.parse(line)); return results; } return { status: batch.status, progress: `${batch.request_counts.completed}/${batch.request_counts.total}` }; }

Impacto en costos

Para un job nocturno que procesa 10,000 ítems:

API real-time (GPT-4.1 mini):
  10,000 × (500 input + 800 output tokens)
  = (5M × $0.20 + 8M × $0.80) / 1M = $7.40

Batch API (50% descuento):
  = $3.70

Ahorro mensual: ~$111 (asumiendo ejecución diaria)
Ahorro anual: ~$1,332

Estrategia 5: Gateway LLM y Observabilidad

No podés optimizar lo que no podés medir. Un gateway LLM se interpone entre tu aplicación y los proveedores, dándote:

  • Atribución de costos por feature — sabé qué feature está quemando plata
  • Retry automático y failover — si OpenAI cae, redirigí a Anthropic
  • Rate limiting — prevení costos descontrolados por bugs o abuso
  • Analytics de uso — encontrá oportunidades de optimización

Construyendo un gateway liviano

interface LLMRequest { featureId: string; prompt: string; systemPrompt: string; model?: string; maxTokens?: number; userId?: string; } interface LLMMetrics { featureId: string; model: string; inputTokens: number; outputTokens: number; cost: number; latencyMs: number; cached: boolean; timestamp: number; } class LLMGateway { private metrics: LLMMetrics[] = []; private rateLimiter: Map<string, { count: number; resetAt: number }> = new Map(); async query(request: LLMRequest): Promise<string> { // 1. Rate limiting this.enforceRateLimit(request.featureId); // 2. Chequeo de presupuesto await this.checkBudget(request.featureId); const startTime = Date.now(); // 3. Intentar semantic cache primero const cached = await queryWithSemanticCache( request.prompt, request.systemPrompt, request.model ); if (cached.cached) { this.recordMetrics({ featureId: request.featureId, model: request.model || 'gpt-4.1-mini', inputTokens: 0, outputTokens: 0, cost: 0, latencyMs: Date.now() - startTime, cached: true, timestamp: Date.now(), }); return cached.response; } // 4. Rutear al modelo óptimo const result = await routedQuery(request.prompt, request.systemPrompt); // 5. Registrar métricas this.recordMetrics({ featureId: request.featureId, model: result.model, inputTokens: estimateTokens(request.prompt + request.systemPrompt), outputTokens: estimateTokens(result.response), cost: result.cost, latencyMs: Date.now() - startTime, cached: false, timestamp: Date.now(), }); return result.response; } getFeatureCosts(period: 'day' | 'week' | 'month'): Record<string, number> { const cutoff = { day: 86400000, week: 604800000, month: 2592000000, }[period]; const recent = this.metrics.filter( m => Date.now() - m.timestamp < cutoff ); return recent.reduce((acc, m) => { acc[m.featureId] = (acc[m.featureId] || 0) + m.cost; return acc; }, {} as Record<string, number>); } private enforceRateLimit(featureId: string) { const limit = this.rateLimiter.get(featureId); const now = Date.now(); if (limit && now < limit.resetAt && limit.count >= 1000) { throw new Error(`Rate limit exceeded for feature: ${featureId}`); } if (!limit || now >= limit.resetAt) { this.rateLimiter.set(featureId, { count: 1, resetAt: now + 60000 }); } else { limit.count++; } } private async checkBudget(featureId: string) { const monthlyCosts = this.getFeatureCosts('month'); const featureBudget = await getFeatureBudget(featureId); if ((monthlyCosts[featureId] || 0) >= featureBudget) { throw new Error( `Monthly budget exceeded for ${featureId}: $${monthlyCosts[featureId]?.toFixed(2)} / $${featureBudget}` ); } } private recordMetrics(metrics: LLMMetrics) { this.metrics.push(metrics); // En producción: enviar a tu pipeline de analytics } }

El dashboard que necesitás

Como mínimo, rastreá esto por feature, por día:

┌─────────────────────────────────────────────┐
│ Dashboard de Costos LLM - Marzo 2026       │
├──────────────┬────────┬────────┬────────────┤
│ Feature      │ Calls  │ Costo  │ Cache Hit  │
├──────────────┼────────┼────────┼────────────┤
│ Chat Soporte │ 45,231 │ $89.40 │    72%     │
│ Code Review  │ 12,847 │ $67.20 │    34%     │
│ Resúmenes    │  8,392 │ $12.10 │    81%     │
│ Búsqueda     │ 31,094 │ $23.40 │    68%     │
│ Traducción   │  3,201 │  $8.90 │    45%     │
├──────────────┼────────┼────────┼────────────┤
│ Total        │100,765 │$201.00 │    63%     │
└──────────────┴────────┴────────┴────────────┘

 Mes anterior sin optimización: $890
 Mes actual con todas las estrategias: $201
 Ahorro total: $689 (77%)

Combinando todo: El stack de optimización

Estas estrategias se potencian entre sí:

Request LLM entrante
        │
        ▼
  ┌─────────────┐
  │ Rate Limiter │─── ¿Excedido? → Error
  └──────┬──────┘
         │
         ▼
  ┌──────────────┐
  │ Budget Check  │─── ¿Excedido? → Error
  └──────┬───────┘
         │
         ▼
  ┌────────────────────┐
  │ Semantic Cache      │─── ¿Hit? → Devolver cacheado
  └──────────┬─────────┘
             │ Miss
             ▼
  ┌────────────────────┐
  │ Compresión Prompt   │─── Reducir tokens
  └──────────┬─────────┘
             │
             ▼
  ┌────────────────────┐
  │ Model Router        │─── Elegir el modelo más barato capaz
  └──────────┬─────────┘
             │
             ▼
  ┌────────────────────┐
  │ API Call + Métricas │─── Registrar todo
  └──────────┬─────────┘
             │
             ▼
  ┌────────────────────┐
  │ Cachear Respuesta   │─── Guardar para futuros hits
  └────────────────────┘

Ahorro combinado realista

Modelemos una aplicación real — un asistente de documentación procesando 200,000 consultas/mes con Claude Sonnet 4.6 para todo:

Baseline (sin optimización):
  200,000 consultas × 600 avg input tokens × 1,200 avg output tokens
  Input: 120M tokens × $3.00/1M = $360
  Output: 240M tokens × $15.00/1M = $3,600
  Total: $3,960/mes

Con el stack completo de optimización:
  1. Semantic caching (70% hit rate): 140,000 consultas eliminadas
     Restantes: 60,000 / Embeddings: $0.24 / Cache infra: $15/mes

  2. Routing del resto:
     - 15% complex → Claude Sonnet 4.6 (9,000 consultas)
     - 25% moderate → Claude Haiku 4.5 (15,000 consultas)
     - 40% simple → GPT-4.1 mini (24,000 consultas)
     - 20% trivial → GPT-4.1 nano (12,000 consultas)

  3. Compresión de prompts (30% menos tokens)

  Cálculo de costo:
     Sonnet: $124.74 / Haiku: $69.30
     Mini: $18.14 / Nano: $2.27
     Clasificación: $0.36 / Cache infra: $15 / Embeddings: $0.24

  Total: ~$230/mes

  Ahorro: $3,730/mes (94% de reducción)

De 3,960a3,960 a 230 por mes. Son $44,760 anuales. Para muchas startups, esa es la diferencia entre ser rentable e irse quedando sin runway.

Errores comunes a evitar

1. Caching sin invalidación

Las respuestas cacheadas se ponen viejas. Si tu info cambió, el bot no debería servir respuestas de ayer. Implementá TTLs y cache busting manual cuando cambie el contenido.

2. Sobre-routing a modelos baratos

Si el 5% de tus usuarios recibe respuestas degradadas porque una consulta fue mal clasificada, ahorraste plata pero perdiste confianza. Monitoreá quality scores y usá el patrón de fallback descrito arriba.

3. Comprimir demasiado

Eliminar contexto puede degradar la calidad de formas sutiles. Siempre hacé A/B testing con métricas de calidad antes de aplicar cambios de prompts a producción.

4. Ignorar diferencias entre proveedores

Cada proveedor tiene fortalezas. Claude se destaca en análisis extenso. GPT-4.1 nano es imbatible para clasificación. Gemini Flash tiene el mejor ratio precio-rendimiento para tareas generales. No te ates a un solo proveedor.

5. Olvidar los costos de embeddings

El semantic caching requiere embeddear cada consulta. A escala, se acumula. Usá text-embedding-3-small (no large) y batcheá los embeddings cuando sea posible.

Conclusión

Los costos de API LLM no son leyes de la física — son problemas de ingeniería con soluciones de ingeniería. Las cinco estrategias de esta guía — semantic caching, routing inteligente, compresión de prompts, batch processing y observabilidad — pueden reducir tu gasto entre 70-90% sin degradar la experiencia del usuario.

Orden de prioridad para implementación:

  1. Semantic caching — mayor ROI, implementá primero
  2. Compresión de prompts — ganancia rápida, auditá tus system prompts hoy
  3. Routing de modelos — ahorro significativo, complejidad moderada
  4. Observabilidad — necesitás esto para encontrar la próxima optimización
  5. Batch processing — ahorro fácil para workloads de fondo

Empezá con una estrategia, medí el impacto y apilá la siguiente encima. En mi experiencia, los equipos que implementan las cinco pasan de "necesitamos levantar una ronda solo para pagar OpenAI" a "nuestros costos de LLM son un error de redondeo."

Tu factura de API no tiene que dar miedo. Hacela aburrida.

AILLMOpenAIAnthropiccost-optimizationsemantic-cachingprompt-engineeringTypeScript

Explora herramientas relacionadas

Prueba estas herramientas gratuitas de Pockit