Módulo 3: Serverless & Lambda for AI

7. Cost Estimation para Serverless AI

Descripción

En esta cápsula vas a aprender a calcular el coste real de correr AI workloads en Lambda — no el coste teórico de la documentación, sino el número que aparece en tu factura. Al terminar, podrás estimar costes antes de deployar, comparar Lambda vs VPS a diferentes niveles de tráfico, y saber exactamente cuándo Lambda deja de ser la opción económica.

Contexto: "Lambda es barato" es verdad para workloads ligeros. Pero una función AI que tarda 5 segundos por invocación con 768MB de memoria tiene un perfil de coste muy diferente a un webhook de 100ms con 128MB. Además, Lambda no es el único coste — API Gateway, CloudWatch, y sobre todo la API de OpenAI son parte de la factura. Esta cápsula te enseña a ver el cuadro completo.


Modelo de Precios de Lambda

Los tres componentes

Factura Lambda = Requests + Compute + (Provisioned Concurrency)

1. Requests: $0.20 por millón de invocaciones
2. Compute:  $0.0000166667 por GB-segundo (x86)
             $0.0000133334 por GB-segundo (arm64 — 20% menos)
3. Free tier: 1M requests + 400,000 GB-s/mes (siempre gratis)

Qué es un GB-segundo

GB-segundo = (Memoria en GB) × (Duración en segundos)

Ejemplo:
- Función con 768MB que tarda 3 segundos
- GB-s = 0.75 GB × 3s = 2.25 GB-s
- Coste compute = 2.25 × $0.0000166667 = $0.0000375

Ejemplo AI:
- Función con 768MB que tarda 8 segundos (LLM call lento)
- GB-s = 0.75 GB × 8s = 6.0 GB-s
- Coste compute = 6.0 × $0.0000166667 = $0.0001000

¡La misma función cuesta 2.67x más cuando el LLM tarda más!

Billed Duration

Lambda redondea la duración al milisegundo más cercano (mínimo 1ms):

Duración real: 2,345.6ms → Billed: 2,346ms (redondeado al ms)
Duración real: 0.3ms     → Billed: 1ms (mínimo)

Calculadora de Costes para AI Workloads

Escenario 1: AI Chatbot interno (bajo tráfico)

Parámetros:
├── Invocaciones: 1,000/día = 30,000/mes
├── Memoria: 768MB (0.75 GB)
├── Duración promedio: 4s (gpt-4o-mini, ~300 tokens)
├── Arquitectura: arm64

Cálculo Lambda:
├── Requests: 30,000 / 1,000,000 × $0.20 = $0.006
├── GB-seconds: 30,000 × 0.75 × 4 = 90,000 GB-s
├── Compute: 90,000 × $0.0000133334 = $1.20
├── Free tier: -400,000 GB-s → 0 GB-s cobrables
└── Total Lambda: $0.006 (solo requests, compute en free tier)

Coste OpenAI (el coste REAL):
├── Input: 30,000 × 100 tokens × $0.00015/1K = $0.45
├── Output: 30,000 × 300 tokens × $0.0006/1K = $5.40
└── Total OpenAI: $5.85/mes

API Gateway (HTTP API):
└── 30,000 × $1.00/millón = $0.03

CloudWatch Logs:
└── ~$0.50/mes (ingestion + storage)

═══════════════════════════════════════
TOTAL MENSUAL: ~$6.39
├── Lambda: $0.01 (despreciable)
├── OpenAI: $5.85 (92% del coste)
├── API Gateway: $0.03
└── CloudWatch: $0.50
═══════════════════════════════════════

Escenario 2: API pública (tráfico medio)

Parámetros:
├── Invocaciones: 10,000/día = 300,000/mes
├── Memoria: 768MB
├── Duración promedio: 5s (mix gpt-4o-mini y gpt-4o)
├── Arquitectura: arm64

Cálculo Lambda:
├── Requests: 300,000 / 1M × $0.20 = $0.06
├── GB-seconds: 300,000 × 0.75 × 5 = 1,125,000 GB-s
├── Free tier: 1,125,000 - 400,000 = 725,000 GB-s cobrables
├── Compute: 725,000 × $0.0000133334 = $9.67
└── Total Lambda: $9.73

Coste OpenAI:
├── 70% gpt-4o-mini: 210,000 × 400 tokens avg
│   Input: 210,000 × 100 × $0.00015/1K = $3.15
│   Output: 210,000 × 300 × $0.0006/1K = $37.80
├── 30% gpt-4o: 90,000 × 500 tokens avg
│   Input: 90,000 × 150 × $0.0025/1K = $33.75
│   Output: 90,000 × 350 × $0.01/1K = $315.00
└── Total OpenAI: $389.70/mes

