Módulo 2: Latencia y costo como arquitectura

3. El presupuesto de latencia y de costo

Descripción

Al terminar esta lección vas a tener la herramienta que convierte las dos restricciones medibles de la lección 2 en una regla de diseño: el latency budget y el cost budget de una feature. Un presupuesto es un umbral explícito —"una búsqueda semántica debe responder en menos de 800 ms" y "debe costar menos de X al mes"— que la arquitectura tiene que respetar, igual que un puente tiene un límite de carga que no se negocia. Sin un presupuesto, "rápido" y "barato" son opiniones: cada quien tolera una latencia distinta y estima un costo distinto. Con un presupuesto, se vuelven una compuerta: una opción de diseño pasa o viola el umbral, y eso se puede verificar ejecutando una función. Vas a escribir esa compuerta —fits(value, budget)— y a pasar por ella la opción ingenua ("todo al modelo caro"), que vas a ver violar los dos presupuestos de la búsqueda semántica de Mercado: el de latencia en las queries pesadas y el de costo a escala.

Esto importa porque el presupuesto es lo que da dirección a todo el diseño. Las tres técnicas que vienen después —cascade, caché, async— no son adornos que se aplican "porque son buenas prácticas"; son los mecanismos para cumplir un presupuesto que la opción ingenua no cumple. Sin el umbral, no sabes si necesitas cascade o no, ni cuánta caché, ni si el streaming es opcional u obligatorio: estás optimizando a ciegas, sin una meta. Con el umbral, cada técnica tiene un trabajo claro y medible: bajar el costo de $25,200 a menos del presupuesto, bajar la latencia de la query pesada por debajo de 800 ms. El presupuesto es la restricción que ordena el módulo entero, y esta lección es donde la fijas y la vuelves ejecutable.

Conexión con el módulo: esta lección es la bisagra. La lección 2 te dio la báscula (medir latencia y costo); esta pone la línea que no se debe cruzar. Lo que viene después son las técnicas para respetar esa línea cuando la opción obvia la cruza: la lección 4 (cascade) ataca el presupuesto de costo enrutando lo fácil al barato; la 5 (caché) lo ataca no repagando lo repetido; la 6 (async/streaming) ataca el presupuesto de latencia mostrando la respuesta antes o sacando el trabajo del camino crítico. La lección 7 las compone y verifica —con la misma compuerta fits— que la feature termina dentro de su presupuesto. Todo lo que sigue rinde cuentas a la línea que trazas aquí.

El límite de carga del puente

Piénsalo así. Un puente tiene un cartel: límite de carga, 10 toneladas. No es una sugerencia ni una opinión sobre "qué tan pesado se siente" un camión; es un umbral físico, y hay dos formas de tratarlo. La primera es la del ingeniero descuidado: "pues que pasen los camiones, y si el puente aguanta, aguanta". La segunda es la del ingeniero serio: antes de dejar pasar un camión, pesarlo y comparar contra el límite. Nueve toneladas: pasa. Once toneladas: no pasa, sin importar qué tan urgente sea la carga. El límite convierte una pregunta borrosa ("¿aguantará?") en una compuerta binaria y verificable ("¿pesa menos de 10?").

Una feature de IA tiene dos de esos carteles. El primero es de latencia: "una búsqueda debe responder en menos de 800 ms". No es un capricho —es el punto donde la evidencia dice que el usuario percibe la búsqueda como lenta y empieza a abandonar—. El segundo es de costo: "esta feature no debe costar más de X al mes". Tampoco es un capricho —es lo que el negocio asignó, arriba de lo cual la feature deja de ser rentable—. Y con los dos carteles, el trabajo del arquitecto es el del ingeniero serio: antes de aceptar un diseño, pesarlo contra los dos límites. Si una opción tarda 1500 ms, viola el cartel de latencia; si cuesta $25,200 contra un presupuesto de $3,000, viola el de costo. No importa cuán buena sea en otras cosas: un diseño que viola su presupuesto es un camión de once toneladas sobre un puente de diez. Esta lección es aprender a poner los carteles y a pesar los camiones.

Ejemplo trabajado: la compuerta de presupuesto de Mercado

Vamos a definir el presupuesto de la búsqueda semántica de Mercado y a pesar la opción ingenua contra él. Dos presupuestos, dos compuertas.

