Módulo 6: Modal — Deployment serverless de LLMs

Cost optimization

Tu endpoint funciona. Ya sabes hacer autoscaling. Ahora viene la pregunta que te van a hacer cuando muestres esto en una reunión: "¿Cuánto nos cuesta cada request? ¿Y si servimos 1M al mes?"

Esta cápsula te enseña a contestar eso con números y a aplicar las optimizaciones que más impacto tienen. No es teoría — al final vas a tener una hoja de cálculo mental de cuánto te cuesta cada deployment y vas a poder explicarle a tu cofounder dónde puedes recortar 50% sin sacrificar producto.

Al terminar vas a poder:

  • Calcular el costo real por request de tu deployment (GPU + CPU + storage + egress)
  • Elegir la GPU correcta según tu modelo y throughput esperado
  • Aplicar las tres optimizaciones de mayor impacto: batching, cuantización, sizing de GPU
  • Decidir cuándo Modal deja de ser barato y deberías cambiar a alternativa

El modelo mental: tres componentes de costo

Tu factura de Modal se descompone en:

ComponenteCuándo se cobraOrden de magnitud
GPU timePor segundo, mientras un container con GPU está prendido$$$$ (lo grueso)
CPU timePor segundo, para containers sin GPU$
StoragePor GB-mes, por todos los volumes y imágenes$
EgressPor GB transferido fuera de Modal$ (negligible para chat texto)

95% del costo de un deployment LLM = GPU time. Por eso esta cápsula se enfoca casi exclusivamente en optimizar GPU.


Calcular cost-per-request: el método

Tres números te dan el costo:

costo_por_request ≈ tiempo_gpu_por_request × costo_por_segundo_de_GPU

Paso 1 — Mide cuánto GPU usa tu request

Logs de Modal te dicen cuánto tarda cada request en GPU. Para un request promedio de tu Mistral:

modal app logs mistral-api --tail 200 | grep "handled request"
# [container-abc123] handled request in 1.82s
# [container-def456] handled request in 2.04s
# [container-ghi789] handled request in 1.91s

Promedio aproximado: ~2s de GPU por request.

Paso 2 — Mira el precio por segundo de tu GPU

De modal.com/pricing — a inicios de 2026, precios aproximados (verifica el actual):

GPUCosto por segundo aprox
T4~$0.00017
A10G~$0.00030
L4~$0.00025
A100 40GB~$0.00100
H100~$0.00250

Con A10G y 2s por request:

costo_por_request = 2 × $0.00030 = $0.0006

Paso 3 — Escala a tu volumen

VolumenCosto GPU mensual
1,000 requests$0.60
100,000 requests$60
1,000,000 requests$600
10,000,000 requests$6,000

Más warm pool: si min_containers=1 mantiene una A10G prendida 24/7, suma ~$720/mes adicional sea cual sea el volumen.


Comparación con alternativas a este punto

Es útil tener referencia. Para 1M requests/mes (~2 req/s sostenidos, 100 tokens output promedio):

OpciónCosto aprox/mesNotas
Modal (Mistral 7B + warm pool)~$600 + $720 = $1,320Tu modelo, tu pricing
OpenAI GPT-4o-mini~$300-500Token-based; depende de longitud
Self-hosted Ollama (A10G en AWS 24/7)~$1,800GPU prendida siempre
OpenRouter (variable)~$200-1,500Según modelo elegido

Modal con warm pool no siempre gana. Si tu volumen es alto y constante, OpenAI puede ser más barato. Si tienes restricciones de privacidad o de modelo, Modal sigue siendo justificado aunque cueste un poco más.


Las cuatro optimizaciones de mayor impacto

Optimización 1 — Batching (ganancia: 2-4×)

vLLM batchea automáticamente requests concurrentes en una sola pasada de GPU. Tu cliente puede enviar múltiples prompts juntos:

@modal.method()
def generar_batch(self, prompts: list[str], max_tokens: int = 256) -> list[str]:
    from vllm import SamplingParams
    sampling = SamplingParams(temperature=0.7, max_tokens=max_tokens)
    prompts_fmt = [f"[INST] {p} [/INST]" for p in prompts]
    outputs = self.llm.generate(prompts_fmt, sampling)
    return [o.outputs[0].text.strip() for o in outputs]

Medición: procesar 8 prompts uno por uno = 8 × 2s = 16s. Procesar los 8 en batch = ~5s. Costo por request baja ~3×.