API Gateway:
└── 300,000 × $1.00/M = $0.30

CloudWatch:
└── ~$3.00/mes

═══════════════════════════════════════
TOTAL MENSUAL: ~$402.73
├── Lambda: $9.73 (2.4%)
├── OpenAI: $389.70 (96.8%)
├── API Gateway: $0.30
└── CloudWatch: $3.00
═══════════════════════════════════════

Escenario 3: Producción (tráfico alto)

Parámetros:
├── Invocaciones: 100,000/día = 3,000,000/mes
├── Memoria: 1024MB
├── Duración promedio: 6s
├── Arquitectura: arm64
├── Provisioned concurrency: 10 instancias

Cálculo Lambda:
├── Requests: 3,000,000 / 1M × $0.20 = $0.60
├── GB-seconds: 3,000,000 × 1.0 × 6 = 18,000,000 GB-s
├── Free tier: 18,000,000 - 400,000 = 17,600,000 GB-s
├── Compute: 17,600,000 × $0.0000133334 = $234.67
├── Provisioned: 10 × 1.0GB × 2,592,000s/mes × $0.0000041667 = $108.00
└── Total Lambda: $343.27

OpenAI (100% gpt-4o-mini para controlar costes):
├── Input: 3,000,000 × 100 × $0.00015/1K = $45.00
├── Output: 3,000,000 × 300 × $0.0006/1K = $540.00
└── Total OpenAI: $585.00/mes

API Gateway:
└── 3,000,000 × $1.00/M = $3.00

CloudWatch:
└── ~$15.00/mes

═══════════════════════════════════════
TOTAL MENSUAL: ~$946.27
├── Lambda: $343.27 (36.3%)
├── OpenAI: $585.00 (61.8%)
├── API Gateway: $3.00
└── CloudWatch: $15.00
═══════════════════════════════════════

La lección

A bajo tráfico: OpenAI es >90% de tu factura. Lambda es gratis.
A alto tráfico: Lambda crece, pero OpenAI sigue siendo la mayoría.
El coste de Lambda NUNCA es tu problema principal con AI workloads.

Lambda vs VPS: Comparación a Diferentes Niveles

El cálculo

# Calculadora Lambda vs VPS
def lambda_monthly_cost(
    invocations_per_month: int,
    memory_mb: int = 768,
    duration_s: float = 5.0,
    architecture: str = "arm64"
) -> dict:
    price_per_gb_s = 0.0000133334 if architecture == "arm64" else 0.0000166667
    price_per_request = 0.20 / 1_000_000
    free_tier_gb_s = 400_000
    free_tier_requests = 1_000_000

    gb_seconds = invocations_per_month * (memory_mb / 1024) * duration_s
    billable_gb_s = max(0, gb_seconds - free_tier_gb_s)
    billable_requests = max(0, invocations_per_month - free_tier_requests)

    compute_cost = billable_gb_s * price_per_gb_s
    request_cost = billable_requests * price_per_request

    return {
        "compute": round(compute_cost, 2),
        "requests": round(request_cost, 2),
        "total": round(compute_cost + request_cost, 2),
        "gb_seconds": round(gb_seconds),
        "cost_per_invocation": round((compute_cost + request_cost) / max(1, invocations_per_month), 6),
    }

# Comparar
for monthly in [10_000, 100_000, 500_000, 1_000_000, 5_000_000]:
    cost = lambda_monthly_cost(monthly)
    print(f"{monthly:>10,} inv/mes → Lambda: ${cost['total']:>8.2f}")

# Resultado:
#     10,000 inv/mes → Lambda: $    0.00  (free tier)
#    100,000 inv/mes → Lambda: $    1.85
#    500,000 inv/mes → Lambda: $   22.00
#  1,000,000 inv/mes → Lambda: $   46.67
#  5,000,000 inv/mes → Lambda: $  244.00

VPS pricing (referencia)

Provider       Plan          RAM     CPU    Precio/mes
────────────────────────────────────────────────────────
Hetzner        CX22          4GB     2 vCPU   $4.50
DigitalOcean   Basic         4GB     2 vCPU   $24.00
AWS EC2        t3.medium     4GB     2 vCPU   $30.37
Render         Starter       2GB     1 CPU    $7.00
Railway        Pro           8GB     8 vCPU   $20.00 + usage

Un VPS de $25/mes corre tu FastAPI 24/7 con ~50-100 req/s de capacidad.

Tabla comparativa