El latency budget es por llamada: 800 ms. Arriba de eso, el usuario percibe la búsqueda como lenta. Lo probamos con dos tipos de query: una típica (150 tokens de salida) y una pesada (400 tokens de salida), porque —de la lección 2— la latencia crece con la salida, y una feature real recibe de las dos.

El cost budget es mensual: $3,000/mes, lo que el negocio asignó a la feature, a un volumen de 100,000 búsquedas al día. Lo pesamos con la query típica como unidad de costo.

La compuerta es una función de una línea: fits(value, budget) devuelve "OK" si el valor cabe y "VIOLA" si lo excede. Con ella recorremos las opciones.

# Leccion 03 — el latency budget y el cost budget de una feature
# STUB del LLM: todo SIMULADO. Cero red, cero API, cero claves.

MODELS = {
    "cheap":  dict(usd_in=0.0008, usd_out=0.004, base_ms=90,  ms_per_tok=0.4),
    "strong": dict(usd_in=0.008,  usd_out=0.040, base_ms=300, ms_per_tok=3.0),
}

def call_llm(model, in_tokens, out_tokens):
    m = MODELS[model]
    latency_ms = m["base_ms"] + out_tokens * m["ms_per_tok"]
    cost_usd = (in_tokens / 1000) * m["usd_in"] + (out_tokens / 1000) * m["usd_out"]
    return latency_ms, cost_usd

# --- EL PRESUPUESTO de la busqueda semantica de Mercado (la restriccion de diseno) ---
LATENCY_BUDGET_MS   = 800        # arriba de esto el usuario percibe lentitud y abandona
MONTHLY_COST_BUDGET = 3000.0     # dolares/mes que el negocio asigno a la feature
SEARCHES_PER_DAY    = 100_000
IN_TOK = 300

def fits(value, budget):
    return "OK   " if value <= budget else "VIOLA"

# --- Compuerta 1: el LATENCY BUDGET (por llamada) ---
# Se prueba con una query tipica (150 tok de salida) y una pesada (400 tok).
print("== Latency budget (<= 800 ms por busqueda) ==")
print(f"{'option':<14}{'query':<9}{'latency_ms':>12}{'verdict':>9}")
for model in ("cheap", "strong"):
    for label, out_tok in (("typical", 150), ("heavy", 400)):
        lat, _ = call_llm(model, IN_TOK, out_tok)
        print(f"all_{model:<10}{label:<9}{lat:>12.1f}{fits(lat, LATENCY_BUDGET_MS):>9}")

# --- Compuerta 2: el COST BUDGET (mensual, con la query tipica como unidad) ---
print(f"\n== Cost budget (<= ${MONTHLY_COST_BUDGET:,.0f}/mes, {SEARCHES_PER_DAY:,} busquedas/dia) ==")
print(f"{'option':<14}{'unit_usd':>10}{'monthly_usd':>13}{'verdict':>9}")
for model in ("cheap", "strong"):
    _, unit = call_llm(model, IN_TOK, 150)
    monthly = unit * SEARCHES_PER_DAY * 30
    print(f"all_{model:<10}{unit:>10.6f}{monthly:>13,.0f}{fits(monthly, MONTHLY_COST_BUDGET):>9}")

Qué esperar. Al correrlo:

== Latency budget (<= 800 ms por busqueda) ==
option        query      latency_ms  verdict
all_cheap     typical         150.0    OK   
all_cheap     heavy           250.0    OK   
all_strong    typical         750.0    OK   
all_strong    heavy          1500.0    VIOLA

== Cost budget (<= $3,000/mes, 100,000 busquedas/dia) ==
option          unit_usd  monthly_usd  verdict
all_cheap       0.000840        2,520    OK   
all_strong      0.008400       25,200    VIOLA

Aquí está el puente con sus carteles, y aquí está por qué la opción ingenua no cabe. Léelo por compuerta.

El latency budget. El cheap model pasa siempre: 150 ms la típica, 250 ms la pesada, ambos bajo 800. El strong model pasa por poco en la típica (750 ms, apenas debajo del cartel) y viola en la pesada: 1500 ms, casi el doble del presupuesto. Esto ya te dice algo importante: mandar todo al strong model no solo es caro, es que en las queries que generan respuestas largas rompe el presupuesto de latencia. El usuario que busca algo que produce una respuesta larga espera un segundo y medio mirando una pantalla que no responde. El cheap model no tiene ese problema —pero (adelanto de la frontera con el módulo 3) el cheap model puede dar peor calidad, y esa es otra restricción que un presupuesto de latencia no ve—.