Aplicabilidad: funciona si tu uso lo permite (procesos batch, embebido en pipelines async). No funciona para un chatbot 1-a-1 donde cada usuario espera su respuesta.

Optimización 2 — Cuantización (ganancia: 2-3× en throughput, ~10% pérdida de calidad)

Mistral 7B en fp16 ocupa 14GB y procesa ~50 tokens/s en A10G. La versión cuantizada AWQ (4-bit) ocupa ~4GB y procesa ~150 tokens/s. Esto significa:

  • Tu request se completa 2-3× más rápido → menos tiempo de GPU → menos costo
  • Cabe en GPUs más chicas (T4 sirve para AWQ) → costo por segundo más bajo
MODELO = "TheBloke/Mistral-7B-Instruct-v0.2-AWQ"  # versión cuantizada

@app.cls(
    image=imagen.pip_install("autoawq"),
    gpu="T4",  # ¡cabe en T4 ahora!
    ...
)
class MistralServiceAWQ:
    @modal.enter()
    def cargar(self):
        from vllm import LLM
        self.llm = LLM(model=MODELO, quantization="awq")

Trade-off: la cuantización pierde un poco de precisión. Para tareas conversacionales generales, casi imperceptible. Para tareas que requieren razonamiento preciso (matemáticas, código), evalúa antes de adoptar.

Optimización 3 — GPU sizing correcto (ganancia: 30-60% por cambio de GPU)

Más caro no siempre = mejor para tu caso. La pregunta importante: ¿estás "GPU-bound" o "memory-bound"?

Si estás...SíntomaAcción
Memory-bound"Out of memory" o KV cache llenoPasa a GPU con más VRAM (A10G→L4 no ayuda; A10G→A100 sí)
Compute-boundGPU al 100% utilization, latencia altaPasa a GPU más rápida (A10G→L4 o A100)
SobredimensionadoGPU al 30% utilization, latencia okBaja a GPU más chica

Ver utilización: modal app logs o el dashboard de Modal muestran métricas de GPU. Si tu A10G nunca pasa de 40% utilización, una L4 o T4 (con cuantización) sirve igual y cuesta menos.

Optimización 4 — Reducir max_tokens razonablemente (ganancia: lineal)

Tu latencia (y costo) es proporcional al número de tokens generados. Generar 256 tokens cuesta 2× que generar 128. Si tu producto no necesita respuestas larguísimas:

class ChatRequest(BaseModel):
    prompt: str
    max_tokens: int = Field(150, ge=1, le=512)  # default 150, no 512

Combina con prompt engineering: pide al modelo que sea conciso ("Responde en 3 frases"). Funciona sorprendentemente bien.


Storage: el componente olvidado

Los Volume cobran ~$0.10/GB/mes. Si tienes:

  • mistral-pesos (14GB) → ~$1.40/mes
  • llama-pesos (40GB) → ~$4/mes
  • 10 versiones de modelos viejos olvidadas → puede sumar
modal volume list                # ver tus volumes
modal volume du mistral-pesos    # tamaño exacto
modal volume delete xxx          # eliminar

No es un montón, pero vale la pena auditarlo trimestralmente. Cuesta cero borrar un volume viejo.


Cuándo Modal deja de ser barato

Tres señales de que Modal ya no es el camino correcto:

Señal 1 — Tráfico muy constante y muy alto (>10 req/s 24/7). Si tu GPU está saturada todo el tiempo, "pago por uso" termina siendo más caro que "renta fija". Un A10G en AWS reservado cuesta ~$0.40/hr (vs $1+/hr en Modal). Si tu utilización es 95%, self-hosted gana.

Señal 2 — Necesitas GPUs muy específicas que Modal no ofrece. H200, MI300 (AMD), TPUs — Modal no las tiene. Si tu modelo requiere alguna, pasa a Replicate, RunPod, o cloud directo.

Señal 3 — Compliance estricto que Modal no certifica. HIPAA, SOC2 specific, on-prem mandatorio — verifica certificaciones actuales. Modal SOC2 Type II existe, pero HIPAA puede ser conversación con el equipo de ventas.

Para el 80% de los casos en startups, Modal es óptimo. Las señales de arriba son excepciones.


Trampas comunes