Invocaciones/mes    Lambda (arm64)   VPS ($25/mes)   Ganador
──────────────────────────────────────────────────────────────
10,000              $0.00            $25.00           Lambda
50,000              $0.00            $25.00           Lambda
100,000             $1.85            $25.00           Lambda
300,000             $11.67           $25.00           Lambda
500,000             $22.00           $25.00           Lambda
750,000             $35.00           $25.00           VPS
1,000,000           $46.67           $25.00           VPS
5,000,000           $244.00          $25.00           VPS

Break-even: ~600,000-700,000 invocaciones/mes
(con 768MB y 5s de duración promedio)
Break-even visual:

Coste ($)
│
250 ┤                                                    ╱ Lambda
│                                                  ╱
200 ┤                                            ╱
│                                          ╱
150 ┤                                      ╱
│                                    ╱
100 ┤                              ╱
│                           ╱
 50 ┤────────────────────╱────────────────────── VPS ($25)
│                 ╱
  0 ┤─────────────╱
└──┬──┬──┬──┬──┬──┬──┬──┬──┬──┬─── Invocaciones (×100K)
  0  1  2  3  4  5  6  7  8  9 10

Lambda es más barato hasta ~600K inv/mes.
Después de eso, un VPS fijo gana.

Pero la comparación no es solo dinero

Factor                Lambda           VPS
─────────────────────────────────────────────────
Coste a 0 tráfico    $0               $25/mes
Escalabilidad        Automática       Manual
Cold starts          1-8s             No
Disponibilidad       99.95% SLA       Depende de ti
Mantenimiento        Zero             Patches, updates, monitoring
Deploy               Push code        SSH, Docker, systemd
Concurrencia         1000+ parallel   Limitada por CPU/RAM
Timeout              15 min           Sin límite
GPU                  No               Posible
Custom runtime       Limitado         Total control

El Coste Real: Todos los Componentes

Desglose completo para un AI endpoint

Lambda AI Endpoint — Coste mensual real:

Servicio              Bajo (30K/mes)  Medio (300K/mes)  Alto (3M/mes)
─────────────────────────────────────────────────────────────────────
Lambda compute        $0.00*          $9.73             $234.67
Lambda requests       $0.01           $0.06             $0.60
Lambda provisioned    $0.00           $0.00             $108.00
API Gateway           $0.03           $0.30             $3.00
CloudWatch Logs       $0.50           $3.00             $15.00
CloudWatch Metrics    $0.00           $0.00             $3.00
X-Ray (si enabled)    $0.00           $1.50             $15.00
Secrets Manager       $0.40           $0.40             $0.40
─────────────────────────────────────────────────────────────────────
Subtotal AWS          $0.94           $14.99            $379.67

OpenAI API**          $5.85           $389.70           $585.00
─────────────────────────────────────────────────────────────────────
TOTAL                 $6.79           $404.69           $964.67

* Dentro del free tier
** El coste real de la API del LLM domina en todos los escenarios

Costes ocultos que la gente olvida

1. CloudWatch Logs
   Lambda loguea automáticamente a CloudWatch.
   Ingestion: $0.50/GB. Storage: $0.03/GB/mes.
   Si logeas mucho JSON → crece rápido.
   
   Mitigación: filtra log level, usa sampling para requests de alto volumen.

2. API Gateway
   HTTP API: $1.00/millón. Parece nada, pero a 10M requests/mes = $10.
   REST API: $3.50/millón. 3.5x más caro.
   
3. Secrets Manager
   $0.40/secret/mes + $0.05/10K API calls.
   Para 1-2 secrets (API keys) → ~$1/mes.
   
4. Data transfer
   Primeros 100GB/mes gratis. Después: $0.09/GB.
   Las responses AI son texto → volumen bajo → raramente un problema.

5. Provisioned Concurrency
   Pagas por mantener instancias "warm" 24/7.
   10 instancias × 768MB × 30 días = ~$83/mes
   Solo úsalo si cold starts son inaceptables para tu caso.

Estrategias de Optimización de Costes

1. Memory tuning

Problema: memoria excesiva para funciones I/O bound.

Antes: 1769MB (1 vCPU), 5s duración
  → 1.73 GB × 5s = 8.65 GB-s × $0.0000133334 = $0.0001153/inv

Después: 512MB (suficiente para API calls), 5.2s duración
  → 0.5 GB × 5.2s = 2.6 GB-s × $0.0000133334 = $0.0000347/inv

Ahorro: 70% por invocación.
A 300K inv/mes: $34.59 → $10.40 = $24.19 ahorrados/mes.

2. Response caching

# Cache responses idénticas para evitar llamadas repetidas al LLM
import hashlib
import json
import os
import boto3
from openai import OpenAI