El cost budget. Aquí la opción ingenua se cae con estrépito. El cheap model cabe: $2,520/mes, bajo el presupuesto de $3,000. Pero el strong model —la opción de "usa el mejor modelo para todo, por si acaso"— cuesta $25,200/mes, más de ocho veces el presupuesto. Ese es el número de la lección 2, ahora con un veredicto: VIOLA. La feature, tal como la diseñaste ingenuamente, no es rentable: se come más de ocho veces el dinero que el negocio le dio.

Junta las dos compuertas y tienes el problema del módulo planteado con precisión: "todo al strong model" viola los dos presupuestos —latencia en las queries pesadas, costo a escala—. Pero "todo al cheap model" tampoco es la respuesta: cabe en los dos presupuestos, sí, pero al costo de la calidad (que aquí no medimos, es el módulo 3). Ninguno de los dos extremos sirve. La arquitectura que respeta el presupuesto sin tirar la calidad es una que usa el barato donde alcanza y el caro solo donde hace falta, y que no vuelve a pagar lo que ya calculó. Eso es, exactamente, el cascade (lección 4) y la caché (lección 5). El presupuesto es lo que hace obligatorias esas técnicas.

Profundización: cómo se fija un presupuesto (y qué NO es)

De dónde sale el número de latencia. El 800 ms no es arbitrario, pero tampoco es una ley universal: sale del contexto. Hay evidencia de sobra de que, en una búsqueda interactiva, la latencia percibida arriba de cierto umbral (del orden de cientos de milisegundos a un segundo) empieza a costar abandonos y satisfacción. El número exacto depende de tu feature: una búsqueda en el camino crítico de cada tecleo tiene un presupuesto más estricto que un "describe tu producto" que el vendedor pide una vez. La regla: fija el latency budget por lo que el usuario tolera en ESA feature, no por lo que el modelo casualmente tarda. El presupuesto manda; el diseño se adapta a él, no al revés.

De dónde sale el número de costo. El cost budget viene del negocio, no de la ingeniería: es la fracción del margen (o del presupuesto de producto) que la feature puede consumir sin dejar de valer la pena. Si cada búsqueda semántica ayuda a cerrar ventas que dejan cierto margen, el costo de la búsqueda tiene que ser una porción pequeña de ese margen, o la feature destruye valor en vez de crearlo. La regla: el cost budget se negocia con quien conoce el margen, y luego la arquitectura tiene que caber en él. Un presupuesto que la ingeniería se inventa sin hablar con el negocio es un cartel sin autoridad.

Presupuesto de latencia: promedio, o cola. Un matiz honesto sobre el latency budget: ¿el umbral aplica al promedio, o al peor caso? La respuesta seria es a un percentil alto (p95 o p99): no basta con que la búsqueda promedio tarde 300 ms si una de cada veinte tarda 2 segundos, porque esa de cada veinte es un usuario furioso. En este módulo simplificamos y medimos latencias por-query, pero recuérdalo: un presupuesto de latencia serio se fija sobre la cola, no sobre el promedio, porque la cola es donde vive la mala experiencia. (El análisis de percentiles a fondo es de system-design; aquí basta con saber que el presupuesto se mide donde duele.)

Lo que un presupuesto NO es. No es un objetivo aspiracional ("ojalá tarde poco"): es un límite que se verifica y que, si se viola, bloquea el diseño —como el puente que no deja pasar el camión de once toneladas—. Y no es un sustituto de la calidad: el latency budget y el cost budget dicen que la feature es rápida y barata, pero no que sus respuestas sean buenas. Esa tercera compuerta —el eval gate— es todo el módulo 3, y es tan obligatoria como estas dos. Una feature de IA bien arquitecta pasa tres compuertas: cabe en su presupuesto de latencia, cabe en su presupuesto de costo, y cabe en su umbral de calidad. Este módulo te da las dos primeras.

Errores comunes

