Inicio / Inteligencia Artificial / AI-First Full Stack: Construye Apps con IA / Costos, Rate Limiting y Optimización

Costos, Rate Limiting y Optimización

Cálculo de costos por token, caché semántico, fallback de modelos, throttling y optimización de latencia.

Avanzado
🔒 Solo lectura
📖

Estás en modo lectura

Puedes leer toda la lección, pero para marcar progreso, hacer ejercicios y ganar XP necesitas una cuenta Pro.

Desbloquear por $9/mes

Costos, Rate Limiting y Optimización

El costo es uno de los factores más críticos en aplicaciones AI-First. A diferencia de servidores tradicionales donde pagas por infraestructura, con LLMs pagas por cada token procesado. Dominar la optimización de costos y latencia es esencial para la viabilidad del negocio.


Cálculo de costos

Modelos y precios (2025-2026)

Modelo Input (1M tokens) Output (1M tokens) Velocidad
GPT-4o $2.50 $10.00 ~80 tok/s
GPT-4o mini $0.15 $0.60 ~120 tok/s
Claude 3.5 Sonnet $3.00 $15.00 ~70 tok/s
Claude Haiku $0.25 $1.25 ~150 tok/s
Gemini 2.0 Flash $0.10 $0.40 ~150 tok/s

Estimador de costos

interface CostEstimate {
  inputCost: number;
  outputCost: number;
  totalCost: number;
  monthlyEstimate: number;
}

const MODEL_PRICING: Record<string, { input: number; output: number }> = {
  'gpt-4o':         { input: 2.50,  output: 10.00 },
  'gpt-4o-mini':    { input: 0.15,  output: 0.60 },
  'claude-sonnet':  { input: 3.00,  output: 15.00 },
  'claude-haiku':   { input: 0.25,  output: 1.25 },
  'gemini-flash':   { input: 0.10,  output: 0.40 },
};

function estimateCost(
  model: string,
  inputTokens: number,
  outputTokens: number,
  requestsPerDay: number
): CostEstimate {
  const pricing = MODEL_PRICING[model];
  const inputCost = (inputTokens / 1_000_000) * pricing.input;
  const outputCost = (outputTokens / 1_000_000) * pricing.output;
  const totalCost = inputCost + outputCost;

  return {
    inputCost,
    outputCost,
    totalCost,
    monthlyEstimate: totalCost * requestsPerDay * 30,
  };
}

// Ejemplo: 1000 requests/día, 500 input tokens, 300 output tokens
const cost = estimateCost('gpt-4o-mini', 500, 300, 1000);
console.log(`Costo mensual: $${cost.monthlyEstimate.toFixed(2)}`);
// ~$7.20/mes con GPT-4o-mini
// ~$127.50/mes con GPT-4o

Caché semántico

Evita llamadas repetidas al LLM cacheando respuestas para preguntas similares:

class SemanticCache {
  private ttl: number;

  constructor(ttlSeconds = 3600) {
    this.ttl = ttlSeconds;
  }

  async get(query: string): Promise<string | null> {
    const queryEmbedding = await getEmbedding(query);

    const cached = await db.query(`
      SELECT response, 1 - (query_embedding <=> $1::vector) AS similarity
      FROM ai_cache
      WHERE 1 - (query_embedding <=> $1::vector) > 0.95
        AND created_at > NOW() - INTERVAL '${this.ttl} seconds'
      ORDER BY similarity DESC
      LIMIT 1
    `, [JSON.stringify(queryEmbedding)]);

    if (cached.rows.length > 0) {
      console.log(`Cache hit! Similarity: ${cached.rows[0].similarity}`);
      return cached.rows[0].response;
    }
    return null;
  }

  async set(query: string, response: string): Promise<void> {
    const queryEmbedding = await getEmbedding(query);

    await db.query(`
      INSERT INTO ai_cache (query, query_embedding, response, created_at)
      VALUES ($1, $2::vector, $3, NOW())
    `, [query, JSON.stringify(queryEmbedding), response]);
  }
}

// Uso en el servicio de chat
class CachedChatService {
  private cache = new SemanticCache(3600);

  async chat(message: string): Promise<string> {
    // 1. Intentar caché
    const cached = await this.cache.get(message);
    if (cached) return cached;

    // 2. Llamar al LLM
    const response = await llm.chat(message);

    // 3. Guardar en caché
    await this.cache.set(message, response);

    return response;
  }
}

Fallback de modelos

interface ModelConfig {
  id: string;
  provider: 'openai' | 'anthropic' | 'google';
  costTier: 'cheap' | 'standard' | 'premium';
}

const MODEL_TIERS: ModelConfig[] = [
  { id: 'gpt-4o-mini',     provider: 'openai',    costTier: 'cheap' },
  { id: 'gemini-flash',    provider: 'google',    costTier: 'cheap' },
  { id: 'gpt-4o',          provider: 'openai',    costTier: 'standard' },
  { id: 'claude-sonnet',   provider: 'anthropic', costTier: 'premium' },
];