client = OpenAI(api_key=os.environ["OPENAI_API_KEY"], timeout=25)

# Usa DynamoDB como cache (o Redis vía ElastiCache)
dynamodb = boto3.resource("dynamodb")
cache_table = dynamodb.Table(os.environ.get("CACHE_TABLE", "ai-cache"))

CACHE_TTL = int(os.environ.get("CACHE_TTL", "3600"))

def get_cache_key(prompt, model, max_tokens):
    raw = f"{prompt}:{model}:{max_tokens}"
    return hashlib.sha256(raw.encode()).hexdigest()[:16]

def handler(event, context):
    body = json.loads(event.get("body", "{}"))
    prompt = body["prompt"]
    model = body.get("model", "gpt-4o-mini")
    max_tokens = body.get("max_tokens", 500)

    cache_key = get_cache_key(prompt, model, max_tokens)

    # Check cache
    try:
        cached = cache_table.get_item(Key={"pk": cache_key})
        if "Item" in cached:
            import time
            if cached["Item"].get("ttl", 0) > time.time():
                return {
                    "statusCode": 200,
                    "body": json.dumps({
                        "answer": cached["Item"]["answer"],
                        "cached": True,
                        "tokens_saved": int(cached["Item"]["tokens"]),
                    })
                }
    except Exception:
        pass

    # LLM call
    response = client.chat.completions.create(
        model=model,
        messages=[{"role": "user", "content": prompt}],
        max_tokens=max_tokens,
    )
    answer = response.choices[0].message.content
    tokens = response.usage.total_tokens

    # Store in cache
    import time
    try:
        cache_table.put_item(Item={
            "pk": cache_key,
            "answer": answer,
            "tokens": tokens,
            "ttl": int(time.time()) + CACHE_TTL,
        })
    except Exception:
        pass

    return {
        "statusCode": 200,
        "body": json.dumps({
            "answer": answer,
            "cached": False,
            "tokens_used": tokens,
        })
    }
Impacto del caching:
Si 30% de las requests son duplicadas:
├── Sin cache: 300,000 LLM calls/mes = $389.70 OpenAI
├── Con cache: 210,000 LLM calls/mes = $272.79 OpenAI
├── DynamoDB cache: ~$2.50/mes (on-demand)
└── Ahorro: $114.41/mes (29% menos en OpenAI)

3. Model selection inteligente

# Usa gpt-4o-mini por default, gpt-4o solo cuando el usuario lo pida
# La diferencia de coste es ~17x

# gpt-4o-mini: $0.15/1M input + $0.60/1M output
# gpt-4o:      $2.50/1M input + $10.00/1M output

def select_model(prompt, user_tier="free"):
    if user_tier == "premium":
        return "gpt-4o"

    # Para prompts simples, gpt-4o-mini es suficiente
    if len(prompt) < 200:
        return "gpt-4o-mini"

    return "gpt-4o-mini"

4. Batching

Si procesas múltiples items, agrúpalos en una sola invocación
en vez de una Lambda por item.

Sin batching: 1000 items → 1000 invocaciones → 1000 × overhead
Con batching: 1000 items → 10 invocaciones de 100 items → 10 × overhead

El overhead de Lambda (cold start, init, API Gateway) se amortiza.
Limitación: Lambda timeout de 15 min y API Gateway de 29s.

5. arm64 (Graviton)

Simplemente cambiar de x86_64 a arm64:
├── x86: $0.0000166667/GB-s
├── arm64: $0.0000133334/GB-s
├── Ahorro: 20% en compute
└── Compatibilidad: openai SDK funciona perfecto en arm64

En el ejemplo de 300K inv/mes con 512MB:
├── x86: 780,000 GB-s × $0.0000166667 = $13.00
├── arm64: 780,000 GB-s × $0.0000133334 = $10.40
└── Ahorro: $2.60/mes (20%)

Break-even Analysis

Cuándo Lambda deja de ser la opción económica

def break_even_analysis():
    """Calcula el punto de break-even Lambda vs VPS."""
    vps_cost = 25.00  # VPS mensual (Hetzner/DO)
    memory_gb = 0.75  # 768MB
    duration_s = 5.0
    price_per_gb_s = 0.0000133334  # arm64
    free_tier_gb_s = 400_000

    # Buscar el punto donde Lambda > VPS
    for inv_k in range(0, 2000, 50):
        invocations = inv_k * 1000
        gb_s = invocations * memory_gb * duration_s
        billable = max(0, gb_s - free_tier_gb_s)
        lambda_cost = billable * price_per_gb_s + (invocations / 1_000_000) * 0.20

        if lambda_cost > vps_cost:
            print(f"Break-even: ~{invocations:,} invocaciones/mes")
            print(f"  Lambda: ${lambda_cost:.2f}")
            print(f"  VPS:    ${vps_cost:.2f}")
            return invocations

    return None