No fijar un presupuesto (de omisión). Qué pasa: el equipo diseña la feature sin un umbral explícito de latencia ni de costo, confiando en que "saldrá bien". La latencia y el costo solo se vuelven visibles cuando un usuario se queja o llega la factura, y para entonces la arquitectura ya está montada y es cara de cambiar. Por qué pasa: fijar el presupuesto exige hablar con el negocio (costo) y decidir qué tolera el usuario (latencia), y es más fácil saltarse ese paso y programar. Cómo detectarlo: si no puedes decir en un número cuánto puede tardar y cuánto puede costar tu feature, no tienes presupuesto —tienes una esperanza—. Cómo corregirlo: fija los dos umbrales antes de elegir la arquitectura, para que la arquitectura tenga a qué rendir cuentas.

Diseñar para el promedio e ignorar la cola (de latencia). Qué pasa: el presupuesto se verifica contra la query típica (150 tokens, 750 ms, "pasa") y se ignora la pesada (400 tokens, 1500 ms, viola). El promedio se ve bien y la feature igual frustra a los usuarios cuyas queries generan respuestas largas. Por qué pasa: la query típica es la que uno prueba, y la pesada aparece en producción con volumen real. Cómo detectarlo: si tu verificación de presupuesto solo usó un tamaño de query, no probaste la cola. Cómo corregirlo: pesa el presupuesto contra la query pesada (y en serio, contra un percentil alto), no solo contra la típica —la cola es donde el presupuesto se rompe—.

Confundir el presupuesto con la calidad (de alcance). Qué pasa: el equipo ve que el cheap model cabe en los dos presupuestos y concluye "listo, usemos el cheap para todo". Pasa las compuertas de latencia y costo, pero ignora que el cheap puede dar respuestas peores —viola una compuerta de calidad que nadie puso—. Por qué pasa: latencia y costo son fáciles de medir y el presupuesto los hace visibles; la calidad es más difícil y no tiene (todavía) su compuerta. Cómo detectarlo: si tu decisión de modelo se tomó solo con latencia y costo, te falta la tercera compuerta. Cómo corregirlo: recuerda que el presupuesto de este módulo son dos de las tres restricciones; la calidad (el eval gate, módulo 3) es la tercera, y "barato y rápido pero malo" no es una feature aceptable.

Ejercicios

Ejercicio 1 — Fija un presupuesto para otra feature. El generador "describe tu producto" para vendedores de Mercado no está en el camino crítico de nadie: el vendedor lo pide una vez, al crear un producto, y puede esperar. Genera respuestas largas (600 tokens). Propón un latency budget y un cost budget razonables para esta feature, distintos a los de la búsqueda, y justifica por qué difieren.

Ver solución

Latency budget: más laxo, por ejemplo 5,000 ms (o incluso async, sin presupuesto de latencia síncrona). Justificación: a diferencia de la búsqueda —que vive en el camino crítico de cada tecleo y donde 800 ms ya es mucho—, el "describe tu producto" es una acción deliberada y ocasional. El vendedor entiende que "generar una descripción" tome unos segundos, igual que entiende que subir una foto tarde. Con 600 tokens de salida, el strong model tardaría 300 + 600×3 = 1900 ms, que cabe en un presupuesto laxo. (Mejor aún, es un candidato perfecto para async —lección 6—: se saca del camino crítico y el vendedor ni espera.)

Cost budget: más caro por llamada, pero de bajo volumen total. Justificación: los vendedores crean productos con mucha menos frecuencia que los clientes buscan, así que el volumen es órdenes de magnitud menor. Una descripción cuesta más por llamada (600 tokens de salida al strong = 0.5×0.008 + 0.6×0.040 = $0.028), pero si se generan, digamos, 2,000 al día, el mensual es 0.028 × 2,000 × 30 = $1,680/mes —manejable—. La diferencia clave: el presupuesto se fija por el contexto de uso (crítico vs ocasional, alto vs bajo volumen), no por el modelo. La misma llamada cara es un problema en la búsqueda de alto volumen y un no-problema en el generador de bajo volumen.

Ejercicio 2 — Ajusta el volumen y revisa el veredicto. La búsqueda semántica de Mercado arranca con solo 8,000 búsquedas al día (es un piloto). Con el strong model (unit_cost $0.008400 por búsqueda típica) y el mismo presupuesto de $3,000/mes, ¿pasa o viola el cost budget? ¿A qué volumen diario el strong model empieza a violarlo?

Ver solución
  • A 8,000/día: monthly = 0.008400 × 8,000 × 30 = $2,016/mes. Como $2,016 ≤ $3,000, pasa (OK).
  • Volumen umbral: buscamos el volumen V donde el mensual iguala el presupuesto: 0.008400 × V × 30 = 3,000, de donde V = 3,000 / (0.008400 × 30) = 3,000 / 0.252 ≈ 11,905 búsquedas/día.