class SmartModelRouter {
  async chat(message: string, options: {
    requiredQuality: 'low' | 'medium' | 'high';
    maxCostPerRequest: number;
    maxLatencyMs: number;
  }): Promise<string> {
    // Seleccionar modelo según requerimientos
    const qualityMap = { low: 'cheap', medium: 'standard', high: 'premium' };
    const targetTier = qualityMap[options.requiredQuality];

    const candidates = MODEL_TIERS.filter(m =>
      this.getTierOrder(m.costTier) <= this.getTierOrder(targetTier)
    );

    // Intentar de más barato a más caro
    for (const model of candidates) {
      try {
        const response = await this.callModel(model, message, options.maxLatencyMs);
        return response;
      } catch (error) {
        console.warn(`Model ${model.id} failed, trying next...`);
      }
    }

    throw new Error('All models failed');
  }

  private getTierOrder(tier: string): number {
    return { cheap: 0, standard: 1, premium: 2 }[tier] ?? 1;
  }
}

Rate Limiting avanzado

Token bucket con Redis

import Redis from 'ioredis';

const redis = new Redis(process.env.REDIS_URL);

class TokenBucketRateLimiter {
  async checkLimit(userId: string, plan: Plan): Promise<{
    allowed: boolean;
    remaining: number;
    resetAt: number;
  }> {
    const limits = PLAN_LIMITS[plan];
    const key = `ratelimit:${userId}:${this.getWindowKey()}`;

    const current = await redis.incr(key);

    if (current === 1) {
      await redis.expire(key, 60); // 1 minuto de ventana
    }

    return {
      allowed: current <= limits.messagesPerMinute,
      remaining: Math.max(0, limits.messagesPerMinute - current),
      resetAt: Date.now() + (await redis.ttl(key)) * 1000,
    };
  }

  private getWindowKey(): string {
    return Math.floor(Date.now() / 60000).toString(); // Ventana de 1 minuto
  }
}

Optimización de prompts

1. Reducir tokens en system prompt

// ❌ Sistema verbose (150+ tokens)
const verboseSystem = `
Eres un asistente de inteligencia artificial diseñado para ayudar
a los usuarios con sus preguntas técnicas. Debes ser amable,
profesional y proporcionar respuestas detalladas. Si no conoces
la respuesta a algo, debes decirlo claramente en lugar de inventar
información. Responde siempre en español.
`;

// ✅ Sistema conciso (40 tokens)
const conciseSystem = `Asistente técnico experto. Responde en español.
Sé preciso y conciso. Si no sabes, dilo.`;

2. Limitar el historial de conversación

function trimConversationHistory(
  messages: Message[],
  maxTokens: number = 4000
): Message[] {
  let totalTokens = 0;
  const trimmed: Message[] = [];

  // Siempre incluir el system prompt
  const system = messages.find(m => m.role === 'system');
  if (system) {
    trimmed.push(system);
    totalTokens += estimateTokens(system.content);
  }

  // Incluir mensajes recientes primero
  const nonSystem = messages.filter(m => m.role !== 'system').reverse();

  for (const msg of nonSystem) {
    const tokens = estimateTokens(msg.content);
    if (totalTokens + tokens > maxTokens) break;
    trimmed.unshift(msg);
    totalTokens += tokens;
  }

  return trimmed;
}

function estimateTokens(text: string): number {
  return Math.ceil(text.length / 4); // Approximación: 4 chars ≈ 1 token
}

3. Usar el modelo correcto para cada tarea

async function smartRoute(task: string, content: string): Promise<string> {
  // Tareas simples → modelo barato
  const simpleTasks = ['classify', 'extract', 'format', 'translate'];
  if (simpleTasks.some(t => task.includes(t))) {
    return llm.chat(content, { model: 'gpt-4o-mini' });
  }

  // Razonamiento complejo → modelo capaz
  const complexTasks = ['analyze', 'debug', 'architect', 'review'];
  if (complexTasks.some(t => task.includes(t))) {
    return llm.chat(content, { model: 'gpt-4o' });
  }

  // Default
  return llm.chat(content, { model: 'gpt-4o-mini' });
}

Optimización de latencia

Técnica Reducción Complejidad
Streaming Percepción instantánea Baja
Modelo más pequeño 2-3x más rápido Baja
Caché semántico 100x (cache hit) Media
Prompt más corto 10-30% Baja
Parallel tool calls 2-5x en multi-tool Media
Speculative decoding 2-3x Alta
Edge deployment -50ms latencia Alta
🔒

Ejercicio práctico disponible

Calculadora de costos y caché semántico

Desbloquear ejercicios
// Calculadora de costos y caché semántico
// Desbloquea Pro para acceder a este ejercicio
// y ganar +50 XP al completarlo

function ejemplo() {
    // Tu código aquí...
}

¿Te gustó esta lección?

Con Pro puedes marcar progreso, hacer ejercicios, tomar quizzes, ganar XP y obtener tu constancia.

Ver planes desde $9/mes