# break_even_analysis()
# Break-even: ~650,000 invocaciones/mes
#   Lambda: $25.34
#   VPS:    $25.00

La tabla de decisión

Invocaciones/mes    ¿Lambda o VPS?
────────────────────────────────────────────────────────────
< 100K              Lambda (free tier cubre casi todo)
100K - 500K         Lambda (más barato, zero maintenance)
500K - 700K         Zona gris (similar coste, elige por features)
> 700K              VPS (Lambda ya cuesta más)
> 2M                VPS (Lambda es 5-10x más caro)

PERO incluye estos factores:
├── ¿Necesitas scaling automático? → Lambda gana siempre
├── ¿Cold starts son inaceptables? → VPS gana
├── ¿Zero maintenance? → Lambda gana
├── ¿GPU para inferencia local? → VPS es la única opción
├── ¿Requests spike impredecibles? → Lambda maneja spikes gratis
└── ¿Budget fijo? → VPS es predecible; Lambda es variable

Factor tráfico irregular

Lambda brilla cuando el tráfico es irregular:

Patrón: 100K requests/mes, pero 80% en horario laboral (8h/día)

VPS: paga $25/mes 24/7, incluso cuando duermes → $25/mes
Lambda: paga solo por lo que usas → ~$1.85/mes

Patrón: 500K requests/mes, distribuidos 24/7

VPS: necesita capacidad para picos → $25/mes
Lambda: cada invocación individual → $22/mes

Pero si el tráfico es constante y alto:
Lambda: 1M requests/mes × 5s × 768MB = $46.67/mes
VPS: maneja todo con un servidor de $25/mes

Herramienta: AWS Pricing Calculator

# Usa la calculadora oficial para estimaciones precisas:
# https://calculator.aws/

# O calcula en tu código:
python3 -c "
memory_mb = 768
duration_s = 5
invocations = 300_000
arch = 'arm64'

gb_s = invocations * (memory_mb/1024) * duration_s
price = 0.0000133334 if arch == 'arm64' else 0.0000166667
free_gb_s = 400_000
free_requests = 1_000_000

compute = max(0, gb_s - free_gb_s) * price
requests = max(0, invocations - free_requests) * 0.20 / 1_000_000

print(f'GB-seconds: {gb_s:,.0f}')
print(f'Billable GB-s: {max(0, gb_s - free_gb_s):,.0f}')
print(f'Compute cost: \${compute:.2f}')
print(f'Request cost: \${requests:.4f}')
print(f'Total Lambda: \${compute + requests:.2f}')
"

Troubleshooting

Problema 1: "La factura es mucho más alta de lo estimado"

# Diagnóstico: verifica duración real vs estimada
aws logs filter-log-events \
  --log-group-name /aws/lambda/ai-endpoint \
  --filter-pattern "REPORT" \
  --limit 50

# Busca Duration y Memory Size en las líneas REPORT:
# REPORT Duration: 8234.56 ms  Billed Duration: 8235 ms  Memory Size: 768 MB

# Si la duración real es mayor a tu estimación:
# 1. El LLM está respondiendo más lento (OpenAI tiene variabilidad)
# 2. Cold starts están sumando duración
# 3. Retries del SDK están duplicando la duración

# Acción: revisa el p99 de duración, no solo el promedio
aws cloudwatch get-metric-statistics \
  --namespace AWS/Lambda \
  --metric-name Duration \
  --dimensions Name=FunctionName,Value=ai-endpoint \
  --start-time 2026-03-01 --end-time 2026-03-08 \
  --period 86400 --statistics Average p99 Maximum

Problema 2: "CloudWatch Logs cuesta más que Lambda"

# Si logeas JSON grande (responses del LLM), los logs crecen rápido
# $0.50/GB ingestion + $0.03/GB/mes storage

# Soluciones:
# 1. No logees el contenido completo de las responses
# 2. Usa log level INFO en producción (no DEBUG)
# 3. Configura log retention (no guardes logs para siempre)
aws logs put-retention-policy \
  --log-group-name /aws/lambda/ai-endpoint \
  --retention-in-days 14

# 4. Usa structured logging con campos selectivos
# Logea: tokens, duration, model, error
# NO logees: prompt completo, response completa

Problema 3: "Provisioned Concurrency duplica mi factura"