Es decir: con el strong model, la feature cabe en el presupuesto de costo hasta unas ~11,900 búsquedas diarias, y a partir de ahí lo viola. La moraleja para el módulo: el veredicto de un presupuesto de costo depende del volumen, y el volumen crece con el éxito de la feature. Una arquitectura ingenua que "cabe" en el piloto (8,000/día) revienta el presupuesto justo cuando la feature se vuelve popular (100,000/día). Por eso no basta con caber hoy: hay que dejar headroom para el crecimiento —y ahí entran el cascade y la caché, que dan margen en vez de dejarte al borde del presupuesto—.

Ejercicio 3 — La compuerta que faltó. Un equipo presenta su búsqueda semántica: "corre en el cheap model, tarda 150 ms (pasa el latency budget) y cuesta $2,520/mes (pasa el cost budget). Está lista para producción." Falta una verificación crítica. ¿Cuál es, y por qué las dos compuertas de este módulo no bastan para aprobar la feature?

Ver solución

Falta la compuerta de calidad (el eval gate): ¿las respuestas del cheap model son lo bastante buenas? Las dos compuertas de este módulo —latencia y costo— confirman que la feature es rápida y barata, pero no dicen nada sobre si la búsqueda semántica devuelve resultados relevantes. Un cheap model podría reordenar mal los productos —poner lo irrelevante arriba— y aun así pasar las dos compuertas de este módulo con banderas al viento: es rapidísimo y baratísimo, simplemente porque es peor.

Por qué las dos compuertas no bastan: latencia y costo son propiedades operacionales (qué tan rápido, qué tan caro), no de calidad (qué tan bien). Una feature de IA necesita las tres:

  1. Latency budget (este módulo): ¿responde a tiempo?
  2. Cost budget (este módulo): ¿cabe en el margen?
  3. Eval gate (módulo 3): ¿la respuesta es buena?

Aprobar con solo las dos primeras es el error del ejercicio: se optimizó latencia y costo hasta el extremo (cheap para todo) sin verificar que la calidad sobrevivió. La respuesta correcta del equipo sería: "pasa latencia y costo; ahora hay que correr el eval-set para confirmar que el cheap model mantiene la relevancia —y si no, escalar las queries difíciles al strong model (cascade), que es como se respetan las tres compuertas a la vez—".

Resumen y siguiente paso

En esta lección convertiste las dos restricciones medibles en una regla de diseño: el latency budget y el cost budget, umbrales explícitos que la arquitectura debe respetar. Con la analogía del puente viste que un presupuesto no es una opinión sino un límite que se verifica: se pesa el diseño y pasa o viola, como el camión contra el cartel de 10 toneladas. Escribiste la compuerta fits(value, budget) y pasaste por ella la opción ingenua de Mercado: "todo al strong model" viola los dos presupuestos —la latencia en las queries pesadas (1500 ms > 800) y el costo a escala ($25,200 > $3,000)—, mientras que "todo al cheap model" cabe en ambos pero (adelanto) sacrifica la calidad. Aprendiste de dónde salen los números (latencia del contexto de uso, costo del margen del negocio), que el presupuesto de latencia serio se fija sobre la cola y no el promedio, y que estas dos compuertas son dos de las tres que toda feature de IA necesita —la tercera, la calidad, es el módulo 3—.

Antes de avanzar deberías poder: definir el latency budget y el cost budget de una feature como umbrales explícitos; escribir y correr una compuerta que verifique si una opción cabe o viola; explicar por qué la opción ingenua viola los dos presupuestos de la búsqueda de Mercado; y reconocer que latencia y costo no cubren la calidad, que tiene su propia compuerta.

Lo que sigue es la primera técnica para respetar el presupuesto de costo sin tirar la calidad. En la lección 4 vas a diseñar el model cascade: un clasificador barato mira cada query, manda las fáciles al modelo barato y solo las difíciles al caro —el call center que atiende con el junior y escala al senior lo complicado—. Vas a medir el ahorro frente a "todo al caro": cuánto baja el costo y la latencia, y —el detalle honesto— por qué el p95 casi no baja, porque las queries difíciles siguen yendo al modelo lento. Es el primer gran mecanismo para meter la feature dentro de su presupuesto.

Recursos