Trampa 1 — "El warm pool me cuesta más que el ahorro." Calcula honesto: si tu min_containers=1 cuesta $720/mes y solo evitas 100 cold starts al mes, no vale la pena (cada cold start cuesta ~$0.05). Solo vale el warm pool si la latencia mejorada genera valor real (usuarios reales que abandonarían si esperan 30s).

Trampa 2 — "Tengo cuenta gratis, ¿por qué me cobran?" El free tier de Modal es $30/mes en créditos. Si te excedes, te cobran la diferencia. Verifica tu uso en el dashboard antes de fin de mes. Pon billing alerts.

Trampa 3 — "Cuantización pareció gratis pero mi calidad bajó mucho." Mide antes de adoptar. Ten un set de 20-50 prompts representativos. Genera respuestas con fp16 y con AWQ. Compara manualmente o con un LLM-as-judge. Si la diferencia de calidad te importa para tu caso, no adoptes.

Trampa 4 — "Estoy pagando GPU mientras el modelo se descarga." Sí. La descarga inicial de 14GB es ~2-4 min de GPU pagada. Optimízalo: pre-bakea pesos en la imagen (vimos esto en la cápsula 06) o usa hf_transfer para acelerar 3-5×.

Trampa 5 — "Mi tráfico es burst pero max_containers=20 me da picos de costo." Tres opciones: (a) baja max_containers y aguanta queueing en bursts; (b) implementa rate limiting frente; (c) agrega caché de respuestas frecuentes (LangCache, semantic cache) para que requests repetidos no toquen GPU.


Ejercicio: estima tu costo mensual

Tu producto tiene este perfil:

  • 50,000 requests/día
  • Promedio 150 tokens output
  • Mistral 7B en A10G
  • 90% del tráfico en horario laboral (9am-6pm)
  • Requieres warm pool durante horario laboral

Estima:

  1. Costo de GPU activa (mientras genera respuestas)
  2. Costo de warm pool durante horario laboral
  3. Costo total mensual aproximado
  4. Si decides cuantizar a AWQ y bajar a T4, ¿cuál sería el nuevo total aprox?
Ver solución

Asumiendo: A10G a $0.00030/s, T4 a $0.00017/s, ~2s/request en A10G fp16, ~0.7s/request en T4 AWQ.

1. Costo de GPU activa (A10G fp16):

  • 50,000 req/día × 30 días = 1,500,000 req/mes
  • 1,500,000 × 2s × $0.00030 = $900/mes

2. Costo de warm pool (horario laboral):

  • 9hrs/día × 22 días laborales/mes ≈ 200hrs/mes
  • 200hrs × 3600s × $0.00030 = $216/mes

3. Total aprox: $900 + $216 + storage(~$2) = ~$1,120/mes

4. Con AWQ en T4:

  • 1,500,000 × 0.7s × $0.00017 = $179/mes (GPU activa)
  • 200hrs × 3600s × $0.00017 = $122/mes (warm pool T4)
  • Total: $179 + $122 + $2 = ~$303/mes

Ahorro: ~73%. Vale la pena medir si la calidad se mantiene aceptable para tu caso de uso.


Resumen

Aprendiste:

  • ✅ Descomponer tu factura: GPU (el grueso) + CPU + storage + egress
  • ✅ Calcular cost-per-request con dos números: tiempo GPU × precio por segundo
  • ✅ Cuatro optimizaciones grandes: batching, cuantización, GPU sizing, max_tokens
  • ✅ Cuándo Modal deja de ser óptimo: tráfico constante alto, GPUs específicas, compliance estricto
  • ✅ Hacer un estimado defensible para una reunión con cofounder/PM

Checkpoint: si te preguntan "¿cuánto cuesta tu deployment al mes con X tráfico?" y puedes dar un número con cálculo, no solo "barato" o "no sé", estás listo.


Siguiente cápsula

En 08 — Proyecto: API escalable vas a integrar todo lo del módulo en un endpoint production-ready: con autoscaling configurado, cost optimization aplicado, monitoring básico, y testing. Es el deliverable que vas a usar en el proyecto final del Módulo 8 (Unified Client) y, ojalá, en algo real tuyo.


Recursos

  1. Modal Pricing — precios actuales por GPU.
  2. vLLM Quantization Guide — AWQ paso a paso.
  3. Modal — Billing dashboard — tu uso actual.
  4. TheBloke on Hugging Face — colección de modelos cuantizados listos para vLLM.
  5. Semantic caching for LLMs — reducir requests duplicados que tocan GPU.