# Provisioned Concurrency cobra 24/7, no por invocación
# 10 instancias × 768MB × 2,592,000 s/mes = ~$83/mes (solo por tenerlas)

# Diagnóstico: ¿realmente necesitas Provisioned Concurrency?
# Si cold starts de 3-5s son aceptables → no lo uses
# Si tienes <1000 inv/día → definitivamente no lo uses

# Si lo necesitas, minimiza:
# 1. Usa scheduled scaling: más instancias en horario pico
# 2. Reduce memoria de las provisioned (menos GB = menos coste)
# 3. Usa en un solo Lambda (el más crítico), no en todos

Problema 4: "No entiendo la diferencia entre Duration y Billed Duration"

Duration: tiempo real de ejecución de tu código
Billed Duration: redondeado al ms (desde Dec 2020)
Init Duration: tiempo de cold start (solo primera invocación)

REPORT RequestId: abc-123
  Duration: 3456.78 ms
  Billed Duration: 3457 ms    ← Pagas por esto
  Memory Size: 768 MB         ← Lo que configuraste
  Max Memory Used: 180 MB     ← Lo que realmente usaste
  Init Duration: 1234.56 ms   ← Cold start (solo si fue cold)

Init Duration NO se cobra por separado — ya está incluida en Duration.
Pero cuando calculas tu timeout, recuerda que el cold start
come parte de tu timeout window.

Ejercicios Prácticos

Ejercicio 1: Calcula el coste de tu endpoint

Escribe una función Python que reciba: invocaciones por día, memoria en MB, duración promedio en segundos, y porcentaje de invocaciones que son cold starts. Calcula el coste mensual desglosado (compute, requests, API Gateway, CloudWatch estimado) y muestra el coste por invocación.

Ver solución
def calculate_monthly_cost(
    invocations_per_day: int,
    memory_mb: int,
    avg_duration_s: float,
    cold_start_pct: float = 5.0,
    cold_start_overhead_s: float = 3.0,
    architecture: str = "arm64",
    api_gateway: bool = True,
):
    monthly_inv = invocations_per_day * 30

    cold_inv = int(monthly_inv * cold_start_pct / 100)
    warm_inv = monthly_inv - cold_inv

    warm_gb_s = warm_inv * (memory_mb / 1024) * avg_duration_s
    cold_gb_s = cold_inv * (memory_mb / 1024) * (avg_duration_s + cold_start_overhead_s)
    total_gb_s = warm_gb_s + cold_gb_s

    price_gb_s = 0.0000133334 if architecture == "arm64" else 0.0000166667
    free_gb_s = 400_000
    free_requests = 1_000_000

    billable_gb_s = max(0, total_gb_s - free_gb_s)
    billable_requests = max(0, monthly_inv - free_requests)

    compute_cost = billable_gb_s * price_gb_s
    request_cost = billable_requests * 0.20 / 1_000_000
    lambda_total = compute_cost + request_cost

    gw_cost = monthly_inv * 1.00 / 1_000_000 if api_gateway else 0
    cw_cost = max(0.50, monthly_inv * 0.001 / 1000)

    total = lambda_total + gw_cost + cw_cost
    per_inv = total / max(1, monthly_inv)

    print(f"=== Cost Estimate ({invocations_per_day:,}/day, {memory_mb}MB, {avg_duration_s}s avg) ===")
    print(f"Monthly invocations: {monthly_inv:,}")
    print(f"Total GB-seconds:    {total_gb_s:,.0f} (billable: {billable_gb_s:,.0f})")
    print(f"")
    print(f"Lambda compute:      ${compute_cost:.2f}")
    print(f"Lambda requests:     ${request_cost:.4f}")
    print(f"API Gateway:         ${gw_cost:.2f}")
    print(f"CloudWatch (est):    ${cw_cost:.2f}")
    print(f"────────────────────────────")
    print(f"TOTAL:               ${total:.2f}/month")
    print(f"Per invocation:      ${per_inv:.6f}")
    return total

calculate_monthly_cost(1000, 768, 5.0)
calculate_monthly_cost(10000, 768, 5.0)
calculate_monthly_cost(100000, 1024, 6.0, cold_start_pct=2.0)

Ejercicio 2: Compara Lambda vs VPS para tu caso

Usando la calculadora del ejercicio 1, genera una tabla que compare Lambda arm64 vs un VPS de $25/mes para 5 niveles de tráfico: 1K, 5K, 10K, 50K, y 100K invocaciones/día. Incluye el coste total (Lambda + API Gateway + CloudWatch) y marca con ✅ el ganador en cada nivel.

Ver solución
def lambda_cost(inv_day, memory_mb=768, duration_s=5.0):
    monthly = inv_day * 30
    gb_s = monthly * (memory_mb / 1024) * duration_s
    billable_gb_s = max(0, gb_s - 400_000)
    billable_req = max(0, monthly - 1_000_000)

    compute = billable_gb_s * 0.0000133334
    requests = billable_req * 0.20 / 1_000_000
    gw = monthly * 1.00 / 1_000_000
    cw = max(0.50, monthly * 0.001 / 1000)

    return compute + requests + gw + cw

vps_cost = 25.00

print(f"{'Inv/día':>10} {'Inv/mes':>12} {'Lambda':>10} {'VPS':>10} {'Ganador':>10}")
print("─" * 58)

for daily in [1_000, 5_000, 10_000, 50_000, 100_000]:
    monthly = daily * 30
    lc = lambda_cost(daily)
    winner = "Lambda ✅" if lc < vps_cost else "VPS ✅"
    print(f"{daily:>10,} {monthly:>12,} ${lc:>8.2f} ${vps_cost:>8.2f} {winner:>10}")

# Resultado:
#    Inv/día      Inv/mes     Lambda        VPS    Ganador
# ──────────────────────────────────────────────────────────
#      1,000       30,000      $0.53      $25.00  Lambda ✅
#      5,000      150,000      $4.70      $25.00  Lambda ✅
#     10,000      300,000     $11.98      $25.00  Lambda ✅
#     50,000    1,500,000     $70.84      $25.00     VPS ✅
#    100,000    3,000,000    $148.20      $25.00     VPS ✅

Ejercicio 3: Estima el impacto del caching

Tu endpoint recibe 10,000 invocaciones/día. Después de analizar los logs, descubres que el 35% son prompts repetidos. Calcula: (a) el ahorro mensual en OpenAI si implementas cache, (b) el coste de DynamoDB on-demand para el cache (estimando 100K reads y 65K writes/mes), (c) el ROI del caching.

Ver solución
inv_per_day = 10_000
monthly_inv = inv_per_day * 30  # 300,000
cache_hit_rate = 0.35
avg_tokens_input = 100
avg_tokens_output = 300

# Coste OpenAI SIN cache
openai_no_cache = (
    monthly_inv * avg_tokens_input * 0.00015 / 1000 +
    monthly_inv * avg_tokens_output * 0.0006 / 1000
)

# Coste OpenAI CON cache
uncached_inv = int(monthly_inv * (1 - cache_hit_rate))
openai_with_cache = (
    uncached_inv * avg_tokens_input * 0.00015 / 1000 +
    uncached_inv * avg_tokens_output * 0.0006 / 1000
)

openai_savings = openai_no_cache - openai_with_cache

# DynamoDB on-demand
reads = 300_000  # Todas las invocaciones hacen read
writes = int(monthly_inv * (1 - cache_hit_rate))  # Solo misses escriben

dynamo_read_cost = reads * 0.25 / 1_000_000  # $0.25 per 1M RRU
dynamo_write_cost = writes * 1.25 / 1_000_000  # $1.25 per 1M WRU
dynamo_storage = 0.25  # ~1GB estimado
dynamo_total = dynamo_read_cost + dynamo_write_cost + dynamo_storage

net_savings = openai_savings - dynamo_total
roi = (net_savings / dynamo_total) * 100

print(f"=== Cache Impact Analysis ===")
print(f"Monthly invocations: {monthly_inv:,}")
print(f"Cache hit rate: {cache_hit_rate:.0%}")
print(f"")
print(f"OpenAI without cache: ${openai_no_cache:.2f}/mes")
print(f"OpenAI with cache:    ${openai_with_cache:.2f}/mes")
print(f"OpenAI savings:       ${openai_savings:.2f}/mes")
print(f"")
print(f"DynamoDB cost:        ${dynamo_total:.2f}/mes")
print(f"Net savings:          ${net_savings:.2f}/mes")
print(f"ROI:                  {roi:.0f}%")

# === Cache Impact Analysis ===
# Monthly invocations: 300,000
# Cache hit rate: 35%
# OpenAI without cache: $58.50/mes
# OpenAI with cache:    $38.03/mes
# OpenAI savings:       $20.48/mes
# DynamoDB cost:        $0.57/mes
# Net savings:          $19.91/mes
# ROI:                  3493%

Ejercicio 4: Presupuesto mensual con alertas

Usando CloudWatch Billing Alarms y AWS Budgets, documenta (con código AWS CLI) cómo configurar: (a) una alerta cuando Lambda supere $10/mes, (b) una alerta cuando el gasto total de la cuenta supere $50/mes, (c) un budget mensual con notificación al 80% del límite.

Ver solución
# (a) Alerta Lambda > $10/mes
# Primero, habilita billing alerts en tu cuenta
# AWS Console → Billing → Billing Preferences → Receive Billing Alerts

# Crear SNS topic para notificaciones
aws sns create-topic --name billing-alerts
aws sns subscribe \
  --topic-arn arn:aws:sns:us-east-1:ACCOUNT:billing-alerts \
  --protocol email \
  --notification-endpoint tu@email.com

# Crear CloudWatch Alarm para Lambda
aws cloudwatch put-metric-alarm \
  --alarm-name "Lambda-Cost-Over-10" \
  --alarm-description "Lambda monthly cost exceeds $10" \
  --metric-name EstimatedCharges \
  --namespace AWS/Billing \
  --statistic Maximum \
  --period 21600 \
  --threshold 10 \
  --comparison-operator GreaterThanThreshold \
  --dimensions Name=ServiceName,Value=AWSLambda Name=Currency,Value=USD \
  --evaluation-periods 1 \
  --alarm-actions arn:aws:sns:us-east-1:ACCOUNT:billing-alerts

# (b) Alerta cuenta total > $50/mes
aws cloudwatch put-metric-alarm \
  --alarm-name "Total-Cost-Over-50" \
  --alarm-description "Total monthly cost exceeds $50" \
  --metric-name EstimatedCharges \
  --namespace AWS/Billing \
  --statistic Maximum \
  --period 21600 \
  --threshold 50 \
  --comparison-operator GreaterThanThreshold \
  --dimensions Name=Currency,Value=USD \
  --evaluation-periods 1 \
  --alarm-actions arn:aws:sns:us-east-1:ACCOUNT:billing-alerts

# (c) AWS Budget con notificación al 80%
aws budgets create-budget \
  --account-id ACCOUNT_ID \
  --budget '{
    "BudgetName": "Monthly-AI-Budget",
    "BudgetLimit": {"Amount": "50", "Unit": "USD"},
    "TimeUnit": "MONTHLY",
    "BudgetType": "COST"
  }' \
  --notifications-with-subscribers '[
    {
      "Notification": {
        "NotificationType": "ACTUAL",
        "ComparisonOperator": "GREATER_THAN",
        "Threshold": 80,
        "ThresholdType": "PERCENTAGE"
      },
      "Subscribers": [
        {"SubscriptionType": "EMAIL", "Address": "tu@email.com"}
      ]
    },
    {
      "Notification": {
        "NotificationType": "ACTUAL",
        "ComparisonOperator": "GREATER_THAN",
        "Threshold": 100,
        "ThresholdType": "PERCENTAGE"
      },
      "Subscribers": [
        {"SubscriptionType": "EMAIL", "Address": "tu@email.com"}
      ]
    }
  ]'

Resumen

  • Lambda pricing = requests + GB-seconds. El free tier (1M requests + 400K GB-s) cubre la mayoría de proyectos de learning y MVPs.
  • Para AI workloads, el coste de OpenAI/Anthropic API es >90% de tu factura en tráfico bajo/medio. Lambda es casi gratis comparado.
  • El coste real incluye: Lambda + API Gateway + CloudWatch + Secrets Manager + LLM API. No calcules solo Lambda.
  • Break-even Lambda vs VPS: ~600-700K invocaciones/mes (con 768MB, 5s duración). Debajo de eso, Lambda gana. Arriba, VPS es más económico.
  • Optimiza en este orden: (1) modelo LLM más barato, (2) caching de responses, (3) memory tuning, (4) arm64 architecture.
  • Provisioned Concurrency es caro. Solo úsalo si cold starts son inaceptables para tu caso de negocio.
  • Configura alertas de billing desde el día 1. Un bug que genera invocaciones infinitas puede costarte cientos de dólares en horas.
  • Lambda brilla con tráfico irregular. Pagas $0 cuando nadie usa tu endpoint. Un VPS cuesta $25/mes llueva o truene.

Recursos Adicionales

  1. Lambda Pricing — Precios actualizados y free tier
  2. AWS Pricing Calculator — Calculadora oficial para estimaciones
  3. API Gateway Pricing — HTTP API vs REST API pricing
  4. CloudWatch Pricing — Logs, metrics, alarms
  5. OpenAI Pricing — Precios por modelo y por token
  6. AWS Budgets — Configurar alertas de coste
  7. Lambda Power Tuning — Optimizar relación coste/rendimiento
  8. Serverless Cost Calculator (community) — Estimador alternativo para serverless